@kraki/head 0.1.0 → 0.2.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.
package/package.json CHANGED
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "@kraki/head",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Kraki relay server — the brain that routes messages between tentacles and apps",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/corelli18512/kraki",
8
+ "directory": "packages/head"
9
+ },
10
+ "homepage": "https://github.com/corelli18512/kraki/tree/main/packages/head#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/corelli18512/kraki/issues"
13
+ },
5
14
  "type": "module",
6
15
  "main": "dist/index.js",
7
16
  "types": "dist/index.d.ts",
@@ -20,7 +29,7 @@
20
29
  "undici": "^7.24.5",
21
30
  "uuid": "^13.0.0",
22
31
  "ws": "^8.19.0",
23
- "@kraki/protocol": "0.1.0"
32
+ "@kraki/protocol": "0.2.0"
24
33
  },
25
34
  "devDependencies": {
26
35
  "@types/better-sqlite3": "^7.6.0",
@@ -1,97 +0,0 @@
1
- import type { DeviceSummary, SessionSummary, DeviceRole, DeviceKind, DeviceCapabilities } from '@kraki/protocol';
2
- import type { AuthUser } from './auth.js';
3
- import { Storage } from './storage.js';
4
- export interface ConnectedDevice {
5
- deviceId: string;
6
- channelId: string;
7
- name: string;
8
- role: DeviceRole;
9
- kind?: DeviceKind;
10
- publicKey?: string;
11
- encryptionKey?: string;
12
- capabilities?: DeviceCapabilities;
13
- send: (data: string) => void;
14
- }
15
- export interface RegisterDeviceInput {
16
- channelId: string;
17
- name: string;
18
- role: DeviceRole;
19
- send: (data: string) => void;
20
- kind?: DeviceKind;
21
- publicKey?: string;
22
- encryptionKey?: string;
23
- capabilities?: DeviceCapabilities;
24
- /** Client-provided stable device ID for reconnection. If omitted, a new one is generated. */
25
- clientDeviceId?: string;
26
- }
27
- export interface SessionMeta {
28
- agent: string;
29
- model?: string;
30
- }
31
- export declare class ChannelManager {
32
- private storage;
33
- /** In-memory map of connected devices by deviceId */
34
- private connections;
35
- /** Session tracking: sessionId → SessionRecord */
36
- private sessions;
37
- /** Reverse index: deviceId → Set of sessionIds (for fast cleanup) */
38
- private deviceSessions;
39
- /** Per-channel seq counter */
40
- private seqCounters;
41
- constructor(storage: Storage);
42
- /**
43
- * Get or create a channel for a user. Returns the channel ID.
44
- */
45
- getOrCreateChannel(user: AuthUser): string;
46
- /**
47
- * Register a device connection. Returns the assigned deviceId.
48
- * If clientDeviceId is provided and matches an existing device, reuses it (no ghost).
49
- */
50
- registerDevice(input: RegisterDeviceInput): string;
51
- /**
52
- * Remove a device connection (on disconnect).
53
- */
54
- disconnectDevice(deviceId: string): ConnectedDevice | undefined;
55
- /**
56
- * Register that a tentacle owns a session, with metadata.
57
- */
58
- registerSession(sessionId: string, deviceId: string, meta: SessionMeta): void;
59
- /**
60
- * Delete a session and all its associated data (messages, read state).
61
- * Returns true if the session existed.
62
- */
63
- deleteSession(sessionId: string, channelId: string): boolean;
64
- /**
65
- * Get the tentacle deviceId that owns a session.
66
- * Checks in-memory first, then falls back to persistent storage.
67
- */
68
- getSessionOwner(sessionId: string): string | undefined;
69
- /**
70
- * Get the next seq number for a channel (monotonically increasing).
71
- */
72
- nextSeq(channelId: string): number;
73
- /**
74
- * Get all connected devices on a channel.
75
- */
76
- getConnectedDevices(channelId: string): ConnectedDevice[];
77
- /**
78
- * Get connected devices filtered by role.
79
- */
80
- getConnectedByRole(channelId: string, role: DeviceRole): ConnectedDevice[];
81
- /**
82
- * Get device summaries for a channel (includes offline devices from storage).
83
- */
84
- getDeviceSummaries(channelId: string): DeviceSummary[];
85
- /**
86
- * Get session summaries for a channel.
87
- */
88
- getSessionSummaries(channelId: string): SessionSummary[];
89
- /**
90
- * Get a specific connected device.
91
- */
92
- getConnection(deviceId: string): ConnectedDevice | undefined;
93
- /**
94
- * Get the underlying storage instance.
95
- */
96
- getStorage(): Storage;
97
- }
@@ -1,215 +0,0 @@
1
- import { v4 as uuid } from 'uuid';
2
- export class ChannelManager {
3
- storage;
4
- /** In-memory map of connected devices by deviceId */
5
- connections = new Map();
6
- /** Session tracking: sessionId → SessionRecord */
7
- sessions = new Map();
8
- /** Reverse index: deviceId → Set of sessionIds (for fast cleanup) */
9
- deviceSessions = new Map();
10
- /** Per-channel seq counter */
11
- seqCounters = new Map();
12
- constructor(storage) {
13
- this.storage = storage;
14
- }
15
- /**
16
- * Get or create a channel for a user. Returns the channel ID.
17
- */
18
- getOrCreateChannel(user) {
19
- this.storage.upsertUser(user.id, user.login, user.provider, user.email);
20
- const existing = this.storage.getChannelByOwner(user.id);
21
- if (existing)
22
- return existing.id;
23
- const channelId = `ch_${uuid().slice(0, 12)}`;
24
- this.storage.createChannel(channelId, user.id);
25
- return channelId;
26
- }
27
- /**
28
- * Register a device connection. Returns the assigned deviceId.
29
- * If clientDeviceId is provided and matches an existing device, reuses it (no ghost).
30
- */
31
- registerDevice(input) {
32
- const deviceId = input.clientDeviceId ?? `dev_${uuid().slice(0, 12)}`;
33
- this.storage.upsertDevice(deviceId, input.channelId, input.name, input.role, input.kind, input.publicKey, input.encryptionKey);
34
- this.connections.set(deviceId, {
35
- deviceId,
36
- channelId: input.channelId,
37
- name: input.name,
38
- role: input.role,
39
- kind: input.kind,
40
- publicKey: input.publicKey,
41
- encryptionKey: input.encryptionKey,
42
- capabilities: input.capabilities,
43
- send: input.send,
44
- });
45
- return deviceId;
46
- }
47
- /**
48
- * Remove a device connection (on disconnect).
49
- */
50
- disconnectDevice(deviceId) {
51
- const device = this.connections.get(deviceId);
52
- if (device) {
53
- this.connections.delete(deviceId);
54
- this.deviceSessions.delete(deviceId);
55
- }
56
- return device;
57
- }
58
- /**
59
- * Register that a tentacle owns a session, with metadata.
60
- */
61
- registerSession(sessionId, deviceId, meta) {
62
- this.sessions.set(sessionId, { deviceId, meta });
63
- if (!this.deviceSessions.has(deviceId)) {
64
- this.deviceSessions.set(deviceId, new Set());
65
- }
66
- this.deviceSessions.get(deviceId).add(sessionId);
67
- // Persist to storage for durability across restarts
68
- const device = this.connections.get(deviceId);
69
- const channelId = device?.channelId ?? this.storage.getDevice(deviceId)?.channelId;
70
- if (channelId) {
71
- this.storage.upsertSession(sessionId, channelId, deviceId, meta.agent, meta.model);
72
- }
73
- }
74
- /**
75
- * Delete a session and all its associated data (messages, read state).
76
- * Returns true if the session existed.
77
- */
78
- deleteSession(sessionId, channelId) {
79
- const existed = this.sessions.has(sessionId) || !!this.storage.getSessionById(sessionId);
80
- // Remove from in-memory maps
81
- const record = this.sessions.get(sessionId);
82
- if (record) {
83
- this.sessions.delete(sessionId);
84
- this.deviceSessions.get(record.deviceId)?.delete(sessionId);
85
- }
86
- // Remove from persistent storage
87
- this.storage.deleteSessionMessages(channelId, sessionId);
88
- this.storage.deleteSessionReadState(channelId, sessionId);
89
- this.storage.deleteSession(sessionId);
90
- return existed;
91
- }
92
- /**
93
- * Get the tentacle deviceId that owns a session.
94
- * Checks in-memory first, then falls back to persistent storage.
95
- */
96
- getSessionOwner(sessionId) {
97
- const inMemory = this.sessions.get(sessionId);
98
- if (inMemory)
99
- return inMemory.deviceId;
100
- // Check persistent storage (session may have survived a head restart)
101
- const stored = this.storage.getSessionById(sessionId);
102
- if (stored) {
103
- // Restore to in-memory map
104
- this.sessions.set(sessionId, {
105
- deviceId: stored.deviceId,
106
- meta: { agent: stored.agent, model: stored.model ?? undefined },
107
- });
108
- return stored.deviceId;
109
- }
110
- return undefined;
111
- }
112
- /**
113
- * Get the next seq number for a channel (monotonically increasing).
114
- */
115
- nextSeq(channelId) {
116
- if (!this.seqCounters.has(channelId)) {
117
- const maxSeq = this.storage.getMaxSeq(channelId);
118
- this.seqCounters.set(channelId, maxSeq);
119
- }
120
- const next = this.seqCounters.get(channelId) + 1;
121
- this.seqCounters.set(channelId, next);
122
- return next;
123
- }
124
- /**
125
- * Get all connected devices on a channel.
126
- */
127
- getConnectedDevices(channelId) {
128
- // TODO: Add channelId → Set<deviceId> index if this becomes a bottleneck
129
- return Array.from(this.connections.values()).filter(d => d.channelId === channelId);
130
- }
131
- /**
132
- * Get connected devices filtered by role.
133
- */
134
- getConnectedByRole(channelId, role) {
135
- return this.getConnectedDevices(channelId).filter(d => d.role === role);
136
- }
137
- /**
138
- * Get device summaries for a channel (includes offline devices from storage).
139
- */
140
- getDeviceSummaries(channelId) {
141
- const stored = this.storage.getDevicesByChannel(channelId);
142
- return stored.map(d => {
143
- const conn = this.connections.get(d.id);
144
- return {
145
- id: d.id,
146
- name: d.name,
147
- role: d.role,
148
- kind: d.kind ?? undefined,
149
- publicKey: d.publicKey ?? undefined,
150
- encryptionKey: conn?.encryptionKey ?? d.encryptionKey ?? undefined,
151
- online: !!conn,
152
- capabilities: conn?.capabilities,
153
- };
154
- });
155
- }
156
- /**
157
- * Get session summaries for a channel.
158
- */
159
- getSessionSummaries(channelId) {
160
- // Merge in-memory sessions with persisted sessions from storage
161
- const seen = new Set();
162
- const summaries = [];
163
- // In-memory sessions first (most up-to-date)
164
- for (const [sessionId, record] of this.sessions) {
165
- const conn = this.connections.get(record.deviceId);
166
- const channelMatch = conn
167
- ? conn.channelId === channelId
168
- : this.storage.getDevice(record.deviceId)?.channelId === channelId;
169
- if (channelMatch) {
170
- seen.add(sessionId);
171
- let deviceName = conn?.name;
172
- if (!deviceName) {
173
- const stored = this.storage.getDevice(record.deviceId);
174
- deviceName = stored?.name ?? record.deviceId;
175
- }
176
- summaries.push({
177
- id: sessionId,
178
- deviceId: record.deviceId,
179
- deviceName,
180
- agent: record.meta.agent,
181
- model: record.meta.model,
182
- messageCount: 0,
183
- });
184
- }
185
- }
186
- // Add persisted sessions not already in memory (survives head restart)
187
- for (const stored of this.storage.getSessionsByChannel(channelId)) {
188
- if (!seen.has(stored.id)) {
189
- const device = this.storage.getDevice(stored.deviceId);
190
- summaries.push({
191
- id: stored.id,
192
- deviceId: stored.deviceId,
193
- deviceName: device?.name ?? stored.deviceId,
194
- agent: stored.agent,
195
- model: stored.model ?? undefined,
196
- messageCount: 0,
197
- });
198
- }
199
- }
200
- return summaries;
201
- }
202
- /**
203
- * Get a specific connected device.
204
- */
205
- getConnection(deviceId) {
206
- return this.connections.get(deviceId);
207
- }
208
- /**
209
- * Get the underlying storage instance.
210
- */
211
- getStorage() {
212
- return this.storage;
213
- }
214
- }
215
- //# sourceMappingURL=channel-manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"channel-manager.js","sourceRoot":"","sources":["../src/channel-manager.ts"],"names":[],"mappings":"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"}
package/dist/router.d.ts DELETED
@@ -1,30 +0,0 @@
1
- import type { ProducerMessage, ConsumerMessage, HeadNotice, EncryptedMessage } from '@kraki/protocol';
2
- import { ChannelManager } from './channel-manager.js';
3
- type IncomingMessage = ProducerMessage | ConsumerMessage | EncryptedMessage;
4
- export declare class Router {
5
- private cm;
6
- constructor(cm: ChannelManager);
7
- /**
8
- * Handle an incoming message from a connected device.
9
- * Assigns seq, stores if needed, routes to correct recipients.
10
- */
11
- handleMessage(fromDeviceId: string, raw: IncomingMessage): void;
12
- /**
13
- * Replay stored messages to a device after a given seq.
14
- * Filters out encrypted messages the device cannot decrypt.
15
- */
16
- replay(deviceId: string, afterSeq: number, sessionId?: string): void;
17
- /**
18
- * Send a HeadNotice to all connected devices on a channel.
19
- */
20
- broadcastNotice(channelId: string, notice: HeadNotice): void;
21
- private broadcastToTentacles;
22
- private sendToApps;
23
- private sendToSessionOwner;
24
- /**
25
- * Route create_session to a specific tentacle.
26
- * Works for both plaintext and encrypted (targetDeviceId from envelope).
27
- */
28
- private sendToTentacle;
29
- }
30
- export {};
package/dist/router.js DELETED
@@ -1,217 +0,0 @@
1
- import { shouldStore } from './storage.js';
2
- import { getLogger } from './logger.js';
3
- /** Normalize SQLite datetime ("2024-01-15 20:00:00") to ISO 8601 ("2024-01-15T20:00:00.000Z") */
4
- function toISO(sqliteTimestamp) {
5
- if (sqliteTimestamp.includes('T'))
6
- return sqliteTimestamp; // already ISO
7
- return sqliteTimestamp.replace(' ', 'T') + '.000Z';
8
- }
9
- export class Router {
10
- cm;
11
- constructor(cm) {
12
- this.cm = cm;
13
- }
14
- /**
15
- * Handle an incoming message from a connected device.
16
- * Assigns seq, stores if needed, routes to correct recipients.
17
- */
18
- handleMessage(fromDeviceId, raw) {
19
- const device = this.cm.getConnection(fromDeviceId);
20
- if (!device)
21
- return;
22
- const channelId = device.channelId;
23
- const seq = this.cm.nextSeq(channelId);
24
- const logger = getLogger();
25
- // Track session ownership on session_created (narrow on raw, not stamped)
26
- if (raw.type === 'session_created' && raw.sessionId) {
27
- const payload = raw.payload;
28
- this.cm.registerSession(raw.sessionId, fromDeviceId, {
29
- agent: payload.agent,
30
- model: payload.model,
31
- });
32
- logger.debug('Session registered', { sessionId: raw.sessionId, device: fromDeviceId, agent: payload.agent });
33
- }
34
- // In E2E mode, encrypted messages from tentacles may contain session_created.
35
- // The tentacle exposes agent/model in the outer envelope for session registration.
36
- if (device.role === 'tentacle' && raw.sessionId && !this.cm.getSessionOwner(raw.sessionId)) {
37
- const enc = raw.type === 'encrypted' ? raw : null;
38
- this.cm.registerSession(raw.sessionId, fromDeviceId, {
39
- agent: enc?.agent ?? raw.payload?.agent ?? 'unknown',
40
- model: enc?.model ?? raw.payload?.model,
41
- });
42
- logger.debug('Session registered (from envelope)', { sessionId: raw.sessionId, device: fromDeviceId });
43
- }
44
- // Stamp envelope fields
45
- const stamped = {
46
- ...raw,
47
- channel: channelId,
48
- deviceId: fromDeviceId,
49
- seq,
50
- timestamp: new Date().toISOString(),
51
- };
52
- // Store if this is a storable message type (skip ephemeral messages like deltas)
53
- const isEphemeral = stamped.type === 'encrypted' && stamped.ephemeral;
54
- if (shouldStore(stamped.type) && !isEphemeral) {
55
- // For encrypted messages, store the full envelope (head can't read the inner payload)
56
- let payloadToStore;
57
- if (stamped.type === 'encrypted') {
58
- const enc = stamped;
59
- payloadToStore = JSON.stringify({ iv: enc.iv, ciphertext: enc.ciphertext, tag: enc.tag, keys: enc.keys });
60
- }
61
- else {
62
- payloadToStore = JSON.stringify(stamped.payload);
63
- }
64
- this.cm.getStorage().storeMessage({
65
- channelId,
66
- deviceId: fromDeviceId,
67
- sessionId: stamped.sessionId ?? null,
68
- seq,
69
- type: stamped.type,
70
- payload: payloadToStore,
71
- });
72
- }
73
- const serialized = JSON.stringify(stamped);
74
- // Route based on sender role
75
- if (device.role === 'tentacle') {
76
- this.sendToApps(channelId, serialized);
77
- logger.debug('Routed tentacle→apps', { type: stamped.type, seq, channel: channelId });
78
- }
79
- else if (device.role === 'app') {
80
- // Encrypted create_session: targetDeviceId in outer envelope
81
- const targetDeviceId = raw.type === 'create_session'
82
- ? raw.payload?.targetDeviceId
83
- : raw.targetDeviceId;
84
- if (targetDeviceId) {
85
- const requestId = raw.type === 'create_session'
86
- ? raw.payload?.requestId
87
- : undefined;
88
- this.sendToTentacle(channelId, targetDeviceId, serialized, logger, fromDeviceId, requestId);
89
- }
90
- else {
91
- this.sendToSessionOwner(stamped.sessionId, serialized);
92
- logger.debug('Routed app→tentacle', { type: stamped.type, seq, sessionId: stamped.sessionId });
93
- }
94
- }
95
- }
96
- /**
97
- * Replay stored messages to a device after a given seq.
98
- * Filters out encrypted messages the device cannot decrypt.
99
- */
100
- replay(deviceId, afterSeq, sessionId) {
101
- const device = this.cm.getConnection(deviceId);
102
- if (!device)
103
- return;
104
- const logger = getLogger();
105
- const storage = this.cm.getStorage();
106
- const messages = storage.getMessagesForDevice(device.channelId, afterSeq, deviceId, sessionId);
107
- let sent = 0;
108
- let skipped = 0;
109
- for (const msg of messages) {
110
- try {
111
- let envelope;
112
- if (msg.type === 'encrypted') {
113
- // Encrypted messages: reconstruct original wire format
114
- const stored = JSON.parse(msg.payload);
115
- envelope = {
116
- channel: msg.channelId,
117
- deviceId: msg.deviceId,
118
- seq: msg.seq,
119
- timestamp: toISO(msg.createdAt),
120
- type: 'encrypted',
121
- sessionId: msg.sessionId,
122
- iv: stored.iv,
123
- ciphertext: stored.ciphertext,
124
- tag: stored.tag,
125
- keys: stored.keys,
126
- };
127
- }
128
- else {
129
- // Normal messages: reconstruct envelope with parsed payload
130
- envelope = {
131
- channel: msg.channelId,
132
- deviceId: msg.deviceId,
133
- seq: msg.seq,
134
- timestamp: toISO(msg.createdAt),
135
- type: msg.type,
136
- sessionId: msg.sessionId,
137
- payload: JSON.parse(msg.payload),
138
- };
139
- }
140
- device.send(JSON.stringify(envelope));
141
- sent++;
142
- }
143
- catch {
144
- logger.warn('Skipped corrupt message during replay', {
145
- messageId: msg.id,
146
- seq: msg.seq,
147
- type: msg.type,
148
- });
149
- skipped++;
150
- }
151
- }
152
- // Send replay_complete with the channel's max seq so the client
153
- // advances past skipped messages and doesn't re-request them.
154
- const lastSeq = storage.getMaxSeq(device.channelId);
155
- device.send(JSON.stringify({ type: 'replay_complete', lastSeq }));
156
- logger.debug('Replay complete', { deviceId, afterSeq, sent, skipped, lastSeq });
157
- }
158
- /**
159
- * Send a HeadNotice to all connected devices on a channel.
160
- */
161
- broadcastNotice(channelId, notice) {
162
- const serialized = JSON.stringify(notice);
163
- for (const device of this.cm.getConnectedDevices(channelId)) {
164
- device.send(serialized);
165
- }
166
- }
167
- broadcastToTentacles(channelId, notice) {
168
- const serialized = JSON.stringify(notice);
169
- for (const tentacle of this.cm.getConnectedByRole(channelId, 'tentacle')) {
170
- tentacle.send(serialized);
171
- }
172
- }
173
- sendToApps(channelId, data) {
174
- for (const app of this.cm.getConnectedByRole(channelId, 'app')) {
175
- app.send(data);
176
- }
177
- }
178
- sendToSessionOwner(sessionId, data) {
179
- if (!sessionId)
180
- return;
181
- const ownerDeviceId = this.cm.getSessionOwner(sessionId);
182
- if (!ownerDeviceId)
183
- return;
184
- const device = this.cm.getConnection(ownerDeviceId);
185
- if (device)
186
- device.send(data);
187
- }
188
- /**
189
- * Route create_session to a specific tentacle.
190
- * Works for both plaintext and encrypted (targetDeviceId from envelope).
191
- */
192
- sendToTentacle(channelId, targetDeviceId, serialized, logger, fromDeviceId, requestId) {
193
- const device = this.cm.getConnection(targetDeviceId);
194
- // Verify target is a tentacle in the SAME channel
195
- if (device && device.role === 'tentacle' && device.channelId === channelId) {
196
- device.send(serialized);
197
- logger.debug('Routed create_session→tentacle', { targetDeviceId });
198
- }
199
- else {
200
- const reason = device && device.channelId !== channelId
201
- ? `Target device "${targetDeviceId}" belongs to a different channel`
202
- : `Target device "${targetDeviceId}" is not online`;
203
- logger.warn('create_session rejected', { targetDeviceId, reason });
204
- if (fromDeviceId) {
205
- const sender = this.cm.getConnection(fromDeviceId);
206
- if (sender) {
207
- sender.send(JSON.stringify({
208
- type: 'server_error',
209
- message: reason,
210
- requestId,
211
- }));
212
- }
213
- }
214
- }
215
- }
216
- }
217
- //# sourceMappingURL=router.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}