diff --git a/.chronus/changes/add-streaming-2024-8-25-11-52-49.md b/.chronus/changes/add-streaming-2024-8-25-11-52-49.md new file mode 100644 index 0000000000..f3ea9a0511 --- /dev/null +++ b/.chronus/changes/add-streaming-2024-8-25-11-52-49.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/events" +--- + +Adds a new core package for describing events. \ No newline at end of file diff --git a/.chronus/changes/add-streaming-2024-8-25-11-53-37.md b/.chronus/changes/add-streaming-2024-8-25-11-53-37.md new file mode 100644 index 0000000000..9eff9f7a59 --- /dev/null +++ b/.chronus/changes/add-streaming-2024-8-25-11-53-37.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/streams" +--- + +Adds a new core package for describing streams and the type of data they contain. diff --git a/.chronus/changes/add-streaming-2024-8-25-11-54-27.md b/.chronus/changes/add-streaming-2024-8-25-11-54-27.md new file mode 100644 index 0000000000..51a7a423b4 --- /dev/null +++ b/.chronus/changes/add-streaming-2024-8-25-11-54-27.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/sse" +--- + +Adds a new core package to describe server-sent events. \ No newline at end of file diff --git a/.chronus/changes/add-streaming-2024-8-25-11-56-3.md b/.chronus/changes/add-streaming-2024-8-25-11-56-3.md new file mode 100644 index 0000000000..00b64884ff --- /dev/null +++ b/.chronus/changes/add-streaming-2024-8-25-11-56-3.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/http" +--- + +Adds HttpStream and JsonlStream models to to support streaming use-cases. \ No newline at end of file diff --git a/.chronus/changes/add-streaming-2024-8-25-11-56-36.md b/.chronus/changes/add-streaming-2024-8-25-11-56-36.md new file mode 100644 index 0000000000..6d4e774ab0 --- /dev/null +++ b/.chronus/changes/add-streaming-2024-8-25-11-56-36.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/compiler" +--- + +Fixes issue with the semantic walker where `exitTuple` was not being emitted. \ No newline at end of file diff --git a/docs/libraries/events/reference/decorators.md b/docs/libraries/events/reference/decorators.md new file mode 100644 index 0000000000..69772a8bbd --- /dev/null +++ b/docs/libraries/events/reference/decorators.md @@ -0,0 +1,112 @@ +--- +title: "Decorators" +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +# Decorators + +## TypeSpec.Events + +### `@contentType` {#@TypeSpec.Events.contentType} + +Specifies the content type of the event envelope, event body, or event payload. +When applied to an event payload, that field must also have a corresponding `@data` +decorator. + +```typespec +@TypeSpec.Events.contentType(contentType: valueof string) +``` + +#### Target + +`UnionVariant | ModelProperty` + +#### Parameters + +| Name | Type | Description | +| ----------- | ---------------- | ----------- | +| contentType | `valueof string` | | + +#### Examples + +```typespec +@events +union MixedEvents { + @contentType("application/json") + message: { + id: string, + text: string, + }, +} +``` + +##### Specify the content type of the event payload. + +```typespec +@events +union MixedEvents { + { + done: true, + }, + { + done: false, + @data @contentType("text/plain") value: string, + }, +} +``` + +### `@data` {#@TypeSpec.Events.data} + +Identifies the payload of an event. +Only one field in an event can be marked as the payload. + +```typespec +@TypeSpec.Events.data +``` + +#### Target + +`ModelProperty` + +#### Parameters + +None + +#### Examples + +```typespec +@events +union MixedEvents { + { + metadata: Record, + @data payload: string, + }, +} +``` + +### `@events` {#@TypeSpec.Events.events} + +Specify that this union describes a set of events. + +```typespec +@TypeSpec.Events.events +``` + +#### Target + +`Union` + +#### Parameters + +None + +#### Examples + +```typespec +@events +union MixedEvents { + pingEvent: string, + doneEvent: "done", +} +``` diff --git a/docs/libraries/events/reference/index.mdx b/docs/libraries/events/reference/index.mdx new file mode 100644 index 0000000000..514d08760f --- /dev/null +++ b/docs/libraries/events/reference/index.mdx @@ -0,0 +1,40 @@ +--- +title: Overview +sidebar_position: 0 +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Overview + +TypeSpec library providing events bindings + +## Install + + + + +```bash +npm install @typespec/events +``` + + + + +```bash +npm install --save-peer @typespec/events +``` + + + + +## TypeSpec.Events + +### Decorators + +- [`@contentType`](./decorators.md#@TypeSpec.Events.contentType) +- [`@data`](./decorators.md#@TypeSpec.Events.data) +- [`@events`](./decorators.md#@TypeSpec.Events.events) diff --git a/docs/libraries/sse/reference/data-types.md b/docs/libraries/sse/reference/data-types.md new file mode 100644 index 0000000000..d322877397 --- /dev/null +++ b/docs/libraries/sse/reference/data-types.md @@ -0,0 +1,71 @@ +--- +title: "Data types" +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +# Data types + +## TypeSpec.SSE + +### `SSEStream` {#TypeSpec.SSE.SSEStream} + +Describes a stream of server-sent events. + +The content-type is set to `text/event-stream`. + +The server-sent events are described by `Type`. +The event type for any event can be defined by using named union variants. +When a union variant is not named, it is considered a 'message' event. + +```typespec +model TypeSpec.SSE.SSEStream +``` + +#### Template Parameters + +| Name | Description | +| ---- | ---------------------------------------------------- | +| Type | The set of models describing the server-sent events. | + +#### Examples + +##### Mix of named union variants and terminal event + +```typespec +model UserConnect { + username: string; + time: string; +} + +model UserMessage { + username: string; + time: string; + text: string; +} + +model UserDisconnect { + username: string; + time: string; +} + +@TypeSpec.Events.events +union ChannelEvents { + userconnect: UserConnect, + usermessage: UserMessage, + userdisconnect: UserDisconnect, + + @Events.contentType("text/plain") + @terminalEvent + "[unsubscribe]", +} + +op subscribeToChannel(): SSEStream; +``` + +#### Properties + +| Name | Type | Description | +| ----------- | --------------------- | ----------- | +| contentType | `"text/event-stream"` | | +| body | `string` | | diff --git a/docs/libraries/sse/reference/decorators.md b/docs/libraries/sse/reference/decorators.md new file mode 100644 index 0000000000..a92b00db99 --- /dev/null +++ b/docs/libraries/sse/reference/decorators.md @@ -0,0 +1,26 @@ +--- +title: "Decorators" +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +# Decorators + +## TypeSpec.SSE + +### `@terminalEvent` {#@TypeSpec.SSE.terminalEvent} + +Indicates that the presence of this event is a terminal event, +and the client should disconnect from the server. + +```typespec +@TypeSpec.SSE.terminalEvent +``` + +#### Target + +`UnionVariant` + +#### Parameters + +None diff --git a/docs/libraries/sse/reference/index.mdx b/docs/libraries/sse/reference/index.mdx new file mode 100644 index 0000000000..fd60078eb0 --- /dev/null +++ b/docs/libraries/sse/reference/index.mdx @@ -0,0 +1,42 @@ +--- +title: Overview +sidebar_position: 0 +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Overview + +TypeSpec library providing server sent events bindings + +## Install + + + + +```bash +npm install @typespec/sse +``` + + + + +```bash +npm install --save-peer @typespec/sse +``` + + + + +## TypeSpec.SSE + +### Decorators + +- [`@terminalEvent`](./decorators.md#@TypeSpec.SSE.terminalEvent) + +### Models + +- [`SSEStream`](./data-types.md#TypeSpec.SSE.SSEStream) diff --git a/docs/libraries/stream/reference/data-types.md b/docs/libraries/stream/reference/data-types.md new file mode 100644 index 0000000000..6b52f0434f --- /dev/null +++ b/docs/libraries/stream/reference/data-types.md @@ -0,0 +1,31 @@ +--- +title: "Data types" +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +# Data types + +## TypeSpec.Streams + +### `Stream` {#TypeSpec.Streams.Stream} + +Defines a model that represents a stream protocol type whose data is described +by `Type`. + +This can be useful when the underlying data type is not relevant, or to serve as +a base type for custom streams. + +```typespec +model TypeSpec.Streams.Stream +``` + +#### Template Parameters + +| Name | Description | +| ---- | ------------------------------ | +| Type | The type of the stream's data. | + +#### Properties + +None diff --git a/docs/libraries/stream/reference/decorators.md b/docs/libraries/stream/reference/decorators.md new file mode 100644 index 0000000000..7baec7a7bb --- /dev/null +++ b/docs/libraries/stream/reference/decorators.md @@ -0,0 +1,42 @@ +--- +title: "Decorators" +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +# Decorators + +## TypeSpec.Streams + +### `@streamOf` {#@TypeSpec.Streams.streamOf} + +Specify that a model represents a stream protocol type whose data is described +by `Type`. + +```typespec +@TypeSpec.Streams.streamOf(type: unknown) +``` + +#### Target + +`Model` + +#### Parameters + +| Name | Type | Description | +| ---- | --------- | ------------------------------------------------------- | +| type | `unknown` | The type that models the underlying data of the stream. | + +#### Examples + +```typespec +model Message { + id: string; + text: string; +} + +@streamOf(Message) +model Response { + @body body: string; +} +``` diff --git a/docs/libraries/stream/reference/index.mdx b/docs/libraries/stream/reference/index.mdx new file mode 100644 index 0000000000..854a1d24a3 --- /dev/null +++ b/docs/libraries/stream/reference/index.mdx @@ -0,0 +1,42 @@ +--- +title: Overview +sidebar_position: 0 +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Overview + +TypeSpec library providing stream bindings + +## Install + + + + +```bash +npm install @typespec/streams +``` + + + + +```bash +npm install --save-peer @typespec/streams +``` + + + + +## TypeSpec.Streams + +### Decorators + +- [`@streamOf`](./decorators.md#@TypeSpec.Streams.streamOf) + +### Models + +- [`Stream`](./data-types.md#TypeSpec.Streams.Stream) diff --git a/docs/libraries/streams/reference/data-types.md b/docs/libraries/streams/reference/data-types.md new file mode 100644 index 0000000000..6b52f0434f --- /dev/null +++ b/docs/libraries/streams/reference/data-types.md @@ -0,0 +1,31 @@ +--- +title: "Data types" +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +# Data types + +## TypeSpec.Streams + +### `Stream` {#TypeSpec.Streams.Stream} + +Defines a model that represents a stream protocol type whose data is described +by `Type`. + +This can be useful when the underlying data type is not relevant, or to serve as +a base type for custom streams. + +```typespec +model TypeSpec.Streams.Stream +``` + +#### Template Parameters + +| Name | Description | +| ---- | ------------------------------ | +| Type | The type of the stream's data. | + +#### Properties + +None diff --git a/docs/libraries/streams/reference/decorators.md b/docs/libraries/streams/reference/decorators.md new file mode 100644 index 0000000000..7baec7a7bb --- /dev/null +++ b/docs/libraries/streams/reference/decorators.md @@ -0,0 +1,42 @@ +--- +title: "Decorators" +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +# Decorators + +## TypeSpec.Streams + +### `@streamOf` {#@TypeSpec.Streams.streamOf} + +Specify that a model represents a stream protocol type whose data is described +by `Type`. + +```typespec +@TypeSpec.Streams.streamOf(type: unknown) +``` + +#### Target + +`Model` + +#### Parameters + +| Name | Type | Description | +| ---- | --------- | ------------------------------------------------------- | +| type | `unknown` | The type that models the underlying data of the stream. | + +#### Examples + +```typespec +model Message { + id: string; + text: string; +} + +@streamOf(Message) +model Response { + @body body: string; +} +``` diff --git a/docs/libraries/streams/reference/index.mdx b/docs/libraries/streams/reference/index.mdx new file mode 100644 index 0000000000..854a1d24a3 --- /dev/null +++ b/docs/libraries/streams/reference/index.mdx @@ -0,0 +1,42 @@ +--- +title: Overview +sidebar_position: 0 +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Overview + +TypeSpec library providing stream bindings + +## Install + + + + +```bash +npm install @typespec/streams +``` + + + + +```bash +npm install --save-peer @typespec/streams +``` + + + + +## TypeSpec.Streams + +### Decorators + +- [`@streamOf`](./decorators.md#@TypeSpec.Streams.streamOf) + +### Models + +- [`Stream`](./data-types.md#TypeSpec.Streams.Stream) diff --git a/packages/compiler/src/core/semantic-walker.ts b/packages/compiler/src/core/semantic-walker.ts index cf470f5a09..e32ee72630 100644 --- a/packages/compiler/src/core/semantic-walker.ts +++ b/packages/compiler/src/core/semantic-walker.ts @@ -327,6 +327,7 @@ function navigateTupleType(type: Tuple, context: NavigationContext) { for (const value of type.values) { navigateTypeInternal(value, context); } + context.emit("exitTuple", type); } function navigateStringTemplate(type: StringTemplate, context: NavigationContext) { if (checkVisited(context.visited, type)) { diff --git a/packages/compiler/test/semantic-walker.test.ts b/packages/compiler/test/semantic-walker.test.ts index 6d5964c4cc..5240e001db 100644 --- a/packages/compiler/test/semantic-walker.test.ts +++ b/packages/compiler/test/semantic-walker.test.ts @@ -8,6 +8,7 @@ import { Namespace, Operation, SemanticNodeListener, + Tuple, Union, UnionVariant, getNamespaceFullName, @@ -38,6 +39,8 @@ describe("compiler: semantic walker", () => { interfaces: [] as Interface[], unions: [] as Union[], unionVariants: [] as UnionVariant[], + tuples: [] as Tuple[], + exitTuples: [] as Tuple[], }; const listener: SemanticNodeListener = { @@ -81,6 +84,14 @@ describe("compiler: semantic walker", () => { result.unionVariants.push(x); return customListener?.unionVariant?.(x); }, + tuple: (x) => { + result.tuples.push(x); + return customListener?.tuple?.(x); + }, + exitTuple: (x) => { + result.exitTuples.push(x); + return customListener?.exitTuple?.(x); + }, }; return [result, listener] as const; } @@ -238,6 +249,28 @@ describe("compiler: semantic walker", () => { strictEqual(result.unionVariants[0].name!, "x"); }); + it("finds tuples", async () => { + const result = await runNavigator(` + model ContainsTuple { + tuple: [string]; + } + `); + + strictEqual(result.tuples.length, 1); + strictEqual(result.tuples[0].values.length, 1); + }); + + it("finds exit tuples", async () => { + const result = await runNavigator(` + model ContainsTuple { + tuple: [string]; + } + `); + + strictEqual(result.exitTuples.length, 1); + strictEqual(result.exitTuples[0].values.length, 1); + }); + it("finds interfaces", async () => { const result = await runNavigator(` model B { }; diff --git a/packages/events/CHANGELOG.md b/packages/events/CHANGELOG.md new file mode 100644 index 0000000000..84aaa27d33 --- /dev/null +++ b/packages/events/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog - @typespec/events diff --git a/packages/events/README.md b/packages/events/README.md new file mode 100644 index 0000000000..144249df7f --- /dev/null +++ b/packages/events/README.md @@ -0,0 +1,120 @@ +# @typespec/events + +TypeSpec library providing events bindings + +## Install + +```bash +npm install @typespec/events +``` + +## Decorators + +### TypeSpec.Events + +- [`@contentType`](#@contenttype) +- [`@data`](#@data) +- [`@events`](#@events) + +#### `@contentType` + +Specifies the content type of the event envelope, event body, or event payload. +When applied to an event payload, that field must also have a corresponding `@data` +decorator. + +```typespec +@TypeSpec.Events.contentType(contentType: valueof string) +``` + +##### Target + +`UnionVariant | ModelProperty` + +##### Parameters + +| Name | Type | Description | +| ----------- | ---------------- | ----------- | +| contentType | `valueof string` | | + +##### Examples + +```typespec +@events +union MixedEvents { + @contentType("application/json") + message: { + id: string, + text: string, + }, +} +``` + +###### Specify the content type of the event payload. + +```typespec +@events +union MixedEvents { + { + done: true, + }, + { + done: false, + @data @contentType("text/plain") value: string, + }, +} +``` + +#### `@data` + +Identifies the payload of an event. +Only one field in an event can be marked as the payload. + +```typespec +@TypeSpec.Events.data +``` + +##### Target + +`ModelProperty` + +##### Parameters + +None + +##### Examples + +```typespec +@events +union MixedEvents { + { + metadata: Record, + @data payload: string, + }, +} +``` + +#### `@events` + +Specify that this union describes a set of events. + +```typespec +@TypeSpec.Events.events +``` + +##### Target + +`Union` + +##### Parameters + +None + +##### Examples + +```typespec +@events +union MixedEvents { + pingEvent: string, + doneEvent: "done", +} +``` diff --git a/packages/events/generated-defs/TypeSpec.Events.ts b/packages/events/generated-defs/TypeSpec.Events.ts new file mode 100644 index 0000000000..00f7e0c222 --- /dev/null +++ b/packages/events/generated-defs/TypeSpec.Events.ts @@ -0,0 +1,63 @@ +import type { DecoratorContext, ModelProperty, Union, UnionVariant } from "@typespec/compiler"; + +/** + * Specify that this union describes a set of events. + * + * @example + * ```typespec + * @events + * union MixedEvents { + * pingEvent: string; + * + * doneEvent: "done"; + * } + * ``` + */ +export type EventsDecorator = (context: DecoratorContext, target: Union) => void; + +/** + * Specifies the content type of the event envelope, event body, or event payload. + * When applied to an event payload, that field must also have a corresponding `@data` + * decorator. + * + * @example + * ```typespec + * @events union MixedEvents { + * @contentType("application/json") + * message: { id: string, text: string, } + * } + * ``` + * @example Specify the content type of the event payload. + * + * ```typespec + * @events union MixedEvents { + * { done: true }, + * + * { done: false, @data @contentType("text/plain") value: string,} + * } + * ``` + */ +export type ContentTypeDecorator = ( + context: DecoratorContext, + target: UnionVariant | ModelProperty, + contentType: string, +) => void; + +/** + * Identifies the payload of an event. + * Only one field in an event can be marked as the payload. + * + * @example + * ```typespec + * @events union MixedEvents { + * { metadata: Record, @data payload: string,} + * } + * ``` + */ +export type DataDecorator = (context: DecoratorContext, target: ModelProperty) => void; + +export type TypeSpecEventsDecorators = { + events: EventsDecorator; + contentType: ContentTypeDecorator; + data: DataDecorator; +}; diff --git a/packages/events/generated-defs/TypeSpec.Events.ts-test.ts b/packages/events/generated-defs/TypeSpec.Events.ts-test.ts new file mode 100644 index 0000000000..896c0a989a --- /dev/null +++ b/packages/events/generated-defs/TypeSpec.Events.ts-test.ts @@ -0,0 +1,5 @@ +/** An error here would mean that the decorator is not exported or doesn't have the right name. */ +import { $decorators } from "@typespec/events"; +import type { TypeSpecEventsDecorators } from "./TypeSpec.Events.js"; +/** An error here would mean that the exported decorator is not using the same signature. Make sure to have export const $decName: DecNameDecorator = (...) => ... */ +const _: TypeSpecEventsDecorators = $decorators["TypeSpec.Events"]; diff --git a/packages/events/lib/decorators.tsp b/packages/events/lib/decorators.tsp new file mode 100644 index 0000000000..a216bd869b --- /dev/null +++ b/packages/events/lib/decorators.tsp @@ -0,0 +1,59 @@ +using TypeSpec.Reflection; + +namespace TypeSpec.Events; + +/** + * Specify that this union describes a set of events. + * + * @example + * + * ```typespec + * @events + * union MixedEvents { + * pingEvent: string; + * + * doneEvent: "done"; + * } + * ``` + */ +extern dec events(target: Union); + +/** + * Specifies the content type of the event envelope, event body, or event payload. + * When applied to an event payload, that field must also have a corresponding `@data` + * decorator. + * + * @example + * + * ```typespec + * @events union MixedEvents { + * @contentType("application/json") + * message: { id: string, text: string, } + * } + * ``` + * + * @example Specify the content type of the event payload. + * + * ```typespec + * @events union MixedEvents { + * { done: true }, + * + * { done: false, @data @contentType("text/plain") value: string,} + * } + * ``` + */ +extern dec contentType(target: UnionVariant | ModelProperty, contentType: valueof string); + +/** + * Identifies the payload of an event. + * Only one field in an event can be marked as the payload. + * + * @example + * + * ```typespec + * @events union MixedEvents { + * { metadata: Record, @data payload: string,} + * } + * ``` + */ +extern dec data(target: ModelProperty); diff --git a/packages/events/lib/main.tsp b/packages/events/lib/main.tsp new file mode 100644 index 0000000000..da8917d9d6 --- /dev/null +++ b/packages/events/lib/main.tsp @@ -0,0 +1,2 @@ +import "../dist/src/tsp-index.js"; +import "./decorators.tsp"; diff --git a/packages/events/package.json b/packages/events/package.json new file mode 100644 index 0000000000..f8e3a2510c --- /dev/null +++ b/packages/events/package.json @@ -0,0 +1,67 @@ +{ + "name": "@typespec/events", + "version": "0.60.0", + "author": "Microsoft Corporation", + "description": "TypeSpec library providing events bindings", + "homepage": "https://typespec.io", + "readme": "https://github.com/microsoft/typespec/blob/main/README.md", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/microsoft/typespec.git" + }, + "bugs": { + "url": "https://github.com/microsoft/typespec/issues" + }, + "keywords": [ + "typespec" + ], + "type": "module", + "main": "dist/src/index.js", + "tspMain": "lib/main.tsp", + "exports": { + ".": "./dist/src/index.js", + "./testing": "./dist/src/testing/index.js", + "./experimental": { + "types": "./dist/src/experimental/index.d.ts", + "default": "./dist/src/experimental/index.js" + } + }, + "engines": { + "node": ">=18.0.0" + }, + "scripts": { + "clean": "rimraf ./dist ./temp", + "build": "npm run gen-extern-signature && tsc -p . && npm run lint-typespec-library", + "watch": "tsc -p . --watch", + "gen-extern-signature": "tspd --enable-experimental gen-extern-signature .", + "lint-typespec-library": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit", + "test": "vitest run", + "test:watch": "vitest -w", + "test:ui": "vitest --ui", + "test-official": "vitest run --coverage --reporter=junit --reporter=default --no-file-parallelism", + "lint": "eslint . --ext .ts --max-warnings=0", + "lint:fix": "eslint . --fix --ext .ts", + "regen-docs": "tspd doc . --enable-experimental --output-dir ../../docs/libraries/events/reference" + }, + "files": [ + "lib/*.tsp", + "dist/**", + "!dist/test/**" + ], + "peerDependencies": { + "@typespec/compiler": "workspace:~" + }, + "devDependencies": { + "@types/node": "~22.7.1", + "@typespec/compiler": "workspace:~", + "@typespec/library-linter": "workspace:~", + "@typespec/tspd": "workspace:~", + "@vitest/coverage-v8": "^2.1.1", + "@vitest/ui": "^2.1.1", + "c8": "^10.1.2", + "rimraf": "~6.0.1", + "typescript": "~5.6.2", + "vitest": "^2.1.1" + } +} diff --git a/packages/events/src/decorators.ts b/packages/events/src/decorators.ts new file mode 100644 index 0000000000..1a2e7c6146 --- /dev/null +++ b/packages/events/src/decorators.ts @@ -0,0 +1,34 @@ +import { type ModelProperty, type Union, type UnionVariant } from "@typespec/compiler"; +import { unsafe_useStateMap, unsafe_useStateSet } from "@typespec/compiler/experimental"; +import type { + ContentTypeDecorator, + DataDecorator, + EventsDecorator, +} from "../generated-defs/TypeSpec.Events.js"; +import { EventsStateKeys } from "./lib.js"; + +const [isEvents, setEvents] = unsafe_useStateSet(EventsStateKeys.events); + +export const $eventsDecorator: EventsDecorator = (context, target) => { + setEvents(context.program, target); +}; + +export { isEvents }; + +const [getContentType, setContentType] = unsafe_useStateMap( + EventsStateKeys.contentType, +); + +export const $contentTypeDecorator: ContentTypeDecorator = (context, target, contentType) => { + setContentType(context.program, target, contentType); +}; + +export { getContentType }; + +const [isEventData, setEventData] = unsafe_useStateSet(EventsStateKeys.data); + +export const $dataDecorator: DataDecorator = (context, target) => { + setEventData(context.program, target); +}; + +export { isEventData }; diff --git a/packages/events/src/experimental/get-event-definitions.ts b/packages/events/src/experimental/get-event-definitions.ts new file mode 100644 index 0000000000..2efb68d6c0 --- /dev/null +++ b/packages/events/src/experimental/get-event-definitions.ts @@ -0,0 +1,253 @@ +import { + createDiagnosticCollector, + navigateType, + type Diagnostic, + type DiagnosticResult, + type Model, + type ModelProperty, + type Program, + type Tuple, + type Type, + type Union, + type UnionVariant, +} from "@typespec/compiler"; +import { getContentType, isEventData } from "../decorators.js"; +import { createDiagnostic } from "../lib.js"; + +function validateContentType(program: Program, target: ModelProperty): Diagnostic | undefined { + const contentType = getContentType(program, target); + if (!contentType || isEventData(program, target)) return; + + return createDiagnostic({ + code: "invalid-content-type-target", + target, + }); +} + +function stringifyPropertyPath(path: Array): string { + return path + .map((p) => { + switch (p.kind) { + case "ModelProperty": + return p.name; + case "Tuple": + return "[]"; + case "Model": + return; + } + }) + .filter(Boolean) + .join("."); +} + +function getEventDefinition( + program: Program, + target: UnionVariant, +): DiagnosticResult { + const diagnostics = createDiagnosticCollector(); + + // If the variant has a name, that may be used for out-of-band event types. + const eventType = typeof target.name === "string" ? target.name : undefined; + const envelopeContentType = getContentType(program, target); + + let payloadType: Type | undefined; + let payloadContentType: string | undefined; + let pathToPayload: string = ""; + + // Keeps track of if we're in a Record or Array. + let indexerDepth = 0; + + // Keeps track of the path from the target to the current model property. + const currentPropertyPath: Array = []; + + // Keeps track of the types that have a descendant that leads to the event payload. + const typesThatChainToPayload = new Set(); + + // Look for a model property that is decorated with `@data`. + // This property will be used as the event payload. + // It can only be applied once within an event, and if it is not found, + // the target type is the payload. + navigateType( + target.type, + { + modelProperty(prop) { + currentPropertyPath.push(prop); + const contentTypeDiagnostic = validateContentType(program, prop); + if (contentTypeDiagnostic) { + diagnostics.add(contentTypeDiagnostic); + } + + // This detects the scenario where a model that contains a `@data` property + // is referenced multiple times directly or indirectly by the target event. + if (typesThatChainToPayload.has(prop.type)) { + diagnostics.add( + createDiagnostic({ + code: "multiple-event-payloads", + format: { + dataPath: pathToPayload, + currentPath: stringifyPropertyPath(currentPropertyPath), + }, + target, + }), + ); + return; + } + + // Haven't found a payload property yet, move on. + if (!isEventData(program, prop)) return; + + // Mark all the types in the current path as having a descendant that leads to the payload. + currentPropertyPath.forEach((p) => { + if (p.kind === "ModelProperty") { + typesThatChainToPayload.add(p.type); + } else if (p.kind === "Model" || p.kind === "Tuple") { + typesThatChainToPayload.add(p); + } + }); + + // Found the payload property but it's referenced indirectly by + // a Record or Array, which implies there would be more than 1 payload. + if (indexerDepth > 0) { + diagnostics.add( + createDiagnostic({ + code: "multiple-event-payloads", + messageId: "payloadInIndexedModel", + format: { + dataPath: stringifyPropertyPath(currentPropertyPath.slice(0, -1)), + }, + target, + }), + ); + return; + } + + // A payload type was previously found, but only one is allowed. + if (payloadType) { + diagnostics.add( + createDiagnostic({ + code: "multiple-event-payloads", + format: { + dataPath: pathToPayload, + currentPath: stringifyPropertyPath(currentPropertyPath), + }, + target, + }), + ); + return; + } + + // A payload property was found. + payloadType = prop.type; + payloadContentType = getContentType(program, prop); + pathToPayload = stringifyPropertyPath(currentPropertyPath); + }, + exitModelProperty() { + currentPropertyPath.pop(); + }, + tuple(tuple) { + currentPropertyPath.push(tuple); + // Check if any of the tuple values have already been marked as a payload/payload ancestor. + // They won't be visited again, so need to create diagnostic here. + tuple.values.forEach((value) => { + if (typesThatChainToPayload.has(value)) { + diagnostics.add( + createDiagnostic({ + code: "multiple-event-payloads", + format: { + dataPath: pathToPayload, + currentPath: stringifyPropertyPath(currentPropertyPath), + }, + target, + }), + ); + return; + } + }); + }, + exitTuple() { + currentPropertyPath.pop(); + }, + model(model) { + if (model.indexer) { + indexerDepth++; + } + currentPropertyPath.push(model); + }, + exitModel(model) { + if (model.indexer) { + indexerDepth--; + } + currentPropertyPath.pop(); + }, + }, + {}, + ); + + const eventDefinition: EventDefinition = { + eventType, + root: target, + isEventEnvelope: !!payloadType, + type: target.type, + contentType: envelopeContentType, + payloadType: payloadType ?? target.type, + payloadContentType: payloadType ? payloadContentType : envelopeContentType, + }; + + return diagnostics.wrap(eventDefinition); +} + +export function getEventDefinitions( + program: Program, + target: Union, +): DiagnosticResult { + const diagnostics = createDiagnosticCollector(); + // 1. Iterate over each variant of the action + const events: EventDefinition[] = []; + + target.variants.forEach((variant) => { + events.push(diagnostics.pipe(getEventDefinition(program, variant))); + }); + + return diagnostics.wrap(events); +} + +/** + * Represents the definition of an event. + */ +export interface EventDefinition { + /** + * The name of the event type. + * This may be used when the underlying event protocol supports event types + * out-of-band from the event evelope or event payload. + */ + readonly eventType?: string; + /** + * The root variant of the union that represents the event. + */ + readonly root: UnionVariant; + /** + * Indicates whether the `type` describes an event envelope + * with a separate event payload. + */ + readonly isEventEnvelope: boolean; + /** + * The type of the event. + * This represents an event envelope if `isEventEnvelope` is `true`. + */ + readonly type: Type; + /** + * The content type of the event. + * This represents the content type of the event envelope if `isEventEnvelope` is `true`. + */ + readonly contentType?: string; + /** + * The type of the event payload. + * This matches `type` if `isEventEnvelope` is `false`. + */ + readonly payloadType: Type; + /** + * The content type of the event payload. + * This matches `contentType` if `isEventEnvelope` is `false`. + */ + readonly payloadContentType?: string; +} diff --git a/packages/events/src/experimental/index.ts b/packages/events/src/experimental/index.ts new file mode 100644 index 0000000000..bfc258df45 --- /dev/null +++ b/packages/events/src/experimental/index.ts @@ -0,0 +1,2 @@ +export { getEventDefinitions as unsafe_getEventDefinitions } from "./get-event-definitions.js"; +export type { EventDefinition as unsafe_EventDefinition } from "./get-event-definitions.js"; diff --git a/packages/events/src/index.ts b/packages/events/src/index.ts new file mode 100644 index 0000000000..934b144737 --- /dev/null +++ b/packages/events/src/index.ts @@ -0,0 +1,5 @@ +export { $lib } from "./lib.js"; + +export { $decorators, $onValidate } from "./tsp-index.js"; + +export { getContentType, isEventData, isEvents } from "./decorators.js"; diff --git a/packages/events/src/lib.ts b/packages/events/src/lib.ts new file mode 100644 index 0000000000..63c50dd393 --- /dev/null +++ b/packages/events/src/lib.ts @@ -0,0 +1,28 @@ +import { createTypeSpecLibrary, paramMessage } from "@typespec/compiler"; + +export const $lib = createTypeSpecLibrary({ + name: "@typespec/events", + diagnostics: { + "invalid-content-type-target": { + severity: "error", + messages: { + default: `@contentType can only be specified on the top-level event envelope, or the event payload marked with @data`, + }, + }, + "multiple-event-payloads": { + severity: "error", + messages: { + default: paramMessage`Event payload already applied to ${"dataPath"} but also exists under ${"currentPath"}`, + + payloadInIndexedModel: paramMessage`Event payload applied from inside a Record or Array at ${"dataPath"}`, + }, + }, + }, + state: { + events: { description: "State for the @events decorator." }, + contentType: { description: "State for the @contentType decorator." }, + data: { description: "State for the @data decorator." }, + }, +}); + +export const { reportDiagnostic, createDiagnostic, stateKeys: EventsStateKeys } = $lib; diff --git a/packages/events/src/testing/index.ts b/packages/events/src/testing/index.ts new file mode 100644 index 0000000000..66ba1a1bc0 --- /dev/null +++ b/packages/events/src/testing/index.ts @@ -0,0 +1,6 @@ +import { createTestLibrary, findTestPackageRoot } from "@typespec/compiler/testing"; + +export const EventsTestLibrary = createTestLibrary({ + name: "@typespec/events", + packageRoot: await findTestPackageRoot(import.meta.url), +}); diff --git a/packages/events/src/tsp-index.ts b/packages/events/src/tsp-index.ts new file mode 100644 index 0000000000..4192e91137 --- /dev/null +++ b/packages/events/src/tsp-index.ts @@ -0,0 +1,11 @@ +import { $contentTypeDecorator, $dataDecorator, $eventsDecorator } from "./decorators.js"; + +export { $lib } from "./lib.js"; +export { $onValidate } from "./validate.js"; +export const $decorators = { + "TypeSpec.Events": { + contentType: $contentTypeDecorator, + data: $dataDecorator, + events: $eventsDecorator, + }, +}; diff --git a/packages/events/src/validate.ts b/packages/events/src/validate.ts new file mode 100644 index 0000000000..eaa439979e --- /dev/null +++ b/packages/events/src/validate.ts @@ -0,0 +1,13 @@ +import type { Program, Union } from "@typespec/compiler"; +import { unsafe_getEventDefinitions } from "./experimental/index.js"; +import { EventsStateKeys } from "./lib.js"; +export function $onValidate(program: Program) { + checkForInvalidEvents(program); +} + +function checkForInvalidEvents(program: Program) { + program.stateSet(EventsStateKeys.events).forEach((events) => { + const [, diagnostics] = unsafe_getEventDefinitions(program, events as Union); + program.reportDiagnostics(diagnostics); + }); +} diff --git a/packages/events/test/decorators.test.ts b/packages/events/test/decorators.test.ts new file mode 100644 index 0000000000..3a03a41b5a --- /dev/null +++ b/packages/events/test/decorators.test.ts @@ -0,0 +1,339 @@ +import type { Model, Union } from "@typespec/compiler"; +import { + expectDiagnosticEmpty, + expectDiagnostics, + type BasicTestRunner, +} from "@typespec/compiler/testing"; +import { assert, beforeEach, describe, expect, it } from "vitest"; +import { getContentType, isEventData, isEvents } from "../src/decorators.js"; +import { unsafe_getEventDefinitions as getEventDefinitions } from "../src/experimental/index.js"; +import { createEventsTestRunner } from "./test-host.js"; + +let runner: BasicTestRunner; + +beforeEach(async () => { + runner = await createEventsTestRunner(); +}); + +describe("@events", () => { + it("marks the union as containing event definitions", async () => { + const { MixedEvents } = await runner.compile(`@test @events union MixedEvents {}`); + + expect(isEvents(runner.program, MixedEvents as Union)).toBe(true); + }); + + it("can contain multiple event definitions", async () => { + const { MixedEvents, JsonEvent, StringEvent } = await runner.compile( + ` +@test +model StringEvent { + payload: { + @Events.contentType("text/plain") + @Events.data + foo: string; + }; +} + +@test +model JsonEvent { + @Events.data + @Events.contentType("application/json") + payload: { + foo: string; + bar: string; + }; +} + +@test +@events +union MixedEvents { + @Events.contentType("application/json") + stringEvent: StringEvent, + + JsonEvent, + + @Events.contentType("text/plain") + "[done]", +} + `, + ); + + assert(MixedEvents.kind === "Union"); + assert(JsonEvent.kind === "Model"); + assert(StringEvent.kind === "Model"); + + const variants = Array.from(MixedEvents.variants.values()); + + expect(isEvents(runner.program, MixedEvents)).toBe(true); + const [eventDefinitions, diagnostics] = getEventDefinitions(runner.program, MixedEvents); + expectDiagnosticEmpty(diagnostics); + + expect(eventDefinitions.length).toBe(3); + + // Verify `StringEvent` + expect(eventDefinitions[0].root).toBe(variants[0]); + expect(eventDefinitions[0].eventType).toBe("stringEvent"); + expect(eventDefinitions[0].type).toBe(StringEvent); + expect(eventDefinitions[0].contentType).toBe("application/json"); + const stringEventPayloadProp = StringEvent.properties.get("payload")!.type as Model; + expect(eventDefinitions[0].payloadType).toBe( + stringEventPayloadProp.properties.get("foo")!.type, + ); + expect(eventDefinitions[0].payloadContentType).toBe("text/plain"); + + // Verify `JsonEvent` + expect(eventDefinitions[1].root).toBe(variants[1]); + expect(eventDefinitions[1].eventType).toBeUndefined(); + expect(eventDefinitions[1].type).toBe(JsonEvent); + expect(eventDefinitions[1].contentType).toBeUndefined(); + expect(eventDefinitions[1].payloadType).toBe(JsonEvent.properties.get("payload")!.type); + expect(eventDefinitions[1].payloadContentType).toBe("application/json"); + + //Verify `[done]` + expect(eventDefinitions[2].root).toBe(variants[2]); + expect(eventDefinitions[2].eventType).toBeUndefined(); + expect(eventDefinitions[2].type).toMatchObject({ kind: "String", value: "[done]" }); + expect(eventDefinitions[2].contentType).toBe("text/plain"); + expect(eventDefinitions[2].payloadType).toBe(eventDefinitions[2].type); + expect(eventDefinitions[2].payloadContentType).toBe(eventDefinitions[2].contentType); + }); +}); + +describe("@data", () => { + it("marks a model property as being the event payload", async () => { + const { Event } = await runner.compile(`@test model Event { @data foo: string }`); + assert(Event.kind === "Model"); + + expect(isEventData(runner.program, Event.properties.get("foo")!)).toBe(true); + }); + + it("can be applied directly only once in an event model", async () => { + const diagnostics = await runner.diagnose( + ` +model SampleEvent { + @data + foo: string; +} + +@events +union SampleEvents { + SampleEvent, + + inlineEvent: { + @data + bar: string; + } +} + `, + ); + + expectDiagnosticEmpty(diagnostics); + }); + + it("cannot be applied directly more than once in an event model", async () => { + const diagnostics = await runner.diagnose( + ` +model SampleEvent { + @data + foo: string; + + @data + bar: string; +} + +@events +union SampleEvents { + SampleEvent, +} + `, + ); + + expectDiagnostics(diagnostics, { + code: "@typespec/events/multiple-event-payloads", + severity: "error", + }); + }); + + it("cannot be applied indirectly more than once in an event model", async () => { + const diagnostics = await runner.diagnose( + ` +model Foo { + @data + foo: string; +} + +model SampleEvent { + first: Foo; + second: Foo; +} + +@events +union SampleEvents { + SampleEvent, +} + `, + ); + + expectDiagnostics(diagnostics, { + code: "@typespec/events/multiple-event-payloads", + severity: "error", + }); + }); + + it("cannot be applied in a Record", async () => { + const diagnostics = await runner.diagnose( + ` +model Foo { + @data + foo: string; +} + +model SampleEvent { + payload: Record; +} + +@events +union SampleEvents { + SampleEvent, +} + `, + ); + + expectDiagnostics(diagnostics, { + code: "@typespec/events/multiple-event-payloads", + severity: "error", + }); + }); + + it("cannot be applied in an Array", async () => { + const diagnostics = await runner.diagnose( + ` +model Foo { + @data + foo: string; +} + +model SampleEvent { + payload: Array; +} + +@events +union SampleEvents { + SampleEvent, +} + `, + ); + + expectDiagnostics(diagnostics, { + code: "@typespec/events/multiple-event-payloads", + severity: "error", + }); + }); + + it("detects multiple event payloads nested in tuples", async () => { + const diagnostics = await runner.diagnose( + ` +model Foo { + @data + foo: string; +} + +model SampleEvent { + tuple: [ + { + tuple: [Foo]; + }, + { + tuple: [Foo]; + } + ]; +} + +@events +union SampleEvents { + SampleEvent, +} + `, + ); + + expectDiagnostics(diagnostics, { + code: "@typespec/events/multiple-event-payloads", + severity: "error", + }); + }); +}); + +describe("@contentType", () => { + it("can set the top-level event's content-type", async () => { + const { MixedEvents, TargetEvent } = await runner.compile( + ` +model StringEvent { + @Events.contentType("text/plain") + @Events.data + payload: string; +} + +@test +@events +union MixedEvents { + @test("TargetEvent") + @Events.contentType("application/json") + stringEvent: StringEvent, +} + `, + ); + + assert(MixedEvents.kind === "Union"); + assert(TargetEvent.kind === "UnionVariant"); + + expect(getContentType(runner.program, TargetEvent)).toBe("application/json"); + }); + + it("can set the event payload's content-type", async () => { + const { MixedEvents, EventPayload } = await runner.compile( + ` +model StringEvent { + @test("EventPayload") + @Events.contentType("text/plain") + @Events.data + payload: string; +} + +@test +@events +union MixedEvents { + @Events.contentType("application/json") + stringEvent: StringEvent, +} + `, + ); + + assert(MixedEvents.kind === "Union"); + assert(EventPayload.kind === "ModelProperty"); + + expect(getContentType(runner.program, EventPayload)).toBe("text/plain"); + }); + + it("cannot be set on a non-payload property", async () => { + const diagnostics = await runner.diagnose( + ` +model StringEvent { + @test("EventPayload") + @Events.contentType("text/plain") + payload: string; +} + +@test +@events +union MixedEvents { + stringEvent: StringEvent, +} + `, + ); + + expectDiagnostics(diagnostics, { + code: "@typespec/events/invalid-content-type-target", + severity: "error", + }); + }); +}); diff --git a/packages/events/test/test-host.ts b/packages/events/test/test-host.ts new file mode 100644 index 0000000000..41e474b99b --- /dev/null +++ b/packages/events/test/test-host.ts @@ -0,0 +1,13 @@ +import { createTestHost, createTestWrapper } from "@typespec/compiler/testing"; +import { EventsTestLibrary } from "../src/testing/index.js"; + +export async function createEventsTestHost() { + return createTestHost({ + libraries: [EventsTestLibrary], + }); +} + +export async function createEventsTestRunner() { + const host = await createEventsTestHost(); + return createTestWrapper(host, { autoUsings: ["TypeSpec.Events"] }); +} diff --git a/packages/events/tsconfig.config.json b/packages/events/tsconfig.config.json new file mode 100644 index 0000000000..79fb341f39 --- /dev/null +++ b/packages/events/tsconfig.config.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": {} +} diff --git a/packages/events/tsconfig.json b/packages/events/tsconfig.json new file mode 100644 index 0000000000..19de0b3a83 --- /dev/null +++ b/packages/events/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "references": [{ "path": "../compiler/tsconfig.json" }], + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo", + "verbatimModuleSyntax": true + }, + "include": ["src/**/*.ts", "generated-defs/**/*.ts", "test/**/*.ts"] +} diff --git a/packages/events/vitest.config.ts b/packages/events/vitest.config.ts new file mode 100644 index 0000000000..15eeaceb85 --- /dev/null +++ b/packages/events/vitest.config.ts @@ -0,0 +1,4 @@ +import { defineConfig, mergeConfig } from "vitest/config"; +import { defaultTypeSpecVitestConfig } from "../../vitest.workspace.js"; + +export default mergeConfig(defaultTypeSpecVitestConfig, defineConfig({})); diff --git a/packages/http/lib/streams/main.tsp b/packages/http/lib/streams/main.tsp new file mode 100644 index 0000000000..1d4f0ca01d --- /dev/null +++ b/packages/http/lib/streams/main.tsp @@ -0,0 +1,51 @@ +import "@typespec/streams"; +import "../http.tsp"; + +using TypeSpec.Streams; + +namespace TypeSpec.Http.Streams; + +/** + * Defines a model that represents a stream protocol type whose data is described + * by `Type`. + * + * The `ContentType` and `BodyType` describe how the stream is encoded over the wire, + * while `Type` describes the data that the stream contains. + * + * @template Type The type of the stream's data. + * @template ContentType The content type of the stream. + * @template BodyType The underlying wire type of the stream. + */ +@doc("") +model HttpStream + is Stream { + @header contentType: typeof ContentType; + @body body: BodyType; +} + +/** + * Describes a stream of JSON data with one JSON object per line and sets + * the content type to `application/jsonl`. + * + * The JSON data is described by `Type`. + * + * @template Type The set of models describing the JSON data in the stream. + * + * @example + * + * ```typespec + * model Message { + * id: string; + * text: string; + * } + * + * @TypeSpec.Events.events + * union Events { + * Message, + * } + * + * op subscribe(): JsonlStream; + * ``` + */ +@doc("") +model JsonlStream is HttpStream; diff --git a/packages/http/package.json b/packages/http/package.json index aa4f2a4ad2..657f7731f9 100644 --- a/packages/http/package.json +++ b/packages/http/package.json @@ -28,6 +28,11 @@ "./testing": { "types": "./dist/src/testing/index.d.ts", "default": "./dist/src/testing/index.js" + }, + "./streams": { + "typespec": "./lib/streams/main.tsp", + "types": "./dist/src/streams/index.d.ts", + "default": "./dist/src/streams/index.js" } }, "engines": { @@ -48,17 +53,24 @@ "regen-docs": "tspd doc . --enable-experimental --output-dir ../../docs/libraries/http/reference" }, "files": [ - "lib/*.tsp", + "lib/**/*.tsp", "dist/**", "!dist/test/**" ], "peerDependencies": { - "@typespec/compiler": "workspace:~" + "@typespec/compiler": "workspace:~", + "@typespec/streams": "workspace:~" + }, + "peerDependenciesMeta": { + "@typespec/streams": { + "optional": true + } }, "devDependencies": { "@types/node": "~22.7.1", "@typespec/compiler": "workspace:~", "@typespec/library-linter": "workspace:~", + "@typespec/streams": "workspace:~", "@typespec/tspd": "workspace:~", "@vitest/coverage-v8": "^2.1.1", "@vitest/ui": "^2.1.1", diff --git a/packages/http/src/streams/index.ts b/packages/http/src/streams/index.ts new file mode 100644 index 0000000000..9aaab6781e --- /dev/null +++ b/packages/http/src/streams/index.ts @@ -0,0 +1,2 @@ +// This is a placeholder for the streams submodule. +export {}; diff --git a/packages/http/test/streams/streams.test.ts b/packages/http/test/streams/streams.test.ts new file mode 100644 index 0000000000..b67121b163 --- /dev/null +++ b/packages/http/test/streams/streams.test.ts @@ -0,0 +1,62 @@ +import { + createTestHost, + createTestWrapper, + type BasicTestRunner, +} from "@typespec/compiler/testing"; +import { getStreamOf } from "@typespec/streams"; +import { StreamsTestLibrary } from "@typespec/streams/testing"; +import { assert, beforeEach, describe, expect, it } from "vitest"; +import { getContentTypes } from "../../src/content-types.js"; +import { HttpTestLibrary } from "../../src/testing/index.js"; + +let runner: BasicTestRunner; + +beforeEach(async () => { + const host = await createTestHost({ + libraries: [StreamsTestLibrary, HttpTestLibrary], + }); + runner = createTestWrapper(host, { + autoImports: [`@typespec/http/streams`], + autoUsings: ["TypeSpec.Http.Streams"], + }); +}); + +describe("HttpStream", () => { + it("sets streamOf, contentType, and body", async () => { + const { Foo, Message } = await runner.compile(` + @test + model Message { id: string, text: string } + + @test model Foo is HttpStream; + `); + assert(Foo.kind === "Model"); + assert(Message.kind === "Model"); + + expect(getStreamOf(runner.program, Foo)).toBe(Message); + expect(getContentTypes(Foo.properties.get("contentType")!)[0]).toEqual(["application/jsonl"]); + expect(Foo.properties.get("body")!.type).toMatchObject({ + kind: "Scalar", + name: "string", + }); + }); +}); + +describe("JsonlStream", () => { + it("sets streamOf, contentType ('application/jsonl'), and body", async () => { + const { Foo, Message } = await runner.compile(` + @test + model Message { id: string, text: string } + + @test model Foo is JsonlStream; + `); + assert(Foo.kind === "Model"); + assert(Message.kind === "Model"); + + expect(getStreamOf(runner.program, Foo)).toBe(Message); + expect(getContentTypes(Foo.properties.get("contentType")!)[0]).toEqual(["application/jsonl"]); + expect(Foo.properties.get("body")!.type).toMatchObject({ + kind: "Scalar", + name: "string", + }); + }); +}); diff --git a/packages/playground-website/package.json b/packages/playground-website/package.json index 15731dfea6..4405a52231 100644 --- a/packages/playground-website/package.json +++ b/packages/playground-website/package.json @@ -64,6 +64,7 @@ "@typespec/playground": "workspace:~", "@typespec/protobuf": "workspace:~", "@typespec/rest": "workspace:~", + "@typespec/streams": "workspace:~", "@typespec/versioning": "workspace:~", "es-module-shims": "~1.10.0", "react": "~18.3.1", diff --git a/packages/playground-website/src/config.ts b/packages/playground-website/src/config.ts index 11f68ed4c8..543d8e6755 100644 --- a/packages/playground-website/src/config.ts +++ b/packages/playground-website/src/config.ts @@ -11,6 +11,7 @@ export const TypeSpecPlaygroundConfig = { "@typespec/openapi3", "@typespec/json-schema", "@typespec/protobuf", + "@typespec/streams", ], samples, } as const; diff --git a/packages/samples/package.json b/packages/samples/package.json index d84d7d4314..790faeed0d 100644 --- a/packages/samples/package.json +++ b/packages/samples/package.json @@ -45,6 +45,7 @@ "dependencies": { "@typespec/best-practices": "workspace:~", "@typespec/compiler": "workspace:~", + "@typespec/events": "workspace:~", "@typespec/html-program-viewer": "workspace:~", "@typespec/http": "workspace:~", "@typespec/http-server-javascript": "workspace:~", @@ -52,6 +53,8 @@ "@typespec/openapi": "workspace:~", "@typespec/openapi3": "workspace:~", "@typespec/rest": "workspace:~", + "@typespec/sse": "workspace:~", + "@typespec/streams": "workspace:~", "@typespec/versioning": "workspace:~", "@typespec/protobuf": "workspace:~" }, diff --git a/packages/sse/CHANGELOG.md b/packages/sse/CHANGELOG.md new file mode 100644 index 0000000000..b6a447457c --- /dev/null +++ b/packages/sse/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog - @typespec/sse diff --git a/packages/sse/README.md b/packages/sse/README.md new file mode 100644 index 0000000000..6ee6722c60 --- /dev/null +++ b/packages/sse/README.md @@ -0,0 +1,32 @@ +# @typespec/sse + +TypeSpec library providing server sent events bindings + +## Install + +```bash +npm install @typespec/sse +``` + +## Decorators + +### TypeSpec.SSE + +- [`@terminalEvent`](#@terminalevent) + +#### `@terminalEvent` + +Indicates that the presence of this event is a terminal event, +and the client should disconnect from the server. + +```typespec +@TypeSpec.SSE.terminalEvent +``` + +##### Target + +`UnionVariant` + +##### Parameters + +None diff --git a/packages/sse/generated-defs/TypeSpec.SSE.ts b/packages/sse/generated-defs/TypeSpec.SSE.ts new file mode 100644 index 0000000000..387c44b7bd --- /dev/null +++ b/packages/sse/generated-defs/TypeSpec.SSE.ts @@ -0,0 +1,11 @@ +import type { DecoratorContext, UnionVariant } from "@typespec/compiler"; + +/** + * Indicates that the presence of this event is a terminal event, + * and the client should disconnect from the server. + */ +export type TerminalEventDecorator = (context: DecoratorContext, target: UnionVariant) => void; + +export type TypeSpecSSEDecorators = { + terminalEvent: TerminalEventDecorator; +}; diff --git a/packages/sse/generated-defs/TypeSpec.SSE.ts-test.ts b/packages/sse/generated-defs/TypeSpec.SSE.ts-test.ts new file mode 100644 index 0000000000..1c2059c361 --- /dev/null +++ b/packages/sse/generated-defs/TypeSpec.SSE.ts-test.ts @@ -0,0 +1,5 @@ +/** An error here would mean that the decorator is not exported or doesn't have the right name. */ +import { $decorators } from "@typespec/sse"; +import type { TypeSpecSSEDecorators } from "./TypeSpec.SSE.js"; +/** An error here would mean that the exported decorator is not using the same signature. Make sure to have export const $decName: DecNameDecorator = (...) => ... */ +const _: TypeSpecSSEDecorators = $decorators["TypeSpec.SSE"]; diff --git a/packages/sse/lib/decorators.tsp b/packages/sse/lib/decorators.tsp new file mode 100644 index 0000000000..e6a64c854f --- /dev/null +++ b/packages/sse/lib/decorators.tsp @@ -0,0 +1,9 @@ +using TypeSpec.Reflection; + +namespace TypeSpec.SSE; + +/** + * Indicates that the presence of this event is a terminal event, + * and the client should disconnect from the server. + */ +extern dec terminalEvent(target: UnionVariant); diff --git a/packages/sse/lib/main.tsp b/packages/sse/lib/main.tsp new file mode 100644 index 0000000000..39e7b447c2 --- /dev/null +++ b/packages/sse/lib/main.tsp @@ -0,0 +1,3 @@ +import "../dist/src/tsp-index.js"; +import "./decorators.tsp"; +import "./types.tsp"; diff --git a/packages/sse/lib/types.tsp b/packages/sse/lib/types.tsp new file mode 100644 index 0000000000..1a0d2f927d --- /dev/null +++ b/packages/sse/lib/types.tsp @@ -0,0 +1,52 @@ +import "@typespec/http/streams"; + +using Http.Streams; + +namespace TypeSpec.SSE; + +/** + * Describes a stream of server-sent events. + * + * The content-type is set to `text/event-stream`. + * + * The server-sent events are described by `Type`. + * The event type for any event can be defined by using named union variants. + * When a union variant is not named, it is considered a 'message' event. + * + * @template Type The set of models describing the server-sent events. + * + * @example Mix of named union variants and terminal event + * + * ```typespec + * model UserConnect { + * username: string; + * time: string; + * } + * + * model UserMessage { + * username: string; + * time: string; + * text: string; + * } + * + * model UserDisconnect { + * username: string; + * time: string; + * } + * + * @TypeSpec.Events.events + * union ChannelEvents { + * userconnect: UserConnect, + * usermessage: UserMessage, + * userdisconnect: UserDisconnect, + * + * @Events.contentType("text/plain") + * @terminalEvent + * "[unsubscribe]", + * } + * + * op subscribeToChannel(): SSEStream; + * ``` + */ +@doc("") +model SSEStream is HttpStream; diff --git a/packages/sse/package.json b/packages/sse/package.json new file mode 100644 index 0000000000..7c251fc22d --- /dev/null +++ b/packages/sse/package.json @@ -0,0 +1,69 @@ +{ + "name": "@typespec/sse", + "version": "0.60.0", + "author": "Microsoft Corporation", + "description": "TypeSpec library providing server sent events bindings", + "homepage": "https://typespec.io", + "readme": "https://github.com/microsoft/typespec/blob/main/README.md", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/microsoft/typespec.git" + }, + "bugs": { + "url": "https://github.com/microsoft/typespec/issues" + }, + "keywords": [ + "typespec" + ], + "type": "module", + "main": "dist/src/index.js", + "tspMain": "lib/main.tsp", + "exports": { + ".": "./dist/src/index.js", + "./testing": "./dist/src/testing/index.js" + }, + "engines": { + "node": ">=18.0.0" + }, + "scripts": { + "clean": "rimraf ./dist ./temp", + "build": "npm run gen-extern-signature && tsc -p . && npm run lint-typespec-library", + "watch": "tsc -p . --watch", + "gen-extern-signature": "tspd --enable-experimental gen-extern-signature .", + "lint-typespec-library": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit", + "test": "vitest run", + "test:watch": "vitest -w", + "test:ui": "vitest --ui", + "test-official": "vitest run --coverage --reporter=junit --reporter=default --no-file-parallelism", + "lint": "eslint . --ext .ts --max-warnings=0", + "lint:fix": "eslint . --fix --ext .ts", + "regen-docs": "tspd doc . --enable-experimental --output-dir ../../docs/libraries/sse/reference" + }, + "files": [ + "lib/*.tsp", + "dist/**", + "!dist/test/**" + ], + "peerDependencies": { + "@typespec/compiler": "workspace:~", + "@typespec/events": "workspace:~", + "@typespec/http": "workspace:~", + "@typespec/streams": "workspace:~" + }, + "devDependencies": { + "@types/node": "~22.7.1", + "@typespec/compiler": "workspace:~", + "@typespec/events": "workspace:~", + "@typespec/http": "workspace:~", + "@typespec/library-linter": "workspace:~", + "@typespec/streams": "workspace:~", + "@typespec/tspd": "workspace:~", + "@vitest/coverage-v8": "^2.1.1", + "@vitest/ui": "^2.1.1", + "c8": "^10.1.2", + "rimraf": "~6.0.1", + "typescript": "~5.6.2", + "vitest": "^2.1.1" + } +} diff --git a/packages/sse/src/decorators.ts b/packages/sse/src/decorators.ts new file mode 100644 index 0000000000..566e1df5b6 --- /dev/null +++ b/packages/sse/src/decorators.ts @@ -0,0 +1,14 @@ +import type { UnionVariant } from "@typespec/compiler"; +import { unsafe_useStateSet } from "@typespec/compiler/experimental"; +import type { TerminalEventDecorator } from "../generated-defs/TypeSpec.SSE.js"; +import { SSEStateKeys } from "./lib.js"; + +const [isTerminalEvent, setTerminalEvent] = unsafe_useStateSet( + SSEStateKeys.terminalEvent, +); + +export const $terminalEventDecorator: TerminalEventDecorator = (context, target) => { + setTerminalEvent(context.program, target); +}; + +export { isTerminalEvent }; diff --git a/packages/sse/src/index.ts b/packages/sse/src/index.ts new file mode 100644 index 0000000000..9288bd937a --- /dev/null +++ b/packages/sse/src/index.ts @@ -0,0 +1,5 @@ +export { $lib } from "./lib.js"; + +export { isTerminalEvent } from "./decorators.js"; + +export { $decorators, $onValidate } from "./tsp-index.js"; diff --git a/packages/sse/src/lib.ts b/packages/sse/src/lib.ts new file mode 100644 index 0000000000..e3f4824c57 --- /dev/null +++ b/packages/sse/src/lib.ts @@ -0,0 +1,19 @@ +import { createTypeSpecLibrary } from "@typespec/compiler"; + +export const $lib = createTypeSpecLibrary({ + name: "@typespec/sse", + diagnostics: { + "terminal-event-not-in-events": { + severity: "error", + messages: { + default: + "A field marked as '@terminalEvent' must be a member of a type decorated with '@TpeSpec.Events.events'.", + }, + }, + }, + state: { + terminalEvent: { description: "State for the @terminalEvent decorator." }, + }, +}); + +export const { reportDiagnostic, createDiagnostic, stateKeys: SSEStateKeys } = $lib; diff --git a/packages/sse/src/testing/index.ts b/packages/sse/src/testing/index.ts new file mode 100644 index 0000000000..aaced1410b --- /dev/null +++ b/packages/sse/src/testing/index.ts @@ -0,0 +1,6 @@ +import { createTestLibrary, findTestPackageRoot } from "@typespec/compiler/testing"; + +export const SSETestLibrary = createTestLibrary({ + name: "@typespec/sse", + packageRoot: await findTestPackageRoot(import.meta.url), +}); diff --git a/packages/sse/src/tsp-index.ts b/packages/sse/src/tsp-index.ts new file mode 100644 index 0000000000..b78a21abd5 --- /dev/null +++ b/packages/sse/src/tsp-index.ts @@ -0,0 +1,11 @@ +import { $terminalEventDecorator } from "./decorators.js"; + +export { $lib } from "./lib.js"; + +export const $decorators = { + "TypeSpec.SSE": { + terminalEvent: $terminalEventDecorator, + }, +}; + +export { $onValidate } from "./validate.js"; diff --git a/packages/sse/src/validate.ts b/packages/sse/src/validate.ts new file mode 100644 index 0000000000..08868aa2ce --- /dev/null +++ b/packages/sse/src/validate.ts @@ -0,0 +1,26 @@ +import type { Program, UnionVariant } from "@typespec/compiler"; +import { isEvents } from "@typespec/events"; +import { reportDiagnostic, SSEStateKeys } from "./lib.js"; + +export function $onValidate(program: Program) { + checkForIncorrectlyAssignedTerminalEvents(program); +} + +function checkForIncorrectlyAssignedTerminalEvents(program: Program) { + program.stateSet(SSEStateKeys.terminalEvent).forEach((terminalEvent) => { + if (!("union" in terminalEvent)) { + return; + } + validateTerminalEvent(program, terminalEvent); + }); +} + +export function validateTerminalEvent(program: Program, target: UnionVariant) { + // Check that the union is decorated with `@TypeSpec.Events.events`. + if (!isEvents(program, target.union)) { + reportDiagnostic(program, { + code: "terminal-event-not-in-events", + target, + }); + } +} diff --git a/packages/sse/test/decorators.test.ts b/packages/sse/test/decorators.test.ts new file mode 100644 index 0000000000..45babde4ed --- /dev/null +++ b/packages/sse/test/decorators.test.ts @@ -0,0 +1,48 @@ +import type { UnionVariant } from "@typespec/compiler"; +import { expectDiagnostics, type BasicTestRunner } from "@typespec/compiler/testing"; +import { beforeEach, describe, expect, it } from "vitest"; +import { isTerminalEvent } from "../src/decorators.js"; +import { createSSETestRunner } from "./test-host.js"; + +let runner: BasicTestRunner; + +beforeEach(async () => { + runner = await createSSETestRunner(); +}); + +describe("@terminalEvent", () => { + it("marks the model as a terminal event", async () => { + const { TerminalEvent } = await runner.compile( + ` +@events +union TestEvents { + { done: false, @data message: string}, + + @test("TerminalEvent") + @terminalEvent + { done: true } +} + `, + ); + + expect(isTerminalEvent(runner.program, TerminalEvent as UnionVariant)).toBe(true); + }); + + it("can only be applied to union variants within a union decorated with @events", async () => { + const diagnostics = await runner.diagnose( + ` +union TestEvents { + { done: false, @data message: string}, + + @terminalEvent + { done: true } +} + `, + ); + + expectDiagnostics(diagnostics, { + code: "@typespec/sse/terminal-event-not-in-events", + severity: "error", + }); + }); +}); diff --git a/packages/sse/test/models.test.ts b/packages/sse/test/models.test.ts new file mode 100644 index 0000000000..57e0db242c --- /dev/null +++ b/packages/sse/test/models.test.ts @@ -0,0 +1,36 @@ +import type { BasicTestRunner } from "@typespec/compiler/testing"; +import { getContentTypes } from "@typespec/http"; +import { getStreamOf } from "@typespec/streams"; +import { assert, beforeEach, describe, expect, it } from "vitest"; +import { createSSETestRunner } from "./test-host.js"; + +let runner: BasicTestRunner; + +beforeEach(async () => { + runner = await createSSETestRunner(); +}); + +describe("SSEStream", () => { + it("sets streamOf, contentType ('text/event-stream'), and body", async () => { + const { Foo, TestEvents } = await runner.compile(` + @test + @events + union TestEvents { + foo: string, + + bar: string, + } + + @test model Foo is SSEStream; + `); + assert(Foo.kind === "Model"); + assert(TestEvents.kind === "Union"); + + expect(getStreamOf(runner.program, Foo)).toBe(TestEvents); + expect(getContentTypes(Foo.properties.get("contentType")!)[0]).toEqual(["text/event-stream"]); + expect(Foo.properties.get("body")!.type).toMatchObject({ + kind: "Scalar", + name: "string", + }); + }); +}); diff --git a/packages/sse/test/test-host.ts b/packages/sse/test/test-host.ts new file mode 100644 index 0000000000..0f27e4efb6 --- /dev/null +++ b/packages/sse/test/test-host.ts @@ -0,0 +1,16 @@ +import { createTestHost, createTestWrapper } from "@typespec/compiler/testing"; +import { EventsTestLibrary } from "@typespec/events/testing"; +import { HttpTestLibrary } from "@typespec/http/testing"; +import { StreamsTestLibrary } from "@typespec/streams/testing"; +import { SSETestLibrary } from "../src/testing/index.js"; + +export async function createSSETestHost() { + return createTestHost({ + libraries: [EventsTestLibrary, HttpTestLibrary, StreamsTestLibrary, SSETestLibrary], + }); +} + +export async function createSSETestRunner() { + const host = await createSSETestHost(); + return createTestWrapper(host, { autoUsings: ["TypeSpec.Events", "TypeSpec.SSE"] }); +} diff --git a/packages/sse/tsconfig.config.json b/packages/sse/tsconfig.config.json new file mode 100644 index 0000000000..79fb341f39 --- /dev/null +++ b/packages/sse/tsconfig.config.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": {} +} diff --git a/packages/sse/tsconfig.json b/packages/sse/tsconfig.json new file mode 100644 index 0000000000..19de0b3a83 --- /dev/null +++ b/packages/sse/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "references": [{ "path": "../compiler/tsconfig.json" }], + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo", + "verbatimModuleSyntax": true + }, + "include": ["src/**/*.ts", "generated-defs/**/*.ts", "test/**/*.ts"] +} diff --git a/packages/sse/vitest.config.ts b/packages/sse/vitest.config.ts new file mode 100644 index 0000000000..15eeaceb85 --- /dev/null +++ b/packages/sse/vitest.config.ts @@ -0,0 +1,4 @@ +import { defineConfig, mergeConfig } from "vitest/config"; +import { defaultTypeSpecVitestConfig } from "../../vitest.workspace.js"; + +export default mergeConfig(defaultTypeSpecVitestConfig, defineConfig({})); diff --git a/packages/streams/CHANGELOG.md b/packages/streams/CHANGELOG.md new file mode 100644 index 0000000000..87db52e4a7 --- /dev/null +++ b/packages/streams/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog - @typespec/streams diff --git a/packages/streams/README.md b/packages/streams/README.md new file mode 100644 index 0000000000..0c3eac3908 --- /dev/null +++ b/packages/streams/README.md @@ -0,0 +1,48 @@ +# @typespec/streams + +TypeSpec library providing stream bindings + +## Install + +```bash +npm install @typespec/streams +``` + +## Decorators + +### TypeSpec.Streams + +- [`@streamOf`](#@streamof) + +#### `@streamOf` + +Specify that a model represents a stream protocol type whose data is described +by `Type`. + +```typespec +@TypeSpec.Streams.streamOf(type: unknown) +``` + +##### Target + +`Model` + +##### Parameters + +| Name | Type | Description | +| ---- | --------- | ------------------------------------------------------- | +| type | `unknown` | The type that models the underlying data of the stream. | + +##### Examples + +```typespec +model Message { + id: string; + text: string; +} + +@streamOf(Message) +model Response { + @body body: string; +} +``` diff --git a/packages/streams/generated-defs/TypeSpec.Streams.ts b/packages/streams/generated-defs/TypeSpec.Streams.ts new file mode 100644 index 0000000000..92e5538c69 --- /dev/null +++ b/packages/streams/generated-defs/TypeSpec.Streams.ts @@ -0,0 +1,25 @@ +import type { DecoratorContext, Model, Type } from "@typespec/compiler"; + +/** + * Specify that a model represents a stream protocol type whose data is described + * by `Type`. + * + * @param type The type that models the underlying data of the stream. + * @example + * ```typespec + * model Message { + * id: string; + * text: string; + * } + * + * @streamOf(Message) + * model Response { + * @body body: string; + * } + * ``` + */ +export type StreamOfDecorator = (context: DecoratorContext, target: Model, type: Type) => void; + +export type TypeSpecStreamsDecorators = { + streamOf: StreamOfDecorator; +}; diff --git a/packages/streams/generated-defs/TypeSpec.Streams.ts-test.ts b/packages/streams/generated-defs/TypeSpec.Streams.ts-test.ts new file mode 100644 index 0000000000..3058e67eaa --- /dev/null +++ b/packages/streams/generated-defs/TypeSpec.Streams.ts-test.ts @@ -0,0 +1,5 @@ +/** An error here would mean that the decorator is not exported or doesn't have the right name. */ +import { $decorators } from "@typespec/streams"; +import type { TypeSpecStreamsDecorators } from "./TypeSpec.Streams.js"; +/** An error here would mean that the exported decorator is not using the same signature. Make sure to have export const $decName: DecNameDecorator = (...) => ... */ +const _: TypeSpecStreamsDecorators = $decorators["TypeSpec.Streams"]; diff --git a/packages/streams/lib/decorators.tsp b/packages/streams/lib/decorators.tsp new file mode 100644 index 0000000000..2d0065bf5d --- /dev/null +++ b/packages/streams/lib/decorators.tsp @@ -0,0 +1,25 @@ +using TypeSpec.Reflection; + +namespace TypeSpec.Streams; + +/** + * Specify that a model represents a stream protocol type whose data is described + * by `Type`. + * + * @param type The type that models the underlying data of the stream. + * + * @example + * + * ```typespec + * model Message { + * id: string; + * text: string; + * } + * + * @streamOf(Message) + * model Response { + * @body body: string; + * } + * ``` + */ +extern dec streamOf(target: Model, type: unknown); diff --git a/packages/streams/lib/main.tsp b/packages/streams/lib/main.tsp new file mode 100644 index 0000000000..39e7b447c2 --- /dev/null +++ b/packages/streams/lib/main.tsp @@ -0,0 +1,3 @@ +import "../dist/src/tsp-index.js"; +import "./decorators.tsp"; +import "./types.tsp"; diff --git a/packages/streams/lib/types.tsp b/packages/streams/lib/types.tsp new file mode 100644 index 0000000000..a422acfb7f --- /dev/null +++ b/packages/streams/lib/types.tsp @@ -0,0 +1,14 @@ +namespace TypeSpec.Streams; + +/** + * Defines a model that represents a stream protocol type whose data is described + * by `Type`. + * + * This can be useful when the underlying data type is not relevant, or to serve as + * a base type for custom streams. + * + * @template Type The type of the stream's data. + */ +@doc("") +@streamOf(Type) +model Stream {} diff --git a/packages/streams/package.json b/packages/streams/package.json new file mode 100644 index 0000000000..bc902655d2 --- /dev/null +++ b/packages/streams/package.json @@ -0,0 +1,69 @@ +{ + "name": "@typespec/streams", + "version": "0.60.0", + "author": "Microsoft Corporation", + "description": "TypeSpec library providing stream bindings", + "homepage": "https://typespec.io", + "readme": "https://github.com/microsoft/typespec/blob/main/README.md", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/microsoft/typespec.git" + }, + "bugs": { + "url": "https://github.com/microsoft/typespec/issues" + }, + "keywords": [ + "typespec" + ], + "type": "module", + "main": "dist/src/index.js", + "tspMain": "lib/main.tsp", + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "default": "./dist/src/index.js" + }, + "./testing": { + "types": "./dist/src/testing/index.d.ts", + "default": "./dist/src/testing/index.js" + } + }, + "engines": { + "node": ">=18.0.0" + }, + "scripts": { + "clean": "rimraf ./dist ./temp", + "build": "npm run gen-extern-signature && tsc -p . && npm run lint-typespec-library", + "watch": "tsc -p . --watch", + "gen-extern-signature": "tspd --enable-experimental gen-extern-signature .", + "lint-typespec-library": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit", + "test": "vitest run", + "test:watch": "vitest -w", + "test:ui": "vitest --ui", + "test-official": "vitest run --coverage --reporter=junit --reporter=default --no-file-parallelism", + "lint": "eslint . --ext .ts --max-warnings=0", + "lint:fix": "eslint . --fix --ext .ts", + "regen-docs": "tspd doc . --enable-experimental --output-dir ../../docs/libraries/streams/reference" + }, + "files": [ + "lib/*.tsp", + "dist/**", + "!dist/test/**" + ], + "peerDependencies": { + "@typespec/compiler": "workspace:~" + }, + "devDependencies": { + "@types/node": "~22.7.1", + "@typespec/compiler": "workspace:~", + "@typespec/library-linter": "workspace:~", + "@typespec/tspd": "workspace:~", + "@vitest/coverage-v8": "^2.1.1", + "@vitest/ui": "^2.1.1", + "c8": "^10.1.2", + "rimraf": "~6.0.1", + "typescript": "~5.6.2", + "vitest": "^2.1.1" + } +} diff --git a/packages/streams/src/decorators.ts b/packages/streams/src/decorators.ts new file mode 100644 index 0000000000..bf5608ece6 --- /dev/null +++ b/packages/streams/src/decorators.ts @@ -0,0 +1,16 @@ +import type { Model, Program, Type } from "@typespec/compiler"; +import { unsafe_useStateMap } from "@typespec/compiler/experimental"; +import type { StreamOfDecorator } from "../generated-defs/TypeSpec.Streams.js"; +import { StreamStateKeys } from "./lib.js"; + +const [getStreamOf, setStreamOf] = unsafe_useStateMap(StreamStateKeys.streamOf); + +export const $streamOfDecorator: StreamOfDecorator = (context, target, type) => { + setStreamOf(context.program, target, type); +}; + +export function isStream(program: Program, target: Model): boolean { + return getStreamOf(program, target) !== undefined; +} + +export { getStreamOf }; diff --git a/packages/streams/src/index.ts b/packages/streams/src/index.ts new file mode 100644 index 0000000000..6844509afd --- /dev/null +++ b/packages/streams/src/index.ts @@ -0,0 +1,5 @@ +export { $lib } from "./lib.js"; + +export { getStreamOf, isStream } from "./decorators.js"; + +export { $decorators } from "./tsp-index.js"; diff --git a/packages/streams/src/lib.ts b/packages/streams/src/lib.ts new file mode 100644 index 0000000000..3f1fb5768e --- /dev/null +++ b/packages/streams/src/lib.ts @@ -0,0 +1,11 @@ +import { createTypeSpecLibrary } from "@typespec/compiler"; + +export const $lib = createTypeSpecLibrary({ + name: "@typespec/streams", + diagnostics: {}, + state: { + streamOf: { description: "State for the @streamOf decorator." }, + }, +}); + +export const { reportDiagnostic, createDiagnostic, stateKeys: StreamStateKeys } = $lib; diff --git a/packages/streams/src/testing/index.ts b/packages/streams/src/testing/index.ts new file mode 100644 index 0000000000..1308ba5390 --- /dev/null +++ b/packages/streams/src/testing/index.ts @@ -0,0 +1,6 @@ +import { createTestLibrary, findTestPackageRoot } from "@typespec/compiler/testing"; + +export const StreamsTestLibrary = createTestLibrary({ + name: "@typespec/streams", + packageRoot: await findTestPackageRoot(import.meta.url), +}); diff --git a/packages/streams/src/tsp-index.ts b/packages/streams/src/tsp-index.ts new file mode 100644 index 0000000000..56e9c0cbf3 --- /dev/null +++ b/packages/streams/src/tsp-index.ts @@ -0,0 +1,8 @@ +import { $streamOfDecorator } from "./decorators.js"; +export { $lib } from "./lib.js"; + +export const $decorators = { + "TypeSpec.Streams": { + streamOf: $streamOfDecorator, + }, +}; diff --git a/packages/streams/test/decorators.test.ts b/packages/streams/test/decorators.test.ts new file mode 100644 index 0000000000..4c3465d059 --- /dev/null +++ b/packages/streams/test/decorators.test.ts @@ -0,0 +1,38 @@ +import type { Model } from "@typespec/compiler"; +import type { BasicTestRunner } from "@typespec/compiler/testing"; +import { beforeEach, describe, expect, it } from "vitest"; +import { getStreamOf } from "../src/decorators.js"; +import { createStreamsTestRunner } from "./test-host.js"; + +let runner: BasicTestRunner; + +beforeEach(async () => { + runner = await createStreamsTestRunner(); +}); + +describe("@streamOf", () => { + it("provides stream protocol type", async () => { + const { Blob } = await runner.compile(`@test @streamOf(string) model Blob {}`); + + expect(getStreamOf(runner.program, Blob as Model)).toMatchObject({ + kind: "Scalar", + name: "string", + }); + }); + + it("returns undefined if model is not decorated", async () => { + const { Blob } = await runner.compile(`@test model Blob {}`); + + expect(getStreamOf(runner.program, Blob as Model)).toBeUndefined(); + }); + + it("is automatically set on the Stream model", async () => { + const { CustomStream, Message } = await runner.compile( + ` + @test model Message { id: string, text: string } + @test model CustomStream is Stream {}`, + ); + + expect(getStreamOf(runner.program, CustomStream as Model)).toBe(Message); + }); +}); diff --git a/packages/streams/test/test-host.ts b/packages/streams/test/test-host.ts new file mode 100644 index 0000000000..1bb51f7ac3 --- /dev/null +++ b/packages/streams/test/test-host.ts @@ -0,0 +1,13 @@ +import { createTestHost, createTestWrapper } from "@typespec/compiler/testing"; +import { StreamsTestLibrary } from "../src/testing/index.js"; + +export async function createStreamsTestHost() { + return createTestHost({ + libraries: [StreamsTestLibrary], + }); +} + +export async function createStreamsTestRunner() { + const host = await createStreamsTestHost(); + return createTestWrapper(host, { autoUsings: ["TypeSpec.Streams"] }); +} diff --git a/packages/streams/tsconfig.config.json b/packages/streams/tsconfig.config.json new file mode 100644 index 0000000000..79fb341f39 --- /dev/null +++ b/packages/streams/tsconfig.config.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": {} +} diff --git a/packages/streams/tsconfig.json b/packages/streams/tsconfig.json new file mode 100644 index 0000000000..284b90bcdc --- /dev/null +++ b/packages/streams/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "references": [{ "path": "../compiler/tsconfig.json" }], + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo" + }, + "include": ["src/**/*.ts", "generated-defs/**/*.ts", "test/**/*.ts"] +} diff --git a/packages/streams/vitest.config.ts b/packages/streams/vitest.config.ts new file mode 100644 index 0000000000..15eeaceb85 --- /dev/null +++ b/packages/streams/vitest.config.ts @@ -0,0 +1,4 @@ +import { defineConfig, mergeConfig } from "vitest/config"; +import { defaultTypeSpecVitestConfig } from "../../vitest.workspace.js"; + +export default mergeConfig(defaultTypeSpecVitestConfig, defineConfig({})); diff --git a/packages/website/sidebars.ts b/packages/website/sidebars.ts index 55deaf0c05..32601bbc1e 100644 --- a/packages/website/sidebars.ts +++ b/packages/website/sidebars.ts @@ -138,6 +138,7 @@ const sidebars: SidebarsConfig = { type: "category", label: "📚 Libraries", items: [ + createLibraryReferenceStructure("libraries/events", "Events", false, []), createLibraryReferenceStructure("libraries/http", "Http", true, [ "libraries/http/cheat-sheet", "libraries/http/authentication", @@ -152,6 +153,8 @@ const sidebars: SidebarsConfig = { "libraries/rest/resource-routing", ]), createLibraryReferenceStructure("libraries/openapi", "OpenAPI", false, []), + createLibraryReferenceStructure("libraries/sse", "Server-Sent Events", false, []), + createLibraryReferenceStructure("libraries/streams", "Streams", false, []), createLibraryReferenceStructure("libraries/versioning", "Versioning", false, [ "libraries/versioning/guide", ]), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dbeb9e5672..8a2299f65e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,7 +22,7 @@ importers: version: 9.11.1 '@microsoft/api-extractor': specifier: ^7.47.9 - version: 7.47.9(@types/node@22.7.3) + version: 7.47.9(@types/node@22.7.2) '@octokit/core': specifier: ^6.1.2 version: 6.1.2 @@ -40,10 +40,10 @@ importers: version: 4.0.9 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) c8: specifier: ^10.1.2 version: 10.1.2 @@ -67,7 +67,7 @@ importers: version: 55.0.0(eslint@9.11.1(jiti@1.21.0)) eslint-plugin-vitest: specifier: ^0.5.4 - version: 0.5.4(eslint@9.11.1(jiti@1.21.0))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 0.5.4(eslint@9.11.1(jiti@1.21.0))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) micromatch: specifier: ^4.0.8 version: 4.0.8 @@ -97,7 +97,7 @@ importers: version: 8.7.0(eslint@9.11.1(jiti@1.21.0))(typescript@5.6.2) vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) yaml: specifier: ~2.5.1 version: 2.5.1 @@ -108,13 +108,13 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -129,7 +129,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/bundle-uploader: dependencies: @@ -157,13 +157,13 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/semver': specifier: ^7.5.8 version: 7.5.8 '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -178,7 +178,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/bundler: dependencies: @@ -215,13 +215,13 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/yargs': specifier: ~17.0.33 version: 17.0.33 '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -236,10 +236,10 @@ importers: version: 5.6.2 vite: specifier: ^5.4.8 - version: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + version: 5.4.8(@types/node@22.7.2)(terser@5.30.0) vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/compiler: dependencies: @@ -294,7 +294,7 @@ importers: version: 4.2.5 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/prompts': specifier: ~2.4.9 version: 2.4.9 @@ -309,7 +309,7 @@ importers: version: link:../internal-build-utils '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -330,13 +330,13 @@ importers: version: link:../tmlanguage-generator ts-node: specifier: ~10.9.2 - version: 10.9.2(@swc/core@1.7.28)(@types/node@22.7.3)(typescript@5.6.2) + version: 10.9.2(@swc/core@1.7.28)(@types/node@22.7.2)(typescript@5.6.2) typescript: specifier: ~5.6.2 version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) vscode-oniguruma: specifier: ~2.0.1 version: 2.0.1 @@ -352,7 +352,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typescript-eslint/parser': specifier: ^8.7.0 version: 8.7.0(eslint@9.11.1(jiti@1.21.0))(typescript@5.6.2) @@ -364,7 +364,7 @@ importers: version: 8.7.0 '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -382,13 +382,46 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + + packages/events: + devDependencies: + '@types/node': + specifier: ~22.7.1 + version: 22.7.2 + '@typespec/compiler': + specifier: workspace:~ + version: link:../compiler + '@typespec/library-linter': + specifier: workspace:~ + version: link:../library-linter + '@typespec/tspd': + specifier: workspace:~ + version: link:../tspd + '@vitest/coverage-v8': + specifier: ^2.1.1 + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + '@vitest/ui': + specifier: ^2.1.1 + version: 2.1.1(vitest@2.1.1) + c8: + specifier: ^10.1.2 + version: 10.1.2 + rimraf: + specifier: ~6.0.1 + version: 6.0.1 + typescript: + specifier: ~5.6.2 + version: 5.6.2 + vitest: + specifier: ^2.1.1 + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/html-program-viewer: dependencies: '@fluentui/react-components': specifier: ~9.54.16 - version: 9.54.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + version: 9.54.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-icons': specifier: ^2.0.258 version: 2.0.258(react@18.3.1) @@ -419,7 +452,7 @@ importers: version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/react': specifier: ~18.3.9 version: 18.3.9 @@ -434,10 +467,10 @@ importers: version: link:../react-components '@vitejs/plugin-react': specifier: ~4.3.1 - version: 4.3.1(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 4.3.1(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -452,34 +485,37 @@ importers: version: 5.6.2 vite: specifier: ^5.4.8 - version: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + version: 5.4.8(@types/node@22.7.2)(terser@5.30.0) vite-plugin-checker: specifier: ^0.8.0 - version: 0.8.0(eslint@9.11.1(jiti@1.21.0))(optionator@0.9.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 0.8.0(eslint@9.11.1(jiti@1.21.0))(optionator@0.9.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) vite-plugin-dts: specifier: 4.2.2 - version: 4.2.2(@types/node@22.7.3)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 4.2.2(@types/node@22.7.2)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/http: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler '@typespec/library-linter': specifier: workspace:~ version: link:../library-linter + '@typespec/streams': + specifier: workspace:~ + version: link:../streams '@typespec/tspd': specifier: workspace:~ version: link:../tspd '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -494,7 +530,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/http-server-csharp: dependencies: @@ -507,7 +543,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler @@ -528,7 +564,7 @@ importers: version: link:../tspd '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -543,7 +579,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/http-server-javascript: dependencies: @@ -553,7 +589,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler @@ -599,7 +635,7 @@ importers: version: 1.4.12 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/openapi': specifier: workspace:~ version: link:../openapi @@ -636,7 +672,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/semver': specifier: ^7.5.8 version: 7.5.8 @@ -645,7 +681,7 @@ importers: version: 17.0.33 '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -663,7 +699,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/json-schema: dependencies: @@ -673,7 +709,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler @@ -688,7 +724,7 @@ importers: version: link:../tspd '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -709,19 +745,19 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/library-linter: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -736,7 +772,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/monarch: dependencies: @@ -746,10 +782,10 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -767,13 +803,13 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/openapi: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler @@ -791,7 +827,7 @@ importers: version: link:../tspd '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -806,7 +842,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/openapi3: dependencies: @@ -819,7 +855,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/yargs': specifier: ~17.0.33 version: 17.0.33 @@ -846,7 +882,7 @@ importers: version: link:../versioning '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -864,13 +900,13 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/playground: dependencies: '@fluentui/react-components': specifier: ~9.54.16 - version: 9.54.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + version: 9.54.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-icons': specifier: ^2.0.258 version: 2.0.258(react@18.3.1) @@ -949,7 +985,7 @@ importers: version: 8.3.3(@storybook/test@8.3.3(storybook@8.3.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3)(typescript@5.6.2) '@storybook/react-vite': specifier: ^8.3.3 - version: 8.3.3(@storybook/test@8.3.3(storybook@8.3.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.4)(storybook@8.3.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 8.3.3(@storybook/test@8.3.3(storybook@8.3.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.4)(storybook@8.3.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) '@storybook/test': specifier: ^8.3.3 version: 8.3.3(storybook@8.3.3) @@ -961,7 +997,7 @@ importers: version: 1.2.4 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/react': specifier: ~18.3.9 version: 18.3.9 @@ -976,7 +1012,7 @@ importers: version: link:../react-components '@vitejs/plugin-react': specifier: ~4.3.1 - version: 4.3.1(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 4.3.1(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) c8: specifier: ^10.1.2 version: 10.1.2 @@ -994,19 +1030,19 @@ importers: version: 5.6.2 vite: specifier: ^5.4.8 - version: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + version: 5.4.8(@types/node@22.7.2)(terser@5.30.0) vite-plugin-checker: specifier: ^0.8.0 - version: 0.8.0(eslint@9.11.1(jiti@1.21.0))(optionator@0.9.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 0.8.0(eslint@9.11.1(jiti@1.21.0))(optionator@0.9.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) vite-plugin-dts: specifier: 4.2.2 - version: 4.2.2(@types/node@22.7.3)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 4.2.2(@types/node@22.7.2)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) packages/playground-website: dependencies: '@fluentui/react-components': specifier: ~9.54.16 - version: 9.54.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + version: 9.54.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-icons': specifier: ^2.0.258 version: 2.0.258(react@18.3.1) @@ -1037,6 +1073,9 @@ importers: '@typespec/rest': specifier: workspace:~ version: link:../rest + '@typespec/streams': + specifier: workspace:~ + version: link:../streams '@typespec/versioning': specifier: workspace:~ version: link:../versioning @@ -1061,7 +1100,7 @@ importers: version: 1.2.4 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/react': specifier: ~18.3.9 version: 18.3.9 @@ -1073,10 +1112,10 @@ importers: version: 3.52.4 '@vitejs/plugin-react': specifier: ~4.3.1 - version: 4.3.1(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 4.3.1(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1097,13 +1136,13 @@ importers: version: 5.6.2 vite: specifier: ^5.4.8 - version: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + version: 5.4.8(@types/node@22.7.2)(terser@5.30.0) vite-plugin-dts: specifier: 4.2.2 - version: 4.2.2(@types/node@22.7.3)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 4.2.2(@types/node@22.7.2)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/prettier-plugin-typespec: dependencies: @@ -1134,7 +1173,7 @@ importers: version: 4.22.4 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/protobuf: devDependencies: @@ -1143,7 +1182,7 @@ importers: version: 4.0.9 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler @@ -1152,7 +1191,7 @@ importers: version: link:../tspd '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1170,13 +1209,13 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/react-components: dependencies: '@fluentui/react-components': specifier: ~9.54.16 - version: 9.54.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + version: 9.54.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-icons': specifier: ^2.0.258 version: 2.0.258(react@18.3.1) @@ -1201,7 +1240,7 @@ importers: version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/react': specifier: ~18.3.9 version: 18.3.9 @@ -1210,10 +1249,10 @@ importers: version: 18.3.0 '@vitejs/plugin-react': specifier: ~4.3.1 - version: 4.3.1(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 4.3.1(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1228,22 +1267,22 @@ importers: version: 5.6.2 vite: specifier: ^5.4.8 - version: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + version: 5.4.8(@types/node@22.7.2)(terser@5.30.0) vite-plugin-checker: specifier: ^0.8.0 - version: 0.8.0(eslint@9.11.1(jiti@1.21.0))(optionator@0.9.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 0.8.0(eslint@9.11.1(jiti@1.21.0))(optionator@0.9.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) vite-plugin-dts: specifier: 4.2.2 - version: 4.2.2(@types/node@22.7.3)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + version: 4.2.2(@types/node@22.7.2)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/rest: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler @@ -1258,7 +1297,7 @@ importers: version: link:../tspd '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1273,7 +1312,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/samples: dependencies: @@ -1283,6 +1322,9 @@ importers: '@typespec/compiler': specifier: workspace:~ version: link:../compiler + '@typespec/events': + specifier: workspace:~ + version: link:../events '@typespec/html-program-viewer': specifier: workspace:~ version: link:../html-program-viewer @@ -1307,19 +1349,25 @@ importers: '@typespec/rest': specifier: workspace:~ version: link:../rest + '@typespec/sse': + specifier: workspace:~ + version: link:../sse + '@typespec/streams': + specifier: workspace:~ + version: link:../streams '@typespec/versioning': specifier: workspace:~ version: link:../versioning devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/internal-build-utils': specifier: workspace:~ version: link:../internal-build-utils '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1337,13 +1385,13 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/spec: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/internal-build-utils': specifier: workspace:~ version: link:../internal-build-utils @@ -1404,7 +1452,7 @@ importers: version: 1.4.12 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/xml2js': specifier: ^0.4.11 version: 0.4.14 @@ -1413,7 +1461,7 @@ importers: version: 17.0.33 '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1425,7 +1473,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/spec-core: dependencies: @@ -1525,7 +1573,7 @@ importers: version: 1.4.12 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/node-fetch': specifier: ^2.6.3 version: 2.6.11 @@ -1552,7 +1600,7 @@ importers: version: 12.25.0 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 devDependencies: rimraf: specifier: ~6.0.1 @@ -1578,7 +1626,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/tspd': specifier: workspace:~ version: link:../tspd @@ -1589,6 +1637,81 @@ importers: specifier: ~5.6.2 version: 5.6.2 + packages/sse: + devDependencies: + '@types/node': + specifier: ~22.7.1 + version: 22.7.2 + '@typespec/compiler': + specifier: workspace:~ + version: link:../compiler + '@typespec/events': + specifier: workspace:~ + version: link:../events + '@typespec/http': + specifier: workspace:~ + version: link:../http + '@typespec/library-linter': + specifier: workspace:~ + version: link:../library-linter + '@typespec/streams': + specifier: workspace:~ + version: link:../streams + '@typespec/tspd': + specifier: workspace:~ + version: link:../tspd + '@vitest/coverage-v8': + specifier: ^2.1.1 + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + '@vitest/ui': + specifier: ^2.1.1 + version: 2.1.1(vitest@2.1.1) + c8: + specifier: ^10.1.2 + version: 10.1.2 + rimraf: + specifier: ~6.0.1 + version: 6.0.1 + typescript: + specifier: ~5.6.2 + version: 5.6.2 + vitest: + specifier: ^2.1.1 + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + + packages/streams: + devDependencies: + '@types/node': + specifier: ~22.7.1 + version: 22.7.2 + '@typespec/compiler': + specifier: workspace:~ + version: link:../compiler + '@typespec/library-linter': + specifier: workspace:~ + version: link:../library-linter + '@typespec/tspd': + specifier: workspace:~ + version: link:../tspd + '@vitest/coverage-v8': + specifier: ^2.1.1 + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + '@vitest/ui': + specifier: ^2.1.1 + version: 2.1.1(vitest@2.1.1) + c8: + specifier: ^10.1.2 + version: 10.1.2 + rimraf: + specifier: ~6.0.1 + version: 6.0.1 + typescript: + specifier: ~5.6.2 + version: 5.6.2 + vitest: + specifier: ^2.1.1 + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + packages/tmlanguage-generator: dependencies: onigasm: @@ -1600,7 +1723,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/plist': specifier: ~3.0.5 version: 3.0.5 @@ -1631,7 +1754,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/yargs': specifier: ~17.0.33 version: 17.0.33 @@ -1640,7 +1763,7 @@ importers: version: link:../prettier-plugin-typespec '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1664,7 +1787,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/typespec-vs: devDependencies: @@ -1691,7 +1814,7 @@ importers: version: 10.0.8 '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/vscode': specifier: ~1.93.0 version: 1.93.0 @@ -1703,7 +1826,7 @@ importers: version: link:../internal-build-utils '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1730,7 +1853,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) vscode-languageclient: specifier: ~9.0.1 version: 9.0.1 @@ -1739,7 +1862,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler @@ -1751,7 +1874,7 @@ importers: version: link:../tspd '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1766,7 +1889,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages/website: dependencies: @@ -1790,7 +1913,7 @@ importers: version: 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.9)(react@18.3.1))(@swc/core@1.7.28(@swc/helpers@0.5.8))(eslint@9.11.1(jiti@1.21.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)(vue-template-compiler@2.7.16))(@mdx-js/react@3.0.1(@types/react@18.3.9)(react@18.3.1))(@swc/core@1.7.28(@swc/helpers@0.5.8))(eslint@9.11.1(jiti@1.21.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)(vue-template-compiler@2.7.16) '@fluentui/react-components': specifier: ~9.54.16 - version: 9.54.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + version: 9.54.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-icons': specifier: ^2.0.258 version: 2.0.258(react@18.3.1) @@ -1833,7 +1956,7 @@ importers: version: 1.7.28(@swc/helpers@0.5.8) '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@types/react': specifier: ~18.3.9 version: 18.3.9 @@ -1911,7 +2034,7 @@ importers: devDependencies: '@types/node': specifier: ~22.7.1 - version: 22.7.3 + version: 22.7.2 '@typespec/compiler': specifier: workspace:~ version: link:../compiler @@ -1923,7 +2046,7 @@ importers: version: link:../tspd '@vitest/coverage-v8': specifier: ^2.1.1 - version: 2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) + version: 2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)) '@vitest/ui': specifier: ^2.1.1 version: 2.1.1(vitest@2.1.1) @@ -1938,7 +2061,7 @@ importers: version: 5.6.2 vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + version: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) packages: @@ -3680,24 +3803,24 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-breadcrumb@9.0.39': - resolution: {integrity: sha512-Y/d3+qwco1WPB/t7BpEES1LIqBrR1A/7r4jdVuNylgiK5OoRRDgRdu7+7ecT0sjnfyhHwv+PnImtXIOnGyKgrQ==} + '@fluentui/react-breadcrumb@9.0.38': + resolution: {integrity: sha512-VWf/nNrJSWtYpT4eR4vl4+QNf8idXtdqChB22siAaFg8pBndBE6N4nsSgMcs70E+VQ4SuJVp9HQVSx8vpngi0Q==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-button@9.3.92': - resolution: {integrity: sha512-awMMtr3MnXB5Q8ItYJ6s4k5U3RKJImm8qAh0Zm/quK1Aj62fKa4Ro/P+dMzKhi+86VmE9wqVwWr9vim/MHGgow==} + '@fluentui/react-button@9.3.91': + resolution: {integrity: sha512-g/0kn9S/SO/XRUkRpxnAfpe6rv2Tn/zJhygeyTy+rOGuR5MxAEDhauRnpjntt+h8U6088LGImZUTfU5vHjsVNg==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-card@9.0.94': - resolution: {integrity: sha512-TUzQLdCFcBkESgj6fVRH201OHvYPWB1n8b7unDSX5VjxcnHT8MKu2DWj5KHFmVaEd6sNEgNm58qiAGGjTSvkgg==} + '@fluentui/react-card@9.0.93': + resolution: {integrity: sha512-HhaNzhnk1htPGF1Lvh9G9Bohm26Tt49csjz8/Xc+u/dfzoXPAmYJxgCOzHT6QPp0/e21Fy+cQONV051BO5dE5w==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -3712,16 +3835,16 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-combobox@9.13.8': - resolution: {integrity: sha512-+QuiFt1P93JwjtAy2b0cXah9BT0h9I2T1+fm4aX9j1sWME/r5XI/gGgYT15+PvAjxmBxcabYtd+VYYB0MKUoxw==} + '@fluentui/react-combobox@9.13.7': + resolution: {integrity: sha512-UQnUdThddkwDzvPZmPTH3kFNYTotTmO2cg5+oKzhYfC5I8Km3tzclItRjNRxjjo9hdjDHn2ZiXpvr8qFWJbS/A==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-components@9.54.17': - resolution: {integrity: sha512-brnvcEGQG+S16hc9o+cXB9EEJmpicjP1+plYBuc5xKtz2Ljo1fAijM5MGP/pwMcQUU0GATFiVkIzvGwyD7y5aQ==} + '@fluentui/react-components@9.54.16': + resolution: {integrity: sha512-XLy3ZKlmb+BqJIWeOXEzh8yCFn/gkKWlSt50tAEck0WapUpCPcB+Ccst4eT81GJipH6yjyy/jZUnEEkKAYRvLA==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -3737,8 +3860,8 @@ packages: react-dom: '>=16.14.0 <19.0.0' scheduler: '>=0.19.0 <=0.23.0' - '@fluentui/react-dialog@9.11.16': - resolution: {integrity: sha512-PP15i+mN6XI7knfrdTNexNHtGLBNbf7WmJZGiXZViBWrlGEAUyxdRqmNwQEXwz0xYduqMX7ddEw26e/Ag/BzwA==} + '@fluentui/react-dialog@9.11.15': + resolution: {integrity: sha512-yfEw7uc8wVvgK17YW7035TDfDAf86Ti/DRJaw/D9Ld/gOB9nLG1L6NBjbfYE4x+f0+r/BtG+0nhrNM95zG0sog==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -3753,8 +3876,8 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-drawer@9.5.16': - resolution: {integrity: sha512-GORGm43E981KHfg2HB/picUwpf3BbdwcfPUVslAdyqaR2A6OJ+fQGKjGDcHn/CPIfgPsg0wHVpVTkvJLTt/BzA==} + '@fluentui/react-drawer@9.5.15': + resolution: {integrity: sha512-YE6Dhv+8clafDiBHpUPF2P3WR0er2PO3HtyXCN/rUs5AKQpVYu4Uc2eQu/C6wnQMWgEui//FP6qTS3UXRMIJ/A==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -3850,8 +3973,8 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-message-bar@9.2.12': - resolution: {integrity: sha512-d18VBkEJnKqhhkiuxzoan91BEt/x/at6/pR6TH0sn9C7Snvxu88Ywl2ZrKEpaNUAvG0Ww3qE0lNepm/fOEuR+g==} + '@fluentui/react-message-bar@9.2.11': + resolution: {integrity: sha512-JQFbO1EKx0Qel6hdQbSJTdKdPGCyaprt/pFabHpbhmMbIRwtMPuPbni6/tX7Eak5a8fHTVmTaaPZaeDEDB5kww==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' '@types/react-dom': '>=16.8.0 <19.0.0' @@ -4016,8 +4139,8 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-table@9.15.18': - resolution: {integrity: sha512-JbQeo8JW3o6kZ/01ynouCv6kTA22+lOUnig5h6npbuxTc8pR8erJ0a+D384a80o+vjN26ww1KXhCpkJLDWG6Bg==} + '@fluentui/react-table@9.15.17': + resolution: {integrity: sha512-5PuN2OC/DaFEZdrw7WTIcZFqZbTAJU8gTtgbDHSvM3+KMsTE65JHus24sDrnAshjiNcYorEKZdoWZq/bDr46Aw==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -4040,8 +4163,8 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-tag-picker@9.3.4': - resolution: {integrity: sha512-eV6snlflC9LCZeqrhPDU/p9OeXC/Kb5CX502/N6yuT25GcV1u3pePvPBKG4ac090nSlC54/GgYBmCHS5m5+r4w==} + '@fluentui/react-tag-picker@9.3.3': + resolution: {integrity: sha512-okIO+Ock5t7dvNUHTtJyw6OPTqYsSnDy8mePhG67pGwDDOTGWqgikEfUBDN1bO8NaQf56tivubyyg7s2boLZTg==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -4056,8 +4179,8 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-teaching-popover@9.1.18': - resolution: {integrity: sha512-v2HMRMj9etIUPs8G+pfv57SODwjTnZ9trNoSq5IfM5Fh1Rg6TnFAUGweWA2k0M0JKtRXkCixOCqNUiBXen0zXw==} + '@fluentui/react-teaching-popover@9.1.17': + resolution: {integrity: sha512-aA7ImKM4xGf/CK1Bhs5MD8suow76vdRzscHnvCRMBZ9MSqLlkLglvJevzntyhuUAEV1qXxaJZHHbWhY5+/cfHA==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' '@types/react-dom': '>=16.8.0 <19.0.0' @@ -4091,8 +4214,8 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-toolbar@9.2.6': - resolution: {integrity: sha512-G+rFX0vuufM+GZVIdcFn15kdVYw2+j32rj3jHHwAbT1wx8W6OVSR0opVGcJTwYAuKXq39J/1sHEcwbX4vAG0TQ==} + '@fluentui/react-toolbar@9.2.5': + resolution: {integrity: sha512-Z4FEfrNsI5WJKv0/cuU6ysyGVi35EXVpkuLxnodUkFxTXu3nNUrBnqgEomz7p6psnOjFXJP1PvxU+ndAQhtVJg==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -4107,8 +4230,8 @@ packages: react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - '@fluentui/react-tree@9.8.2': - resolution: {integrity: sha512-b4Zfq+pMQIgHGoQA6V6AnehnmOKoV8KMxNpUOn/73N16NphbhrI8KnsVph1Wst/pLT/7p6ANdKt9nnE9SMai/A==} + '@fluentui/react-tree@9.8.1': + resolution: {integrity: sha512-nKvzBl5hLHUU7NcRlljxfWhEeRsPZrTGAz6+aVbT6C1Lu6AC2kOhLryjRqGct0/9KK7N3WS0UjNjDS7dXtt8TQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -4121,8 +4244,8 @@ packages: '@types/react': '>=16.14.0 <19.0.0' react: '>=16.14.0 <19.0.0' - '@fluentui/react-virtualizer@9.0.0-alpha.85': - resolution: {integrity: sha512-zdwqj3sLH1TeMwgXNFOVsWtWrH/zD4vmq1s/WkbB4Wu5h/CeemQEN3//WVpz0AB3cZGvcPiTitKH12AfaCqXIQ==} + '@fluentui/react-virtualizer@9.0.0-alpha.84': + resolution: {integrity: sha512-CM0fKLVKQ++Z1KCFDQpxo9gULkIwAbtOFFcJwl5nxqszRmML3dL+dSX5NZMSCk2bg1VlQ+Dx1tqL5Q/Eh1f2aQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -5412,8 +5535,8 @@ packages: '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} - '@types/node@22.7.3': - resolution: {integrity: sha512-qXKfhXXqGTyBskvWEzJZPUxSslAiLaB6JGP1ic/XTH9ctGgzdgYguuLP1C601aRTSDNlLb0jbKqXjZ48GNraSA==} + '@types/node@22.7.2': + resolution: {integrity: sha512-866lXSrpGpgyHBZUa2m9YNWqHDjjM0aBTJlNtYaGEw4rqY/dcD7deRVTbBBAJelfA7oaGDbNftXF/TL/A6RgoA==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -10218,11 +10341,21 @@ packages: resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} engines: {node: '>=8'} + playwright-core@1.47.0: + resolution: {integrity: sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==} + engines: {node: '>=18'} + hasBin: true + playwright-core@1.47.2: resolution: {integrity: sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==} engines: {node: '>=18'} hasBin: true + playwright@1.47.0: + resolution: {integrity: sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==} + engines: {node: '>=18'} + hasBin: true + playwright@1.47.2: resolution: {integrity: sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==} engines: {node: '>=18'} @@ -12844,7 +12977,7 @@ snapshots: '@babel/generator@7.24.10': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.24.9 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 @@ -12858,7 +12991,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.22.5': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.24.9 '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': dependencies: @@ -13444,7 +13577,7 @@ snapshots: '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.25.2) - '@babel/types': 7.25.6 + '@babel/types': 7.24.9 transitivePeerDependencies: - supports-color @@ -13699,7 +13832,7 @@ snapshots: '@babel/helper-hoist-variables': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7 '@babel/parser': 7.24.8 - '@babel/types': 7.25.6 + '@babel/types': 7.24.9 debug: 4.3.7(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: @@ -14960,7 +15093,7 @@ snapshots: '@fluentui/react-alert@9.0.0-beta.124(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) - '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-button': 9.3.91(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-icons': 2.0.258(react@18.3.1) '@fluentui/react-jsx-runtime': 9.0.43(@types/react@18.3.9)(react@18.3.1) '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -15023,10 +15156,10 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@fluentui/react-breadcrumb@9.0.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@fluentui/react-breadcrumb@9.0.38(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-button': 9.3.91(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-icons': 2.0.258(react@18.3.1) '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) '@fluentui/react-link': 9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -15041,7 +15174,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@fluentui/react-button@9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@fluentui/react-button@9.3.91(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@fluentui/keyboard-keys': 9.0.7 '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -15058,7 +15191,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@fluentui/react-card@9.0.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@fluentui/react-card@9.0.93(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@fluentui/keyboard-keys': 9.0.7 '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) @@ -15092,7 +15225,7 @@ snapshots: transitivePeerDependencies: - scheduler - '@fluentui/react-combobox@9.13.8(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-combobox@9.13.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: '@fluentui/keyboard-keys': 9.0.7 '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -15115,21 +15248,21 @@ snapshots: transitivePeerDependencies: - scheduler - '@fluentui/react-components@9.54.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-components@9.54.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: '@fluentui/react-accordion': 9.5.5(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-alert': 9.0.0-beta.124(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-badge': 9.2.43(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-breadcrumb': 9.0.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-card': 9.0.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-breadcrumb': 9.0.38(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-button': 9.3.91(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-card': 9.0.93(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-checkbox': 9.2.37(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) - '@fluentui/react-combobox': 9.13.8(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) - '@fluentui/react-dialog': 9.11.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-combobox': 9.13.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-dialog': 9.11.15(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-divider': 9.2.75(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-drawer': 9.5.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-drawer': 9.5.15(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-image': 9.1.73(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-infobutton': 9.0.0-beta.102(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) @@ -15138,7 +15271,7 @@ snapshots: '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-link': 9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-menu': 9.14.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) - '@fluentui/react-message-bar': 9.2.12(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-message-bar': 9.2.11(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-overflow': 9.1.30(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-persona': 9.2.98(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) @@ -15158,21 +15291,21 @@ snapshots: '@fluentui/react-spinner': 9.4.14(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-swatch-picker': 9.1.10(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-switch': 9.1.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) - '@fluentui/react-table': 9.15.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-table': 9.15.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-tabs': 9.5.1(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-tag-picker': 9.3.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-tag-picker': 9.3.3(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-tags': 9.3.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) - '@fluentui/react-teaching-popover': 9.1.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-teaching-popover': 9.1.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-text': 9.4.25(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-textarea': 9.3.88(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-theme': 9.1.17 '@fluentui/react-toast': 9.3.56(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-toolbar': 9.2.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-toolbar': 9.2.5(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-tooltip': 9.4.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-tree': 9.8.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-tree': 9.8.1(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) - '@fluentui/react-virtualizer': 9.0.0-alpha.85(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-virtualizer': 9.0.0-alpha.84(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@griffel/react': 1.5.22(react@18.3.1) '@swc/helpers': 0.5.8 '@types/react': 18.3.9 @@ -15192,7 +15325,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) scheduler: 0.23.2 - '@fluentui/react-dialog@9.11.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-dialog@9.11.15(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: '@fluentui/keyboard-keys': 9.0.7 '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -15227,9 +15360,9 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@fluentui/react-drawer@9.5.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-drawer@9.5.15(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: - '@fluentui/react-dialog': 9.11.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-dialog': 9.11.15(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) @@ -15418,9 +15551,9 @@ snapshots: transitivePeerDependencies: - scheduler - '@fluentui/react-message-bar@9.2.12(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@fluentui/react-message-bar@9.2.11(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-button': 9.3.91(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-icons': 2.0.258(react@18.3.1) '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) @@ -15740,7 +15873,7 @@ snapshots: transitivePeerDependencies: - scheduler - '@fluentui/react-table@9.15.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-table@9.15.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: '@fluentui/keyboard-keys': 9.0.7 '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -15794,11 +15927,11 @@ snapshots: react-dom: 18.3.1(react@18.3.1) tabster: 8.0.1 - '@fluentui/react-tag-picker@9.3.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-tag-picker@9.3.3(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: '@fluentui/keyboard-keys': 9.0.7 '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-combobox': 9.13.8(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) + '@fluentui/react-combobox': 9.13.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-icons': 2.0.258(react@18.3.1) @@ -15839,10 +15972,10 @@ snapshots: transitivePeerDependencies: - scheduler - '@fluentui/react-teaching-popover@9.1.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-teaching-popover@9.1.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-button': 9.3.91(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-icons': 2.0.258(react@18.3.1) '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) @@ -15914,9 +16047,9 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@fluentui/react-toolbar@9.2.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-toolbar@9.2.5(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: - '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-button': 9.3.91(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-divider': 9.2.75(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) @@ -15951,12 +16084,12 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@fluentui/react-tree@9.8.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': + '@fluentui/react-tree@9.8.1(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)': dependencies: '@fluentui/keyboard-keys': 9.0.7 '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) - '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@fluentui/react-button': 9.3.91(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@fluentui/react-checkbox': 9.2.37(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2) '@fluentui/react-icons': 2.0.258(react@18.3.1) @@ -15985,7 +16118,7 @@ snapshots: '@types/react': 18.3.9 react: 18.3.1 - '@fluentui/react-virtualizer@9.0.0-alpha.85(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@fluentui/react-virtualizer@9.0.0-alpha.84(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) @@ -16068,17 +16201,17 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/yargs': 17.0.33 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0))': dependencies: glob: 7.2.3 glob-promise: 4.2.2(glob@7.2.3) magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.6.2) - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) optionalDependencies: typescript: 5.6.2 @@ -16163,31 +16296,31 @@ snapshots: dependencies: langium: 3.0.0 - '@microsoft/api-extractor-model@7.29.6(@types/node@22.7.3)': + '@microsoft/api-extractor-model@7.29.6(@types/node@22.7.2)': dependencies: '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.7.0(@types/node@22.7.3) + '@rushstack/node-core-library': 5.7.0(@types/node@22.7.2) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor-model@7.29.8(@types/node@22.7.3)': + '@microsoft/api-extractor-model@7.29.8(@types/node@22.7.2)': dependencies: '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.9.0(@types/node@22.7.3) + '@rushstack/node-core-library': 5.9.0(@types/node@22.7.2) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.47.7(@types/node@22.7.3)': + '@microsoft/api-extractor@7.47.7(@types/node@22.7.2)': dependencies: - '@microsoft/api-extractor-model': 7.29.6(@types/node@22.7.3) + '@microsoft/api-extractor-model': 7.29.6(@types/node@22.7.2) '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.7.0(@types/node@22.7.3) + '@rushstack/node-core-library': 5.7.0(@types/node@22.7.2) '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.14.0(@types/node@22.7.3) - '@rushstack/ts-command-line': 4.22.6(@types/node@22.7.3) + '@rushstack/terminal': 0.14.0(@types/node@22.7.2) + '@rushstack/ts-command-line': 4.22.6(@types/node@22.7.2) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.8 @@ -16197,15 +16330,15 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.47.9(@types/node@22.7.3)': + '@microsoft/api-extractor@7.47.9(@types/node@22.7.2)': dependencies: - '@microsoft/api-extractor-model': 7.29.8(@types/node@22.7.3) + '@microsoft/api-extractor-model': 7.29.8(@types/node@22.7.2) '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.9.0(@types/node@22.7.3) + '@rushstack/node-core-library': 5.9.0(@types/node@22.7.2) '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.14.2(@types/node@22.7.3) - '@rushstack/ts-command-line': 4.22.8(@types/node@22.7.3) + '@rushstack/terminal': 0.14.2(@types/node@22.7.2) + '@rushstack/ts-command-line': 4.22.8(@types/node@22.7.2) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.8 @@ -16240,7 +16373,7 @@ snapshots: dependencies: agent-base: 7.1.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.4 + https-proxy-agent: 7.0.5 lru-cache: 10.2.0 socks-proxy-agent: 8.0.2 transitivePeerDependencies: @@ -16877,7 +17010,7 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@rushstack/node-core-library@5.7.0(@types/node@22.7.3)': + '@rushstack/node-core-library@5.7.0(@types/node@22.7.2)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -16888,9 +17021,9 @@ snapshots: resolve: 1.22.8 semver: 7.5.4 optionalDependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 - '@rushstack/node-core-library@5.9.0(@types/node@22.7.3)': + '@rushstack/node-core-library@5.9.0(@types/node@22.7.2)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -16901,39 +17034,39 @@ snapshots: resolve: 1.22.8 semver: 7.5.4 optionalDependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@rushstack/rig-package@0.5.3': dependencies: resolve: 1.22.8 strip-json-comments: 3.1.1 - '@rushstack/terminal@0.14.0(@types/node@22.7.3)': + '@rushstack/terminal@0.14.0(@types/node@22.7.2)': dependencies: - '@rushstack/node-core-library': 5.7.0(@types/node@22.7.3) + '@rushstack/node-core-library': 5.7.0(@types/node@22.7.2) supports-color: 8.1.1 optionalDependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 - '@rushstack/terminal@0.14.2(@types/node@22.7.3)': + '@rushstack/terminal@0.14.2(@types/node@22.7.2)': dependencies: - '@rushstack/node-core-library': 5.9.0(@types/node@22.7.3) + '@rushstack/node-core-library': 5.9.0(@types/node@22.7.2) supports-color: 8.1.1 optionalDependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 - '@rushstack/ts-command-line@4.22.6(@types/node@22.7.3)': + '@rushstack/ts-command-line@4.22.6(@types/node@22.7.2)': dependencies: - '@rushstack/terminal': 0.14.0(@types/node@22.7.3) + '@rushstack/terminal': 0.14.0(@types/node@22.7.2) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 transitivePeerDependencies: - '@types/node' - '@rushstack/ts-command-line@4.22.8(@types/node@22.7.3)': + '@rushstack/ts-command-line@4.22.8(@types/node@22.7.2)': dependencies: - '@rushstack/terminal': 0.14.2(@types/node@22.7.3) + '@rushstack/terminal': 0.14.2(@types/node@22.7.2) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 @@ -17027,7 +17160,7 @@ snapshots: storybook: 8.3.3 uuid: 9.0.1 - '@storybook/builder-vite@8.3.3(storybook@8.3.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0))': + '@storybook/builder-vite@8.3.3(storybook@8.3.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0))': dependencies: '@storybook/csf-plugin': 8.3.3(storybook@8.3.3) '@types/find-cache-dir': 3.2.1 @@ -17039,7 +17172,7 @@ snapshots: magic-string: 0.30.11 storybook: 8.3.3 ts-dedent: 2.2.0 - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) optionalDependencies: typescript: 5.6.2 transitivePeerDependencies: @@ -17151,11 +17284,11 @@ snapshots: react-dom: 18.3.1(react@18.3.1) storybook: 8.3.3 - '@storybook/react-vite@8.3.3(@storybook/test@8.3.3(storybook@8.3.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.4)(storybook@8.3.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0))': + '@storybook/react-vite@8.3.3(@storybook/test@8.3.3(storybook@8.3.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.4)(storybook@8.3.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) '@rollup/pluginutils': 5.1.0(rollup@4.22.4) - '@storybook/builder-vite': 8.3.3(storybook@8.3.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + '@storybook/builder-vite': 8.3.3(storybook@8.3.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) '@storybook/react': 8.3.3(@storybook/test@8.3.3(storybook@8.3.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.3.3)(typescript@5.6.2) find-up: 5.0.0 magic-string: 0.30.11 @@ -17165,7 +17298,7 @@ snapshots: resolve: 1.22.8 storybook: 8.3.3 tsconfig-paths: 4.2.0 - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) transitivePeerDependencies: - '@preact/preset-vite' - '@storybook/test' @@ -17184,7 +17317,7 @@ snapshots: '@storybook/theming': 8.3.3(storybook@8.3.3) '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 - '@types/node': 22.7.3 + '@types/node': 22.7.2 acorn: 7.4.1 acorn-jsx: 5.3.2(acorn@7.4.1) acorn-walk: 7.2.0 @@ -17468,26 +17601,26 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/bonjour@3.5.13': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/braces@3.0.4': {} '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 4.17.43 - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/connect@3.4.38': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/cross-spawn@6.0.6': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/d3-scale-chromatic@3.0.3': {} @@ -17531,7 +17664,7 @@ snapshots: '@types/express-serve-static-core@4.17.43': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/qs': 6.9.14 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -17548,7 +17681,7 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/gtag.js@0.0.12': {} @@ -17566,7 +17699,7 @@ snapshots: '@types/http-proxy@1.17.14': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/istanbul-lib-coverage@2.0.6': {} @@ -17608,7 +17741,7 @@ snapshots: '@types/morgan@1.9.9': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/ms@0.7.34': {} @@ -17620,16 +17753,16 @@ snapshots: '@types/node-fetch@2.6.11': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 form-data: 4.0.0 '@types/node-forge@1.3.11': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/node@17.0.45': {} - '@types/node@22.7.3': + '@types/node@22.7.2': dependencies: undici-types: 6.19.8 @@ -17639,14 +17772,14 @@ snapshots: '@types/plist@3.0.5': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 xmlbuilder: 15.1.1 '@types/prismjs@1.26.3': {} '@types/prompts@2.4.9': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 kleur: 3.0.3 '@types/prop-types@15.7.12': {} @@ -17687,14 +17820,14 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/semver@7.5.8': {} '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/serve-index@1.9.4': dependencies: @@ -17704,15 +17837,15 @@ snapshots: dependencies: '@types/http-errors': 2.0.4 '@types/mime': 3.0.4 - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/sockjs@0.3.36': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/ssri@7.1.5': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/swagger-ui-dist@3.30.5': {} @@ -17730,11 +17863,11 @@ snapshots: '@types/ws@8.5.10': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/xml2js@0.4.14': dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@types/yargs-parser@21.0.3': {} @@ -17876,18 +18009,18 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react@4.3.1(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0))': + '@vitejs/plugin-react@4.3.1(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0))': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2) '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.25.2) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0))': + '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -17901,7 +18034,7 @@ snapshots: std-env: 3.7.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + vitest: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) transitivePeerDependencies: - supports-color @@ -17919,13 +18052,13 @@ snapshots: chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0))': + '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0))': dependencies: '@vitest/spy': 2.1.1 estree-walker: 3.0.3 magic-string: 0.30.11 optionalDependencies: - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) '@vitest/pretty-format@2.0.5': dependencies: @@ -17967,7 +18100,7 @@ snapshots: sirv: 2.0.4 tinyglobby: 0.2.6 tinyrainbow: 1.2.0 - vitest: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + vitest: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) '@vitest/utils@2.0.5': dependencies: @@ -18014,7 +18147,7 @@ snapshots: koa-mount: 4.0.0 koa-static: 5.0.0 minimist: 1.2.8 - playwright: 1.47.2 + playwright: 1.47.0 tar-fs: 3.0.6 vscode-uri: 3.0.8 transitivePeerDependencies: @@ -18227,9 +18360,9 @@ snapshots: acorn: 7.4.1 acorn-walk: 7.2.0 - acorn-import-assertions@1.9.0(acorn@8.12.1): + acorn-import-assertions@1.9.0(acorn@8.11.3): dependencies: - acorn: 8.12.1 + acorn: 8.11.3 acorn-jsx@5.3.2(acorn@7.4.1): dependencies: @@ -20361,12 +20494,12 @@ snapshots: semver: 7.6.3 strip-indent: 3.0.0 - eslint-plugin-vitest@0.5.4(eslint@9.11.1(jiti@1.21.0))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)): + eslint-plugin-vitest@0.5.4(eslint@9.11.1(jiti@1.21.0))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0)): dependencies: '@typescript-eslint/utils': 7.17.0(eslint@9.11.1(jiti@1.21.0))(typescript@5.6.2) eslint: 9.11.1(jiti@1.21.0) optionalDependencies: - vitest: 2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) + vitest: 2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0) transitivePeerDependencies: - supports-color - typescript @@ -20492,7 +20625,7 @@ snapshots: eval@0.1.8: dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 require-like: 0.1.2 event-target-shim@5.0.1: {} @@ -21749,7 +21882,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.7.3 + '@types/node': 22.7.2 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -21757,13 +21890,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -23697,8 +23830,16 @@ snapshots: dependencies: find-up: 3.0.0 + playwright-core@1.47.0: {} + playwright-core@1.47.2: {} + playwright@1.47.0: + dependencies: + playwright-core: 1.47.0 + optionalDependencies: + fsevents: 2.3.2 + playwright@1.47.2: dependencies: playwright-core: 1.47.2 @@ -25517,14 +25658,14 @@ snapshots: ts-dedent@2.2.0: {} - ts-node@10.9.2(@swc/core@1.7.28)(@types/node@22.7.3)(typescript@5.6.2): + ts-node@10.9.2(@swc/core@1.7.28)(@types/node@22.7.2)(typescript@5.6.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.7.3 + '@types/node': 22.7.2 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 @@ -25904,12 +26045,12 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vite-node@2.1.1(@types/node@22.7.3)(terser@5.30.0): + vite-node@2.1.1(@types/node@22.7.2)(terser@5.30.0): dependencies: cac: 6.7.14 debug: 4.3.7(supports-color@8.1.1) pathe: 1.1.2 - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) transitivePeerDependencies: - '@types/node' - less @@ -25921,7 +26062,7 @@ snapshots: - supports-color - terser - vite-plugin-checker@0.8.0(eslint@9.11.1(jiti@1.21.0))(optionator@0.9.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)): + vite-plugin-checker@0.8.0(eslint@9.11.1(jiti@1.21.0))(optionator@0.9.3)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)): dependencies: '@babel/code-frame': 7.24.7 ansi-escapes: 4.3.2 @@ -25933,7 +26074,7 @@ snapshots: npm-run-path: 4.0.1 strip-ansi: 6.0.1 tiny-invariant: 1.3.3 - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) vscode-languageclient: 7.0.0 vscode-languageserver: 7.0.0 vscode-languageserver-textdocument: 1.0.12 @@ -25943,9 +26084,9 @@ snapshots: optionator: 0.9.3 typescript: 5.6.2 - vite-plugin-dts@4.2.2(@types/node@22.7.3)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)): + vite-plugin-dts@4.2.2(@types/node@22.7.2)(rollup@4.22.4)(typescript@5.6.2)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)): dependencies: - '@microsoft/api-extractor': 7.47.7(@types/node@22.7.3) + '@microsoft/api-extractor': 7.47.7(@types/node@22.7.2) '@rollup/pluginutils': 5.1.0(rollup@4.22.4) '@volar/typescript': 2.4.4 '@vue/language-core': 2.1.6(typescript@5.6.2) @@ -25956,26 +26097,26 @@ snapshots: magic-string: 0.30.11 typescript: 5.6.2 optionalDependencies: - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite@5.4.8(@types/node@22.7.3)(terser@5.30.0): + vite@5.4.8(@types/node@22.7.2)(terser@5.30.0): dependencies: esbuild: 0.21.5 postcss: 8.4.45 rollup: 4.22.4 optionalDependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 fsevents: 2.3.3 terser: 5.30.0 - vitest@2.1.1(@types/node@22.7.3)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0): + vitest@2.1.1(@types/node@22.7.2)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(jsdom@19.0.0)(terser@5.30.0): dependencies: '@vitest/expect': 2.1.1 - '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@22.7.3)(terser@5.30.0)) + '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.8(@types/node@22.7.2)(terser@5.30.0)) '@vitest/pretty-format': 2.1.1 '@vitest/runner': 2.1.1 '@vitest/snapshot': 2.1.1 @@ -25990,11 +26131,11 @@ snapshots: tinyexec: 0.3.0 tinypool: 1.0.0 tinyrainbow: 1.2.0 - vite: 5.4.8(@types/node@22.7.3)(terser@5.30.0) - vite-node: 2.1.1(@types/node@22.7.3)(terser@5.30.0) + vite: 5.4.8(@types/node@22.7.2)(terser@5.30.0) + vite-node: 2.1.1(@types/node@22.7.2)(terser@5.30.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.7.3 + '@types/node': 22.7.2 '@vitest/ui': 2.1.1(vitest@2.1.1) happy-dom: 15.7.4 jsdom: 19.0.0 @@ -26095,7 +26236,7 @@ snapshots: webpack-bundle-analyzer@4.10.1: dependencies: '@discoveryjs/json-ext': 0.5.7 - acorn: 8.12.1 + acorn: 8.11.3 acorn-walk: 8.3.2 commander: 7.2.0 debounce: 1.2.1 @@ -26177,8 +26318,8 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.12.1 - acorn-import-assertions: 1.9.0(acorn@8.12.1) + acorn: 8.11.3 + acorn-import-assertions: 1.9.0(acorn@8.11.3) browserslist: 4.23.2 chrome-trace-event: 1.0.3 enhanced-resolve: 5.16.0