@amalgm/chat 0.1.0 → 0.1.2

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 CHANGED
@@ -17,7 +17,7 @@ itself — independent of any particular host, harness, or UI. If it spawns a
17
17
  process, opens a socket, or touches a disk, it is a host adapter behind a
18
18
  port, not a law.
19
19
 
20
- ## The seven jobs
20
+ ## The eight jobs
21
21
 
22
22
  1. **The event grammar.** One canonical vocabulary (`text.delta` …
23
23
  `usage.final` … `done`) that every harness's native events are translated
@@ -49,6 +49,10 @@ port, not a law.
49
49
  the ownership fork (amalgm billing → proxy meters via egress; byok /
50
50
  provider_auth → local logging), and the cost rules (unknown cost is
51
51
  null, never zero).
52
+ 8. **Session-bound relays.** Amalgm-auth turns reach the billing proxy only
53
+ through a per-session egress token, and harness MCP traffic reaches only
54
+ servers frozen into that session's contract. Request paths never choose
55
+ an arbitrary credential or destination.
52
56
 
53
57
  ## Axioms
54
58
 
@@ -81,13 +85,17 @@ port, not a law.
81
85
  10. **Amalgm dogfoods its own SDK.** The end state (spec §10): ChatView's
82
86
  data layer imports nothing but `@amalgm/chat`; the engine host mounts
83
87
  these laws instead of containing them.
88
+ 11. **Relay authority comes from the frozen contract.** Egress replaces the
89
+ session token with the host's proxy credential and stamps usage identity;
90
+ MCP relay replaces caller auth with the selected frozen server headers.
91
+ Neither relay accepts an upstream URL from the request.
84
92
 
85
93
  ## Five surfaces
86
94
 
87
95
  | Surface | Form | Status |
88
96
  |---|---|---|
