@crow-agent/server 0.0.0-stage → 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/README.md +108 -2
- package/dist/public-api.d.ts +5 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -0
- package/dist/server-connection.d.ts +32 -0
- package/dist/server-connection.d.ts.map +1 -0
- package/dist/server-connection.js +5 -0
- package/dist/server-connection.js.map +1 -0
- package/dist/server-errors.d.ts +31 -0
- package/dist/server-errors.d.ts.map +1 -0
- package/dist/server-errors.js +41 -0
- package/dist/server-errors.js.map +1 -0
- package/dist/server-listener.d.ts +8 -0
- package/dist/server-listener.d.ts.map +1 -0
- package/dist/server-listener.js +2 -0
- package/dist/server-listener.js.map +1 -0
- package/dist/server-types.d.ts +52 -0
- package/dist/server-types.d.ts.map +1 -0
- package/dist/server-types.js +2 -0
- package/dist/server-types.js.map +1 -0
- package/dist/session-routing.d.ts +42 -0
- package/dist/session-routing.d.ts.map +1 -0
- package/dist/session-routing.js +300 -0
- package/dist/session-routing.js.map +1 -0
- package/dist/session-server.d.ts +14 -0
- package/dist/session-server.d.ts.map +1 -0
- package/dist/session-server.js +678 -0
- package/dist/session-server.js.map +1 -0
- package/dist/testing/public-api.d.ts +6 -0
- package/dist/testing/public-api.d.ts.map +1 -0
- package/dist/testing/public-api.js +4 -0
- package/dist/testing/public-api.js.map +1 -0
- package/dist/testing/test-client.d.ts +29 -0
- package/dist/testing/test-client.d.ts.map +1 -0
- package/dist/testing/test-client.js +196 -0
- package/dist/testing/test-client.js.map +1 -0
- package/dist/testing/test-host.d.ts +62 -0
- package/dist/testing/test-host.d.ts.map +1 -0
- package/dist/testing/test-host.js +241 -0
- package/dist/testing/test-host.js.map +1 -0
- package/dist/testing/test-server.d.ts +13 -0
- package/dist/testing/test-server.d.ts.map +1 -0
- package/dist/testing/test-server.js +17 -0
- package/dist/testing/test-server.js.map +1 -0
- package/dist/transports/unix/public-api.d.ts +5 -0
- package/dist/transports/unix/public-api.d.ts.map +1 -0
- package/dist/transports/unix/public-api.js +4 -0
- package/dist/transports/unix/public-api.js.map +1 -0
- package/dist/transports/unix/socket-address.d.ts +3 -0
- package/dist/transports/unix/socket-address.d.ts.map +1 -0
- package/dist/transports/unix/socket-address.js +11 -0
- package/dist/transports/unix/socket-address.js.map +1 -0
- package/dist/transports/unix/unix-listener.d.ts +18 -0
- package/dist/transports/unix/unix-listener.d.ts.map +1 -0
- package/dist/transports/unix/unix-listener.js +511 -0
- package/dist/transports/unix/unix-listener.js.map +1 -0
- package/dist/transports/unix/unix-preset.d.ts +7 -0
- package/dist/transports/unix/unix-preset.d.ts.map +1 -0
- package/dist/transports/unix/unix-preset.js +25 -0
- package/dist/transports/unix/unix-preset.js.map +1 -0
- package/dist/transports/unix/unix-types.d.ts +14 -0
- package/dist/transports/unix/unix-types.d.ts.map +1 -0
- package/dist/transports/unix/unix-types.js +2 -0
- package/dist/transports/unix/unix-types.js.map +1 -0
- package/package.json +53 -4
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT, MemorySessionRepo, } from "@crow-agent/agent-core";
|
|
2
|
+
import { SessionAmbiguousError, SessionNotFoundError, } from "../server-errors.js";
|
|
3
|
+
export class Deferred {
|
|
4
|
+
#promise;
|
|
5
|
+
#resolve = () => undefined;
|
|
6
|
+
constructor() {
|
|
7
|
+
this.#promise = new Promise((resolve) => {
|
|
8
|
+
this.#resolve = resolve;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
get promise() {
|
|
12
|
+
return this.#promise;
|
|
13
|
+
}
|
|
14
|
+
resolve(value) {
|
|
15
|
+
this.#resolve(value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** A manually-released checkpoint: `pass()` signals entry, then waits for `release`. */
|
|
19
|
+
class Gate {
|
|
20
|
+
entered = new Deferred();
|
|
21
|
+
release = new Deferred();
|
|
22
|
+
async pass() {
|
|
23
|
+
this.entered.resolve(undefined);
|
|
24
|
+
await this.release.promise;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** A single client lease on a TestHarness; release is idempotent per source ordering. */
|
|
28
|
+
class HarnessLease {
|
|
29
|
+
#harness;
|
|
30
|
+
#released = false;
|
|
31
|
+
constructor(harness) {
|
|
32
|
+
this.#harness = harness;
|
|
33
|
+
}
|
|
34
|
+
invokeService = (call) => this.#harness.invokeService(call);
|
|
35
|
+
release(_context) {
|
|
36
|
+
if (this.#released)
|
|
37
|
+
return;
|
|
38
|
+
const harness = this.#harness;
|
|
39
|
+
const releases = harness.attachmentReleaseCount + 1;
|
|
40
|
+
harness.attachmentReleaseCount = releases;
|
|
41
|
+
const failure = harness.failAttachmentRelease;
|
|
42
|
+
if (failure !== undefined)
|
|
43
|
+
throw failure;
|
|
44
|
+
this.#released = true;
|
|
45
|
+
harness.attachedClients = harness.attachedClients - 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export class TestHarness {
|
|
49
|
+
session;
|
|
50
|
+
serviceCalls = [];
|
|
51
|
+
closed = new Deferred();
|
|
52
|
+
#termination = new Deferred();
|
|
53
|
+
attachedClients = 0;
|
|
54
|
+
attachmentReleaseCount = 0;
|
|
55
|
+
closeCount = 0;
|
|
56
|
+
failAttachmentRelease;
|
|
57
|
+
failClose;
|
|
58
|
+
nextServiceError;
|
|
59
|
+
nextServiceResult = { ok: true };
|
|
60
|
+
#closeGate;
|
|
61
|
+
#serviceGate;
|
|
62
|
+
constructor(session) {
|
|
63
|
+
this.session = session;
|
|
64
|
+
}
|
|
65
|
+
get terminated() {
|
|
66
|
+
return this.#termination.promise;
|
|
67
|
+
}
|
|
68
|
+
attachClient(_context) {
|
|
69
|
+
const count = this.attachedClients + 1;
|
|
70
|
+
this.attachedClients = count;
|
|
71
|
+
return new HarnessLease(this);
|
|
72
|
+
}
|
|
73
|
+
async invokeService(call) {
|
|
74
|
+
const calls = this.serviceCalls;
|
|
75
|
+
calls.push(call);
|
|
76
|
+
const failure = this.nextServiceError;
|
|
77
|
+
this.nextServiceError = undefined;
|
|
78
|
+
if (failure !== undefined)
|
|
79
|
+
throw failure;
|
|
80
|
+
const gate = this.#serviceGate;
|
|
81
|
+
this.#serviceGate = undefined;
|
|
82
|
+
await this.passGate(gate);
|
|
83
|
+
return this.takeServiceResult();
|
|
84
|
+
}
|
|
85
|
+
async close(context) {
|
|
86
|
+
this.closeCount = this.closeCount + 1;
|
|
87
|
+
const gate = this.#closeGate;
|
|
88
|
+
this.#closeGate = undefined;
|
|
89
|
+
await this.passGate(gate);
|
|
90
|
+
const failure = this.failClose;
|
|
91
|
+
this.failClose = undefined;
|
|
92
|
+
if (failure !== undefined)
|
|
93
|
+
throw failure;
|
|
94
|
+
const session = this.session;
|
|
95
|
+
const closing = session.close(context);
|
|
96
|
+
await closing;
|
|
97
|
+
this.closed.resolve(undefined);
|
|
98
|
+
this.#termination.resolve(undefined);
|
|
99
|
+
}
|
|
100
|
+
async terminate(error) {
|
|
101
|
+
const session = this.session;
|
|
102
|
+
await session.close(BACKGROUND_CONTEXT);
|
|
103
|
+
this.#termination.resolve(error);
|
|
104
|
+
}
|
|
105
|
+
gateNextClose() {
|
|
106
|
+
const gate = new Gate();
|
|
107
|
+
this.#closeGate = gate;
|
|
108
|
+
return gate;
|
|
109
|
+
}
|
|
110
|
+
gateNextServiceCall() {
|
|
111
|
+
const gate = new Gate();
|
|
112
|
+
this.#serviceGate = gate;
|
|
113
|
+
return gate;
|
|
114
|
+
}
|
|
115
|
+
async passGate(gate) {
|
|
116
|
+
if (gate !== undefined)
|
|
117
|
+
await gate.pass();
|
|
118
|
+
}
|
|
119
|
+
takeServiceResult() {
|
|
120
|
+
const result = this.nextServiceResult;
|
|
121
|
+
this.nextServiceResult = { ok: true };
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const SESSION_MANAGEMENT = "crow.session-management";
|
|
126
|
+
function isAttachCall(call) {
|
|
127
|
+
if (call.instance !== undefined)
|
|
128
|
+
return false;
|
|
129
|
+
const serviceMatch = call.serviceId === SESSION_MANAGEMENT && call.member === "attach";
|
|
130
|
+
if (!serviceMatch)
|
|
131
|
+
return false;
|
|
132
|
+
const [target] = call.args;
|
|
133
|
+
return call.args.length === 1 && typeof target === "string";
|
|
134
|
+
}
|
|
135
|
+
function isDetachCall(call) {
|
|
136
|
+
if (call.instance !== undefined)
|
|
137
|
+
return false;
|
|
138
|
+
const serviceMatch = call.serviceId === SESSION_MANAGEMENT && call.member === "detach";
|
|
139
|
+
if (!serviceMatch)
|
|
140
|
+
return false;
|
|
141
|
+
return call.args.length === 0;
|
|
142
|
+
}
|
|
143
|
+
function unsupportedService(call) {
|
|
144
|
+
return new Error(`Unsupported test server service ${call.serviceId}.${call.member}`);
|
|
145
|
+
}
|
|
146
|
+
export function createTestServerServices() {
|
|
147
|
+
const dispatch = async (presentation, call, context) => {
|
|
148
|
+
if (isAttachCall(call)) {
|
|
149
|
+
const [sessionId] = call.args;
|
|
150
|
+
await presentation.attachSession(sessionId, context);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
if (isDetachCall(call)) {
|
|
154
|
+
await presentation.detachSession(context);
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
throw unsupportedService(call);
|
|
158
|
+
};
|
|
159
|
+
const attachClient = (presentation) => ({
|
|
160
|
+
invokeService: (call, _publish, context) => dispatch(presentation, call, context),
|
|
161
|
+
release: () => undefined,
|
|
162
|
+
});
|
|
163
|
+
return { attachClient };
|
|
164
|
+
}
|
|
165
|
+
export class TestServerHost {
|
|
166
|
+
serverServices = createTestServerServices();
|
|
167
|
+
repo = new MemorySessionRepo({ now: () => 1 });
|
|
168
|
+
harnesses = new Map();
|
|
169
|
+
openSessionCount = 0;
|
|
170
|
+
nextOpenSessionError;
|
|
171
|
+
nextHarnessCloseError;
|
|
172
|
+
#openGate;
|
|
173
|
+
async resolveSession(sessionId, context) {
|
|
174
|
+
const sessions = await this.repo.list(undefined, context);
|
|
175
|
+
let found;
|
|
176
|
+
let duplicates = 0;
|
|
177
|
+
for (const candidate of sessions) {
|
|
178
|
+
if (candidate.id !== sessionId)
|
|
179
|
+
continue;
|
|
180
|
+
duplicates += 1;
|
|
181
|
+
found = candidate;
|
|
182
|
+
}
|
|
183
|
+
if (found === undefined)
|
|
184
|
+
throw new SessionNotFoundError(`Unknown session: ${sessionId}`);
|
|
185
|
+
if (duplicates > 1)
|
|
186
|
+
throw new SessionAmbiguousError();
|
|
187
|
+
return found;
|
|
188
|
+
}
|
|
189
|
+
async openSession(metadata, context) {
|
|
190
|
+
this.openSessionCount = this.openSessionCount + 1;
|
|
191
|
+
const gate = this.#openGate;
|
|
192
|
+
this.#openGate = undefined;
|
|
193
|
+
await this.passGate(gate);
|
|
194
|
+
const session = await this.repo.open(metadata, context);
|
|
195
|
+
const outcome = this.buildHarness(metadata, session);
|
|
196
|
+
if ("failure" in outcome) {
|
|
197
|
+
const closing = session.close(context);
|
|
198
|
+
await closing;
|
|
199
|
+
throw outcome.failure;
|
|
200
|
+
}
|
|
201
|
+
return outcome.harness;
|
|
202
|
+
}
|
|
203
|
+
async seed(id = "session-1", parentSessionId) {
|
|
204
|
+
const created = await this.repo.create({ id, parentSessionId }, BACKGROUND_CONTEXT);
|
|
205
|
+
const metadata = created.metadata;
|
|
206
|
+
await created.close(BACKGROUND_CONTEXT);
|
|
207
|
+
return metadata;
|
|
208
|
+
}
|
|
209
|
+
gateNextOpenSession() {
|
|
210
|
+
const gate = new Gate();
|
|
211
|
+
this.#openGate = gate;
|
|
212
|
+
return gate;
|
|
213
|
+
}
|
|
214
|
+
latestHarness(id) {
|
|
215
|
+
const harnesses = this.harnesses.get(id);
|
|
216
|
+
const latest = harnesses === undefined ? undefined : harnesses[harnesses.length - 1];
|
|
217
|
+
if (latest === undefined)
|
|
218
|
+
throw new Error(`No harness for ${id}`);
|
|
219
|
+
return latest;
|
|
220
|
+
}
|
|
221
|
+
async passGate(gate) {
|
|
222
|
+
if (gate !== undefined)
|
|
223
|
+
await gate.pass();
|
|
224
|
+
}
|
|
225
|
+
buildHarness(metadata, session) {
|
|
226
|
+
const failure = this.nextOpenSessionError;
|
|
227
|
+
this.nextOpenSessionError = undefined;
|
|
228
|
+
if (failure !== undefined)
|
|
229
|
+
return { failure };
|
|
230
|
+
const harness = new TestHarness(session);
|
|
231
|
+
const closeFailure = this.nextHarnessCloseError;
|
|
232
|
+
this.nextHarnessCloseError = undefined;
|
|
233
|
+
if (closeFailure !== undefined)
|
|
234
|
+
harness.failClose = closeFailure;
|
|
235
|
+
const harnesses = this.harnesses.get(metadata.id) ?? [];
|
|
236
|
+
harnesses.push(harness);
|
|
237
|
+
this.harnesses.set(metadata.id, harnesses);
|
|
238
|
+
return { harness };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=test-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-host.js","sourceRoot":"","sources":["../../src/testing/test-host.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tJsonValue,\n\tServiceCall,\n} from \"@crow-agent/chord\";\nimport type {\n\tContext,\n\tSession,\n\tSessionMetadata,\n} from \"@crow-agent/agent-core\";\nimport {\n\tBACKGROUND_CONTEXT,\n\tMemorySessionRepo,\n} from \"@crow-agent/agent-core\";\nimport {\n\tSessionAmbiguousError,\n\tSessionNotFoundError,\n} from \"../server-errors.ts\";\nimport type {\n\tRoutedServerPresentation,\n\tRoutedServerServiceHost,\n\tRoutedSessionHandle,\n\tServerHost,\n} from \"../server-types.ts\";\n\nexport class Deferred<T = void> {\n\t#promise: Promise<T>;\n\t#resolve: (value: T) => void = () => undefined;\n\n\tconstructor() {\n\t\tthis.#promise = new Promise<T>((resolve) => {\n\t\t\tthis.#resolve = resolve;\n\t\t});\n\t}\n\n\tget promise(): Promise<T> {\n\t\treturn this.#promise;\n\t}\n\n\tresolve(\n\t\tvalue: T,\n\t): void {\n\t\tthis.#resolve(value);\n\t}\n}\n\n/** A manually-released checkpoint: `pass()` signals entry, then waits for `release`. */\nclass Gate {\n\treadonly entered = new Deferred<void>();\n\treadonly release = new Deferred<void>();\n\n\tasync pass(): Promise<void> {\n\t\tthis.entered.resolve(undefined);\n\t\tawait this.release.promise;\n\t}\n}\n\ntype HarnessAttachment = {\n\tinvokeService: (\n\t\tcall: ServiceCall,\n\t) => Promise<JsonValue | undefined>;\n\trelease: (\n\t\tcontext: Context,\n\t) => void;\n};\n\n/** A single client lease on a TestHarness; release is idempotent per source ordering. */\nclass HarnessLease {\n\t#harness: TestHarness;\n\t#released = false;\n\n\tconstructor(\n\t\tharness: TestHarness,\n\t) {\n\t\tthis.#harness = harness;\n\t}\n\n\tinvokeService = (\n\t\tcall: ServiceCall,\n\t): Promise<JsonValue | undefined> => this.#harness.invokeService(call);\n\n\trelease(\n\t\t_context: Context,\n\t): void {\n\t\tif (this.#released) return;\n\t\tconst harness = this.#harness;\n\t\tconst releases = harness.attachmentReleaseCount + 1;\n\t\tharness.attachmentReleaseCount = releases;\n\t\tconst failure: Error | undefined = harness.failAttachmentRelease;\n\t\tif (failure !== undefined) throw failure;\n\t\tthis.#released = true;\n\t\tharness.attachedClients = harness.attachedClients - 1;\n\t}\n}\n\nexport class TestHarness {\n\treadonly session: Session;\n\treadonly serviceCalls: Array<ServiceCall> = [];\n\treadonly closed: Deferred<void> = new Deferred<void>();\n\t#termination = new Deferred<Error | undefined>();\n\tattachedClients: number = 0;\n\tattachmentReleaseCount: number = 0;\n\tcloseCount: number = 0;\n\tfailAttachmentRelease: Error | undefined;\n\tfailClose: Error | undefined;\n\tnextServiceError: Error | undefined;\n\tnextServiceResult: JsonValue | undefined = { ok: true as const };\n\t#closeGate: Gate | undefined;\n\t#serviceGate: Gate | undefined;\n\n\tconstructor(\n\t\tsession: Session,\n\t) {\n\t\tthis.session = session;\n\t}\n\n\tget terminated(): Promise<Error | undefined> {\n\t\treturn this.#termination.promise;\n\t}\n\n\tattachClient(\n\t\t_context: Context,\n\t): HarnessAttachment {\n\t\tconst count = this.attachedClients + 1;\n\t\tthis.attachedClients = count;\n\t\treturn new HarnessLease(this);\n\t}\n\n\tasync invokeService(\n\t\tcall: ServiceCall,\n\t): Promise<JsonValue | undefined> {\n\t\tconst calls = this.serviceCalls;\n\t\tcalls.push(call);\n\t\tconst failure: Error | undefined = this.nextServiceError;\n\t\tthis.nextServiceError = undefined;\n\t\tif (failure !== undefined) throw failure;\n\t\tconst gate = this.#serviceGate;\n\t\tthis.#serviceGate = undefined;\n\t\tawait this.passGate(gate);\n\t\treturn this.takeServiceResult();\n\t}\n\n\tasync close(\n\t\tcontext: Context,\n\t): Promise<void> {\n\t\tthis.closeCount = this.closeCount + 1;\n\t\tconst gate = this.#closeGate;\n\t\tthis.#closeGate = undefined;\n\t\tawait this.passGate(gate);\n\t\tconst failure: Error | undefined = this.failClose;\n\t\tthis.failClose = undefined;\n\t\tif (failure !== undefined) throw failure;\n\t\tconst session = this.session;\n\t\tconst closing = session.close(context);\n\t\tawait closing;\n\t\tthis.closed.resolve(undefined);\n\t\tthis.#termination.resolve(undefined);\n\t}\n\n\tasync terminate(\n\t\terror: Error,\n\t): Promise<void> {\n\t\tconst session = this.session;\n\t\tawait session.close(BACKGROUND_CONTEXT);\n\t\tthis.#termination.resolve(error);\n\t}\n\n\tgateNextClose(): Gate {\n\t\tconst gate = new Gate();\n\t\tthis.#closeGate = gate;\n\t\treturn gate;\n\t}\n\n\tgateNextServiceCall(): Gate {\n\t\tconst gate = new Gate();\n\t\tthis.#serviceGate = gate;\n\t\treturn gate;\n\t}\n\n\tprivate async passGate(\n\t\tgate: Gate | undefined,\n\t): Promise<void> {\n\t\tif (gate !== undefined) await gate.pass();\n\t}\n\n\tprivate takeServiceResult(): JsonValue | undefined {\n\t\tconst result = this.nextServiceResult;\n\t\tthis.nextServiceResult = { ok: true };\n\t\treturn result;\n\t}\n}\n\nconst SESSION_MANAGEMENT = \"crow.session-management\";\n\nfunction isAttachCall(\n\tcall: ServiceCall,\n): boolean {\n\tif (call.instance !== undefined) return false;\n\tconst serviceMatch = call.serviceId === SESSION_MANAGEMENT && call.member === \"attach\";\n\tif (!serviceMatch) return false;\n\tconst [target] = call.args;\n\treturn call.args.length === 1 && typeof target === \"string\";\n}\n\nfunction isDetachCall(\n\tcall: ServiceCall,\n): boolean {\n\tif (call.instance !== undefined) return false;\n\tconst serviceMatch = call.serviceId === SESSION_MANAGEMENT && call.member === \"detach\";\n\tif (!serviceMatch) return false;\n\treturn call.args.length === 0;\n}\n\nfunction unsupportedService(\n\tcall: ServiceCall,\n): Error {\n\treturn new Error(`Unsupported test server service ${call.serviceId}.${call.member}`);\n}\n\nexport function createTestServerServices(): RoutedServerServiceHost {\n\tconst dispatch = async (\n\t\tpresentation: RoutedServerPresentation,\n\t\tcall: ServiceCall,\n\t\tcontext: Context,\n\t): Promise<JsonValue | null> => {\n\t\tif (isAttachCall(call)) {\n\t\t\tconst [sessionId] = call.args;\n\t\t\tawait presentation.attachSession(sessionId as string, context);\n\t\t\treturn null;\n\t\t}\n\t\tif (isDetachCall(call)) {\n\t\t\tawait presentation.detachSession(context);\n\t\t\treturn null;\n\t\t}\n\t\tthrow unsupportedService(call);\n\t};\n\tconst attachClient = (\n\t\tpresentation: RoutedServerPresentation,\n\t): {\n\t\tinvokeService: (\n\t\t\tcall: ServiceCall,\n\t\t\t_publish: unknown,\n\t\t\tcontext: Context,\n\t\t) => Promise<JsonValue | null>;\n\t\trelease: () => void;\n\t} => ({\n\t\tinvokeService: (call, _publish, context) => dispatch(presentation, call, context),\n\t\trelease: () => undefined,\n\t});\n\treturn { attachClient };\n}\n\nexport class TestServerHost implements ServerHost {\n\treadonly serverServices: RoutedServerServiceHost = createTestServerServices();\n\treadonly repo: MemorySessionRepo = new MemorySessionRepo({ now: () => 1 });\n\treadonly harnesses: Map<string, Array<TestHarness>> = new Map();\n\topenSessionCount: number = 0;\n\tnextOpenSessionError: Error | undefined;\n\tnextHarnessCloseError: Error | undefined;\n\t#openGate: Gate | undefined;\n\n\tasync resolveSession(\n\t\tsessionId: string,\n\t\tcontext: Context,\n\t): Promise<SessionMetadata> {\n\t\tconst sessions = await this.repo.list(undefined, context);\n\t\tlet found: SessionMetadata | undefined;\n\t\tlet duplicates = 0;\n\t\tfor (const candidate of sessions) {\n\t\t\tif (candidate.id !== sessionId) continue;\n\t\t\tduplicates += 1;\n\t\t\tfound = candidate;\n\t\t}\n\t\tif (found === undefined) throw new SessionNotFoundError(`Unknown session: ${sessionId}`);\n\t\tif (duplicates > 1) throw new SessionAmbiguousError();\n\t\treturn found;\n\t}\n\n\tasync openSession(\n\t\tmetadata: SessionMetadata,\n\t\tcontext: Context,\n\t): Promise<RoutedSessionHandle> {\n\t\tthis.openSessionCount = this.openSessionCount + 1;\n\t\tconst gate = this.#openGate;\n\t\tthis.#openGate = undefined;\n\t\tawait this.passGate(gate);\n\t\tconst session = await this.repo.open(metadata, context);\n\t\tconst outcome = this.buildHarness(metadata, session);\n\t\tif (\"failure\" in outcome) {\n\t\t\tconst closing = session.close(context);\n\t\t\tawait closing;\n\t\t\tthrow outcome.failure;\n\t\t}\n\t\treturn outcome.harness;\n\t}\n\n\tasync seed(\n\t\tid: string = \"session-1\",\n\t\tparentSessionId?: string,\n\t): Promise<SessionMetadata> {\n\t\tconst created = await this.repo.create({ id, parentSessionId }, BACKGROUND_CONTEXT);\n\t\tconst metadata = created.metadata;\n\t\tawait created.close(BACKGROUND_CONTEXT);\n\t\treturn metadata;\n\t}\n\n\tgateNextOpenSession(): Gate {\n\t\tconst gate = new Gate();\n\t\tthis.#openGate = gate;\n\t\treturn gate;\n\t}\n\n\tlatestHarness(\n\t\tid: string,\n\t): TestHarness {\n\t\tconst harnesses = this.harnesses.get(id);\n\t\tconst latest = harnesses === undefined ? undefined : harnesses[harnesses.length - 1];\n\t\tif (latest === undefined) throw new Error(`No harness for ${id}`);\n\t\treturn latest;\n\t}\n\n\tprivate async passGate(\n\t\tgate: Gate | undefined,\n\t): Promise<void> {\n\t\tif (gate !== undefined) await gate.pass();\n\t}\n\n\tprivate buildHarness(\n\t\tmetadata: SessionMetadata,\n\t\tsession: Session,\n\t): { harness: TestHarness } | { failure: Error } {\n\t\tconst failure: Error | undefined = this.nextOpenSessionError;\n\t\tthis.nextOpenSessionError = undefined;\n\t\tif (failure !== undefined) return { failure };\n\t\tconst harness = new TestHarness(session);\n\t\tconst closeFailure: Error | undefined = this.nextHarnessCloseError;\n\t\tthis.nextHarnessCloseError = undefined;\n\t\tif (closeFailure !== undefined) harness.failClose = closeFailure;\n\t\tconst harnesses = this.harnesses.get(metadata.id) ?? [];\n\t\tharnesses.push(harness);\n\t\tthis.harnesses.set(metadata.id, harnesses);\n\t\treturn { harness };\n\t}\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Server } from "../session-server.ts";
|
|
2
|
+
import type { ServerHost, ServerOptions } from "../server-types.ts";
|
|
3
|
+
export type TestServerOptions = Omit<ServerOptions, "serverId"> & {
|
|
4
|
+
host?: ServerHost;
|
|
5
|
+
serverId?: string;
|
|
6
|
+
};
|
|
7
|
+
export type TestServer = {
|
|
8
|
+
server: Server;
|
|
9
|
+
host: ServerHost;
|
|
10
|
+
};
|
|
11
|
+
/** Builds an unstarted Server with deterministic defaults for conformance tests. */
|
|
12
|
+
export declare function createTestServer(options: TestServerOptions): TestServer;
|
|
13
|
+
//# sourceMappingURL=test-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-server.d.ts","sourceRoot":"","sources":["../../src/testing/test-server.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,MAAM,EACN,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,MAAM,oBAAoB,CAAC;AAK5B,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,GAAG;IACjE,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;CACjB,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,iBAAiB,GACxB,UAAU,CAYZ"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Server, } from "../session-server.js";
|
|
2
|
+
import { TestServerHost, } from "./test-host.js";
|
|
3
|
+
/** Builds an unstarted Server with deterministic defaults for conformance tests. */
|
|
4
|
+
export function createTestServer(options) {
|
|
5
|
+
const host = options.host ?? new TestServerHost();
|
|
6
|
+
const { listeners, maxFrameLength, handshakeTimeoutMs, onError } = options;
|
|
7
|
+
const serverId = options.serverId ?? "00000000-0000-4000-8000-000000000001";
|
|
8
|
+
const server = new Server(host, {
|
|
9
|
+
listeners,
|
|
10
|
+
maxFrameLength,
|
|
11
|
+
handshakeTimeoutMs,
|
|
12
|
+
serverId,
|
|
13
|
+
onError,
|
|
14
|
+
});
|
|
15
|
+
return { server, host };
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=test-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-server.js","sourceRoot":"","sources":["../../src/testing/test-server.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,MAAM,GACN,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACN,cAAc,GACd,MAAM,gBAAgB,CAAC;AAYxB,oFAAoF;AACpF,MAAM,UAAU,gBAAgB,CAC/B,OAA0B;IAE1B,MAAM,IAAI,GAAe,OAAO,CAAC,IAAI,IAAI,IAAI,cAAc,EAAE,CAAC;IAC9D,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,kBAAkB,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,sCAAsC,CAAC;IAC5E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE;QAC/B,SAAS;QACT,cAAc;QACd,kBAAkB;QAClB,QAAQ;QACR,OAAO;KACP,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC","sourcesContent":["import {\n\tServer,\n} from \"../session-server.ts\";\nimport type {\n\tServerHost,\n\tServerOptions,\n} from \"../server-types.ts\";\nimport {\n\tTestServerHost,\n} from \"./test-host.ts\";\n\nexport type TestServerOptions = Omit<ServerOptions, \"serverId\"> & {\n\thost?: ServerHost;\n\tserverId?: string;\n};\n\nexport type TestServer = {\n\tserver: Server;\n\thost: ServerHost;\n};\n\n/** Builds an unstarted Server with deterministic defaults for conformance tests. */\nexport function createTestServer(\n\toptions: TestServerOptions,\n): TestServer {\n\tconst host: ServerHost = options.host ?? new TestServerHost();\n\tconst { listeners, maxFrameLength, handshakeTimeoutMs, onError } = options;\n\tconst serverId = options.serverId ?? \"00000000-0000-4000-8000-000000000001\";\n\tconst server = new Server(host, {\n\t\tlisteners,\n\t\tmaxFrameLength,\n\t\thandshakeTimeoutMs,\n\t\tserverId,\n\t\tonError,\n\t});\n\treturn { server, host };\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { getUnixSocketPath, } from "./socket-address.ts";
|
|
2
|
+
export { createUnixListener, } from "./unix-listener.ts";
|
|
3
|
+
export { createUnixServer, } from "./unix-preset.ts";
|
|
4
|
+
export type { UnixListenerOptions, UnixServerOptions, } from "./unix-types.ts";
|
|
5
|
+
//# sourceMappingURL=public-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../../../src/transports/unix/public-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,gBAAgB,GAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACX,mBAAmB,EACnB,iBAAiB,GACjB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-api.js","sourceRoot":"","sources":["../../../src/transports/unix/public-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,gBAAgB,GAChB,MAAM,kBAAkB,CAAC","sourcesContent":["export {\n\tgetUnixSocketPath,\n} from \"./socket-address.ts\";\nexport {\n\tcreateUnixListener,\n} from \"./unix-listener.ts\";\nexport {\n\tcreateUnixServer,\n} from \"./unix-preset.ts\";\nexport type {\n\tUnixListenerOptions,\n\tUnixServerOptions,\n} from \"./unix-types.ts\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket-address.d.ts","sourceRoot":"","sources":["../../../src/transports/unix/socket-address.ts"],"names":[],"mappings":"AAMA,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GACrB,MAAM,CAMR"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { join, } from "node:path";
|
|
2
|
+
const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
3
|
+
/** Computes the local Unix socket path for one logical server identity. */
|
|
4
|
+
export function getUnixSocketPath(serverId, serverDirectory) {
|
|
5
|
+
if (UUID_V4_PATTERN.test(serverId) === false) {
|
|
6
|
+
throw new TypeError("Unix serverId must be a canonical lowercase UUIDv4");
|
|
7
|
+
}
|
|
8
|
+
const file = `${serverId}.sock`;
|
|
9
|
+
return join(serverDirectory, file);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=socket-address.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket-address.js","sourceRoot":"","sources":["../../../src/transports/unix/socket-address.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,IAAI,GACJ,MAAM,WAAW,CAAC;AAEnB,MAAM,eAAe,GAAG,uEAAuE,CAAC;AAEhG,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAChC,QAAgB,EAChB,eAAuB;IAEvB,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,EAAE,CAAC;QAC9C,MAAM,IAAI,SAAS,CAAC,oDAAoD,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,QAAQ,OAAO,CAAC;IAChC,OAAO,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC","sourcesContent":["import {\n\tjoin,\n} from \"node:path\";\n\nconst UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\n\n/** Computes the local Unix socket path for one logical server identity. */\nexport function getUnixSocketPath(\n\tserverId: string,\n\tserverDirectory: string,\n): string {\n\tif (UUID_V4_PATTERN.test(serverId) === false) {\n\t\tthrow new TypeError(\"Unix serverId must be a canonical lowercase UUIDv4\");\n\t}\n\tconst file = `${serverId}.sock`;\n\treturn join(serverDirectory, file);\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Socket } from "node:net";
|
|
2
|
+
import type { ByteConnection } from "../../server-connection.ts";
|
|
3
|
+
import type { ServerListener } from "../../server-listener.ts";
|
|
4
|
+
import type { UnixListenerOptions } from "./unix-types.ts";
|
|
5
|
+
/** Exported for transport-level verification; not part of the public API surface. */
|
|
6
|
+
export declare class UnixByteConnection implements ByteConnection {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(socket: Socket, gracefulCloseTimeoutMs: number, maxPendingBytes: number);
|
|
9
|
+
get closed(): boolean;
|
|
10
|
+
send(chunk: Uint8Array): Promise<void>;
|
|
11
|
+
close(finalChunk?: Uint8Array): Promise<void>;
|
|
12
|
+
markClosed(): void;
|
|
13
|
+
private forceClose;
|
|
14
|
+
private endSocket;
|
|
15
|
+
private flush;
|
|
16
|
+
}
|
|
17
|
+
export declare function createUnixListener(options: UnixListenerOptions): ServerListener;
|
|
18
|
+
//# sourceMappingURL=unix-listener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unix-listener.d.ts","sourceRoot":"","sources":["../../../src/transports/unix/unix-listener.ts"],"names":[],"mappings":"AAeA,OAAO,EAIN,KAAK,MAAM,EACX,MAAM,UAAU,CAAC;AAMlB,OAAO,KAAK,EACX,cAAc,EAEd,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACX,cAAc,EACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACX,mBAAmB,EACnB,MAAM,iBAAiB,CAAC;AAsOzB,qFAAqF;AACrF,qBAAa,kBAAmB,YAAW,cAAc;;IAWxD,YAAY,MAAM,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAIlF;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBrC;IAED,KAAK,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB5C;IAED,UAAU,IAAI,IAAI,CAOjB;IAED,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,KAAK;CAwBb;AAqHD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,mBAAmB,GAC1B,cAAc,CAEhB"}
|