@agent-relay/protocol 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.
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Channel and User Protocol Types
3
+ *
4
+ * Extends the Agent Relay Protocol to support:
5
+ * - First-class user entities (humans, not just AI agents)
6
+ * - Channels for group communication
7
+ * - Direct messaging between any combination of users and agents
8
+ */
9
+ import { PROTOCOL_VERSION, type EntityType, type MessageAttachment, type ChannelJoinEnvelope, type ChannelLeaveEnvelope, type ChannelMessageEnvelope } from './types.js';
10
+ export type { MessageAttachment, ChannelJoinPayload, ChannelLeavePayload, ChannelMessagePayload, ChannelJoinEnvelope, ChannelLeaveEnvelope, ChannelMessageEnvelope, } from './types.js';
11
+ export { PROTOCOL_VERSION };
12
+ /**
13
+ * Extended message types for channels.
14
+ */
15
+ export type ChannelMessageType = 'CHANNEL_JOIN' | 'CHANNEL_LEAVE' | 'CHANNEL_MESSAGE' | 'CHANNEL_INFO' | 'CHANNEL_MEMBERS' | 'CHANNEL_TYPING';
16
+ /**
17
+ * Channel member info.
18
+ */
19
+ export interface ChannelMember {
20
+ name: string;
21
+ entityType: EntityType;
22
+ displayName?: string;
23
+ avatarUrl?: string;
24
+ status?: 'online' | 'away' | 'offline';
25
+ }
26
+ /**
27
+ * Payload for CHANNEL_INFO.
28
+ * Contains metadata about a channel.
29
+ */
30
+ export interface ChannelInfoPayload {
31
+ /** Channel identifier */
32
+ channel: string;
33
+ /** Human-readable channel name */
34
+ name: string;
35
+ /** Optional description */
36
+ description?: string;
37
+ /** Optional current topic */
38
+ topic?: string;
39
+ /** List of members */
40
+ members: ChannelMember[];
41
+ /** When the channel was created */
42
+ createdAt: string;
43
+ /** Whether the channel is private */
44
+ isPrivate?: boolean;
45
+ }
46
+ /**
47
+ * Payload for CHANNEL_MEMBERS.
48
+ * List of members in a channel.
49
+ */
50
+ export interface ChannelMembersPayload {
51
+ channel: string;
52
+ members: ChannelMember[];
53
+ }
54
+ /**
55
+ * Payload for CHANNEL_TYPING.
56
+ * Indicates someone is typing in a channel.
57
+ */
58
+ export interface ChannelTypingPayload {
59
+ channel: string;
60
+ isTyping: boolean;
61
+ }
62
+ /**
63
+ * Check if an entity type represents a user.
64
+ */
65
+ export declare function isUserEntity(entityType: EntityType | undefined): boolean;
66
+ /**
67
+ * Check if an entity type represents an agent.
68
+ * Undefined defaults to agent for backwards compatibility.
69
+ */
70
+ export declare function isAgentEntity(entityType: EntityType | undefined): boolean;
71
+ /**
72
+ * Type guard to check if an envelope is a channel message.
73
+ */
74
+ export declare function isChannelMessage(envelope: {
75
+ type: string;
76
+ }): envelope is ChannelMessageEnvelope;
77
+ /**
78
+ * Type guard to check if an envelope is a channel join.
79
+ */
80
+ export declare function isChannelJoin(envelope: {
81
+ type: string;
82
+ }): envelope is ChannelJoinEnvelope;
83
+ /**
84
+ * Type guard to check if an envelope is a channel leave.
85
+ */
86
+ export declare function isChannelLeave(envelope: {
87
+ type: string;
88
+ }): envelope is ChannelLeaveEnvelope;
89
+ /**
90
+ * Create a CHANNEL_JOIN envelope.
91
+ */
92
+ export declare function createChannelJoinEnvelope(from: string, channel: string, options?: {
93
+ displayName?: string;
94
+ avatarUrl?: string;
95
+ }): ChannelJoinEnvelope;
96
+ /**
97
+ * Create a CHANNEL_LEAVE envelope.
98
+ */
99
+ export declare function createChannelLeaveEnvelope(from: string, channel: string, reason?: string): ChannelLeaveEnvelope;
100
+ /**
101
+ * Create a CHANNEL_MESSAGE envelope.
102
+ */
103
+ export declare function createChannelMessageEnvelope(from: string, channel: string, body: string, options?: {
104
+ thread?: string;
105
+ mentions?: string[];
106
+ attachments?: MessageAttachment[];
107
+ data?: Record<string, unknown>;
108
+ }): ChannelMessageEnvelope;
109
+ /**
110
+ * Parse a DM channel name to extract participants.
111
+ * DM channels follow the format: dm:<participant1>:<participant2>:...
112
+ */
113
+ export declare function parseDmChannel(channel: string): string[] | null;
114
+ /**
115
+ * Create a DM channel name from participants.
116
+ * Participants are sorted alphabetically for consistency.
117
+ */
118
+ export declare function createDmChannelName(...participants: string[]): string;
119
+ /**
120
+ * Check if a channel is a DM (direct message).
121
+ */
122
+ export declare function isDmChannel(channel: string): boolean;
123
+ /**
124
+ * Check if a channel is private.
125
+ */
126
+ export declare function isPrivateChannel(channel: string): boolean;
127
+ /**
128
+ * Check if a channel is a public channel (starts with #).
129
+ */
130
+ export declare function isPublicChannel(channel: string): boolean;
131
+ /**
132
+ * Normalize channel name for storage/lookup.
133
+ * - Removes leading # from public channels
134
+ * - Sorts participants in DM channels
135
+ */
136
+ export declare function normalizeChannelName(channel: string): string;
137
+ //# sourceMappingURL=channels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Channel and User Protocol Types
3
+ *
4
+ * Extends the Agent Relay Protocol to support:
5
+ * - First-class user entities (humans, not just AI agents)
6
+ * - Channels for group communication
7
+ * - Direct messaging between any combination of users and agents
8
+ */
9
+ import { generateId } from './id-generator.js';
10
+ import { PROTOCOL_VERSION, } from './types.js';
11
+ // Re-export for convenience
12
+ export { PROTOCOL_VERSION };
13
+ /**
14
+ * Check if an entity type represents a user.
15
+ */
16
+ export function isUserEntity(entityType) {
17
+ return entityType === 'user';
18
+ }
19
+ /**
20
+ * Check if an entity type represents an agent.
21
+ * Undefined defaults to agent for backwards compatibility.
22
+ */
23
+ export function isAgentEntity(entityType) {
24
+ return entityType === 'agent' || entityType === undefined;
25
+ }
26
+ /**
27
+ * Type guard to check if an envelope is a channel message.
28
+ */
29
+ export function isChannelMessage(envelope) {
30
+ return envelope.type === 'CHANNEL_MESSAGE';
31
+ }
32
+ /**
33
+ * Type guard to check if an envelope is a channel join.
34
+ */
35
+ export function isChannelJoin(envelope) {
36
+ return envelope.type === 'CHANNEL_JOIN';
37
+ }
38
+ /**
39
+ * Type guard to check if an envelope is a channel leave.
40
+ */
41
+ export function isChannelLeave(envelope) {
42
+ return envelope.type === 'CHANNEL_LEAVE';
43
+ }
44
+ /**
45
+ * Create a CHANNEL_JOIN envelope.
46
+ */
47
+ export function createChannelJoinEnvelope(from, channel, options) {
48
+ return {
49
+ v: PROTOCOL_VERSION,
50
+ type: 'CHANNEL_JOIN',
51
+ id: generateId(),
52
+ ts: Date.now(),
53
+ from,
54
+ payload: {
55
+ channel,
56
+ displayName: options?.displayName,
57
+ avatarUrl: options?.avatarUrl,
58
+ },
59
+ };
60
+ }
61
+ /**
62
+ * Create a CHANNEL_LEAVE envelope.
63
+ */
64
+ export function createChannelLeaveEnvelope(from, channel, reason) {
65
+ return {
66
+ v: PROTOCOL_VERSION,
67
+ type: 'CHANNEL_LEAVE',
68
+ id: generateId(),
69
+ ts: Date.now(),
70
+ from,
71
+ payload: {
72
+ channel,
73
+ reason,
74
+ },
75
+ };
76
+ }
77
+ /**
78
+ * Create a CHANNEL_MESSAGE envelope.
79
+ */
80
+ export function createChannelMessageEnvelope(from, channel, body, options) {
81
+ return {
82
+ v: PROTOCOL_VERSION,
83
+ type: 'CHANNEL_MESSAGE',
84
+ id: generateId(),
85
+ ts: Date.now(),
86
+ from,
87
+ payload: {
88
+ channel,
89
+ body,
90
+ thread: options?.thread,
91
+ mentions: options?.mentions,
92
+ attachments: options?.attachments,
93
+ data: options?.data,
94
+ },
95
+ };
96
+ }
97
+ /**
98
+ * Parse a DM channel name to extract participants.
99
+ * DM channels follow the format: dm:<participant1>:<participant2>:...
100
+ */
101
+ export function parseDmChannel(channel) {
102
+ if (!channel.startsWith('dm:')) {
103
+ return null;
104
+ }
105
+ const parts = channel.split(':').slice(1);
106
+ return parts.length >= 2 ? parts : null;
107
+ }
108
+ /**
109
+ * Create a DM channel name from participants.
110
+ * Participants are sorted alphabetically for consistency.
111
+ */
112
+ export function createDmChannelName(...participants) {
113
+ if (participants.length < 2) {
114
+ throw new Error('DM requires at least 2 participants');
115
+ }
116
+ const sorted = [...participants].sort();
117
+ return `dm:${sorted.join(':')}`;
118
+ }
119
+ /**
120
+ * Check if a channel is a DM (direct message).
121
+ */
122
+ export function isDmChannel(channel) {
123
+ return channel.startsWith('dm:');
124
+ }
125
+ /**
126
+ * Check if a channel is private.
127
+ */
128
+ export function isPrivateChannel(channel) {
129
+ return channel.startsWith('private:');
130
+ }
131
+ /**
132
+ * Check if a channel is a public channel (starts with #).
133
+ */
134
+ export function isPublicChannel(channel) {
135
+ return channel.startsWith('#');
136
+ }
137
+ /**
138
+ * Normalize channel name for storage/lookup.
139
+ * - Removes leading # from public channels
140
+ * - Sorts participants in DM channels
141
+ */
142
+ export function normalizeChannelName(channel) {
143
+ if (channel.startsWith('#')) {
144
+ return channel.slice(1);
145
+ }
146
+ if (channel.startsWith('dm:')) {
147
+ const participants = parseDmChannel(channel);
148
+ if (participants) {
149
+ return createDmChannelName(...participants);
150
+ }
151
+ }
152
+ return channel;
153
+ }
154
+ //# sourceMappingURL=channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channels.js","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Frame encoding/decoding for the Agent Relay protocol.
3
+ * @agent-relay/sdk
4
+ *
5
+ * Wire format:
6
+ * - 1 byte: format indicator (0 = JSON, 1 = MessagePack)
7
+ * - 4 bytes: big-endian payload length
8
+ * - N bytes: payload (JSON or MessagePack encoded)
9
+ *
10
+ * Legacy format (for backwards compatibility):
11
+ * - 4 bytes: big-endian payload length
12
+ * - N bytes: JSON payload
13
+ */
14
+ import type { Envelope } from './types.js';
15
+ export declare const MAX_FRAME_BYTES: number;
16
+ export declare const HEADER_SIZE = 5;
17
+ export declare const LEGACY_HEADER_SIZE = 4;
18
+ export type WireFormat = 'json' | 'msgpack';
19
+ /**
20
+ * Initialize MessagePack support.
21
+ * Install @msgpack/msgpack to enable: npm install @msgpack/msgpack
22
+ */
23
+ export declare function initMessagePack(): Promise<boolean>;
24
+ /**
25
+ * Check if MessagePack is available.
26
+ */
27
+ export declare function hasMessagePack(): boolean;
28
+ /**
29
+ * Encode a message envelope into a framed buffer.
30
+ *
31
+ * @param envelope - The envelope to encode
32
+ * @param format - Wire format to use (default: 'json')
33
+ * @returns Framed buffer ready for socket write
34
+ */
35
+ export declare function encodeFrame(envelope: Envelope, format?: WireFormat): Buffer;
36
+ /**
37
+ * Encode a frame in legacy format (no format byte, JSON only).
38
+ * Used for backwards compatibility with older clients.
39
+ */
40
+ export declare function encodeFrameLegacy(envelope: Envelope): Buffer;
41
+ /**
42
+ * Ring buffer-based frame parser for streaming data.
43
+ */
44
+ export declare class FrameParser {
45
+ private ring;
46
+ private head;
47
+ private tail;
48
+ private readonly capacity;
49
+ private readonly maxFrameBytes;
50
+ private format;
51
+ private legacyMode;
52
+ constructor(maxFrameBytes?: number);
53
+ /**
54
+ * Set the expected wire format for parsing.
55
+ */
56
+ setFormat(format: WireFormat): void;
57
+ /**
58
+ * Enable legacy mode (4-byte header, JSON only).
59
+ */
60
+ setLegacyMode(legacy: boolean): void;
61
+ /**
62
+ * Get current unread bytes in buffer.
63
+ */
64
+ get pendingBytes(): number;
65
+ /**
66
+ * Push data into the parser and extract complete frames.
67
+ *
68
+ * @param data - Incoming data buffer
69
+ * @returns Array of parsed envelope frames
70
+ */
71
+ push(data: Buffer): Envelope[];
72
+ private extractFrames;
73
+ private decodePayload;
74
+ private compact;
75
+ /**
76
+ * Reset parser state.
77
+ */
78
+ reset(): void;
79
+ }
80
+ //# sourceMappingURL=framing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framing.d.ts","sourceRoot":"","sources":["../src/framing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,eAAe,QAAc,CAAC;AAC3C,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAS5C;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAgBxD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAE,UAAmB,GAAG,MAAM,CAsBnF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAY5D;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,UAAU,CAAS;gBAEf,aAAa,GAAE,MAAwB;IAMnD;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAInC;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAIpC;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE;IAiB9B,OAAO,CAAC,aAAa;IA8CrB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,OAAO;IAWf;;OAEG;IACH,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Frame encoding/decoding for the Agent Relay protocol.
3
+ * @agent-relay/sdk
4
+ *
5
+ * Wire format:
6
+ * - 1 byte: format indicator (0 = JSON, 1 = MessagePack)
7
+ * - 4 bytes: big-endian payload length
8
+ * - N bytes: payload (JSON or MessagePack encoded)
9
+ *
10
+ * Legacy format (for backwards compatibility):
11
+ * - 4 bytes: big-endian payload length
12
+ * - N bytes: JSON payload
13
+ */
14
+ export const MAX_FRAME_BYTES = 1024 * 1024; // 1 MiB
15
+ export const HEADER_SIZE = 5; // 1 byte format + 4 bytes length
16
+ export const LEGACY_HEADER_SIZE = 4; // For backwards compatibility
17
+ // Format indicator bytes
18
+ const FORMAT_JSON = 0;
19
+ const FORMAT_MSGPACK = 1;
20
+ // Optional MessagePack - loaded dynamically if available
21
+ let msgpack = null;
22
+ /**
23
+ * Initialize MessagePack support.
24
+ * Install @msgpack/msgpack to enable: npm install @msgpack/msgpack
25
+ */
26
+ export async function initMessagePack() {
27
+ if (msgpack)
28
+ return true;
29
+ try {
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ const mod = await import('@msgpack/msgpack');
32
+ const encode = mod.encode || mod.default?.encode;
33
+ const decode = mod.decode || mod.default?.decode;
34
+ if (encode && decode) {
35
+ msgpack = { encode, decode };
36
+ return true;
37
+ }
38
+ return false;
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * Check if MessagePack is available.
46
+ */
47
+ export function hasMessagePack() {
48
+ return msgpack !== null;
49
+ }
50
+ /**
51
+ * Encode a message envelope into a framed buffer.
52
+ *
53
+ * @param envelope - The envelope to encode
54
+ * @param format - Wire format to use (default: 'json')
55
+ * @returns Framed buffer ready for socket write
56
+ */
57
+ export function encodeFrame(envelope, format = 'json') {
58
+ let data;
59
+ let formatByte;
60
+ if (format === 'msgpack' && msgpack) {
61
+ const encoded = msgpack.encode(envelope);
62
+ data = Buffer.from(encoded.buffer, encoded.byteOffset, encoded.byteLength);
63
+ formatByte = FORMAT_MSGPACK;
64
+ }
65
+ else {
66
+ data = Buffer.from(JSON.stringify(envelope), 'utf-8');
67
+ formatByte = FORMAT_JSON;
68
+ }
69
+ if (data.length > MAX_FRAME_BYTES) {
70
+ throw new Error(`Frame too large: ${data.length} > ${MAX_FRAME_BYTES}`);
71
+ }
72
+ const header = Buffer.alloc(HEADER_SIZE);
73
+ header.writeUInt8(formatByte, 0);
74
+ header.writeUInt32BE(data.length, 1);
75
+ return Buffer.concat([header, data]);
76
+ }
77
+ /**
78
+ * Encode a frame in legacy format (no format byte, JSON only).
79
+ * Used for backwards compatibility with older clients.
80
+ */
81
+ export function encodeFrameLegacy(envelope) {
82
+ const json = JSON.stringify(envelope);
83
+ const data = Buffer.from(json, 'utf-8');
84
+ if (data.length > MAX_FRAME_BYTES) {
85
+ throw new Error(`Frame too large: ${data.length} > ${MAX_FRAME_BYTES}`);
86
+ }
87
+ const header = Buffer.alloc(LEGACY_HEADER_SIZE);
88
+ header.writeUInt32BE(data.length, 0);
89
+ return Buffer.concat([header, data]);
90
+ }
91
+ /**
92
+ * Ring buffer-based frame parser for streaming data.
93
+ */
94
+ export class FrameParser {
95
+ ring;
96
+ head = 0;
97
+ tail = 0;
98
+ capacity;
99
+ maxFrameBytes;
100
+ format = 'json';
101
+ legacyMode = false;
102
+ constructor(maxFrameBytes = MAX_FRAME_BYTES) {
103
+ this.maxFrameBytes = maxFrameBytes;
104
+ this.capacity = maxFrameBytes * 2 + HEADER_SIZE;
105
+ this.ring = Buffer.allocUnsafe(this.capacity);
106
+ }
107
+ /**
108
+ * Set the expected wire format for parsing.
109
+ */
110
+ setFormat(format) {
111
+ this.format = format;
112
+ }
113
+ /**
114
+ * Enable legacy mode (4-byte header, JSON only).
115
+ */
116
+ setLegacyMode(legacy) {
117
+ this.legacyMode = legacy;
118
+ }
119
+ /**
120
+ * Get current unread bytes in buffer.
121
+ */
122
+ get pendingBytes() {
123
+ return this.tail - this.head;
124
+ }
125
+ /**
126
+ * Push data into the parser and extract complete frames.
127
+ *
128
+ * @param data - Incoming data buffer
129
+ * @returns Array of parsed envelope frames
130
+ */
131
+ push(data) {
132
+ const spaceAtEnd = this.capacity - this.tail;
133
+ if (data.length > spaceAtEnd) {
134
+ this.compact();
135
+ if (data.length > this.capacity - this.tail) {
136
+ throw new Error(`Buffer overflow: data ${data.length} exceeds capacity`);
137
+ }
138
+ }
139
+ data.copy(this.ring, this.tail);
140
+ this.tail += data.length;
141
+ return this.extractFrames();
142
+ }
143
+ extractFrames() {
144
+ const frames = [];
145
+ const headerSize = this.legacyMode ? LEGACY_HEADER_SIZE : HEADER_SIZE;
146
+ while (this.pendingBytes >= headerSize) {
147
+ let formatByte = FORMAT_JSON;
148
+ let frameLength;
149
+ if (this.legacyMode) {
150
+ frameLength = this.ring.readUInt32BE(this.head);
151
+ }
152
+ else {
153
+ formatByte = this.ring.readUInt8(this.head);
154
+ frameLength = this.ring.readUInt32BE(this.head + 1);
155
+ }
156
+ if (frameLength > this.maxFrameBytes) {
157
+ throw new Error(`Frame too large: ${frameLength} > ${this.maxFrameBytes}`);
158
+ }
159
+ const totalLength = headerSize + frameLength;
160
+ if (this.pendingBytes < totalLength) {
161
+ break;
162
+ }
163
+ const payloadStart = this.head + headerSize;
164
+ const payloadEnd = this.head + totalLength;
165
+ let envelope;
166
+ try {
167
+ envelope = this.decodePayload(formatByte, payloadStart, payloadEnd);
168
+ }
169
+ catch (err) {
170
+ throw new Error(`Invalid frame payload: ${err}`);
171
+ }
172
+ this.head += totalLength;
173
+ frames.push(envelope);
174
+ }
175
+ if (this.head > this.capacity / 2 && this.pendingBytes < this.capacity / 4) {
176
+ this.compact();
177
+ }
178
+ return frames;
179
+ }
180
+ decodePayload(formatByte, start, end) {
181
+ if (formatByte === FORMAT_MSGPACK && msgpack) {
182
+ return msgpack.decode(this.ring.subarray(start, end));
183
+ }
184
+ else {
185
+ return JSON.parse(this.ring.toString('utf-8', start, end));
186
+ }
187
+ }
188
+ compact() {
189
+ if (this.head === 0)
190
+ return;
191
+ const unread = this.pendingBytes;
192
+ if (unread > 0) {
193
+ this.ring.copy(this.ring, 0, this.head, this.tail);
194
+ }
195
+ this.head = 0;
196
+ this.tail = unread;
197
+ }
198
+ /**
199
+ * Reset parser state.
200
+ */
201
+ reset() {
202
+ this.head = 0;
203
+ this.tail = 0;
204
+ }
205
+ }
206
+ //# sourceMappingURL=framing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framing.js","sourceRoot":"","sources":["../src/framing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Monotonic ID Generator
3
+ *
4
+ * Generates unique, lexicographically sortable IDs that are faster than UUID v4.
5
+ *
6
+ * Format: <timestamp-base36>-<counter-base36>-<nodeId>
7
+ * Example: "lxyz5g8-0001-7d2a"
8
+ *
9
+ * Properties:
10
+ * - Lexicographically sortable by time
11
+ * - Unique across processes (node prefix)
12
+ * - ~16x faster than UUID v4
13
+ * - Shorter (20-24 chars vs 36 chars)
14
+ */
15
+ export declare class IdGenerator {
16
+ private counter;
17
+ private readonly prefix;
18
+ private lastTs;
19
+ constructor(nodeId?: string);
20
+ /**
21
+ * Generate a unique, monotonically increasing ID.
22
+ */
23
+ next(): string;
24
+ /**
25
+ * Generate a short ID (just timestamp + counter, no node prefix).
26
+ * Use when you don't need cross-process uniqueness.
27
+ */
28
+ short(): string;
29
+ }
30
+ export declare const idGen: IdGenerator;
31
+ /**
32
+ * Generate a unique ID (drop-in replacement for uuid()).
33
+ */
34
+ export declare function generateId(): string;
35
+ //# sourceMappingURL=id-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id-generator.d.ts","sourceRoot":"","sources":["../src/id-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,MAAM,CAAK;gBAEP,MAAM,CAAC,EAAE,MAAM;IAK3B;;OAEG;IACH,IAAI,IAAI,MAAM;IAcd;;;OAGG;IACH,KAAK,IAAI,MAAM;CAYhB;AAGD,eAAO,MAAM,KAAK,aAAoB,CAAC;AAEvC;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}