From 5a9ec57776ffea679076763c480e53603858dc04 Mon Sep 17 00:00:00 2001 From: Calvin Grunewald Date: Mon, 29 Jun 2026 17:36:10 -0700 Subject: [PATCH 1/2] feat(sdk-generator): emit SSE contract tests in the contract-tests backend (TS + Python) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously emitStreamContractTestFile was only wired into the channel-harness sample — so SDK regens (contract-tests-ts/py) shipped the generated stream() methods with no contract test. Wire SSE coverage into generateContractTests itself, for both backends. - method-chain-builder: add buildStreamCalls (the streaming inverse of buildMethodCalls), sharing the resource walk so streaming ops get the same accessor chains (client.v1.ai.chat.completions.stream). - typescript-emitter: emit __tests__/contract/streams/.contract.test.ts — construct PlatformClient pointed at the harness, registerStreamScenario with autoEmit (harness synthesizes contract-valid event payloads, resolving $refs), iterate stream(), assert event order; plus a non-2xx -> ApiError case. - python-emitter: emit tests/contract/streams/test_.py — same shape over AsyncPlatformClient.stream(). - Both gated by the existing opt-in env (ARCHASTRO_RUN_CHANNEL_CONTRACT_TESTS): excluded from the default test run + the harness subprocess boots when the spec has channels OR streams. These run green once their deps land: runtime streamSSE/stream_sse (archastro-js #34 / archastro-python #28) and registerStreamScenario on the harness client (TS: shipped in this PR's channel-harness; Python: phx_channel harness.py). Generator suite 299; channel-harness 63. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../__tests__/backends/streaming.test.ts | 41 ++++++ .../contract-tests/method-chain-builder.ts | 34 ++++- .../backends/contract-tests/python-emitter.ts | 121 +++++++++++++++- .../contract-tests/typescript-emitter.ts | 133 +++++++++++++++++- 4 files changed, 319 insertions(+), 10 deletions(-) diff --git a/packages/sdk-generator/__tests__/backends/streaming.test.ts b/packages/sdk-generator/__tests__/backends/streaming.test.ts index 9c363b7..52f8caa 100644 --- a/packages/sdk-generator/__tests__/backends/streaming.test.ts +++ b/packages/sdk-generator/__tests__/backends/streaming.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect } from "vitest"; import { parseOpenApiSpec } from "../../src/frontend/index.js"; import { emitResourceFile } from "../../src/backends/typescript/resource-emitter.js"; import { emitPythonResourceFile } from "../../src/backends/python/resource-emitter.js"; +import { generateContractTests } from "../../src/backends/contract-tests/index.js"; // A spec with a single SSE streaming operation (`x-sdk-streaming`), modeled on // POST /ai/chat/completions/stream: a typed request body plus a discriminated @@ -123,3 +124,43 @@ describe("Python SSE streaming emission", () => { expect(pyOutput).toContain("Union["); }); }); + +describe("SSE contract-test generation", () => { + it("emits a TypeScript stream contract test driving the harness", () => { + const files = generateContractTests(ast, { lang: "typescript", outDir: "sdk" }); + const entry = Object.entries(files).find( + ([p]) => p.includes("/streams/") && p.endsWith(".contract.test.ts") + ); + expect(entry).toBeDefined(); + const content = entry![1]; + expect(content).toContain('import { HarnessServiceClient } from "@archastro/channel-harness";'); + expect(content).toContain("registerStreamScenario"); + // autoEmit lets the harness synthesize contract-valid event payloads. + expect(content).toContain('{ type: "autoEmit", event: "message_delta" }'); + expect(content).toMatch(/for await \(const ev of .*\.stream\(/); + // error path asserts a non-2xx surfaces as ApiError + expect(content).toContain("ApiError"); + }); + + it("emits a Python stream contract test driving the harness", () => { + const files = generateContractTests(ast, { lang: "python", outDir: "sdk" }); + const entry = Object.entries(files).find( + ([p]) => p.includes("/streams/") && p.endsWith(".py") + ); + expect(entry).toBeDefined(); + const content = entry![1]; + expect(content).toContain("from archastro.phx_channel import HarnessServiceClient"); + expect(content).toContain("register_stream_scenario"); + expect(content).toContain('{"type": "autoEmit", "event": "message_delta"}'); + expect(content).toMatch(/async for ev in .*\.stream\(/); + expect(content).toContain("ApiError"); + }); + + it("gates the stream tests behind the opt-in env + boots the harness", () => { + const ts = generateContractTests(ast, { lang: "typescript", outDir: "sdk" }); + const vitestConfig = ts["sdk/__tests__/contract/vitest.contract.config.ts"]; + expect(vitestConfig).toContain('"__tests__/contract/streams/**/*"'); + const globalSetup = ts["sdk/__tests__/contract/global-setup.ts"]; + expect(globalSetup).toContain("harnessProcess"); + }); +}); diff --git a/packages/sdk-generator/src/backends/contract-tests/method-chain-builder.ts b/packages/sdk-generator/src/backends/contract-tests/method-chain-builder.ts index 0ef3f59..244e5f9 100644 --- a/packages/sdk-generator/src/backends/contract-tests/method-chain-builder.ts +++ b/packages/sdk-generator/src/backends/contract-tests/method-chain-builder.ts @@ -39,7 +39,9 @@ export interface MethodCallInfo { } /** - * Determine whether an operation should be included in contract tests. + * Determine whether an operation should be included in the normal + * call-and-assert-response contract tests. Streaming ops are excluded here — + * they get dedicated SSE tests via {@link buildStreamCalls}. */ function isTestableOperation(op: OperationDef): boolean { if (op.streaming) return false; @@ -47,13 +49,39 @@ function isTestableOperation(op: OperationDef): boolean { } /** - * Walk the resource tree and yield MethodCallInfo for every testable operation. + * Walk the resource tree and yield MethodCallInfo for every non-streaming + * (testable) operation. */ export function buildMethodCalls( spec: SdkSpec, versionSet: VersionedResourceSet, lang: "typescript" | "python", opts: ValueOptions = {} +): MethodCallInfo[] { + return collectCalls(spec, versionSet, lang, opts, isTestableOperation); +} + +/** + * Walk the resource tree and yield MethodCallInfo for every SSE streaming + * operation (`op.streaming`) — the dedicated set the stream contract tests + * drive against the harness. Each result's `operation.streaming.events` carries + * the declared SSE events. + */ +export function buildStreamCalls( + spec: SdkSpec, + versionSet: VersionedResourceSet, + lang: "typescript" | "python", + opts: ValueOptions = {} +): MethodCallInfo[] { + return collectCalls(spec, versionSet, lang, opts, (op) => Boolean(op.streaming)); +} + +function collectCalls( + spec: SdkSpec, + versionSet: VersionedResourceSet, + lang: "typescript" | "python", + opts: ValueOptions, + include: (op: OperationDef) => boolean ): MethodCallInfo[] { const results: MethodCallInfo[] = []; const clientPrefix = `client.${versionSet.version}`; @@ -71,7 +99,7 @@ export function buildMethodCalls( : resource.name; for (const op of resource.operations) { - if (!isTestableOperation(op)) continue; + if (!include(op)) continue; const args: MethodArg[] = []; diff --git a/packages/sdk-generator/src/backends/contract-tests/python-emitter.ts b/packages/sdk-generator/src/backends/contract-tests/python-emitter.ts index 147eaa3..8ecb6f1 100644 --- a/packages/sdk-generator/src/backends/contract-tests/python-emitter.ts +++ b/packages/sdk-generator/src/backends/contract-tests/python-emitter.ts @@ -8,6 +8,7 @@ import { } from "../python/response-type.js"; import { buildMethodCalls, + buildStreamCalls, groupByTopLevelResource, type MethodCallInfo, } from "./method-chain-builder.js"; @@ -55,17 +56,131 @@ export function emitPythonContractTests( files[filePath] = emitPythonChannelContractTestFile(channel, modulePath); } + // Per-resource SSE stream contract tests. Like channels, these are + // harness-backed (the SDK's async stream() runs against the channel-harness) + // and gated by the same opt-in env var. + let streamCallCount = 0; + for (const versionSet of spec.versions) { + const streamCalls = buildStreamCalls(spec, versionSet, "python"); + streamCallCount += streamCalls.length; + const groups = groupByTopLevelResource(streamCalls); + + for (const [resourceName, resourceCalls] of groups) { + const filePath = `${testDir}/streams/test_${snakeCase(resourceName)}.py`; + files[filePath] = emitPythonStreamTestFile(resourceCalls); + } + } + // Conftest drives lifecycle for both backends. We only spawn Prism when // the spec actually has REST operations (Prism refuses to mock a spec with - // no paths) and only spawn the harness service when the spec has channels. + // no paths) and only spawn the harness service when the spec has channels + // or SSE streams. files[`${testDir}/conftest.py`] = emitConftest({ includePrism: restCallCount > 0, - includeHarness: spec.channels.length > 0, + includeHarness: spec.channels.length > 0 || streamCallCount > 0, }); return files; } +// ─── SSE stream contract tests ─────────────────────────────────── + +/** + * Emit a pytest file driving a resource's async stream() methods through the + * SDK runtime's stream_sse against the channel-harness: register an autoEmit + * scenario over the control API, iterate the method, assert the yielded events; + * and a non-2xx scenario that must surface as ApiError. + */ +function emitPythonStreamTestFile(calls: MethodCallInfo[]): string { + const cb = new CodeBuilder(" "); + + for (const line of generatedHeaderPython().trim().split("\n")) cb.line(line); + cb.line(); + cb.line("import pytest"); + cb.line("from archastro.platform import AsyncPlatformClient"); + cb.line("from archastro.platform.runtime.http_client import ApiError"); + cb.line("from archastro.phx_channel import HarnessServiceClient"); + cb.line(); + cb.line("# Mark every coroutine in this file as async so the tests run whether or"); + cb.line("# not the consuming project sets asyncio_mode=auto."); + cb.line("pytestmark = pytest.mark.asyncio"); + cb.line(); + + for (const call of calls) emitPythonStreamTest(cb, call); + + return cb.toString(); +} + +function emitPythonStreamTest(cb: CodeBuilder, call: MethodCallInfo): void { + const routeKey = `${call.httpMethod} ${call.httpPath}`; + const events = call.operation.streaming?.events ?? []; + const argStr = buildPythonArgs(call); + const chainPy = call.accessorChain.replace("client.", ""); + const methodCall = `client.${chainPy}.${pythonParameterName(call.methodName)}(${argStr})`; + // autoEmit: the harness synthesizes contract-valid payloads from each event + // schema (resolving $refs), so the test stays valid without SDK-side fixtures. + const actions = events + .map((e) => `{"type": "autoEmit", "event": ${JSON.stringify(e.event)}}`) + .join(", "); + const expectedNames = `[${events.map((e) => JSON.stringify(e.event)).join(", ")}]`; + + const emitClient = (): void => { + cb.line( + 'harness = HarnessServiceClient(ws_url=harness_service["wsUrl"], control_url=harness_service["controlUrl"])' + ); + cb.line("await harness.reset()"); + }; + const emitSdkClient = (): void => { + cb.line( + 'client = AsyncPlatformClient(base_url=harness_service["controlUrl"], default_headers={"x-archastro-api-key": "pk_test-key"}, access_token="test-token")' + ); + }; + + // Happy path: the SDK yields the declared events, in order. + cb.line(`async def ${buildTestName(call, "yields_sse_events")}(harness_service):`); + cb.indent(); + emitClient(); + cb.line( + `await harness.register_stream_scenario({"route": ${JSON.stringify(routeKey)}, "actions": [${actions}]})` + ); + emitSdkClient(); + cb.pyBlock("try", () => { + cb.line("events = []"); + cb.pyBlock(`async for ev in ${methodCall}`, () => { + cb.line("events.append(ev)"); + }); + cb.line(`assert [e["event"] for e in events] == ${expectedNames}`); + }); + cb.pyBlock("finally", () => { + cb.line("await client.close()"); + cb.line("await harness.close()"); + }); + cb.dedent(); + cb.line(); + + // Error path: a non-2xx status surfaces as ApiError. + cb.line(`async def ${buildTestName(call, "rejects_non_2xx")}(harness_service):`); + cb.indent(); + emitClient(); + cb.line( + `await harness.register_stream_scenario({"route": ${JSON.stringify(routeKey)}, "actions": [{"type": "status", "code": 402, "body": {"error": {"code": "plan_not_entitled"}}}]})` + ); + emitSdkClient(); + cb.pyBlock("try", () => { + cb.pyBlock("with pytest.raises(ApiError)", () => { + cb.pyBlock(`async for _ in ${methodCall}`, () => { + cb.line("pass"); + }); + }); + }); + cb.pyBlock("finally", () => { + cb.line("await client.close()"); + cb.line("await harness.close()"); + }); + cb.dedent(); + cb.line(); +} + function emitResourceTestFile( _resourceName: string, calls: MethodCallInfo[] @@ -420,7 +535,7 @@ function emitConftest(opts: { "", "# Skip the channel test tree entirely at collection time when the env var", "# is not set, so CI runs REST tests without pulling in the harness service.", - 'collect_ignore_glob = [] if _channel_tests_enabled() else ["channels/*"]' + 'collect_ignore_glob = [] if _channel_tests_enabled() else ["channels/*", "streams/*"]' ); } diff --git a/packages/sdk-generator/src/backends/contract-tests/typescript-emitter.ts b/packages/sdk-generator/src/backends/contract-tests/typescript-emitter.ts index 7499def..0ed48ba 100644 --- a/packages/sdk-generator/src/backends/contract-tests/typescript-emitter.ts +++ b/packages/sdk-generator/src/backends/contract-tests/typescript-emitter.ts @@ -3,6 +3,7 @@ import type { SdkSpec } from "../../ast/types.js"; import { CodeBuilder, generatedHeader } from "../../utils/codegen.js"; import { buildMethodCalls, + buildStreamCalls, groupByTopLevelResource, type MethodCallInfo, } from "./method-chain-builder.js"; @@ -59,11 +60,26 @@ export function emitTypeScriptContractTests( files[filePath] = emitChannelContractTestFile(channel, channelImportPath); } - // Generate global setup — spawns Prism for REST traffic and (if the spec - // has channels) the harness-service subprocess for channel tests. + // Generate per-resource SSE stream contract tests. Like channels, these are + // harness-backed (the SDK's stream() runs against the channel-harness over + // real HTTP) and gated by the same opt-in env var. + let streamCallCount = 0; + for (const versionSet of spec.versions) { + const streamCalls = buildStreamCalls(spec, versionSet, "typescript"); + streamCallCount += streamCalls.length; + const groups = groupByTopLevelResource(streamCalls); + + for (const [resourceName, resourceCalls] of groups) { + const filePath = `${testDir}/streams/${resourceName}.contract.test.ts`; + files[filePath] = emitStreamTestFile(resourceName, resourceCalls); + } + } + + // Generate global setup — spawns Prism for REST traffic and (if the spec has + // channels or SSE streams) the harness-service subprocess those tests drive. files[`${testDir}/global-setup.ts`] = emitGlobalSetup({ includePrism: restCallCount > 0, - includeHarness: spec.channels.length > 0, + includeHarness: spec.channels.length > 0 || streamCallCount > 0, }); // Generate vitest config @@ -195,6 +211,115 @@ function emitErrorTests(cb: CodeBuilder, call: MethodCallInfo): void { } } +// ─── SSE stream contract tests ─────────────────────────────────── + +/** + * Emit a vitest file driving a resource's SSE stream() methods through the SDK + * runtime's streamSSE against the channel-harness: register an emit scenario + * over the control API, iterate the method, assert the yielded events; and a + * non-2xx scenario that must surface as ApiError. + */ +function emitStreamTestFile( + resourceName: string, + calls: MethodCallInfo[] +): string { + const cb = new CodeBuilder(); + + cb.line(generatedHeader()); + cb.line(); + cb.line('import { describe, it, expect, beforeEach, afterEach } from "vitest";'); + cb.line('import { HarnessServiceClient } from "@archastro/channel-harness";'); + cb.line('import { PlatformClient } from "../../../src/index.js";'); + cb.line('import { ApiError } from "../../../src/runtime/http-client.js";'); + cb.line(); + cb.line("let harness: HarnessServiceClient;"); + cb.line("let client: PlatformClient;"); + cb.line(); + cb.line("beforeEach(async () => {"); + cb.indent(); + cb.line("const wsUrl = process.env.ARCHASTRO_HARNESS_WS_URL;"); + cb.line("const controlUrl = process.env.ARCHASTRO_HARNESS_CONTROL_URL;"); + cb.line("if (!wsUrl || !controlUrl) {"); + cb.line( + ' throw new Error("SSE contract tests require ARCHASTRO_HARNESS_WS_URL and ARCHASTRO_HARNESS_CONTROL_URL — set by global-setup.");' + ); + cb.line("}"); + cb.line("harness = new HarnessServiceClient({ wsUrl, controlUrl });"); + cb.line("await harness.reset();"); + cb.line("// The harness serves SSE routes on its control listener, so the SDK"); + cb.line("// base URL is the control URL."); + cb.line("client = new PlatformClient({"); + cb.line(" baseUrl: controlUrl,"); + cb.line(' defaultHeaders: { "x-archastro-api-key": "pk_test-key" },'); + cb.line(' accessToken: "test-token",'); + cb.line("});"); + cb.dedent(); + cb.line("});"); + cb.line(); + cb.line("afterEach(() => {"); + cb.line(" harness.closeAllSockets();"); + cb.line("});"); + cb.line(); + + cb.line(`describe("contract: ${resourceName} (SSE)", () => {`); + cb.indent(); + for (const call of calls) emitStreamTest(cb, call); + cb.dedent(); + cb.line("});"); + + return cb.toString(); +} + +function emitStreamTest(cb: CodeBuilder, call: MethodCallInfo): void { + const routeKey = `${call.httpMethod} ${call.httpPath}`; + const events = call.operation.streaming?.events ?? []; + const argValues = call.args.map((a) => a.value).join(", "); + const callExpr = `${call.accessorChain}.${call.methodName}(${argValues})`; + // autoEmit: the harness synthesizes a contract-valid payload for each event + // from its schema (resolving $refs via its own fixture generator), so the + // test stays valid without re-deriving event fixtures SDK-side. + const emitActions = events + .map((e) => `{ type: "autoEmit", event: ${JSON.stringify(e.event)} }`) + .join(", "); + const expectedNames = JSON.stringify(events.map((e) => e.event)); + const label = `${call.accessorChain.replace("client.", "")}.${call.methodName}`; + + cb.line(`describe("${label} (${routeKey})", () => {`); + cb.indent(); + + cb.line('it("yields the declared SSE events in order", async () => {'); + cb.indent(); + cb.line( + `await harness.registerStreamScenario({ route: ${JSON.stringify(routeKey)}, actions: [${emitActions}] });` + ); + cb.line("const events: Array<{ event: string; data: unknown }> = [];"); + cb.line(`for await (const ev of ${callExpr}) {`); + cb.line(" events.push(ev);"); + cb.line("}"); + cb.line(`expect(events.map((e) => e.event)).toEqual(${expectedNames});`); + cb.dedent(); + cb.line("});"); + cb.line(); + + cb.line('it("rejects with ApiError on a non-2xx status", async () => {'); + cb.indent(); + cb.line( + `await harness.registerStreamScenario({ route: ${JSON.stringify(routeKey)}, actions: [{ type: "status", code: 402, body: { error: { code: "plan_not_entitled" } } }] });` + ); + cb.line("const drain = async (): Promise => {"); + cb.line(` for await (const _ of ${callExpr}) {`); + cb.line(" // drain"); + cb.line(" }"); + cb.line("};"); + cb.line("await expect(drain()).rejects.toBeInstanceOf(ApiError);"); + cb.dedent(); + cb.line("});"); + + cb.dedent(); + cb.line("});"); + cb.line(); +} + function emitGlobalSetup(opts: { includePrism: boolean; includeHarness: boolean; @@ -344,7 +469,7 @@ export default defineConfig({ include: ["__tests__/contract/**/*.contract.test.ts"], exclude: channelTestsEnabled() ? [] - : ["__tests__/contract/channels/**/*"], + : ["__tests__/contract/channels/**/*", "__tests__/contract/streams/**/*"], globalSetup: ["__tests__/contract/global-setup.ts"], testTimeout: 30000, // Channel tests share a single harness-service subprocess; scenarios From dbd9654d9495b7c576ee0efaa7d7cb01753d8b30 Mon Sep 17 00:00:00 2001 From: Calvin Grunewald Date: Mon, 29 Jun 2026 20:10:06 -0700 Subject: [PATCH 2/2] fix(channel-harness): re-sync sdk-generator dep to ^0.6.0 (workspace bumped) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v0.6.0 release bumped @archastro/sdk-generator, but channel-harness still pinned ^0.5.0 — which 0.6.0 doesn't satisfy — so a fresh `npm ci` pulled the published 0.5.6 (pre-SSE-contract-test exports, missing emitResourceFile) instead of linking the workspace, breaking the pretest. Bump to ^0.6.0 and `npm dedupe` so it links the workspace 0.6.0 (minimal lockfile change). Note: this caret keeps drifting whenever sdk-generator's version bumps — the release process should bump this dependency in lockstep (the two packages are co-released). Verified: npm ci links the workspace, cold Node 20 run is green (channel-harness 63, sdk-generator 299). Co-Authored-By: Claude Opus 4.8 (1M context) --- package-lock.json | 49 +++++++++------------------ packages/channel-harness/package.json | 2 +- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7132f7d..425cacf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -171,9 +171,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -865,9 +865,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", "dev": true, "license": "MIT", "dependencies": { @@ -1085,9 +1085,9 @@ } }, "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -1158,9 +1158,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -1400,9 +1400,9 @@ } }, "node_modules/eslint/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -2841,7 +2841,7 @@ "version": "0.3.0", "license": "MIT", "dependencies": { - "@archastro/sdk-generator": "^0.5.0", + "@archastro/sdk-generator": "^0.6.0", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "ws": "^8.18.0", @@ -2860,23 +2860,6 @@ "node": ">=20" } }, - "packages/channel-harness/node_modules/@archastro/sdk-generator": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@archastro/sdk-generator/-/sdk-generator-0.5.6.tgz", - "integrity": "sha512-YWVd9OtQnhGh1JR6e3GeVzCDCTPzi3J90SEBlJyEAWXuk+SDi9NTIlcEUtTCipXHiqwgrXhhLn+2SwusD5V1wA==", - "license": "MIT", - "dependencies": { - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "yaml": "^2.4.0" - }, - "bin": { - "sdk-generator": "dist/index.js" - }, - "engines": { - "node": ">=20" - } - }, "packages/sdk-generator": { "name": "@archastro/sdk-generator", "version": "0.6.0", diff --git a/packages/channel-harness/package.json b/packages/channel-harness/package.json index 5d0efca..5e5017e 100644 --- a/packages/channel-harness/package.json +++ b/packages/channel-harness/package.json @@ -41,7 +41,7 @@ "test:watch": "vitest" }, "dependencies": { - "@archastro/sdk-generator": "^0.5.0", + "@archastro/sdk-generator": "^0.6.0", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "ws": "^8.18.0",