stitchkit 0.59.3 → 0.60.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 +14 -4
- package/dist/agent-runtime/admission-lanes.d.ts +35 -0
- package/dist/agent-runtime/admission-lanes.d.ts.map +1 -0
- package/dist/agent-runtime/coordinator.d.ts +36 -2
- package/dist/agent-runtime/coordinator.d.ts.map +1 -1
- package/dist/agent-runtime/events.d.ts +7 -0
- package/dist/agent-runtime/events.d.ts.map +1 -1
- package/dist/agent-runtime/history.d.ts +7 -0
- package/dist/agent-runtime/history.d.ts.map +1 -1
- package/dist/agent-runtime/models.d.ts +2 -3
- package/dist/agent-runtime/models.d.ts.map +1 -1
- package/dist/agent-runtime/observability.d.ts.map +1 -1
- package/dist/agent-runtime/run-execution.d.ts +31 -0
- package/dist/agent-runtime/run-execution.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-internals.d.ts +25 -0
- package/dist/agent-runtime/runtime-internals.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-result.d.ts +11 -0
- package/dist/agent-runtime/runtime-result.d.ts.map +1 -0
- package/dist/agent-runtime/runtime.d.ts +16 -15
- package/dist/agent-runtime/runtime.d.ts.map +1 -1
- package/dist/agent-runtime/schemas.d.ts.map +1 -1
- package/dist/agent-runtime/store-driver.d.ts.map +1 -1
- package/dist/agent-runtime/store.d.ts +9 -2
- package/dist/agent-runtime/store.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-commit.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-status.d.ts +13 -0
- package/dist/agent-runtime/terminal-status.d.ts.map +1 -0
- package/dist/agent-runtime.d.ts +5 -3
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +211 -156
- package/dist/application/activity.d.ts +7 -2
- package/dist/application/activity.d.ts.map +1 -1
- package/dist/application/grammy.d.ts +6 -0
- package/dist/application/grammy.d.ts.map +1 -1
- package/dist/application/health.d.ts +20 -1
- package/dist/application/health.d.ts.map +1 -1
- package/dist/application/kernel.d.ts +49 -3
- package/dist/application/kernel.d.ts.map +1 -1
- package/dist/application/opentelemetry.d.ts +25 -0
- package/dist/application/opentelemetry.d.ts.map +1 -0
- package/dist/application/schemas.d.ts +42 -0
- package/dist/application/schemas.d.ts.map +1 -1
- package/dist/application-opentelemetry.d.ts +2 -0
- package/dist/application-opentelemetry.d.ts.map +1 -0
- package/dist/application-opentelemetry.js +248 -0
- package/dist/application.d.ts +4 -4
- package/dist/application.d.ts.map +1 -1
- package/dist/application.js +69 -1243
- package/dist/cli.js +6 -6
- package/dist/contract/errors.d.ts +6 -0
- package/dist/contract/errors.d.ts.map +1 -1
- package/dist/contract/index.js +1 -1
- package/dist/declaration.d.ts +345 -0
- package/dist/declaration.d.ts.map +1 -0
- package/dist/declaration.js +183 -0
- package/dist/index-1zencgcb.js +651 -0
- package/dist/{index-sa2mbwa7.js → index-2akar0rq.js} +2 -2
- package/dist/{index-41wm56v0.js → index-3hn10n4c.js} +1 -1
- package/dist/{index-f6pymtqe.js → index-3w74r08v.js} +2 -2
- package/dist/{index-7c0gkyvj.js → index-6fbp58g8.js} +2 -2
- package/dist/{index-gnvzyw0k.js → index-8es1hrv4.js} +2 -2
- package/dist/index-8eywc9zv.js +100 -0
- package/dist/{index-3nwng7hs.js → index-8pc5s3pz.js} +4 -4
- package/dist/{index-28cqssm3.js → index-9h1vba8n.js} +6 -0
- package/dist/{index-0nc0cddp.js → index-a59da114.js} +17 -28
- package/dist/{index-0tszzfxp.js → index-f7521k0x.js} +25 -19
- package/dist/{index-y2rb7dwx.js → index-pzyt11ch.js} +5 -1
- package/dist/{index-mr617n62.js → index-svqhcrrj.js} +1 -1
- package/dist/{index-ps5pxp3h.js → index-v6e8hnkx.js} +7 -1
- package/dist/{index-1tkyng3g.js → index-vkk06pv1.js} +1 -9
- package/dist/index-x8v8b7rc.js +560 -0
- package/dist/index.js +1 -1
- package/dist/internal/observability-sink.d.ts.map +1 -1
- package/dist/internal/route-pattern.d.ts +9 -0
- package/dist/internal/route-pattern.d.ts.map +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +12 -12
- package/dist/observability/index.js +5 -5
- package/dist/observability/sanitize.d.ts +3 -1
- package/dist/observability/sanitize.d.ts.map +1 -1
- package/dist/remote.js +3 -3
- package/dist/server/error-hook.d.ts +10 -3
- package/dist/server/error-hook.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +16 -19
- package/dist/server/middleware/cors.d.ts +5 -2
- package/dist/server/middleware/cors.d.ts.map +1 -1
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/socket-io-config.d.ts +68 -3
- package/dist/server/socket-io-config.d.ts.map +1 -1
- package/dist/server/socket-io-node.d.ts +1 -1
- package/dist/server/socket-io-node.d.ts.map +1 -1
- package/dist/server/socket-io.d.ts +1 -1
- package/dist/server/socket-io.d.ts.map +1 -1
- package/dist/testing/managed-resource-conformance-contract.d.ts +114 -0
- package/dist/testing/managed-resource-conformance-contract.d.ts.map +1 -0
- package/dist/testing/managed-resource-conformance-driver.d.ts +20 -0
- package/dist/testing/managed-resource-conformance-driver.d.ts.map +1 -0
- package/dist/testing/managed-resource-conformance-scenarios.d.ts +33 -0
- package/dist/testing/managed-resource-conformance-scenarios.d.ts.map +1 -0
- package/dist/testing/managed-resource-conformance.d.ts +5 -0
- package/dist/testing/managed-resource-conformance.d.ts.map +1 -0
- package/dist/testing/surface-manifest.d.ts.map +1 -1
- package/dist/testing.d.ts +1 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +664 -78
- package/dist/tools/flatten-join.d.ts +2 -0
- package/dist/tools/flatten-join.d.ts.map +1 -1
- package/dist/tools/flatten.d.ts.map +1 -1
- package/dist/tools/mcp-prepare.d.ts +0 -2
- package/dist/tools/mcp-prepare.d.ts.map +1 -1
- package/dist/tools/runtime-tool.d.ts +0 -3
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/dist/tools/schema.d.ts +0 -4
- package/dist/tools/schema.d.ts.map +1 -1
- package/dist/tools.js +9 -9
- package/llms-full.txt +1212 -67
- package/llms.txt +2 -0
- package/package.json +16 -3
package/dist/testing.js
CHANGED
|
@@ -2,16 +2,21 @@ import {
|
|
|
2
2
|
AgentMessageSchema,
|
|
3
3
|
AgentRunSchema
|
|
4
4
|
} from "./index-vtjgx3vv.js";
|
|
5
|
+
import {
|
|
6
|
+
createApplication
|
|
7
|
+
} from "./index-1zencgcb.js";
|
|
8
|
+
import"./index-8eywc9zv.js";
|
|
5
9
|
import {
|
|
6
10
|
RealtimeRequestDisconnectedError,
|
|
7
11
|
RealtimeRequestInvalidAcknowledgementError,
|
|
8
12
|
RealtimeRequestTimeoutError
|
|
9
13
|
} from "./index-557by2db.js";
|
|
14
|
+
import"./index-dk6e56g0.js";
|
|
10
15
|
import {
|
|
11
16
|
mcpProjectionCandidate,
|
|
12
17
|
prepareProjectedMcpTools,
|
|
13
18
|
projectToolSurface
|
|
14
|
-
} from "./index-
|
|
19
|
+
} from "./index-vkk06pv1.js";
|
|
15
20
|
import"./index-6djpbnda.js";
|
|
16
21
|
import {
|
|
17
22
|
toJsonSchema
|
|
@@ -19,9 +24,11 @@ import {
|
|
|
19
24
|
import {
|
|
20
25
|
createClient,
|
|
21
26
|
createClients
|
|
22
|
-
} from "./index-
|
|
27
|
+
} from "./index-svqhcrrj.js";
|
|
23
28
|
import"./index-48ffdxgk.js";
|
|
24
|
-
import
|
|
29
|
+
import {
|
|
30
|
+
joinRoutePath
|
|
31
|
+
} from "./index-pzyt11ch.js";
|
|
25
32
|
import {
|
|
26
33
|
isRecord
|
|
27
34
|
} from "./index-smpbdg6k.js";
|
|
@@ -378,73 +385,649 @@ async function runAgentStoreConformance(config) {
|
|
|
378
385
|
throw new Error("Abandon recovery did not atomically terminalize its assistant record");
|
|
379
386
|
}
|
|
380
387
|
}
|
|
388
|
+
// src/testing/managed-resource-conformance-contract.ts
|
|
389
|
+
import { z } from "zod";
|
|
390
|
+
var ManagedResourceConformanceScenarioIdSchema = z.enum([
|
|
391
|
+
"clean-shutdown",
|
|
392
|
+
"partial-start-rollback",
|
|
393
|
+
"readiness-rejection",
|
|
394
|
+
"completion-before-ready",
|
|
395
|
+
"required-late-completion",
|
|
396
|
+
"optional-late-completion",
|
|
397
|
+
"activation-rejection",
|
|
398
|
+
"shutdown-during-startup",
|
|
399
|
+
"force-after-stalled-close"
|
|
400
|
+
]);
|
|
401
|
+
var ManagedResourceConformanceScenarioSchema = z.discriminatedUnion("id", [
|
|
402
|
+
z.object({ id: z.literal("clean-shutdown"), required: z.literal(true) }).readonly(),
|
|
403
|
+
z.object({ id: z.literal("partial-start-rollback"), required: z.literal(true) }).readonly(),
|
|
404
|
+
z.object({ id: z.literal("readiness-rejection"), required: z.literal(true) }).readonly(),
|
|
405
|
+
z.object({ id: z.literal("completion-before-ready"), required: z.literal(true) }).readonly(),
|
|
406
|
+
z.object({ id: z.literal("required-late-completion"), required: z.literal(true) }).readonly(),
|
|
407
|
+
z.object({ id: z.literal("optional-late-completion"), required: z.literal(false) }).readonly(),
|
|
408
|
+
z.object({ id: z.literal("activation-rejection"), required: z.literal(true) }).readonly(),
|
|
409
|
+
z.object({ id: z.literal("shutdown-during-startup"), required: z.literal(true) }).readonly(),
|
|
410
|
+
z.object({ id: z.literal("force-after-stalled-close"), required: z.literal(true) }).readonly()
|
|
411
|
+
]);
|
|
412
|
+
var ManagedResourceConformancePhaseSchema = z.enum([
|
|
413
|
+
"start",
|
|
414
|
+
"readiness",
|
|
415
|
+
"completion",
|
|
416
|
+
"activate",
|
|
417
|
+
"stop-admission",
|
|
418
|
+
"drain",
|
|
419
|
+
"close",
|
|
420
|
+
"force",
|
|
421
|
+
"dispose"
|
|
422
|
+
]);
|
|
423
|
+
var ManagedResourceConformanceTraceOutcomeSchema = z.enum([
|
|
424
|
+
"enter",
|
|
425
|
+
"resolve",
|
|
426
|
+
"reject"
|
|
427
|
+
]);
|
|
428
|
+
var ManagedResourceConformanceTraceEntrySchema = z.object({
|
|
429
|
+
sequence: z.number().int().nonnegative(),
|
|
430
|
+
phase: ManagedResourceConformancePhaseSchema,
|
|
431
|
+
outcome: ManagedResourceConformanceTraceOutcomeSchema
|
|
432
|
+
}).strict().readonly();
|
|
433
|
+
|
|
434
|
+
class ManagedResourceConformanceError extends Error {
|
|
435
|
+
scenarioId;
|
|
436
|
+
expected;
|
|
437
|
+
trace;
|
|
438
|
+
code = "MANAGED_RESOURCE_CONFORMANCE_FAILED";
|
|
439
|
+
constructor(scenarioId, expected, trace, detail) {
|
|
440
|
+
const observed = trace.length === 0 ? "(empty)" : trace.map((entry) => `${entry.phase}:${entry.outcome}`).join(" -> ");
|
|
441
|
+
super(`[stitchkit] managed resource conformance "${scenarioId}" failed: ${detail}; ` + `expected ${expected.join(" -> ")}; observed ${observed}`);
|
|
442
|
+
this.scenarioId = scenarioId;
|
|
443
|
+
this.expected = expected;
|
|
444
|
+
this.trace = trace;
|
|
445
|
+
this.name = "ManagedResourceConformanceError";
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/testing/managed-resource-conformance-driver.ts
|
|
450
|
+
function controlledPromise() {
|
|
451
|
+
const deferred = Promise.withResolvers();
|
|
452
|
+
let settled = false;
|
|
453
|
+
deferred.promise.catch(() => {
|
|
454
|
+
return;
|
|
455
|
+
});
|
|
456
|
+
return {
|
|
457
|
+
promise: deferred.promise,
|
|
458
|
+
resolve() {
|
|
459
|
+
if (settled)
|
|
460
|
+
return false;
|
|
461
|
+
settled = true;
|
|
462
|
+
deferred.resolve();
|
|
463
|
+
return true;
|
|
464
|
+
},
|
|
465
|
+
reject(error) {
|
|
466
|
+
if (settled)
|
|
467
|
+
return false;
|
|
468
|
+
settled = true;
|
|
469
|
+
deferred.reject(error);
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
class ManagedResourceConformanceTrace {
|
|
476
|
+
entries = [];
|
|
477
|
+
waiters = new Set;
|
|
478
|
+
record(phase, outcome) {
|
|
479
|
+
const entry = ManagedResourceConformanceTraceEntrySchema.parse({
|
|
480
|
+
sequence: this.entries.length,
|
|
481
|
+
phase,
|
|
482
|
+
outcome
|
|
483
|
+
});
|
|
484
|
+
this.entries.push(entry);
|
|
485
|
+
for (const waiter of this.waiters) {
|
|
486
|
+
if (waiter.phase !== phase || waiter.outcome !== outcome)
|
|
487
|
+
continue;
|
|
488
|
+
this.waiters.delete(waiter);
|
|
489
|
+
waiter.resolve();
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
has(phase, outcome) {
|
|
493
|
+
return this.entries.some((entry) => entry.phase === phase && entry.outcome === outcome);
|
|
494
|
+
}
|
|
495
|
+
count(phase, outcome) {
|
|
496
|
+
return this.entries.filter((entry) => entry.phase === phase && entry.outcome === outcome).length;
|
|
497
|
+
}
|
|
498
|
+
waitFor(phase, outcome = "enter") {
|
|
499
|
+
if (this.has(phase, outcome))
|
|
500
|
+
return Promise.resolve();
|
|
501
|
+
return new Promise((resolve) => this.waiters.add({ phase, outcome, resolve }));
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
function createManagedResourceConformanceGates(trace) {
|
|
505
|
+
const startup = controlledPromise();
|
|
506
|
+
const readiness = controlledPromise();
|
|
507
|
+
const completion = controlledPromise();
|
|
508
|
+
const activation = controlledPromise();
|
|
509
|
+
const close = controlledPromise();
|
|
510
|
+
const force = controlledPromise();
|
|
511
|
+
const gateFor = (phase) => {
|
|
512
|
+
if (phase === "start")
|
|
513
|
+
return startup;
|
|
514
|
+
if (phase === "readiness")
|
|
515
|
+
return readiness;
|
|
516
|
+
if (phase === "completion")
|
|
517
|
+
return completion;
|
|
518
|
+
if (phase === "activate")
|
|
519
|
+
return activation;
|
|
520
|
+
if (phase === "close")
|
|
521
|
+
return close;
|
|
522
|
+
return force;
|
|
523
|
+
};
|
|
524
|
+
const resolve = (phase) => {
|
|
525
|
+
if (gateFor(phase).resolve())
|
|
526
|
+
trace.record(phase, "resolve");
|
|
527
|
+
};
|
|
528
|
+
return {
|
|
529
|
+
controls: {
|
|
530
|
+
startup: startup.promise,
|
|
531
|
+
readiness: readiness.promise,
|
|
532
|
+
completion: completion.promise,
|
|
533
|
+
activation: activation.promise,
|
|
534
|
+
close: close.promise,
|
|
535
|
+
force: force.promise
|
|
536
|
+
},
|
|
537
|
+
resolve,
|
|
538
|
+
reject(phase, error) {
|
|
539
|
+
if (gateFor(phase).reject(error))
|
|
540
|
+
trace.record(phase, "reject");
|
|
541
|
+
},
|
|
542
|
+
releaseAll() {
|
|
543
|
+
resolve("start");
|
|
544
|
+
resolve("readiness");
|
|
545
|
+
resolve("completion");
|
|
546
|
+
resolve("activate");
|
|
547
|
+
resolve("close");
|
|
548
|
+
resolve("force");
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
async function observePhase(trace, phase, invoke) {
|
|
553
|
+
trace.record(phase, "enter");
|
|
554
|
+
try {
|
|
555
|
+
const value = await invoke();
|
|
556
|
+
trace.record(phase, "resolve");
|
|
557
|
+
return value;
|
|
558
|
+
} catch (error) {
|
|
559
|
+
trace.record(phase, "reject");
|
|
560
|
+
throw error;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function optionalPhase(resource, trace, phase, invoke) {
|
|
564
|
+
if (!invoke)
|
|
565
|
+
return {};
|
|
566
|
+
return {
|
|
567
|
+
[phase]: (context) => observePhase(trace, phase, () => invoke.call(resource, context))
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function observeManagedResource(resource, required, trace) {
|
|
571
|
+
const start = async (context) => {
|
|
572
|
+
trace.record("start", "enter");
|
|
573
|
+
try {
|
|
574
|
+
const value = await resource.start(context);
|
|
575
|
+
trace.record("start", "resolve");
|
|
576
|
+
if (value === undefined)
|
|
577
|
+
return;
|
|
578
|
+
return value;
|
|
579
|
+
} catch (error) {
|
|
580
|
+
trace.record("start", "reject");
|
|
581
|
+
throw error;
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
return {
|
|
585
|
+
id: resource.id,
|
|
586
|
+
required,
|
|
587
|
+
start,
|
|
588
|
+
...optionalPhase(resource, trace, "activate", resource.activate),
|
|
589
|
+
...resource.stopAdmission ? {
|
|
590
|
+
stopAdmission: (context) => observePhase(trace, "stop-admission", () => resource.stopAdmission?.call(resource, context))
|
|
591
|
+
} : {},
|
|
592
|
+
...optionalPhase(resource, trace, "drain", resource.drain),
|
|
593
|
+
...optionalPhase(resource, trace, "close", resource.close),
|
|
594
|
+
...optionalPhase(resource, trace, "force", resource.force)
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// src/testing/managed-resource-conformance-scenarios.ts
|
|
599
|
+
var MANAGED_RESOURCE_CONFORMANCE_SCENARIOS = ManagedResourceConformanceScenarioSchema.array().parse([
|
|
600
|
+
{ id: "clean-shutdown", required: true },
|
|
601
|
+
{ id: "partial-start-rollback", required: true },
|
|
602
|
+
{ id: "readiness-rejection", required: true },
|
|
603
|
+
{ id: "completion-before-ready", required: true },
|
|
604
|
+
{ id: "required-late-completion", required: true },
|
|
605
|
+
{ id: "optional-late-completion", required: false },
|
|
606
|
+
{ id: "activation-rejection", required: true },
|
|
607
|
+
{ id: "shutdown-during-startup", required: true },
|
|
608
|
+
{ id: "force-after-stalled-close", required: true }
|
|
609
|
+
]);
|
|
610
|
+
var EXPECTED_TRACE = {
|
|
611
|
+
"clean-shutdown": [
|
|
612
|
+
"start:enter",
|
|
613
|
+
"start:resolve",
|
|
614
|
+
"readiness:resolve",
|
|
615
|
+
"activate:enter",
|
|
616
|
+
"activate:resolve",
|
|
617
|
+
"stop-admission:enter",
|
|
618
|
+
"drain:enter",
|
|
619
|
+
"close:enter",
|
|
620
|
+
"close:resolve"
|
|
621
|
+
],
|
|
622
|
+
"partial-start-rollback": ["start:enter", "start:reject", "close:enter", "close:resolve"],
|
|
623
|
+
"readiness-rejection": [
|
|
624
|
+
"start:enter",
|
|
625
|
+
"start:resolve",
|
|
626
|
+
"readiness:reject",
|
|
627
|
+
"close:enter",
|
|
628
|
+
"close:resolve"
|
|
629
|
+
],
|
|
630
|
+
"completion-before-ready": [
|
|
631
|
+
"start:enter",
|
|
632
|
+
"start:resolve",
|
|
633
|
+
"completion:reject",
|
|
634
|
+
"close:enter",
|
|
635
|
+
"close:resolve"
|
|
636
|
+
],
|
|
637
|
+
"required-late-completion": [
|
|
638
|
+
"activate:resolve",
|
|
639
|
+
"completion:reject",
|
|
640
|
+
"stop-admission:enter",
|
|
641
|
+
"drain:enter",
|
|
642
|
+
"close:enter"
|
|
643
|
+
],
|
|
644
|
+
"optional-late-completion": [
|
|
645
|
+
"activate:resolve",
|
|
646
|
+
"completion:reject",
|
|
647
|
+
"stop-admission:enter",
|
|
648
|
+
"drain:enter",
|
|
649
|
+
"close:enter"
|
|
650
|
+
],
|
|
651
|
+
"activation-rejection": [
|
|
652
|
+
"readiness:resolve",
|
|
653
|
+
"activate:enter",
|
|
654
|
+
"activate:reject",
|
|
655
|
+
"close:enter",
|
|
656
|
+
"close:resolve"
|
|
657
|
+
],
|
|
658
|
+
"shutdown-during-startup": ["start:enter", "start:resolve", "close:enter", "close:resolve"],
|
|
659
|
+
"force-after-stalled-close": [
|
|
660
|
+
"stop-admission:enter",
|
|
661
|
+
"drain:enter",
|
|
662
|
+
"close:enter",
|
|
663
|
+
"force:enter",
|
|
664
|
+
"force:resolve"
|
|
665
|
+
]
|
|
666
|
+
};
|
|
667
|
+
function outcomeOf(promise) {
|
|
668
|
+
return promise.then(() => ({ status: "resolved" }), (error) => ({ status: "rejected", error }));
|
|
669
|
+
}
|
|
670
|
+
function requireCondition(condition, detail) {
|
|
671
|
+
if (!condition)
|
|
672
|
+
throw new Error(detail);
|
|
673
|
+
}
|
|
674
|
+
function observedTrace(trace) {
|
|
675
|
+
return trace.entries.map((entry) => `${entry.phase}:${entry.outcome}`);
|
|
676
|
+
}
|
|
677
|
+
function requireTrace(runtime) {
|
|
678
|
+
const expected = EXPECTED_TRACE[runtime.scenario.id];
|
|
679
|
+
const observed = observedTrace(runtime.trace);
|
|
680
|
+
let cursor = 0;
|
|
681
|
+
for (const entry of observed) {
|
|
682
|
+
if (entry === expected[cursor])
|
|
683
|
+
cursor += 1;
|
|
684
|
+
}
|
|
685
|
+
requireCondition(cursor === expected.length, `phase trace omitted or reordered "${expected[cursor] ?? "unknown"}"`);
|
|
686
|
+
}
|
|
687
|
+
async function phaseOrSettlement(trace, phase, settlement) {
|
|
688
|
+
return Promise.race([
|
|
689
|
+
trace.waitFor(phase).then(() => "phase"),
|
|
690
|
+
settlement.then(() => "settled", () => "settled")
|
|
691
|
+
]);
|
|
692
|
+
}
|
|
693
|
+
async function startSuccessfully(runtime) {
|
|
694
|
+
const starting = runtime.application.start();
|
|
695
|
+
const startOutcome = outcomeOf(starting);
|
|
696
|
+
await runtime.trace.waitFor("start");
|
|
697
|
+
runtime.gates.resolve("start");
|
|
698
|
+
runtime.gates.resolve("readiness");
|
|
699
|
+
const activation = await Promise.race([
|
|
700
|
+
runtime.trace.waitFor("activate").then(() => ({ status: "resolved" })),
|
|
701
|
+
startOutcome
|
|
702
|
+
]);
|
|
703
|
+
if (activation.status === "rejected")
|
|
704
|
+
throw activation.error;
|
|
705
|
+
runtime.gates.resolve("activate");
|
|
706
|
+
const outcome = await startOutcome;
|
|
707
|
+
requireCondition(outcome.status === "resolved", "application did not complete successful startup");
|
|
708
|
+
}
|
|
709
|
+
async function closeNormally(runtime) {
|
|
710
|
+
const shuttingDown = runtime.application.shutdown();
|
|
711
|
+
const close = await phaseOrSettlement(runtime.trace, "close", shuttingDown);
|
|
712
|
+
if (close === "phase")
|
|
713
|
+
runtime.gates.resolve("close");
|
|
714
|
+
const outcome = await outcomeOf(shuttingDown);
|
|
715
|
+
requireCondition(outcome.status === "resolved", "application shutdown rejected");
|
|
716
|
+
}
|
|
717
|
+
async function expectStartupFailure(runtime, starting) {
|
|
718
|
+
const close = await phaseOrSettlement(runtime.trace, "close", starting);
|
|
719
|
+
if (close === "phase")
|
|
720
|
+
runtime.gates.resolve("close");
|
|
721
|
+
const outcome = await outcomeOf(starting);
|
|
722
|
+
if (outcome.status === "resolved") {
|
|
723
|
+
await closeNormally(runtime);
|
|
724
|
+
throw new Error("application startup unexpectedly resolved");
|
|
725
|
+
}
|
|
726
|
+
requireCondition(runtime.trace.count("close", "enter") === 1, "attempted resource was not closed once");
|
|
727
|
+
await runtime.application.shutdown();
|
|
728
|
+
}
|
|
729
|
+
function waitForSnapshot(application, predicate) {
|
|
730
|
+
const deferred = Promise.withResolvers();
|
|
731
|
+
let unsubscribe = () => {
|
|
732
|
+
return;
|
|
733
|
+
};
|
|
734
|
+
unsubscribe = application.subscribe((snapshot) => {
|
|
735
|
+
if (!predicate(snapshot))
|
|
736
|
+
return;
|
|
737
|
+
unsubscribe();
|
|
738
|
+
deferred.resolve(snapshot);
|
|
739
|
+
});
|
|
740
|
+
return deferred.promise;
|
|
741
|
+
}
|
|
742
|
+
async function cleanShutdown(runtime) {
|
|
743
|
+
await startSuccessfully(runtime);
|
|
744
|
+
await closeNormally(runtime);
|
|
745
|
+
requireCondition(runtime.application.getSnapshot().lifecycle === "stopped", "clean shutdown did not stop the application");
|
|
746
|
+
}
|
|
747
|
+
async function partialStartRollback(runtime) {
|
|
748
|
+
const starting = runtime.application.start();
|
|
749
|
+
await runtime.trace.waitFor("start");
|
|
750
|
+
runtime.gates.reject("start", new Error("controlled partial startup rejection"));
|
|
751
|
+
await expectStartupFailure(runtime, starting);
|
|
752
|
+
}
|
|
753
|
+
async function readinessRejection(runtime) {
|
|
754
|
+
const starting = runtime.application.start();
|
|
755
|
+
await runtime.trace.waitFor("start");
|
|
756
|
+
runtime.gates.resolve("start");
|
|
757
|
+
await runtime.trace.waitFor("start", "resolve");
|
|
758
|
+
runtime.gates.reject("readiness", new Error("controlled readiness rejection"));
|
|
759
|
+
runtime.gates.resolve("activate");
|
|
760
|
+
await expectStartupFailure(runtime, starting);
|
|
761
|
+
}
|
|
762
|
+
async function completionBeforeReady(runtime) {
|
|
763
|
+
const starting = runtime.application.start();
|
|
764
|
+
await runtime.trace.waitFor("start");
|
|
765
|
+
runtime.gates.resolve("start");
|
|
766
|
+
await runtime.trace.waitFor("start", "resolve");
|
|
767
|
+
runtime.gates.reject("completion", new Error("controlled early completion rejection"));
|
|
768
|
+
runtime.gates.resolve("readiness");
|
|
769
|
+
runtime.gates.resolve("activate");
|
|
770
|
+
await expectStartupFailure(runtime, starting);
|
|
771
|
+
}
|
|
772
|
+
async function lateCompletion(runtime) {
|
|
773
|
+
await startSuccessfully(runtime);
|
|
774
|
+
const expectedHealth = runtime.scenario.required ? "unhealthy" : "degraded";
|
|
775
|
+
const changed = waitForSnapshot(runtime.application, (snapshot2) => snapshot2.health === expectedHealth);
|
|
776
|
+
runtime.gates.reject("completion", new Error("controlled late completion rejection"));
|
|
777
|
+
const snapshot = await changed;
|
|
778
|
+
requireCondition(snapshot.lifecycle === "ready", "late completion changed lifecycle ownership");
|
|
779
|
+
requireCondition(snapshot.health === expectedHealth, "late completion projected the wrong health");
|
|
780
|
+
requireCondition(snapshot.ready === !runtime.scenario.required, "late completion projected the wrong readiness");
|
|
781
|
+
requireCondition(snapshot.admission.accepting === !runtime.scenario.required, "late completion projected the wrong admission state");
|
|
782
|
+
await closeNormally(runtime);
|
|
783
|
+
}
|
|
784
|
+
async function activationRejection(runtime) {
|
|
785
|
+
const starting = runtime.application.start();
|
|
786
|
+
await runtime.trace.waitFor("start");
|
|
787
|
+
runtime.gates.resolve("start");
|
|
788
|
+
await runtime.trace.waitFor("start", "resolve");
|
|
789
|
+
runtime.gates.resolve("readiness");
|
|
790
|
+
await runtime.trace.waitFor("activate");
|
|
791
|
+
runtime.gates.reject("activate", new Error("controlled activation rejection"));
|
|
792
|
+
await expectStartupFailure(runtime, starting);
|
|
793
|
+
}
|
|
794
|
+
async function shutdownDuringStartup(runtime) {
|
|
795
|
+
const starting = runtime.application.start();
|
|
796
|
+
await runtime.trace.waitFor("start");
|
|
797
|
+
const shuttingDown = runtime.application.shutdown();
|
|
798
|
+
runtime.gates.resolve("start");
|
|
799
|
+
const close = await phaseOrSettlement(runtime.trace, "close", shuttingDown);
|
|
800
|
+
if (close === "phase")
|
|
801
|
+
runtime.gates.resolve("close");
|
|
802
|
+
const [startOutcome, shutdownOutcome] = await Promise.all([
|
|
803
|
+
outcomeOf(starting),
|
|
804
|
+
outcomeOf(shuttingDown)
|
|
805
|
+
]);
|
|
806
|
+
requireCondition(startOutcome.status === "rejected", "startup won the shutdown race");
|
|
807
|
+
requireCondition(shutdownOutcome.status === "resolved", "shutdown race rejected");
|
|
808
|
+
requireCondition(!runtime.trace.has("activate", "enter"), "resource activated after shutdown won");
|
|
809
|
+
}
|
|
810
|
+
async function forceAfterStalledClose(runtime) {
|
|
811
|
+
await startSuccessfully(runtime);
|
|
812
|
+
const controller = new AbortController;
|
|
813
|
+
const shuttingDown = runtime.application.shutdown({
|
|
814
|
+
gracePeriodMs: 60000,
|
|
815
|
+
forceTimeoutMs: 60000,
|
|
816
|
+
signal: controller.signal
|
|
817
|
+
});
|
|
818
|
+
await runtime.trace.waitFor("close");
|
|
819
|
+
controller.abort();
|
|
820
|
+
const force = await phaseOrSettlement(runtime.trace, "force", shuttingDown);
|
|
821
|
+
if (force === "phase")
|
|
822
|
+
runtime.gates.resolve("force");
|
|
823
|
+
const result = await shuttingDown;
|
|
824
|
+
requireCondition(runtime.trace.count("close", "enter") === 1, "close was not invoked exactly once");
|
|
825
|
+
requireCondition(runtime.trace.count("force", "enter") === 1, "unfinished close did not invoke force");
|
|
826
|
+
requireCondition(result.outcome === "forced", "forced shutdown reported a clean outcome");
|
|
827
|
+
requireCondition(result.reason === "signal", "forced shutdown lost its signal reason");
|
|
828
|
+
runtime.gates.resolve("close");
|
|
829
|
+
}
|
|
830
|
+
function expectedManagedResourceConformanceTrace(scenarioId) {
|
|
831
|
+
return EXPECTED_TRACE[scenarioId];
|
|
832
|
+
}
|
|
833
|
+
async function executeManagedResourceConformanceScenario(scenario, resource, gates, trace) {
|
|
834
|
+
const application = createApplication({
|
|
835
|
+
id: `conformance-${scenario.id}`,
|
|
836
|
+
resources: [observeManagedResource(resource, scenario.required, trace)]
|
|
837
|
+
});
|
|
838
|
+
const runtime = { scenario, application, gates, trace };
|
|
839
|
+
if (scenario.id === "clean-shutdown")
|
|
840
|
+
await cleanShutdown(runtime);
|
|
841
|
+
else if (scenario.id === "partial-start-rollback")
|
|
842
|
+
await partialStartRollback(runtime);
|
|
843
|
+
else if (scenario.id === "readiness-rejection")
|
|
844
|
+
await readinessRejection(runtime);
|
|
845
|
+
else if (scenario.id === "completion-before-ready")
|
|
846
|
+
await completionBeforeReady(runtime);
|
|
847
|
+
else if (scenario.id === "required-late-completion" || scenario.id === "optional-late-completion") {
|
|
848
|
+
await lateCompletion(runtime);
|
|
849
|
+
} else if (scenario.id === "activation-rejection")
|
|
850
|
+
await activationRejection(runtime);
|
|
851
|
+
else if (scenario.id === "shutdown-during-startup")
|
|
852
|
+
await shutdownDuringStartup(runtime);
|
|
853
|
+
else
|
|
854
|
+
await forceAfterStalledClose(runtime);
|
|
855
|
+
requireTrace(runtime);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// src/testing/managed-resource-conformance.ts
|
|
859
|
+
var DEFAULT_WATCHDOG_TIMEOUT_MS = 2000;
|
|
860
|
+
|
|
861
|
+
class ManagedResourceConformanceWatchdogError extends Error {
|
|
862
|
+
phase;
|
|
863
|
+
constructor(phase) {
|
|
864
|
+
super(`emergency watchdog expired during ${phase}`);
|
|
865
|
+
this.phase = phase;
|
|
866
|
+
this.name = "ManagedResourceConformanceWatchdogError";
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
async function withWatchdog(promise, timeoutMs, phase) {
|
|
870
|
+
let timer;
|
|
871
|
+
const watchdog = new Promise((_resolve, reject) => {
|
|
872
|
+
timer = setTimeout(() => reject(new ManagedResourceConformanceWatchdogError(phase)), timeoutMs);
|
|
873
|
+
});
|
|
874
|
+
try {
|
|
875
|
+
return await Promise.race([promise, watchdog]);
|
|
876
|
+
} finally {
|
|
877
|
+
if (timer !== undefined)
|
|
878
|
+
clearTimeout(timer);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
function detailOf(error) {
|
|
882
|
+
if (error instanceof ManagedResourceConformanceWatchdogError)
|
|
883
|
+
return error.message;
|
|
884
|
+
if (error instanceof Error)
|
|
885
|
+
return error.message;
|
|
886
|
+
return "unknown conformance failure";
|
|
887
|
+
}
|
|
888
|
+
async function runScenario(config, scenario, watchdogTimeoutMs) {
|
|
889
|
+
const trace = new ManagedResourceConformanceTrace;
|
|
890
|
+
const gates = createManagedResourceConformanceGates(trace);
|
|
891
|
+
const fixture = await withWatchdog(Promise.resolve().then(() => config.createFixture({ scenario, controls: gates.controls })), watchdogTimeoutMs, "factory").catch((error) => {
|
|
892
|
+
throw new ManagedResourceConformanceError(scenario.id, expectedManagedResourceConformanceTrace(scenario.id), trace.entries, detailOf(error));
|
|
893
|
+
});
|
|
894
|
+
let failure;
|
|
895
|
+
const execution = executeManagedResourceConformanceScenario(scenario, fixture.resource, gates, trace);
|
|
896
|
+
execution.catch(() => {
|
|
897
|
+
return;
|
|
898
|
+
});
|
|
899
|
+
let settlementIncomplete = false;
|
|
900
|
+
try {
|
|
901
|
+
await withWatchdog(execution, watchdogTimeoutMs, "scenario");
|
|
902
|
+
} catch (error) {
|
|
903
|
+
failure = { value: error };
|
|
904
|
+
} finally {
|
|
905
|
+
gates.releaseAll();
|
|
906
|
+
if (failure?.value instanceof ManagedResourceConformanceWatchdogError) {
|
|
907
|
+
try {
|
|
908
|
+
await withWatchdog(execution, watchdogTimeoutMs, "settlement");
|
|
909
|
+
} catch (error) {
|
|
910
|
+
if (error instanceof ManagedResourceConformanceWatchdogError) {
|
|
911
|
+
settlementIncomplete = true;
|
|
912
|
+
} else {
|
|
913
|
+
failure = { value: error };
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
trace.record("dispose", "enter");
|
|
918
|
+
try {
|
|
919
|
+
await withWatchdog(Promise.resolve(fixture.dispose()), watchdogTimeoutMs, "dispose");
|
|
920
|
+
trace.record("dispose", "resolve");
|
|
921
|
+
} catch (error) {
|
|
922
|
+
trace.record("dispose", "reject");
|
|
923
|
+
if (failure === undefined)
|
|
924
|
+
failure = { value: error };
|
|
925
|
+
}
|
|
926
|
+
if (settlementIncomplete) {
|
|
927
|
+
try {
|
|
928
|
+
await withWatchdog(execution, watchdogTimeoutMs, "settlement");
|
|
929
|
+
settlementIncomplete = false;
|
|
930
|
+
} catch (error) {
|
|
931
|
+
if (error instanceof ManagedResourceConformanceWatchdogError) {
|
|
932
|
+
const original = failure?.value;
|
|
933
|
+
failure = {
|
|
934
|
+
value: new Error(`${detailOf(original)}; execution remained live after fixture disposal`)
|
|
935
|
+
};
|
|
936
|
+
} else {
|
|
937
|
+
settlementIncomplete = false;
|
|
938
|
+
failure = { value: error };
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
if (failure !== undefined) {
|
|
944
|
+
if (failure.value instanceof ManagedResourceConformanceError)
|
|
945
|
+
throw failure.value;
|
|
946
|
+
throw new ManagedResourceConformanceError(scenario.id, expectedManagedResourceConformanceTrace(scenario.id), trace.entries, detailOf(failure.value));
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
async function runManagedResourceConformance(config) {
|
|
950
|
+
const watchdogTimeoutMs = config.watchdogTimeoutMs ?? DEFAULT_WATCHDOG_TIMEOUT_MS;
|
|
951
|
+
if (!Number.isSafeInteger(watchdogTimeoutMs) || watchdogTimeoutMs <= 0) {
|
|
952
|
+
throw new TypeError("[stitchkit] managed resource conformance watchdogTimeoutMs must be positive");
|
|
953
|
+
}
|
|
954
|
+
const selected = new Set((config.scenarios ?? MANAGED_RESOURCE_CONFORMANCE_SCENARIOS.map((scenario) => scenario.id)).map((scenario) => ManagedResourceConformanceScenarioIdSchema.parse(scenario)));
|
|
955
|
+
if (selected.size === 0) {
|
|
956
|
+
throw new TypeError("[stitchkit] managed resource conformance scenarios must not be empty");
|
|
957
|
+
}
|
|
958
|
+
for (const scenario of MANAGED_RESOURCE_CONFORMANCE_SCENARIOS) {
|
|
959
|
+
if (!selected.has(scenario.id))
|
|
960
|
+
continue;
|
|
961
|
+
await runScenario(config, scenario, watchdogTimeoutMs);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
381
964
|
// src/testing/surface-conformance.ts
|
|
382
|
-
import { z as
|
|
965
|
+
import { z as z3 } from "zod";
|
|
383
966
|
|
|
384
967
|
// src/testing/surface-manifest.ts
|
|
385
968
|
import { createHash } from "node:crypto";
|
|
386
|
-
import { z } from "zod";
|
|
387
|
-
var HttpMethodSchema =
|
|
388
|
-
var ToolTransportSchema =
|
|
389
|
-
var SurfaceTransportSchema =
|
|
390
|
-
var SurfaceSchemaDigestsSchema =
|
|
391
|
-
params:
|
|
392
|
-
input:
|
|
393
|
-
output:
|
|
394
|
-
multipart:
|
|
969
|
+
import { z as z2 } from "zod";
|
|
970
|
+
var HttpMethodSchema = z2.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"]);
|
|
971
|
+
var ToolTransportSchema = z2.enum(["MCP", "AGENT", "CLI"]);
|
|
972
|
+
var SurfaceTransportSchema = z2.enum(["HTTP", "MCP", "AGENT", "CLI", "REALTIME"]);
|
|
973
|
+
var SurfaceSchemaDigestsSchema = z2.object({
|
|
974
|
+
params: z2.string().nullable(),
|
|
975
|
+
input: z2.string().nullable(),
|
|
976
|
+
output: z2.string().nullable(),
|
|
977
|
+
multipart: z2.string().nullable()
|
|
395
978
|
});
|
|
396
|
-
var SurfaceManifestOperationSchema =
|
|
397
|
-
kind:
|
|
398
|
-
service:
|
|
399
|
-
action:
|
|
979
|
+
var SurfaceManifestOperationSchema = z2.object({
|
|
980
|
+
kind: z2.enum(["contract", "runtime"]),
|
|
981
|
+
service: z2.string(),
|
|
982
|
+
action: z2.string(),
|
|
400
983
|
method: HttpMethodSchema,
|
|
401
|
-
scope:
|
|
402
|
-
description:
|
|
984
|
+
scope: z2.string().nullable(),
|
|
985
|
+
description: z2.string(),
|
|
403
986
|
schemas: SurfaceSchemaDigestsSchema,
|
|
404
|
-
http:
|
|
987
|
+
http: z2.array(z2.object({ method: HttpMethodSchema, path: z2.string() }))
|
|
405
988
|
});
|
|
406
|
-
var SurfaceManifestToolSchema =
|
|
407
|
-
kind:
|
|
408
|
-
service:
|
|
409
|
-
action:
|
|
410
|
-
name:
|
|
411
|
-
input:
|
|
989
|
+
var SurfaceManifestToolSchema = z2.object({
|
|
990
|
+
kind: z2.enum(["contract", "runtime"]),
|
|
991
|
+
service: z2.string(),
|
|
992
|
+
action: z2.string(),
|
|
993
|
+
name: z2.string(),
|
|
994
|
+
input: z2.string()
|
|
412
995
|
});
|
|
413
|
-
var SurfaceManifestToolSurfaceSchema =
|
|
996
|
+
var SurfaceManifestToolSurfaceSchema = z2.object({
|
|
414
997
|
transport: ToolTransportSchema,
|
|
415
|
-
surface:
|
|
416
|
-
tools:
|
|
998
|
+
surface: z2.string().nullable(),
|
|
999
|
+
tools: z2.array(SurfaceManifestToolSchema)
|
|
417
1000
|
});
|
|
418
|
-
var SurfaceManifestCliCommandSchema =
|
|
419
|
-
name:
|
|
420
|
-
description:
|
|
421
|
-
input:
|
|
422
|
-
output:
|
|
1001
|
+
var SurfaceManifestCliCommandSchema = z2.object({
|
|
1002
|
+
name: z2.string(),
|
|
1003
|
+
description: z2.string(),
|
|
1004
|
+
input: z2.string(),
|
|
1005
|
+
output: z2.string().nullable()
|
|
423
1006
|
});
|
|
424
|
-
var SurfaceManifestExtensionSchema =
|
|
425
|
-
name:
|
|
1007
|
+
var SurfaceManifestExtensionSchema = z2.object({
|
|
1008
|
+
name: z2.string(),
|
|
426
1009
|
transport: SurfaceTransportSchema
|
|
427
1010
|
});
|
|
428
|
-
var SurfaceRealtimeSchemaPairSchema =
|
|
429
|
-
input:
|
|
430
|
-
output:
|
|
1011
|
+
var SurfaceRealtimeSchemaPairSchema = z2.object({
|
|
1012
|
+
input: z2.string(),
|
|
1013
|
+
output: z2.string()
|
|
431
1014
|
});
|
|
432
|
-
var SurfaceManifestRealtimeEventSchema =
|
|
433
|
-
contract:
|
|
434
|
-
direction:
|
|
435
|
-
event:
|
|
1015
|
+
var SurfaceManifestRealtimeEventSchema = z2.object({
|
|
1016
|
+
contract: z2.string(),
|
|
1017
|
+
direction: z2.enum(["serverToClient", "clientToServer"]),
|
|
1018
|
+
event: z2.string(),
|
|
436
1019
|
args: SurfaceRealtimeSchemaPairSchema,
|
|
437
1020
|
acknowledgement: SurfaceRealtimeSchemaPairSchema.nullable()
|
|
438
1021
|
});
|
|
439
|
-
var SurfaceManifestSchema =
|
|
440
|
-
manifestVersion:
|
|
441
|
-
digestVersion:
|
|
442
|
-
operations:
|
|
443
|
-
toolSurfaces:
|
|
444
|
-
realtimeContracts:
|
|
445
|
-
realtime:
|
|
446
|
-
cliOnly:
|
|
447
|
-
extensions:
|
|
1022
|
+
var SurfaceManifestSchema = z2.object({
|
|
1023
|
+
manifestVersion: z2.literal(2),
|
|
1024
|
+
digestVersion: z2.literal(1),
|
|
1025
|
+
operations: z2.array(SurfaceManifestOperationSchema),
|
|
1026
|
+
toolSurfaces: z2.array(SurfaceManifestToolSurfaceSchema),
|
|
1027
|
+
realtimeContracts: z2.array(z2.string()),
|
|
1028
|
+
realtime: z2.array(SurfaceManifestRealtimeEventSchema),
|
|
1029
|
+
cliOnly: z2.array(SurfaceManifestCliCommandSchema),
|
|
1030
|
+
extensions: z2.array(SurfaceManifestExtensionSchema)
|
|
448
1031
|
});
|
|
449
1032
|
function compareCodepoints(left, right) {
|
|
450
1033
|
if (left < right)
|
|
@@ -494,10 +1077,6 @@ function presentationDigest(schema) {
|
|
|
494
1077
|
function multipartDigest(value) {
|
|
495
1078
|
return value === undefined ? null : digestValue(value);
|
|
496
1079
|
}
|
|
497
|
-
function joinPath(...parts) {
|
|
498
|
-
const joined = parts.filter((part) => Boolean(part)).map((part) => part.replace(/^\/+|\/+$/g, "")).filter(Boolean).join("/");
|
|
499
|
-
return `/${joined}`;
|
|
500
|
-
}
|
|
501
1080
|
function operationKey(kind, service, action) {
|
|
502
1081
|
return `${kind}\x00${service}\x00${action}`;
|
|
503
1082
|
}
|
|
@@ -583,7 +1162,7 @@ function buildSurfaceManifest(config) {
|
|
|
583
1162
|
continue;
|
|
584
1163
|
const route = {
|
|
585
1164
|
method: method.method,
|
|
586
|
-
path:
|
|
1165
|
+
path: joinRoutePath(prefix, service.prefix, method.path)
|
|
587
1166
|
};
|
|
588
1167
|
if (!operation.http.some((entry) => entry.method === route.method && entry.path === route.path)) {
|
|
589
1168
|
operation.http.push(route);
|
|
@@ -729,47 +1308,47 @@ actual: ${actual}`);
|
|
|
729
1308
|
}
|
|
730
1309
|
|
|
731
1310
|
// src/testing/surface-conformance.ts
|
|
732
|
-
var RealtimeRejectionObservationSchema =
|
|
733
|
-
direction:
|
|
1311
|
+
var RealtimeRejectionObservationSchema = z3.object({
|
|
1312
|
+
direction: z3.enum([
|
|
734
1313
|
"client-inbound",
|
|
735
1314
|
"client-outbound",
|
|
736
1315
|
"server-inbound",
|
|
737
1316
|
"server-outbound"
|
|
738
1317
|
]),
|
|
739
|
-
phase:
|
|
740
|
-
reason:
|
|
1318
|
+
phase: z3.enum(["arguments", "acknowledgement"]),
|
|
1319
|
+
reason: z3.enum([
|
|
741
1320
|
"unknown-event",
|
|
742
1321
|
"invalid-arguments",
|
|
743
1322
|
"invalid-acknowledgement-value",
|
|
744
1323
|
"missing-acknowledgement"
|
|
745
1324
|
]),
|
|
746
|
-
fault:
|
|
1325
|
+
fault: z3.enum(["peer", "local"])
|
|
747
1326
|
});
|
|
748
1327
|
var ObservationFields = {
|
|
749
|
-
code:
|
|
750
|
-
data:
|
|
751
|
-
diagnostic:
|
|
752
|
-
handlerCalls:
|
|
1328
|
+
code: z3.string().optional(),
|
|
1329
|
+
data: z3.unknown().optional(),
|
|
1330
|
+
diagnostic: z3.string().optional(),
|
|
1331
|
+
handlerCalls: z3.number().int().nonnegative().optional()
|
|
753
1332
|
};
|
|
754
|
-
var RealtimeDisconnectObservationSchema =
|
|
755
|
-
phase:
|
|
1333
|
+
var RealtimeDisconnectObservationSchema = z3.object({
|
|
1334
|
+
phase: z3.enum(["before-invoke", "in-flight"])
|
|
756
1335
|
});
|
|
757
|
-
var TransportObservationSchema =
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
outcome:
|
|
1336
|
+
var TransportObservationSchema = z3.discriminatedUnion("outcome", [
|
|
1337
|
+
z3.object({ outcome: z3.literal("success"), ...ObservationFields }),
|
|
1338
|
+
z3.object({ outcome: z3.literal("validation_error"), ...ObservationFields }),
|
|
1339
|
+
z3.object({ outcome: z3.literal("domain_error"), ...ObservationFields }),
|
|
1340
|
+
z3.object({ outcome: z3.literal("aborted"), ...ObservationFields }),
|
|
1341
|
+
z3.object({
|
|
1342
|
+
outcome: z3.literal("realtime_rejected"),
|
|
764
1343
|
...ObservationFields,
|
|
765
1344
|
rejection: RealtimeRejectionObservationSchema
|
|
766
1345
|
}),
|
|
767
|
-
|
|
768
|
-
outcome:
|
|
1346
|
+
z3.object({
|
|
1347
|
+
outcome: z3.literal("disconnected"),
|
|
769
1348
|
...ObservationFields,
|
|
770
1349
|
disconnect: RealtimeDisconnectObservationSchema
|
|
771
1350
|
}),
|
|
772
|
-
|
|
1351
|
+
z3.object({ outcome: z3.literal("timeout"), ...ObservationFields })
|
|
773
1352
|
]);
|
|
774
1353
|
function scenarioOutcome(scenario) {
|
|
775
1354
|
if (scenario === "event" || scenario === "acknowledgement")
|
|
@@ -1081,6 +1660,12 @@ function createHandlerTestClients(config) {
|
|
|
1081
1660
|
return createClients(config.contracts, createTestClientConfig(config), config.contractConfig);
|
|
1082
1661
|
}
|
|
1083
1662
|
export {
|
|
1663
|
+
ManagedResourceConformanceError,
|
|
1664
|
+
ManagedResourceConformancePhaseSchema,
|
|
1665
|
+
ManagedResourceConformanceScenarioIdSchema,
|
|
1666
|
+
ManagedResourceConformanceScenarioSchema,
|
|
1667
|
+
ManagedResourceConformanceTraceEntrySchema,
|
|
1668
|
+
ManagedResourceConformanceTraceOutcomeSchema,
|
|
1084
1669
|
RealtimeDisconnectObservationSchema,
|
|
1085
1670
|
RealtimeRejectionObservationSchema,
|
|
1086
1671
|
SurfaceManifestExtensionSchema,
|
|
@@ -1103,6 +1688,7 @@ export {
|
|
|
1103
1688
|
createRealtimeProbeDriver,
|
|
1104
1689
|
defineRealtimeProbe,
|
|
1105
1690
|
runAgentStoreConformance,
|
|
1691
|
+
runManagedResourceConformance,
|
|
1106
1692
|
runSurfaceProbes,
|
|
1107
1693
|
serializeSurfaceValue
|
|
1108
1694
|
};
|