89
97
  | SDK | `@amalgm/chat` (this package's `src/`) | porting |
90
- | API | router factory a host mounts | after SDK |
98
+ | API | router factory a host mounts | chat payloads served |
91
99
  | CLI | `amalgm-chat` diagnostic commands | after SDK |
92
100
  | MCP | tool definitions + dispatch | after SDK |
93
101
  | Skill | `skills/chat/SKILL.md` | after SDK |
package/README.md CHANGED
@@ -18,6 +18,7 @@ src/contract/ harnesses, model identities, freeze algebra, chatInput,
18
18
  src/warm/ warm-payload laws: revision, fingerprint, cache policies
19
19
  src/usage/ token algebra, turn finalization, ownership fork, catalog
20
20
  src/normalizers/ claude · codex · opencode · cursor · pi → the grammar
21
+ src/api/ fetch adapters over SDK services
21
22
  src/ports.ts the ports a host injects (clock, hash, uuid)
22
23
  host/ the reference host: adapters, tooling, orchestration,
23
24
  chat-server shell (effectful, imports the laws from dist)
@@ -31,6 +32,30 @@ npm install
31
32
  npm test # build + every exam
32
33
  ```
33
34
 
35
+ ## Serve the machine chat-payload API
36
+
37
+ ```js
38
+ import { createChatPayloadApi } from '@amalgm/chat/api';
39
+ import { ChatPayloadStore } from '@amalgm/chat/warm';
40
+
41
+ const payloads = new ChatPayloadStore({
42
+ store: {
43
+ read: () => readPayloadMapFromYourHost(),
44
+ write: (next) => writePayloadMapFromYourHost(next),
45
+ },
46
+ clockIso: () => new Date().toISOString(),
47
+ clockMs: () => Date.now(),
48
+ emit: (event) => publishStateEventFromYourHost(event),
49
+ });
50
+
51
+ const api = createChatPayloadApi(payloads);
52
+ const response = await api(new Request('http://local/chat-payloads'));
53
+ ```
54
+
55
+ The adapter preserves the engine's `/chat-payloads` list, lookup, and write
56
+ contract. The host chooses persistence, clocks, and state-event delivery;
57
+ record normalization, retention, and route responses stay in this package.
58
+
34
59
  Rules of the house: `src/` is pure — one runtime dependency (zod, axiom 9),
35
60
  no `node:*`, no env, no ambient clock; hosts inject effects through
36
61
  `src/ports.ts`. `host/` is effectful by design but never re-implements a
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Fetch API adapter for engine
3
+ * `runtime/scripts/amalgm-mcp/server/routes/chat-payloads.js`.
4
+ * Route matching and response shapes are byte-for-byte laws; persistence and
5
+ * clocks are already behind `ChatPayloadStore` ports.
6
+ */
7
+ import type { ChatPayloadStore } from '../warm/store.js';
8
+ export type ChatPayloadApi = (request: Request) => Promise<Response>;
9
+ export declare function createChatPayloadApi(store: ChatPayloadStore): ChatPayloadApi;
10
+ //# sourceMappingURL=chat-payloads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-payloads.d.ts","sourceRoot":"","sources":["../../src/api/chat-payloads.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,GAAG,cAAc,CAoC5E"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Fetch API adapter for engine
3
+ * `runtime/scripts/amalgm-mcp/server/routes/chat-payloads.js`.
4
+ * Route matching and response shapes are byte-for-byte laws; persistence and
5
+ * clocks are already behind `ChatPayloadStore` ports.
6
+ */
7
+ export function createChatPayloadApi(store) {
8
+ return async (request) => {
9
+ try {
10
+ const url = new URL(request.url);
11
+ const method = request.method.toUpperCase();
12
+ if (url.pathname === '/chat-payloads' && method === 'GET') {
13
+ const id = url.searchParams.get('id');
14
+ const payload = id ? store.get(id) : null;
15
+ return json(payload ? 200 : (id ? 404 : 200), {
16
+ ...(id && payload ? { payload } : {}),
17
+ payloads: store.list(),
18
+ ...(id && !payload ? { error: 'Chat payload not found' } : {}),
19
+ });
20
+ }
21
+ if (url.pathname === '/chat-payloads/get' && method === 'POST') {
22
+ const body = await jsonBody(request);
23
+ const payload = store.get(value(body, 'id') || value(body, 'payloadId'));
24
+ if (!payload)
25
+ return json(404, { error: 'Chat payload not found' });
26
+ return json(200, { payload });
27
+ }
28
+ if (url.pathname === '/chat-payloads' && (method === 'PUT' || method === 'POST')) {
29
+ const payload = store.write(await jsonBody(request));
30
+ return json(200, { success: true, payload });
31
+ }
32
+ return new Response('Not found', {
33
+ status: 404,
34
+ headers: { 'content-type': 'text/plain' },
35
+ });
36
+ }
37
+ catch {
38
+ return json(500, { error: 'Internal server error' });
39
+ }
40
+ };
41
+ }
42
+ async function jsonBody(request) {
43
+ const raw = await request.text();
44
+ return raw ? JSON.parse(raw) : {};
45
+ }
46
+ function value(input, key) {
47
+ return input && typeof input === 'object' && !Array.isArray(input)
48
+ ? input[key]
49
+ : undefined;
50
+ }
51
+ function json(status, body) {
52
+ return new Response(JSON.stringify(body), {
53
+ status,
54
+ headers: { 'content-type': 'application/json' },
55
+ });
56
+ }
57
+ //# sourceMappingURL=chat-payloads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-payloads.js","sourceRoot":"","sources":["../../src/api/chat-payloads.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** @amalgm/chat API adapters — thin doors over the SDK laws. */
2
+ export type { ChatPayloadApi } from './chat-payloads.js';
3
+ export { createChatPayloadApi } from './chat-payloads.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAEhE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** @amalgm/chat API adapters — thin doors over the SDK laws. */
2
+ export { createChatPayloadApi } from './chat-payloads.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAGhE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -10,7 +10,9 @@
10
10
  * freeze algebra, chatInput, payload merge, input
11
11
  * warm/ warm-payload laws: revision, fingerprint, cache policies
12
12
  * usage/ token algebra, turn finalization, ownership fork, catalog
13
+ * api/ thin fetch adapters over SDK services
13
14
  * normalizers/ native harness events → the grammar (wave B)
15
+ * relay/ session-bound egress and MCP forwarding laws
14
16
  *
15
17
  * Hosts inject effects through the port types in `ports.ts` (axiom 7).
16
18
  * Prefer the subpath exports (`@amalgm/chat/<module>`) — name collisions
@@ -23,5 +25,7 @@ export * as turns from './turns/index.js';
23
25
  export * as contract from './contract/index.js';
24
26
  export * as warm from './warm/index.js';
25
27
  export * as usage from './usage/index.js';
28
+ export * as api from './api/index.js';
29
+ export * as relay from './relay/index.js';
26
30
  export type { ClockMsPort, ClockIsoPort, Sha256HexPort, RandomUuidPort } from './ports.js';
27
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -10,7 +10,9 @@
10
10
  * freeze algebra, chatInput, payload merge, input
11
11
  * warm/ warm-payload laws: revision, fingerprint, cache policies
12
12
  * usage/ token algebra, turn finalization, ownership fork, catalog
13
+ * api/ thin fetch adapters over SDK services
13
14
  * normalizers/ native harness events → the grammar (wave B)
15
+ * relay/ session-bound egress and MCP forwarding laws
14
16
  *
15
17
  * Hosts inject effects through the port types in `ports.ts` (axiom 7).
16
18
  * Prefer the subpath exports (`@amalgm/chat/<module>`) — name collisions
@@ -23,4 +25,6 @@ export * as turns from './turns/index.js';
23
25
  export * as contract from './contract/index.js';
24
26
  export * as warm from './warm/index.js';
25
27
  export * as usage from './usage/index.js';
28
+ export * as api from './api/index.js';
29
+ export * as relay from './relay/index.js';
26
30
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Session-bound relay laws.
3
+ * Engine references:
4
+ * - runtime/scripts/chat-core/egress.js
5
+ * - runtime/scripts/chat-core/tooling/mcp-relay.js
6
+ * - runtime/scripts/chat-core/tooling/mcp-bundle.js
7
+ * - runtime/scripts/chat-core/server.js:115-133
8
+ */
9
+ export interface RelayHeader {
10
+ readonly name: string;
11
+ readonly value: string;
12
+ }
13
+ export interface RelayServer {
14
+ readonly name: string;
15
+ readonly type: 'http' | 'sse';
16
+ readonly url: string;
17
+ readonly headers: readonly RelayHeader[];
18
+ }
19
+ export interface ChatRelayContract {
20
+ readonly sessionId: string;
21
+ readonly userId?: string;
22
+ readonly computerId?: string;
23
+ readonly agentId?: string;
24
+ readonly harness?: string;
25
+ readonly authMethod: string;
26
+ readonly modelId?: string;
27
+ readonly usageModelId?: string;
28
+ readonly cwd?: string;
29
+ readonly usageOwner?: string;
30
+ readonly auth?: {
31
+ readonly tokenRef?: string | null;
32
+ };
33
+ readonly mcpServers?: readonly unknown[];
34
+ }
35
+ export interface ChatRelayTurn {
36
+ readonly turnId?: string;
37
+ readonly assistantMessageId?: string;
38
+ }
39
+ export type RelayFetchPort = (input: string, init: RequestInit) => Promise<Response>;
40
+ export interface ChatRelayApiOptions {
41
+ readonly contractForSession: (sessionId: string) => ChatRelayContract | null;
42
+ readonly turnForSession?: (sessionId: string) => ChatRelayTurn | null;
43
+ readonly proxyCredentials: () => Promise<{
44
+ readonly baseUrl: string;
45
+ readonly token: string;
46
+ }>;
47
+ readonly defaultMcpServer?: (contract: ChatRelayContract) => unknown;
48
+ readonly fetch: RelayFetchPort;
49
+ }
50
+ export declare function parseEgressPath(pathname: unknown): {
51
+ sessionId: string;
52
+ upstreamPath: string;
53
+ } | null;
54
+ export declare function parseMcpRelayPath(pathname: unknown): {
55
+ sessionId: string;
56
+ serverName: string;
57
+ } | null;
58
+ export declare function metadataHeaders(contract: ChatRelayContract, turn?: ChatRelayTurn | null): Record<string, string>;
59
+ export declare function safeMcpServerName(name: unknown): string;
60
+ export declare function headerArrayToRecord(headers: unknown): Record<string, string>;
61
+ export declare function normalizeMcpServer(server: unknown): RelayServer | null;
62
+ export declare function mcpServers(contract: ChatRelayContract, defaultServer?: unknown): RelayServer[];
63
+ export declare function findMcpRelayTarget(contract: ChatRelayContract, serverName: unknown, defaultServer?: unknown): RelayServer | null;
64
+ export declare function createChatRelayApi(options: ChatRelayApiOptions): (request: Request) => Promise<Response>;
65
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Session-bound relay laws.
3
+ * Engine references:
4
+ * - runtime/scripts/chat-core/egress.js
5
+ * - runtime/scripts/chat-core/tooling/mcp-relay.js
6
+ * - runtime/scripts/chat-core/tooling/mcp-bundle.js
7
+ * - runtime/scripts/chat-core/server.js:115-133
8
+ */
9
+ const MCP_HOP_HEADERS = new Set([
10
+ 'connection',
11
+ 'content-length',
12
+ 'host',
13
+ 'keep-alive',
14
+ 'proxy-authenticate',
15
+ 'proxy-authorization',
16
+ 'te',
17
+ 'trailer',
18
+ 'transfer-encoding',
19
+ 'upgrade',
20
+ ]);
21
+ const EGRESS_DROP_REQUEST_HEADERS = new Set([
22
+ 'host', 'authorization', 'x-api-key', 'connection', 'content-length', 'accept-encoding',
23
+ ]);
24
+ const EGRESS_DROP_RESPONSE_HEADERS = new Set(['connection', 'content-encoding', 'transfer-encoding']);
25
+ export function parseEgressPath(pathname) {
26
+ const parts = String(pathname || '').split('/').filter(Boolean);
27
+ if (parts[0] !== 'egress' || !parts[1])
28
+ return null;
29
+ return { sessionId: decodeURIComponent(parts[1]), upstreamPath: `/${parts.slice(2).join('/')}` };
30
+ }
31
+ export function parseMcpRelayPath(pathname) {
32
+ const parts = String(pathname || '').split('/').filter(Boolean);
33
+ if (parts[0] !== 'mcp-relay' || !parts[1] || !parts[2])
34
+ return null;
35
+ return { sessionId: decodeURIComponent(parts[1]), serverName: decodeURIComponent(parts[2]) };
36
+ }
37
+ export function metadataHeaders(contract, turn = null) {
38
+ return {
39
+ 'x-amalgm-session-id': contract.sessionId,
40
+ 'x-amalgm-message-id': turn?.assistantMessageId || turn?.turnId || '',
41
+ 'x-amalgm-turn-id': turn?.turnId || '',
42
+ 'x-amalgm-agent-id': contract.agentId || '',
43
+ 'x-amalgm-harness-id': contract.harness || '',
44
+ 'x-amalgm-auth-method': contract.authMethod,
45
+ 'x-amalgm-model-id': contract.usageModelId || contract.modelId || '',
46
+ 'x-amalgm-cwd': contract.cwd || '',
47
+ 'x-amalgm-usage-owner': contract.usageOwner || '',
48
+ };
49
+ }
50
+ export function safeMcpServerName(name) {
51
+ return String(name || '')
52
+ .trim()
53
+ .replace(/[^A-Za-z0-9_.-]+/g, '_')
54
+ .replace(/^_+|_+$/g, '')
55
+ || 'mcp';
56
+ }
57
+ export function headerArrayToRecord(headers) {
58
+ const out = {};
59
+ for (const header of Array.isArray(headers) ? headers : []) {
60
+ const value = header;
61
+ const name = String(value?.name || '').trim();
62
+ if (name)
63
+ out[name] = String(value?.value || '');
64
+ }
65
+ return out;
66
+ }
67
+ export function normalizeMcpServer(server) {
68
+ if (!server || typeof server !== 'object')
69
+ return null;
70
+ const input = server;
71
+ const name = safeMcpServerName(input.name);
72
+ const url = String(input.url || '').trim();
73
+ if (!name || !url)
74
+ return null;
75
+ const rawHeaders = Array.isArray(input.headers)
76
+ ? input.headers
77
+ : Object.entries(input.headers && typeof input.headers === 'object' ? input.headers : {})
78
+ .filter(([headerName, value]) => headerName && value != null)
79
+ .map(([headerName, value]) => ({ name: headerName, value: String(value) }));
80
+ return {
81
+ name,
82
+ type: String(input.type || '').toLowerCase() === 'sse' ? 'sse' : 'http',
83
+ url,
84
+ headers: rawHeaders.map((header) => ({
85
+ name: String(header.name || ''),
86
+ value: String(header.value || ''),
87
+ })),
88
+ };
89
+ }
90
+ export function mcpServers(contract, defaultServer) {
91
+ const byName = new Map();
92
+ const add = (server) => {
93
+ const normalized = normalizeMcpServer(server);
94
+ if (normalized)
95
+ byName.set(normalized.name, normalized);
96
+ };
97
+ if (defaultServer)
98
+ add(defaultServer);
99
+ for (const server of Array.isArray(contract.mcpServers) ? contract.mcpServers : [])
100
+ add(server);
101
+ return [...byName.values()];
102
+ }
103
+ export function findMcpRelayTarget(contract, serverName, defaultServer) {
104
+ const clean = safeMcpServerName(serverName);
105
+ return mcpServers(contract, defaultServer).find((server) => server.name === clean) || null;
106
+ }
107
+ export function createChatRelayApi(options) {
108
+ return async (request) => {
109
+ const url = new URL(request.url);
110
+ if (request.method === 'GET' && url.pathname === '/egress') {
111
+ return json(200, { service: 'egress', sessionBound: true, route: '/egress/:session/*' });
112
+ }
113
+ if (request.method === 'GET' && url.pathname === '/mcp-relay') {
114
+ return json(200, { service: 'mcp-relay', sessionBound: true, route: '/mcp-relay/:session/:server' });
115
+ }
116
+ const egress = parseEgressPath(url.pathname);
117
+ if (egress)
118
+ return forwardEgress(request, url, egress, options);
119
+ const relay = parseMcpRelayPath(url.pathname);
120
+ if (relay)
121
+ return forwardMcpRelay(request, url, relay, options);
122
+ return json(404, { error: 'Not found' });
123
+ };
124
+ }
125
+ async function forwardEgress(request, url, route, options) {
126
+ const contract = options.contractForSession(route.sessionId);
127
+ if (!contract || contract.authMethod !== 'amalgm') {
128
+ return json(404, { error: 'No Amalgm egress session', sessionId: route.sessionId });
129
+ }
130
+ const authorization = request.headers.get('authorization') || '';
131
+ const bearer = authorization.replace(/^Bearer\s+/i, '').trim();
132
+ const provided = bearer || (request.headers.get('x-api-key') || '').trim();
133
+ if (!contract.auth?.tokenRef || provided !== contract.auth.tokenRef) {
134
+ return json(401, { error: 'Invalid egress token' });
135
+ }
136
+ const proxy = await options.proxyCredentials();
137
+ const headers = copyHeaders(request.headers, EGRESS_DROP_REQUEST_HEADERS);
138
+ Object.assign(headers, metadataHeaders(contract, options.turnForSession?.(route.sessionId) || null));
139
+ headers.Authorization = `Bearer ${proxy.token}`;
140
+ const body = await requestBody(request);
141
+ const response = await options.fetch(`${proxy.baseUrl.replace(/\/$/, '')}${route.upstreamPath}${url.search}`, { method: request.method, headers, ...(body ? { body } : {}) });
142
+ return copyResponse(response, EGRESS_DROP_RESPONSE_HEADERS);
143
+ }
144
+ async function forwardMcpRelay(request, url, route, options) {
145
+ const contract = options.contractForSession(route.sessionId);
146
+ if (!contract)
147
+ return json(404, { error: 'No MCP relay session', sessionId: route.sessionId });
148
+ const target = findMcpRelayTarget(contract, route.serverName, options.defaultMcpServer?.(contract));
149
+ if (!target)
150
+ return json(404, { error: 'Unknown MCP server', serverName: route.serverName });
151
+ const headers = copyHeaders(request.headers, new Set([...MCP_HOP_HEADERS, 'authorization']));
152
+ Object.assign(headers, headerArrayToRecord(target.headers), {
153
+ 'x-amalgm-session-id': contract.sessionId,
154
+ 'x-amalgm-user-id': contract.userId || '',
155
+ 'x-amalgm-computer-id': contract.computerId || '',
156
+ });
157
+ for (const key of Object.keys(headers))
158
+ if (!headers[key])
159
+ delete headers[key];
160
+ const body = await requestBody(request);
161
+ const response = await options.fetch(`${target.url}${url.search}`, {
162
+ method: request.method,
163
+ headers,
164
+ ...(body ? { body } : {}),
165
+ redirect: 'manual',
166
+ });
167
+ return copyResponse(response, MCP_HOP_HEADERS);
168
+ }
169
+ function copyHeaders(headers, drop) {
170
+ const out = {};
171
+ headers.forEach((value, name) => {
172
+ if (!drop.has(name.toLowerCase()))
173
+ out[name] = value;
174
+ });
175
+ return out;
176
+ }
177
+ async function requestBody(request) {
178
+ if (request.method === 'GET' || request.method === 'HEAD')
179
+ return undefined;
180
+ const body = await request.arrayBuffer();
181
+ return body.byteLength > 0 ? body : undefined;
182
+ }
183
+ function copyResponse(response, drop) {
184
+ const headers = new Headers();
185
+ response.headers.forEach((value, name) => {
186
+ if (!drop.has(name.toLowerCase()))
187
+ headers.set(name, value);
188
+ });
189
+ return new Response(response.body, { status: response.status, headers });
190
+ }
191
+ function json(status, body) {
192
+ return new Response(JSON.stringify(body), {
193
+ status,
194
+ headers: { 'content-type': 'application/json', 'cache-control': 'no-cache' },
195
+ });
196
+ }
197
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"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"}
@@ -13,4 +13,6 @@ export type { LaunchEnvelopeCacheEntry } from './client-cache.js';
13
13
  export { CACHE_WARM_DELAY_MS, machineKey, launchEnvelopeCacheKey, launchEnvelopePayloadKey, usableEntry, } from './client-cache.js';
14
14
  export type { ChatPayloadStoreRecord } from './store-policy.js';
15
15
  export { CHAT_PAYLOADS_META_KEY, CHAT_PAYLOADS_RESOURCE, CHAT_PAYLOAD_TTL_MS, CHAT_PAYLOAD_MAX_RECORDS, isPlainObject, cleanString, normalizeChatPayloadRecord, recordTimestamp, sweepChatPayloads, } from './store-policy.js';
16
+ export type { ChatPayloadMapStore, ChatPayloadStateEvent, ChatPayloadStoreOptions, } from './store.js';
17
+ export { ChatPayloadStore } from './store.js';
16
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/warm/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EACV,SAAS,EACT,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,8BAA8B,EAC9B,eAAe,EACf,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,UAAU,EACV,+BAA+B,EAC/B,iCAAiC,EACjC,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,aAAa,EACb,WAAW,EACX,8BAA8B,EAC9B,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,sBAAsB,EACtB,wBAAwB,EACxB,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,0BAA0B,EAC1B,eAAe,EACf,iBAAiB,GAClB,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/warm/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EACV,SAAS,EACT,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,8BAA8B,EAC9B,eAAe,EACf,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,UAAU,EACV,+BAA+B,EAC/B,iCAAiC,EACjC,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,aAAa,EACb,WAAW,EACX,8BAA8B,EAC9B,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,sBAAsB,EACtB,wBAAwB,EACxB,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,0BAA0B,EAC1B,eAAe,EACf,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -8,4 +8,5 @@ export { CONFIRMED_WRITE_TTL_MS, machinePayloadWriteKey, chatPayloadRevision, is
8
8
  export { ENVELOPE_TTL_MS, MAX_ENVELOPES, stableValue, fingerprintLaunchEnvelopeInput, envelopeExpiresAt, pruneAgentLaunchEnvelopes, } from './envelope-cache.js';
9
9
  export { CACHE_WARM_DELAY_MS, machineKey, launchEnvelopeCacheKey, launchEnvelopePayloadKey, usableEntry, } from './client-cache.js';
10
10
  export { CHAT_PAYLOADS_META_KEY, CHAT_PAYLOADS_RESOURCE, CHAT_PAYLOAD_TTL_MS, CHAT_PAYLOAD_MAX_RECORDS, isPlainObject, cleanString, normalizeChatPayloadRecord, recordTimestamp, sweepChatPayloads, } from './store-policy.js';
11
+ export { ChatPayloadStore } from './store.js';
11
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/warm/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,OAAO,EACL,UAAU,EACV,+BAA+B,EAC/B,iCAAiC,EACjC,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AAQtB,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AAMvB,OAAO,EACL,eAAe,EACf,aAAa,EACb,WAAW,EACX,8BAA8B,EAC9B,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,sBAAsB,EACtB,wBAAwB,EACxB,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,0BAA0B,EAC1B,eAAe,EACf,iBAAiB,GAClB,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/warm/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,OAAO,EACL,UAAU,EACV,+BAA+B,EAC/B,iCAAiC,EACjC,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AAQtB,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AAMvB,OAAO,EACL,eAAe,EACf,aAAa,EACb,WAAW,EACX,8BAA8B,EAC9B,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,sBAAsB,EACtB,wBAAwB,EACxB,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,0BAA0B,EAC1B,eAAe,EACf,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAO3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Machine chat-payload store — the effect-port composition of engine
3
+ * `runtime/scripts/amalgm-mcp/lib/chat-payloads.js`.
4
+ *
5
+ * The record, revision, and sweep decisions remain chat law. A host owns the
6
+ * bytes and clocks through these ports, so this module never touches disk or
7
+ * ambient time (PURPOSE.md axiom 7).
8
+ */
9
+ import type { ClockIsoPort, ClockMsPort } from '../ports.js';
10
+ import { CHAT_PAYLOADS_RESOURCE } from './store-policy.js';
11
+ import type { ChatPayloadStoreRecord } from './store-policy.js';
12
+ export interface ChatPayloadMapStore {
13
+ read(): Record<string, unknown>;
14
+ write(payloads: Record<string, ChatPayloadStoreRecord>): void;
15
+ }
16
+ export type ChatPayloadStateEvent = {
17
+ resource: typeof CHAT_PAYLOADS_RESOURCE;
18
+ op: 'invalidate';
19
+ source: 'chat-payloads-gc';
20
+ } | {
21
+ resource: typeof CHAT_PAYLOADS_RESOURCE;
22
+ op: 'update';
23
+ id: string;
24
+ value: ChatPayloadStoreRecord;
25
+ source: string;
26
+ };
27
+ export interface ChatPayloadStoreOptions {
28
+ store: ChatPayloadMapStore;
29
+ clockIso: ClockIsoPort;
30
+ clockMs: ClockMsPort;
31
+ emit?: (event: ChatPayloadStateEvent) => void;
32
+ }
33
+ export declare class ChatPayloadStore {
34
+ #private;
35
+ constructor(options: ChatPayloadStoreOptions);
36
+ list(): Record<string, ChatPayloadStoreRecord>;
37
+ get(id: unknown): ChatPayloadStoreRecord | null;
38
+ write(input: unknown, options?: {
39
+ source?: string;
40
+ }): ChatPayloadStoreRecord;
41
+ }
42
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/warm/store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,sBAAsB,EAKvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,MAAM,WAAW,mBAAmB;IAClC,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,GAAG,IAAI,CAAC;CAC/D;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,EAAE,OAAO,sBAAsB,CAAC;IAAC,EAAE,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GACzF;IACE,QAAQ,EAAE,OAAO,sBAAsB,CAAC;IACxC,EAAE,EAAE,QAAQ,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,sBAAsB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEN,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,mBAAmB,CAAC;IAC3B,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC/C;AAED,qBAAa,gBAAgB;;gBAOf,OAAO,EAAE,uBAAuB;IAO5C,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC;IAK9C,GAAG,CAAC,EAAE,EAAE,OAAO,GAAG,sBAAsB,GAAG,IAAI;IAO/C,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,sBAAsB;CAkCjF"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Machine chat-payload store — the effect-port composition of engine
3
+ * `runtime/scripts/amalgm-mcp/lib/chat-payloads.js`.
4
+ *
5
+ * The record, revision, and sweep decisions remain chat law. A host owns the
6
+ * bytes and clocks through these ports, so this module never touches disk or
7
+ * ambient time (PURPOSE.md axiom 7).
8
+ */
9
+ import { CHAT_PAYLOADS_RESOURCE, cleanString, isPlainObject, normalizeChatPayloadRecord, sweepChatPayloads, } from './store-policy.js';
10
+ export class ChatPayloadStore {
11
+ #store;
12
+ #clockIso;
13
+ #clockMs;
14
+ #emit;
15
+ #sweepDone = false;
16
+ constructor(options) {
17
+ this.#store = options.store;
18
+ this.#clockIso = options.clockIso;
19
+ this.#clockMs = options.clockMs;
20
+ this.#emit = options.emit ?? (() => undefined);
21
+ }
22
+ list() {
23
+ this.#sweepOnce();
24
+ return this.#store.read();
25
+ }
26
+ get(id) {
27
+ this.#sweepOnce();
28
+ const payloadId = cleanString(id);
29
+ if (!payloadId)
30
+ return null;
31
+ return this.#store.read()[payloadId] ?? null;
32
+ }
33
+ write(input, options = {}) {
34
+ this.#sweepOnce();
35
+ const current = this.#store.read();
36
+ const inputId = isPlainObject(input) ? cleanString(input['id'] || input['payloadId']) : null;
37
+ const existing = inputId
38
+ ? current[inputId] ?? null
39
+ : null;
40
+ const record = normalizeChatPayloadRecord(input, existing, this.#clockIso);
41
+ this.#store.write({
42
+ ...current,
43
+ [record.id]: record,
44
+ });
45
+ this.#emit({
46
+ resource: CHAT_PAYLOADS_RESOURCE,
47
+ op: 'update',
48
+ id: record.id,
49
+ value: record,
50
+ source: options.source || 'chat-payloads',
51
+ });
52
+ return record;
53
+ }
54
+ #sweepOnce() {
55
+ if (this.#sweepDone)
56
+ return;
57
+ this.#sweepDone = true;
58
+ const result = sweepChatPayloads(this.#store.read(), this.#clockMs());
59
+ if (!result.changed)
60
+ return;
61
+ this.#store.write(result.next);
62
+ this.#emit({
63
+ resource: CHAT_PAYLOADS_RESOURCE,
64
+ op: 'invalidate',
65
+ source: 'chat-payloads-gc',
66
+ });
67
+ }
68
+ }
69
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/warm/store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,sBAAsB,EACtB,WAAW,EACX,aAAa,EACb,0BAA0B,EAC1B,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAyB3B,MAAM,OAAO,gBAAgB;IAClB,MAAM,CAAsB;IAC5B,SAAS,CAAe;IACxB,QAAQ,CAAc;IACtB,KAAK,CAAyC;IACvD,UAAU,GAAG,KAAK,CAAC;IAEnB,YAAY,OAAgC;QAC1C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACjD,CAAC;IAED,IAAI;QACF,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAA4C,CAAC;IACtE,CAAC;IAED,GAAG,CAAC,EAAW;QACb,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,MAAM,SAAS,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QAC5B,OAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAS,CAAwC,IAAI,IAAI,CAAC;IACvF,CAAC;IAED,KAAK,CAAC,KAAc,EAAE,UAA+B,EAAE;QACrD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7F,MAAM,QAAQ,GAAG,OAAO;YACtB,CAAC,CAAE,OAAO,CAAC,OAAO,CAAwC,IAAI,IAAI;YAClE,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,MAAM,GAAG,0BAA0B,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YAChB,GAAI,OAAkD;YACtD,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM;SACpB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC;YACT,QAAQ,EAAE,sBAAsB;YAChC,EAAE,EAAE,QAAQ;YACZ,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,eAAe;SAC1C,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,UAAU;QACR,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO;QAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC;YACT,QAAQ,EAAE,sBAAsB;YAChC,EAAE,EAAE,YAAY;YAChB,MAAM,EAAE,kBAAkB;SAC3B,CAAC,CAAC;IACL,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amalgm/chat",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The Amalgm chat SDK — the conversation pipeline's laws: turns, messages, streaming assembly, event normalization, and transcript truth, behind host-injected adapters.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -47,6 +47,14 @@
47
47
  "./normalizers": {
48
48
  "types": "./dist/normalizers/index.d.ts",
49
49
  "default": "./dist/normalizers/index.js"
50
+ },
51
+ "./api": {
52
+ "types": "./dist/api/index.d.ts",
53
+ "default": "./dist/api/index.js"
54
+ },
55
+ "./relay": {
56
+ "types": "./dist/relay/index.d.ts",
57
+ "default": "./dist/relay/index.js"
50
58
  }
51
59
  },
52
60
  "files": [