@amalgm/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/PURPOSE.md +94 -0
  2. package/README.md +30 -0
  3. package/dist/adapters/index.d.ts +13 -0
  4. package/dist/adapters/index.d.ts.map +1 -0
  5. package/dist/adapters/index.js +11 -0
  6. package/dist/adapters/index.js.map +1 -0
  7. package/dist/identity/auth-records.d.ts +147 -0
  8. package/dist/identity/auth-records.d.ts.map +1 -0
  9. package/dist/identity/auth-records.js +354 -0
  10. package/dist/identity/auth-records.js.map +1 -0
  11. package/dist/identity/ids.d.ts +57 -0
  12. package/dist/identity/ids.d.ts.map +1 -0
  13. package/dist/identity/ids.js +80 -0
  14. package/dist/identity/ids.js.map +1 -0
  15. package/dist/identity/index.d.ts +14 -0
  16. package/dist/identity/index.d.ts.map +1 -0
  17. package/dist/identity/index.js +14 -0
  18. package/dist/identity/index.js.map +1 -0
  19. package/dist/identity/labels.d.ts +115 -0
  20. package/dist/identity/labels.d.ts.map +1 -0
  21. package/dist/identity/labels.js +154 -0
  22. package/dist/identity/labels.js.map +1 -0
  23. package/dist/identity/layout.d.ts +188 -0
  24. package/dist/identity/layout.d.ts.map +1 -0
  25. package/dist/identity/layout.js +233 -0
  26. package/dist/identity/layout.js.map +1 -0
  27. package/dist/identity/ports.d.ts +31 -0
  28. package/dist/identity/ports.d.ts.map +1 -0
  29. package/dist/identity/ports.js +9 -0
  30. package/dist/identity/ports.js.map +1 -0
  31. package/dist/identity/product-state.d.ts +49 -0
  32. package/dist/identity/product-state.d.ts.map +1 -0
  33. package/dist/identity/product-state.js +55 -0
  34. package/dist/identity/product-state.js.map +1 -0
  35. package/dist/index.d.ts +19 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +19 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/supervision/app-health.d.ts +148 -0
  40. package/dist/supervision/app-health.d.ts.map +1 -0
  41. package/dist/supervision/app-health.js +165 -0
  42. package/dist/supervision/app-health.js.map +1 -0
  43. package/dist/supervision/app-restart.d.ts +105 -0
  44. package/dist/supervision/app-restart.d.ts.map +1 -0
  45. package/dist/supervision/app-restart.js +97 -0
  46. package/dist/supervision/app-restart.js.map +1 -0
  47. package/dist/supervision/health.d.ts +218 -0
  48. package/dist/supervision/health.d.ts.map +1 -0
  49. package/dist/supervision/health.js +227 -0
  50. package/dist/supervision/health.js.map +1 -0
  51. package/dist/supervision/index.d.ts +17 -0
  52. package/dist/supervision/index.d.ts.map +1 -0
  53. package/dist/supervision/index.js +17 -0
  54. package/dist/supervision/index.js.map +1 -0
  55. package/dist/supervision/service-registration.d.ts +343 -0
  56. package/dist/supervision/service-registration.d.ts.map +1 -0
  57. package/dist/supervision/service-registration.js +543 -0
  58. package/dist/supervision/service-registration.js.map +1 -0
  59. package/dist/supervision/update.d.ts +231 -0
  60. package/dist/supervision/update.d.ts.map +1 -0
  61. package/dist/supervision/update.js +336 -0
  62. package/dist/supervision/update.js.map +1 -0
  63. package/dist/transport/admission.d.ts +235 -0
  64. package/dist/transport/admission.d.ts.map +1 -0
  65. package/dist/transport/admission.js +313 -0
  66. package/dist/transport/admission.js.map +1 -0
  67. package/dist/transport/auth.d.ts +232 -0
  68. package/dist/transport/auth.d.ts.map +1 -0
  69. package/dist/transport/auth.js +266 -0
  70. package/dist/transport/auth.js.map +1 -0
  71. package/dist/transport/index.d.ts +21 -0
  72. package/dist/transport/index.d.ts.map +1 -0
  73. package/dist/transport/index.js +21 -0
  74. package/dist/transport/index.js.map +1 -0
  75. package/dist/transport/ingress.d.ts +94 -0
  76. package/dist/transport/ingress.d.ts.map +1 -0
  77. package/dist/transport/ingress.js +171 -0
  78. package/dist/transport/ingress.js.map +1 -0
  79. package/dist/transport/routing.d.ts +235 -0
  80. package/dist/transport/routing.d.ts.map +1 -0
  81. package/dist/transport/routing.js +288 -0
  82. package/dist/transport/routing.js.map +1 -0
  83. package/dist/transport/shipped-routes.d.ts +21 -0
  84. package/dist/transport/shipped-routes.d.ts.map +1 -0
  85. package/dist/transport/shipped-routes.js +53 -0
  86. package/dist/transport/shipped-routes.js.map +1 -0
  87. package/package.json +51 -0
@@ -0,0 +1,288 @@
1
+ /**
2
+ * ONE routing table (axiom 4). The engine carries three drifted copies
3
+ * of these laws — local-gateway.js:133-176,627-654 (the gateway's own
4
+ * dispatch), tunnel-events.js:58-89,279-353 and tunnel-chat.js:33-64,
5
+ * 138-194,286-300 (each tunnel's local delivery) — and every incident
6
+ * where a new REST prefix worked over the tunnel but 404'd locally (or
7
+ * vice versa) is that drift cashing out. This module is the one
8
+ * definition; the table CONTENTS are injected product configuration
9
+ * (the kernel routes, it does not know what chat is — axiom 3), with
10
+ * the engine's shipped lists exported from shipped-routes.ts.
11
+ *
12
+ * The pipe never reads the mail: everything here classifies pathnames
13
+ * and port numbers. Nothing inspects a payload.
14
+ */
15
+ /**
16
+ * The declared-port probe order — tunnel-events.js:315, byte-order
17
+ * preserved (mcp before chat; the sets never overlap in practice, but
18
+ * order is contract until proven dead).
19
+ */
20
+ export const RUNTIME_SERVICES = ['gateway', 'portMonitor', 'mcp', 'chat'];
21
+ /**
22
+ * The prefix law — tunnel-events.js:279-281, identical in chat and
23
+ * gateway: a prefix claims itself and everything below a '/'
24
+ * boundary. '/chat' claims '/chat' and '/chat/x', never
25
+ * '/chat-payloads' — segment-honest matching is what lets '/chat' and
26
+ * '/chat-payloads' live in different buckets.
27
+ */
28
+ export function prefixMatches(pathname, prefix) {
29
+ return pathname === prefix || pathname.startsWith(`${prefix}/`);
30
+ }
31
+ /**
32
+ * tunnel-events.js:283-289 (framePathname) / runtime-auth.js:102-108
33
+ * (pathnameFor) — one copy. Tunnel frame paths and req.url both carry
34
+ * query strings; routing decisions are over the pathname alone.
35
+ * Unparseable input routes as '/'.
36
+ */
37
+ export function pathnameOf(path) {
38
+ try {
39
+ return new URL(path || '/', 'http://127.0.0.1').pathname || '/';
40
+ }
41
+ catch {
42
+ return '/';
43
+ }
44
+ }
45
+ /**
46
+ * The classifier — canonical order is the TUNNEL order
47
+ * (tunnel-events.js:291-300): gateway (exact paths first, then
48
+ * prefixes) → portMonitor → chat → mcp → null.
49
+ *
50
+ * The engine's gateway checks chat → mcp → portMonitor instead
51
+ * (local-gateway.js:627-647, after handling its own routes). The two
52
+ * orders are currently indistinguishable because no prefix in one
53
+ * bucket sits under a prefix in another — no pathname can match two
54
+ * buckets, so match order never decides a winner. That is an
55
+ * assumption about table CONTENTS, so assertNoBucketCollisions below
56
+ * makes it executable: run it over any injected table and the
57
+ * "order doesn't matter" claim is proven, not remembered.
58
+ */
59
+ export function serviceForRuntimePath(pathname, table) {
60
+ if (table.gatewayExactPaths.includes(pathname)
61
+ || table.gatewayPrefixes.some((prefix) => prefixMatches(pathname, prefix))) {
62
+ return 'gateway';
63
+ }
64
+ if (table.portMonitorPrefixes.some((prefix) => prefixMatches(pathname, prefix)))
65
+ return 'portMonitor';
66
+ if (table.chatPrefixes.some((prefix) => prefixMatches(pathname, prefix)))
67
+ return 'chat';
68
+ if (table.mcpPrefixes.some((prefix) => prefixMatches(pathname, prefix)))
69
+ return 'mcp';
70
+ return null;
71
+ }
72
+ /**
73
+ * The executable form of the order-indistinguishability assumption:
74
+ * two prefixes from different buckets may never claim the same
75
+ * pathname. Prefix a and prefix b share a claimable pathname exactly
76
+ * when one prefix-matches the other (then the deeper prefix itself is
77
+ * such a pathname), so that is the whole check. Gateway exact paths
78
+ * are also checked against the other buckets' prefixes: both shipped
79
+ * orders test gateway first, and this keeps even that ordering
80
+ * non-load-bearing.
81
+ */
82
+ export function assertNoBucketCollisions(table) {
83
+ const buckets = [
84
+ ['gateway', table.gatewayPrefixes],
85
+ ['portMonitor', table.portMonitorPrefixes],
86
+ ['chat', table.chatPrefixes],
87
+ ['mcp', table.mcpPrefixes],
88
+ ];
89
+ buckets.forEach(([nameA, prefixesA], index) => {
90
+ for (const [nameB, prefixesB] of buckets.slice(index + 1)) {
91
+ for (const a of prefixesA) {
92
+ for (const b of prefixesB) {
93
+ if (prefixMatches(a, b) || prefixMatches(b, a)) {
94
+ throw new Error(`Route-table bucket collision: ${nameA} '${a}' and ${nameB} '${b}' can claim the same pathname; match order would decide the winner`);
95
+ }
96
+ }
97
+ }
98
+ }
99
+ });
100
+ for (const exact of table.gatewayExactPaths) {
101
+ for (const [name, prefixes] of buckets) {
102
+ if (name === 'gateway')
103
+ continue;
104
+ for (const prefix of prefixes) {
105
+ if (prefixMatches(exact, prefix)) {
106
+ throw new Error(`Route-table bucket collision: gateway exact path '${exact}' sits under ${name} '${prefix}'; gateway-first ordering would become load-bearing`);
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ /**
113
+ * The gateway's prefix-strip law — local-gateway.js:637-645: before
114
+ * proxying to the port monitor it strips '/port-monitor', else
115
+ * '/ports' (first match wins, checked in this order), but deliberately
116
+ * NOT '/api/ports' — that one is the port monitor's own native prefix
117
+ * and forwards verbatim. '/chat' and '/mcp'-bucket paths always
118
+ * forward verbatim (stripPrefix '').
119
+ */
120
+ export const PORT_MONITOR_STRIP_PREFIXES = ['/port-monitor', '/ports'];
121
+ /**
122
+ * Classify a pathname and compute the path to forward upstream —
123
+ * local-gateway.js:627-647 (serviceForPath) + :687-692 (proxiedPath,
124
+ * slice then `|| '/'`), generalized over the injected table. Pathname
125
+ * in, pathname out: the host re-attaches the query string, as
126
+ * proxiedPath does.
127
+ *
128
+ * DRIFT, documented as a wound the cutover closes: the tunnels
129
+ * forward frame paths VERBATIM to the resolved service
130
+ * (tunnel-events.js:678-684 passes frame.path straight to
131
+ * http.request), so '/ports/x' reaches the port monitor as '/ports/x'
132
+ * over a tunnel but as '/x' through the gateway. The gateway behavior
133
+ * ported here is canonical; when the tunnels adopt this function the
134
+ * two paths converge.
135
+ *
136
+ * Two deliberate departures from the engine's serviceForPath, both
137
+ * because this is the whole table rather than the gateway's slice of
138
+ * it: gateway-bucket paths return {service:'gateway'} instead of null
139
+ * (the engine returns null there because the gateway has already
140
+ * handled its own routes by that line), and the strip test uses the
141
+ * classified pathname, where the engine's raw startsWith is
142
+ * indistinguishable ('/portsfoo' never classifies as portMonitor).
143
+ */
144
+ export function forwardPathForService(pathname, table) {
145
+ const service = serviceForRuntimePath(pathname, table);
146
+ if (service === null)
147
+ return null;
148
+ if (service === 'portMonitor') {
149
+ const strip = PORT_MONITOR_STRIP_PREFIXES.find((prefix) => pathname.startsWith(prefix)) ?? '';
150
+ return { service, forwardPath: strip ? pathname.slice(strip.length) || '/' : pathname };
151
+ }
152
+ return { service, forwardPath: pathname };
153
+ }
154
+ // ---------------------------------------------------------------------------
155
+ // Ports
156
+ // ---------------------------------------------------------------------------
157
+ /** tunnel-events.js:274-277 — a port is an integer in (0, 65535], or it is nothing. */
158
+ export function validPort(value) {
159
+ const port = Number(value);
160
+ return Number.isInteger(port) && port > 0 && port <= 65535 ? port : null;
161
+ }
162
+ /**
163
+ * The runtime-state port mapping — the tunnels' `readRuntimePorts`
164
+ * (tunnel-events.js:255-272, byte-identical in tunnel-chat.js:114-131;
165
+ * the engine name is kept — the manifest's declaration-driven
166
+ * `runtimePortsFromState` is a different law and lives in
167
+ * `supervision/service-registration.ts`). Top-level `gateway_port` wins
168
+ * over `ports.gateway` (older writers only wrote the former); the
169
+ * other services live only under `ports.*` in snake_case. `Number(x)
170
+ * || fallback` verbatim: absent, unparseable, and zero all fall back.
171
+ * The engine's catch-branch (unreadable file) is the host's: pass no
172
+ * state and the fallbacks come through whole.
173
+ */
174
+ export function readRuntimePorts(state, fallbacks) {
175
+ return {
176
+ gateway: Number(state?.gateway_port || state?.ports?.gateway) || fallbacks.gateway,
177
+ portMonitor: Number(state?.ports?.port_monitor) || fallbacks.portMonitor,
178
+ mcp: Number(state?.ports?.amalgm_mcp) || fallbacks.mcp,
179
+ chat: Number(state?.ports?.chat_server) || fallbacks.chat,
180
+ };
181
+ }
182
+ /**
183
+ * The mirror-write shape — local-gateway.js:395-402: what the gateway
184
+ * writes is exactly what readRuntimePorts reads, top-level
185
+ * `gateway_port` doubled into `ports.gateway` included.
186
+ */
187
+ export function runtimeStatePortsPatch(ports) {
188
+ return {
189
+ gateway_port: ports.gateway,
190
+ ports: {
191
+ gateway: ports.gateway,
192
+ port_monitor: ports.portMonitor,
193
+ amalgm_mcp: ports.mcp,
194
+ chat_server: ports.chat,
195
+ },
196
+ };
197
+ }
198
+ /** tunnel-events.js:302-308 — which service does a well-known DEFAULT port imply? Checked against defaults, never live ports. */
199
+ export function defaultServiceForPort(port, defaults) {
200
+ if (port === defaults.gateway)
201
+ return 'gateway';
202
+ if (port === defaults.portMonitor)
203
+ return 'portMonitor';
204
+ if (port === defaults.mcp)
205
+ return 'mcp';
206
+ if (port === defaults.chat)
207
+ return 'chat';
208
+ return null;
209
+ }
210
+ /** tunnel-events.js:310-312 — live port if valid, else the default; null when both are broken. */
211
+ export function runtimePortForService(runtimePorts, defaults, service) {
212
+ return validPort(runtimePorts[service]) || validPort(defaults[service]);
213
+ }
214
+ /** tunnel-events.js:314-316 — is this port one the live runtime actually declared? Order-sensitive over RUNTIME_SERVICES. */
215
+ export function isDeclaredRuntimePort(port, runtimePorts) {
216
+ return RUNTIME_SERVICES.some((service) => validPort(runtimePorts[service]) === port);
217
+ }
218
+ /**
219
+ * The full set of ports a tunnel frame may target —
220
+ * tunnel-events.js:318-326: every resolvable service port plus, on
221
+ * the events tunnel, every advertised app-route port. DRIFT:
222
+ * tunnel-chat.js:177-184 omits the app ports (chat frames never
223
+ * target apps); that divergence is this parameter, not a second copy
224
+ * — pass no appRoutePorts and you have the chat version.
225
+ */
226
+ export function allowedTargetPorts(runtimePorts, defaults, appRoutePorts = []) {
227
+ const ports = new Set();
228
+ for (const service of RUNTIME_SERVICES) {
229
+ const port = runtimePortForService(runtimePorts, defaults, service);
230
+ if (port)
231
+ ports.add(port);
232
+ }
233
+ for (const port of appRoutePorts)
234
+ ports.add(port);
235
+ return ports;
236
+ }
237
+ /**
238
+ * The target-port law — canonical form is tunnel-events.js:338-353
239
+ * (tunnel-chat.js:286-300 is the same law with fallbackService
240
+ * 'chat' and no app ports):
241
+ * 1. a requested port the live runtime declared is honored verbatim;
242
+ * 2. otherwise the frame's PATH picks the service — but only when no
243
+ * port was requested, or the requested port is a well-known
244
+ * default (a stale peer aiming at where a service used to live:
245
+ * the path outranks the stale number and both remap to the live
246
+ * port);
247
+ * 3. a requested port that names neither a declared port, a default,
248
+ * nor a routable path must be in the allowed set (app routes) or
249
+ * it resolves to null — and null is the denial contract below.
250
+ */
251
+ export function resolveTargetPort(frame, options) {
252
+ const { runtimePorts, defaults, table } = options;
253
+ const requested = validPort(frame.target_port);
254
+ if (requested && isDeclaredRuntimePort(requested, runtimePorts))
255
+ return requested;
256
+ const defaultService = requested ? defaultServiceForPort(requested, defaults) : options.fallbackService;
257
+ const pathService = (!requested || defaultService)
258
+ ? serviceForRuntimePath(pathnameOf(frame.path), table)
259
+ : null;
260
+ const service = pathService || defaultService;
261
+ if (service) {
262
+ return runtimePortForService(runtimePorts, defaults, service);
263
+ }
264
+ if (!requested)
265
+ return null;
266
+ return allowedTargetPorts(runtimePorts, defaults, options.appRoutePorts ?? []).has(requested)
267
+ ? requested
268
+ : null;
269
+ }
270
+ // ---------------------------------------------------------------------------
271
+ // Denial contracts — byte-exact (axiom 8)
272
+ // ---------------------------------------------------------------------------
273
+ /** Tunnel res-frame denial — tunnel-events.js:668-674 (and stream/ws variants at :710-715,:778-779). */
274
+ export const TARGET_PORT_DENIED_STATUS = 403;
275
+ export const TARGET_PORT_DENIED_MESSAGE = 'Target port is not allowed';
276
+ /** The frozen body bytes of the non-stream denial (JSON.stringify({ error: ... }) at :673). */
277
+ export const TARGET_PORT_DENIED_BODY = '{"error":"Target port is not allowed"}';
278
+ /** WebSocket denial — tunnel-events.js:779: policy-violation close with the same reason. */
279
+ export const WS_CLOSE_TARGET_PORT_DENIED = { code: 1008, reason: TARGET_PORT_DENIED_MESSAGE };
280
+ /** Gateway preview denial — local-gateway.js:675. */
281
+ export function previewPortDeniedError(port) {
282
+ return { status: 403, message: `Preview port is not allowed: ${port}` };
283
+ }
284
+ /** Gateway app denial — local-gateway.js:662. */
285
+ export function appNotRoutableError(appRef) {
286
+ return { status: 404, message: `App is not routable: ${appRef}` };
287
+ }
288
+ //# sourceMappingURL=routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.js","sourceRoot":"","sources":["../../src/transport/routing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The engine's shipped routing table, copied byte-for-byte from
3
+ * tunnel-events.js:58-89 — the canonical of the three engine copies
4
+ * (the other two: tunnel-chat.js:33-64, identical; local-gateway.js:
5
+ * 133-176, which carries only the chat/mcp/portMonitor buckets
6
+ * because the gateway dispatches its own routes before consulting a
7
+ * table, and treats only '/', '/healthz', '/runtime-state' as
8
+ * self-owned exact paths — '/pty/session' and '/pty/resize' fall
9
+ * under its own '/pty' handling).
10
+ *
11
+ * Counts, pinned by tests: 3 gateway prefixes, 5 gateway exact paths,
12
+ * 3 port-monitor prefixes, 7 chat prefixes, 26 MCP prefixes.
13
+ *
14
+ * This is product configuration riding in the kernel repo for the
15
+ * cutover: the table SHAPE is core's; these CONTENTS belong to the
16
+ * products that own the prefixes. A new runtime REST prefix goes here
17
+ * (and, until cutover, in all three engine copies) or UI calls 404.
18
+ */
19
+ import type { RouteTable } from './routing.js';
20
+ export declare const shippedRouteTable: RouteTable;
21
+ //# sourceMappingURL=shipped-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shipped-routes.d.ts","sourceRoot":"","sources":["../../src/transport/shipped-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,eAAO,MAAM,iBAAiB,EAAE,UAiC/B,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The engine's shipped routing table, copied byte-for-byte from
3
+ * tunnel-events.js:58-89 — the canonical of the three engine copies
4
+ * (the other two: tunnel-chat.js:33-64, identical; local-gateway.js:
5
+ * 133-176, which carries only the chat/mcp/portMonitor buckets
6
+ * because the gateway dispatches its own routes before consulting a
7
+ * table, and treats only '/', '/healthz', '/runtime-state' as
8
+ * self-owned exact paths — '/pty/session' and '/pty/resize' fall
9
+ * under its own '/pty' handling).
10
+ *
11
+ * Counts, pinned by tests: 3 gateway prefixes, 5 gateway exact paths,
12
+ * 3 port-monitor prefixes, 7 chat prefixes, 26 MCP prefixes.
13
+ *
14
+ * This is product configuration riding in the kernel repo for the
15
+ * cutover: the table SHAPE is core's; these CONTENTS belong to the
16
+ * products that own the prefixes. A new runtime REST prefix goes here
17
+ * (and, until cutover, in all three engine copies) or UI calls 404.
18
+ */
19
+ export const shippedRouteTable = {
20
+ gatewayPrefixes: ['/__amalgm', '/diagnostics', '/pty'],
21
+ gatewayExactPaths: ['/', '/healthz', '/runtime-state', '/pty/session', '/pty/resize'],
22
+ portMonitorPrefixes: ['/api/ports', '/ports', '/port-monitor'],
23
+ chatPrefixes: ['/chat', '/raw-temp', '/active', '/stop', '/destroy', '/egress', '/mcp-relay'],
24
+ mcpPrefixes: [
25
+ '/mcp',
26
+ '/events',
27
+ '/tasks',
28
+ '/automations',
29
+ '/event-triggers',
30
+ '/workspace',
31
+ '/project-context',
32
+ '/github',
33
+ '/fs',
34
+ '/mcp-connections',
35
+ '/toolbox',
36
+ '/state',
37
+ '/local',
38
+ '/credentials',
39
+ '/chat-payloads',
40
+ '/email',
41
+ '/slack',
42
+ '/user-api-keys',
43
+ '/apps',
44
+ '/artifacts',
45
+ '/agents',
46
+ '/agent-config',
47
+ '/agent-bundles',
48
+ '/skills',
49
+ '/user-preferences',
50
+ '/browser',
51
+ ],
52
+ };
53
+ //# sourceMappingURL=shipped-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shipped-routes.js","sourceRoot":"","sources":["../../src/transport/shipped-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,CAAC,MAAM,iBAAiB,GAAe;IAC3C,eAAe,EAAE,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC;IACtD,iBAAiB,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,CAAC;IACrF,mBAAmB,EAAE,CAAC,YAAY,EAAE,QAAQ,EAAE,eAAe,CAAC;IAC9D,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,CAAC;IAC7F,WAAW,EAAE;QACX,MAAM;QACN,SAAS;QACT,QAAQ;QACR,cAAc;QACd,iBAAiB;QACjB,YAAY;QACZ,kBAAkB;QAClB,SAAS;QACT,KAAK;QACL,kBAAkB;QAClB,UAAU;QACV,QAAQ;QACR,QAAQ;QACR,cAAc;QACd,gBAAgB;QAChB,QAAQ;QACR,QAAQ;QACR,gBAAgB;QAChB,OAAO;QACP,YAAY;QACZ,SAAS;QACT,eAAe;QACf,gBAAgB;QAChB,SAAS;QACT,mBAAmB;QACnB,UAAU;KACX;CACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@amalgm/core",
3
+ "version": "0.1.0",
4
+ "description": "The Amalgm kernel SDK — identity, transport, supervision, and host capability contracts behind host-injected adapters.",
5
+ "type": "module",
6
+ "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/amalgm-inc/amalgm-core.git"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "./identity": {
20
+ "types": "./dist/identity/index.d.ts",
21
+ "default": "./dist/identity/index.js"
22
+ },
23
+ "./transport": {
24
+ "types": "./dist/transport/index.d.ts",
25
+ "default": "./dist/transport/index.js"
26
+ },
27
+ "./supervision": {
28
+ "types": "./dist/supervision/index.d.ts",
29
+ "default": "./dist/supervision/index.js"
30
+ },
31
+ "./adapters": {
32
+ "types": "./dist/adapters/index.d.ts",
33
+ "default": "./dist/adapters/index.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "PURPOSE.md"
39
+ ],
40
+ "engines": {
41
+ "node": ">=18"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.json",
45
+ "test": "npm run build && node --test tests/",
46
+ "test:parity": "npm run build && node --test tests/parity/"
47
+ },
48
+ "devDependencies": {
49
+ "typescript": "^5.7.3"
50
+ }
51
+ }