From f2afec8d47b9aab99e677e90c7ad79bcb1ae8da5 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 21 Aug 2026 16:57:43 +0200 Subject: [PATCH 01/15] Add the composition-openapi package --- packages/composition-openapi/LICENSE | 201 +++++++ packages/composition-openapi/README.md | 24 + packages/composition-openapi/openapi.sh | 29 + .../composition-openapi/openapitools.json | 7 + packages/composition-openapi/package.json | 48 ++ .../src/generated/.openapi-generator-ignore | 23 + .../src/generated/.openapi-generator/FILES | 79 +++ .../src/generated/.openapi-generator/VERSION | 1 + .../src/generated/apis/CompositionsApi.ts | 286 ++++++++++ .../src/generated/apis/EventsApi.ts | 102 ++++ .../src/generated/apis/InputsApi.ts | 194 +++++++ .../src/generated/apis/MediaTransportApi.ts | 195 +++++++ .../src/generated/apis/OutputsApi.ts | 464 ++++++++++++++++ .../src/generated/apis/RenderersApi.ts | 282 ++++++++++ .../src/generated/apis/index.ts | 8 + .../src/generated/index.ts | 5 + .../src/generated/models/ApiError.ts | 63 +++ .../src/generated/models/AudioChannels.ts | 50 ++ .../generated/models/AudioMixingStrategy.ts | 50 ++ .../src/generated/models/AudioScene.ts | 71 +++ .../src/generated/models/AudioSceneInput.ts | 76 +++ .../generated/models/AverageAndMaxBitrate.ts | 86 +++ .../src/generated/models/BoxShadow.ts | 87 +++ .../src/generated/models/Component.ts | 97 ++++ .../models/CompositionCreatedResponse.ts | 87 +++ .../models/CreateCompositionRequest.ts | 80 +++ .../src/generated/models/EasingFunction.ts | 92 ++++ .../generated/models/EasingFunctionBounce.ts | 86 +++ .../models/EasingFunctionCubicBezier.ts | 98 ++++ .../generated/models/EasingFunctionLinear.ts | 86 +++ .../src/generated/models/FontUpload.ts | 63 +++ .../src/generated/models/Framerate.ts | 54 ++ .../src/generated/models/H264EncoderPreset.ts | 58 ++ .../src/generated/models/HorizontalAlign.ts | 52 ++ .../src/generated/models/Image.ts | 113 ++++ .../src/generated/models/ImageSpec.ts | 114 ++++ .../src/generated/models/ImageSpecAuto.ts | 88 ++++ .../src/generated/models/ImageSpecGif.ts | 88 ++++ .../src/generated/models/ImageSpecJpeg.ts | 88 ++++ .../src/generated/models/ImageSpecPng.ts | 88 ++++ .../src/generated/models/ImageSpecSvg.ts | 104 ++++ .../src/generated/models/InputStream.ts | 95 ++++ .../src/generated/models/Interpolation.ts | 50 ++ .../src/generated/models/Mp4Input.ts | 90 ++++ .../src/generated/models/OpusEncoderPreset.ts | 51 ++ .../generated/models/OutputEndCondition.ts | 94 ++++ .../models/OutputRtmpClientAudioOptions.ts | 132 +++++ .../models/OutputRtmpClientVideoOptions.ts | 103 ++++ .../models/OutputWhipAudioOptions.ts | 152 ++++++ .../models/OutputWhipVideoOptions.ts | 100 ++++ .../src/generated/models/Overflow.ts | 51 ++ .../src/generated/models/PixelFormat.ts | 51 ++ .../src/generated/models/PortOrPortRange.ts | 54 ++ .../src/generated/models/RegisterInput.ts | 81 +++ .../generated/models/RegisterInputResponse.ts | 113 ++++ .../src/generated/models/RegisterOutput.ts | 65 +++ .../models/RegisterTemplateOutput.ts | 83 +++ .../src/generated/models/RescaleMode.ts | 50 ++ .../src/generated/models/Rescaler.ts | 278 ++++++++++ .../src/generated/models/Resolution.ts | 72 +++ .../src/generated/models/RtmpInput.ts | 89 ++++ .../src/generated/models/RtmpOutput.ts | 123 +++++ .../models/SendCompositionEventRequest.ts | 82 +++ .../src/generated/models/Text.ts | 234 +++++++++ .../src/generated/models/TextStyle.ts | 51 ++ .../src/generated/models/TextWeight.ts | 57 ++ .../src/generated/models/TextWrapMode.ts | 51 ++ .../src/generated/models/Tiles.ts | 219 ++++++++ .../src/generated/models/Transition.ts | 103 ++++ .../src/generated/models/TransportProtocol.ts | 50 ++ .../src/generated/models/UnregisterInput.ts | 68 +++ .../src/generated/models/UnregisterOutput.ts | 71 +++ .../generated/models/UnregisterRenderer.ts | 71 +++ .../generated/models/UpdateOutputRequest.ts | 91 ++++ .../src/generated/models/VerticalAlign.ts | 52 ++ .../generated/models/VideoEncoderBitrate.ts | 71 +++ .../src/generated/models/VideoScene.ts | 66 +++ .../src/generated/models/View.ts | 349 ++++++++++++ .../src/generated/models/ViewDirection.ts | 50 ++ .../src/generated/models/WhepInput.ts | 105 ++++ .../models/WhipAudioEncoderOptions.ts | 78 +++ .../models/WhipAudioEncoderOptionsAny.ts | 80 +++ .../models/WhipAudioEncoderOptionsOpus.ts | 123 +++++ .../src/generated/models/WhipInput.ts | 92 ++++ .../src/generated/models/WhipOutput.ts | 137 +++++ .../src/generated/models/index.ts | 71 +++ .../src/generated/runtime.ts | 497 ++++++++++++++++++ packages/composition-openapi/src/index.ts | 1 + packages/composition-openapi/tsconfig.json | 8 + 89 files changed, 8872 insertions(+) create mode 100644 packages/composition-openapi/LICENSE create mode 100644 packages/composition-openapi/README.md create mode 100755 packages/composition-openapi/openapi.sh create mode 100644 packages/composition-openapi/openapitools.json create mode 100644 packages/composition-openapi/package.json create mode 100644 packages/composition-openapi/src/generated/.openapi-generator-ignore create mode 100644 packages/composition-openapi/src/generated/.openapi-generator/FILES create mode 100644 packages/composition-openapi/src/generated/.openapi-generator/VERSION create mode 100644 packages/composition-openapi/src/generated/apis/CompositionsApi.ts create mode 100644 packages/composition-openapi/src/generated/apis/EventsApi.ts create mode 100644 packages/composition-openapi/src/generated/apis/InputsApi.ts create mode 100644 packages/composition-openapi/src/generated/apis/MediaTransportApi.ts create mode 100644 packages/composition-openapi/src/generated/apis/OutputsApi.ts create mode 100644 packages/composition-openapi/src/generated/apis/RenderersApi.ts create mode 100644 packages/composition-openapi/src/generated/apis/index.ts create mode 100644 packages/composition-openapi/src/generated/index.ts create mode 100644 packages/composition-openapi/src/generated/models/ApiError.ts create mode 100644 packages/composition-openapi/src/generated/models/AudioChannels.ts create mode 100644 packages/composition-openapi/src/generated/models/AudioMixingStrategy.ts create mode 100644 packages/composition-openapi/src/generated/models/AudioScene.ts create mode 100644 packages/composition-openapi/src/generated/models/AudioSceneInput.ts create mode 100644 packages/composition-openapi/src/generated/models/AverageAndMaxBitrate.ts create mode 100644 packages/composition-openapi/src/generated/models/BoxShadow.ts create mode 100644 packages/composition-openapi/src/generated/models/Component.ts create mode 100644 packages/composition-openapi/src/generated/models/CompositionCreatedResponse.ts create mode 100644 packages/composition-openapi/src/generated/models/CreateCompositionRequest.ts create mode 100644 packages/composition-openapi/src/generated/models/EasingFunction.ts create mode 100644 packages/composition-openapi/src/generated/models/EasingFunctionBounce.ts create mode 100644 packages/composition-openapi/src/generated/models/EasingFunctionCubicBezier.ts create mode 100644 packages/composition-openapi/src/generated/models/EasingFunctionLinear.ts create mode 100644 packages/composition-openapi/src/generated/models/FontUpload.ts create mode 100644 packages/composition-openapi/src/generated/models/Framerate.ts create mode 100644 packages/composition-openapi/src/generated/models/H264EncoderPreset.ts create mode 100644 packages/composition-openapi/src/generated/models/HorizontalAlign.ts create mode 100644 packages/composition-openapi/src/generated/models/Image.ts create mode 100644 packages/composition-openapi/src/generated/models/ImageSpec.ts create mode 100644 packages/composition-openapi/src/generated/models/ImageSpecAuto.ts create mode 100644 packages/composition-openapi/src/generated/models/ImageSpecGif.ts create mode 100644 packages/composition-openapi/src/generated/models/ImageSpecJpeg.ts create mode 100644 packages/composition-openapi/src/generated/models/ImageSpecPng.ts create mode 100644 packages/composition-openapi/src/generated/models/ImageSpecSvg.ts create mode 100644 packages/composition-openapi/src/generated/models/InputStream.ts create mode 100644 packages/composition-openapi/src/generated/models/Interpolation.ts create mode 100644 packages/composition-openapi/src/generated/models/Mp4Input.ts create mode 100644 packages/composition-openapi/src/generated/models/OpusEncoderPreset.ts create mode 100644 packages/composition-openapi/src/generated/models/OutputEndCondition.ts create mode 100644 packages/composition-openapi/src/generated/models/OutputRtmpClientAudioOptions.ts create mode 100644 packages/composition-openapi/src/generated/models/OutputRtmpClientVideoOptions.ts create mode 100644 packages/composition-openapi/src/generated/models/OutputWhipAudioOptions.ts create mode 100644 packages/composition-openapi/src/generated/models/OutputWhipVideoOptions.ts create mode 100644 packages/composition-openapi/src/generated/models/Overflow.ts create mode 100644 packages/composition-openapi/src/generated/models/PixelFormat.ts create mode 100644 packages/composition-openapi/src/generated/models/PortOrPortRange.ts create mode 100644 packages/composition-openapi/src/generated/models/RegisterInput.ts create mode 100644 packages/composition-openapi/src/generated/models/RegisterInputResponse.ts create mode 100644 packages/composition-openapi/src/generated/models/RegisterOutput.ts create mode 100644 packages/composition-openapi/src/generated/models/RegisterTemplateOutput.ts create mode 100644 packages/composition-openapi/src/generated/models/RescaleMode.ts create mode 100644 packages/composition-openapi/src/generated/models/Rescaler.ts create mode 100644 packages/composition-openapi/src/generated/models/Resolution.ts create mode 100644 packages/composition-openapi/src/generated/models/RtmpInput.ts create mode 100644 packages/composition-openapi/src/generated/models/RtmpOutput.ts create mode 100644 packages/composition-openapi/src/generated/models/SendCompositionEventRequest.ts create mode 100644 packages/composition-openapi/src/generated/models/Text.ts create mode 100644 packages/composition-openapi/src/generated/models/TextStyle.ts create mode 100644 packages/composition-openapi/src/generated/models/TextWeight.ts create mode 100644 packages/composition-openapi/src/generated/models/TextWrapMode.ts create mode 100644 packages/composition-openapi/src/generated/models/Tiles.ts create mode 100644 packages/composition-openapi/src/generated/models/Transition.ts create mode 100644 packages/composition-openapi/src/generated/models/TransportProtocol.ts create mode 100644 packages/composition-openapi/src/generated/models/UnregisterInput.ts create mode 100644 packages/composition-openapi/src/generated/models/UnregisterOutput.ts create mode 100644 packages/composition-openapi/src/generated/models/UnregisterRenderer.ts create mode 100644 packages/composition-openapi/src/generated/models/UpdateOutputRequest.ts create mode 100644 packages/composition-openapi/src/generated/models/VerticalAlign.ts create mode 100644 packages/composition-openapi/src/generated/models/VideoEncoderBitrate.ts create mode 100644 packages/composition-openapi/src/generated/models/VideoScene.ts create mode 100644 packages/composition-openapi/src/generated/models/View.ts create mode 100644 packages/composition-openapi/src/generated/models/ViewDirection.ts create mode 100644 packages/composition-openapi/src/generated/models/WhepInput.ts create mode 100644 packages/composition-openapi/src/generated/models/WhipAudioEncoderOptions.ts create mode 100644 packages/composition-openapi/src/generated/models/WhipAudioEncoderOptionsAny.ts create mode 100644 packages/composition-openapi/src/generated/models/WhipAudioEncoderOptionsOpus.ts create mode 100644 packages/composition-openapi/src/generated/models/WhipInput.ts create mode 100644 packages/composition-openapi/src/generated/models/WhipOutput.ts create mode 100644 packages/composition-openapi/src/generated/models/index.ts create mode 100644 packages/composition-openapi/src/generated/runtime.ts create mode 100644 packages/composition-openapi/src/index.ts create mode 100644 packages/composition-openapi/tsconfig.json diff --git a/packages/composition-openapi/LICENSE b/packages/composition-openapi/LICENSE new file mode 100644 index 00000000..c61b6639 --- /dev/null +++ b/packages/composition-openapi/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/packages/composition-openapi/README.md b/packages/composition-openapi/README.md new file mode 100644 index 00000000..1f298d1a --- /dev/null +++ b/packages/composition-openapi/README.md @@ -0,0 +1,24 @@ +# Composition API openapi + +This is internal library, used as part of [`@fishjam-cloud/js-server-sdk`](https://github.com/fishjam-cloud/js-server-sdk/tree/main/packages/js-server-sdk/) +## Generation + +Regenerate with `yarn codegen path/to/openapi.json`, passing the path to the Composition API spec. + +Generation runs with `modelPropertyNaming=camelCase`, unlike `fishjam-openapi`, because that spec is +snake_case while Fishjam's is camelCase. The generated serialisers map between the camelCase surface and the +snake_case wire format in both directions. + +`openapi.sh` ends with a `sed` because the generator serialises the multipart JSON part of +`register_template_output` with `objectToJSON()`, a function it never emits. Verified present in 7.7.0, 7.14.0, +7.23.0 and 7.24.0. Drop the patch once a generator release emits the model serialiser there. + +## License + +Licensed under the [Apache License, Version 2.0](LICENSE) + +## Fishjam is created by Software Mansion + +Since 2012 [Software Mansion](https://swmansion.com) is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues. We can help you build your next dream product – [Hire us](https://swmansion.com/contact/projects?utm_source=fishjam&utm_medium=js-server-readme). + +[![Software Mansion](https://logo.swmansion.com/logo?color=white&variant=desktop&width=200&tag=react-client)](https://swmansion.com/contact/projects?utm_source=fishjam&utm_medium=js-server-readme) diff --git a/packages/composition-openapi/openapi.sh b/packages/composition-openapi/openapi.sh new file mode 100755 index 00000000..e629b3e3 --- /dev/null +++ b/packages/composition-openapi/openapi.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# Usage: +# sh openapi.sh path/to/openapi.json + +set -e + +ROOTDIR=$(dirname "$(readlink -f $0)") + +if [ -z "$1" ]; then + echo "Missing a local openapi.json path as the first argument" 1>&2 + exit 1 +fi + +SPEC=$(readlink -f "$1") + +cd $ROOTDIR \ +&& npx @openapitools/openapi-generator-cli generate \ + -i "$SPEC" \ + -g typescript-fetch \ + --additional-properties=modelPropertyNaming=camelCase \ + --reserved-words-mappings public=public \ + --global-property=apiDocs=false,modelDocs=false \ + -o ./src/generated + +sed -i.bak \ + "s/objectToJSON(requestParameters\['config'\])/RegisterOutputToJSON(requestParameters['config'])/" \ + ./src/generated/apis/OutputsApi.ts +rm ./src/generated/apis/OutputsApi.ts.bak diff --git a/packages/composition-openapi/openapitools.json b/packages/composition-openapi/openapitools.json new file mode 100644 index 00000000..936223a5 --- /dev/null +++ b/packages/composition-openapi/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.24.0" + } +} diff --git a/packages/composition-openapi/package.json b/packages/composition-openapi/package.json new file mode 100644 index 00000000..19f7c428 --- /dev/null +++ b/packages/composition-openapi/package.json @@ -0,0 +1,48 @@ +{ + "name": "@fishjam-cloud/composition-openapi", + "version": "0.29.0", + "private": true, + "description": "Composition OpenAPI", + "homepage": "https://github.com/fishjam-cloud/js-server-sdk", + "author": "Fishjam Team", + "repository": { + "type": "git", + "url": "https://github.com/fishjam-cloud/js-server-sdk.git" + }, + "bugs": { + "url": "https://github.com/fishjam-cloud/js-server-sdk/issues" + }, + "license": "Apache-2.0", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "type": "module", + "files": [ + "dist" + ], + "exports": { + ".": "./dist/index.js" + }, + "scripts": { + "codegen": "sh openapi.sh", + "build": "tsup", + "typecheck": "tsc --noEmit" + }, + "tsup": { + "entry": [ + "src/index.ts" + ], + "dts": true, + "minify": false, + "format": [ + "esm" + ], + "outDir": "dist" + }, + "devDependencies": { + "@openapitools/openapi-generator-cli": "^2.18.4", + "tsup": "^8.4.0" + }, + "engines": { + "node": ">=18" + } +} diff --git a/packages/composition-openapi/src/generated/.openapi-generator-ignore b/packages/composition-openapi/src/generated/.openapi-generator-ignore new file mode 100644 index 00000000..7484ee59 --- /dev/null +++ b/packages/composition-openapi/src/generated/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/packages/composition-openapi/src/generated/.openapi-generator/FILES b/packages/composition-openapi/src/generated/.openapi-generator/FILES new file mode 100644 index 00000000..93e2a8c7 --- /dev/null +++ b/packages/composition-openapi/src/generated/.openapi-generator/FILES @@ -0,0 +1,79 @@ +apis/CompositionsApi.ts +apis/EventsApi.ts +apis/InputsApi.ts +apis/MediaTransportApi.ts +apis/OutputsApi.ts +apis/RenderersApi.ts +apis/index.ts +index.ts +models/ApiError.ts +models/AudioChannels.ts +models/AudioMixingStrategy.ts +models/AudioScene.ts +models/AudioSceneInput.ts +models/AverageAndMaxBitrate.ts +models/BoxShadow.ts +models/Component.ts +models/CompositionCreatedResponse.ts +models/CreateCompositionRequest.ts +models/EasingFunction.ts +models/EasingFunctionBounce.ts +models/EasingFunctionCubicBezier.ts +models/EasingFunctionLinear.ts +models/FontUpload.ts +models/Framerate.ts +models/H264EncoderPreset.ts +models/HorizontalAlign.ts +models/Image.ts +models/ImageSpec.ts +models/ImageSpecAuto.ts +models/ImageSpecGif.ts +models/ImageSpecJpeg.ts +models/ImageSpecPng.ts +models/ImageSpecSvg.ts +models/InputStream.ts +models/Interpolation.ts +models/Mp4Input.ts +models/OpusEncoderPreset.ts +models/OutputEndCondition.ts +models/OutputRtmpClientAudioOptions.ts +models/OutputRtmpClientVideoOptions.ts +models/OutputWhipAudioOptions.ts +models/OutputWhipVideoOptions.ts +models/Overflow.ts +models/PixelFormat.ts +models/PortOrPortRange.ts +models/RegisterInput.ts +models/RegisterInputResponse.ts +models/RegisterOutput.ts +models/RegisterTemplateOutput.ts +models/RescaleMode.ts +models/Rescaler.ts +models/Resolution.ts +models/RtmpInput.ts +models/RtmpOutput.ts +models/SendCompositionEventRequest.ts +models/Text.ts +models/TextStyle.ts +models/TextWeight.ts +models/TextWrapMode.ts +models/Tiles.ts +models/Transition.ts +models/TransportProtocol.ts +models/UnregisterInput.ts +models/UnregisterOutput.ts +models/UnregisterRenderer.ts +models/UpdateOutputRequest.ts +models/VerticalAlign.ts +models/VideoEncoderBitrate.ts +models/VideoScene.ts +models/View.ts +models/ViewDirection.ts +models/WhepInput.ts +models/WhipAudioEncoderOptions.ts +models/WhipAudioEncoderOptionsAny.ts +models/WhipAudioEncoderOptionsOpus.ts +models/WhipInput.ts +models/WhipOutput.ts +models/index.ts +runtime.ts diff --git a/packages/composition-openapi/src/generated/.openapi-generator/VERSION b/packages/composition-openapi/src/generated/.openapi-generator/VERSION new file mode 100644 index 00000000..07832195 --- /dev/null +++ b/packages/composition-openapi/src/generated/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.24.0 diff --git a/packages/composition-openapi/src/generated/apis/CompositionsApi.ts b/packages/composition-openapi/src/generated/apis/CompositionsApi.ts new file mode 100644 index 00000000..c6f7156c --- /dev/null +++ b/packages/composition-openapi/src/generated/apis/CompositionsApi.ts @@ -0,0 +1,286 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import * as runtime from '../runtime'; +import { type ApiError, ApiErrorFromJSON, ApiErrorToJSON } from '../models/ApiError'; +import { + type CompositionCreatedResponse, + CompositionCreatedResponseFromJSON, + CompositionCreatedResponseToJSON, +} from '../models/CompositionCreatedResponse'; +import { + type CreateCompositionRequest, + CreateCompositionRequestFromJSON, + CreateCompositionRequestToJSON, +} from '../models/CreateCompositionRequest'; + +export interface CreateCompositionOperationRequest { + createCompositionRequest: CreateCompositionRequest; +} + +export interface DeleteCompositionRequest { + compositionId: string; +} + +export interface ResetRequest { + compositionId: string; +} + +export interface StartRequest { + compositionId: string; +} + +/** + * + */ +export class CompositionsApi extends runtime.BaseAPI { + /** + * Creates request options for createComposition without sending the request + */ + async createCompositionRequestOpts( + requestParameters: CreateCompositionOperationRequest + ): Promise { + if (requestParameters['createCompositionRequest'] == null) { + throw new runtime.RequiredError( + 'createCompositionRequest', + 'Required parameter "createCompositionRequest" was null or undefined when calling createComposition().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition`; + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: CreateCompositionRequestToJSON(requestParameters['createCompositionRequest']), + }; + } + + /** + * Create a composition + */ + async createCompositionRaw( + requestParameters: CreateCompositionOperationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.createCompositionRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => CompositionCreatedResponseFromJSON(jsonValue)); + } + + /** + * Create a composition + */ + async createComposition( + requestParameters: CreateCompositionOperationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.createCompositionRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for deleteComposition without sending the request + */ + async deleteCompositionRequestOpts(requestParameters: DeleteCompositionRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling deleteComposition().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + + return { + path: urlPath, + method: 'DELETE', + headers: headerParameters, + query: queryParameters, + }; + } + + /** + * Delete a composition + */ + async deleteCompositionRaw( + requestParameters: DeleteCompositionRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.deleteCompositionRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.VoidApiResponse(response); + } + + /** + * Delete a composition + */ + async deleteComposition( + requestParameters: DeleteCompositionRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + await this.deleteCompositionRaw(requestParameters, initOverrides); + } + + /** + * Creates request options for reset without sending the request + */ + async resetRequestOpts(requestParameters: ResetRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling reset().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/reset`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + }; + } + + /** + * Reset a composition + */ + async resetRaw( + requestParameters: ResetRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.resetRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Reset a composition + */ + async reset( + requestParameters: ResetRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.resetRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for start without sending the request + */ + async startRequestOpts(requestParameters: StartRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling start().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/start`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + }; + } + + /** + * Start a composition + */ + async startRaw( + requestParameters: StartRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.startRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Start a composition + */ + async start( + requestParameters: StartRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.startRaw(requestParameters, initOverrides); + return await response.value(); + } +} diff --git a/packages/composition-openapi/src/generated/apis/EventsApi.ts b/packages/composition-openapi/src/generated/apis/EventsApi.ts new file mode 100644 index 00000000..167a3dae --- /dev/null +++ b/packages/composition-openapi/src/generated/apis/EventsApi.ts @@ -0,0 +1,102 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import * as runtime from '../runtime'; +import { type ApiError, ApiErrorFromJSON, ApiErrorToJSON } from '../models/ApiError'; +import { + type SendCompositionEventRequest, + SendCompositionEventRequestFromJSON, + SendCompositionEventRequestToJSON, +} from '../models/SendCompositionEventRequest'; + +export interface SendCompositionEventOperationRequest { + compositionId: string; + sendCompositionEventRequest: SendCompositionEventRequest; +} + +/** + * + */ +export class EventsApi extends runtime.BaseAPI { + /** + * Creates request options for sendCompositionEvent without sending the request + */ + async sendCompositionEventRequestOpts( + requestParameters: SendCompositionEventOperationRequest + ): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling sendCompositionEvent().' + ); + } + + if (requestParameters['sendCompositionEventRequest'] == null) { + throw new runtime.RequiredError( + 'sendCompositionEventRequest', + 'Required parameter "sendCompositionEventRequest" was null or undefined when calling sendCompositionEvent().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/event`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: SendCompositionEventRequestToJSON(requestParameters['sendCompositionEventRequest']), + }; + } + + /** + * Send an event to templates + */ + async sendCompositionEventRaw( + requestParameters: SendCompositionEventOperationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.sendCompositionEventRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Send an event to templates + */ + async sendCompositionEvent( + requestParameters: SendCompositionEventOperationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.sendCompositionEventRaw(requestParameters, initOverrides); + return await response.value(); + } +} diff --git a/packages/composition-openapi/src/generated/apis/InputsApi.ts b/packages/composition-openapi/src/generated/apis/InputsApi.ts new file mode 100644 index 00000000..f73f985c --- /dev/null +++ b/packages/composition-openapi/src/generated/apis/InputsApi.ts @@ -0,0 +1,194 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import * as runtime from '../runtime'; +import { type ApiError, ApiErrorFromJSON, ApiErrorToJSON } from '../models/ApiError'; +import { type RegisterInput, RegisterInputFromJSON, RegisterInputToJSON } from '../models/RegisterInput'; +import { + type RegisterInputResponse, + RegisterInputResponseFromJSON, + RegisterInputResponseToJSON, +} from '../models/RegisterInputResponse'; +import { type UnregisterInput, UnregisterInputFromJSON, UnregisterInputToJSON } from '../models/UnregisterInput'; + +export interface RegisterInputRequest { + compositionId: string; + inputId: string; + registerInput: RegisterInput; +} + +export interface UnregisterInputRequest { + compositionId: string; + inputId: string; + unregisterInput: UnregisterInput; +} + +/** + * + */ +export class InputsApi extends runtime.BaseAPI { + /** + * Creates request options for registerInput without sending the request + */ + async registerInputRequestOpts(requestParameters: RegisterInputRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling registerInput().' + ); + } + + if (requestParameters['inputId'] == null) { + throw new runtime.RequiredError( + 'inputId', + 'Required parameter "inputId" was null or undefined when calling registerInput().' + ); + } + + if (requestParameters['registerInput'] == null) { + throw new runtime.RequiredError( + 'registerInput', + 'Required parameter "registerInput" was null or undefined when calling registerInput().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/input/{input_id}/register`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{input_id}', encodeURIComponent(String(requestParameters['inputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: RegisterInputToJSON(requestParameters['registerInput']), + }; + } + + /** + * Register an input + */ + async registerInputRaw( + requestParameters: RegisterInputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.registerInputRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => RegisterInputResponseFromJSON(jsonValue)); + } + + /** + * Register an input + */ + async registerInput( + requestParameters: RegisterInputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.registerInputRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for unregisterInput without sending the request + */ + async unregisterInputRequestOpts(requestParameters: UnregisterInputRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling unregisterInput().' + ); + } + + if (requestParameters['inputId'] == null) { + throw new runtime.RequiredError( + 'inputId', + 'Required parameter "inputId" was null or undefined when calling unregisterInput().' + ); + } + + if (requestParameters['unregisterInput'] == null) { + throw new runtime.RequiredError( + 'unregisterInput', + 'Required parameter "unregisterInput" was null or undefined when calling unregisterInput().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/input/{input_id}/unregister`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{input_id}', encodeURIComponent(String(requestParameters['inputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: UnregisterInputToJSON(requestParameters['unregisterInput']), + }; + } + + /** + * Unregister an input + */ + async unregisterInputRaw( + requestParameters: UnregisterInputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.unregisterInputRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Unregister an input + */ + async unregisterInput( + requestParameters: UnregisterInputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.unregisterInputRaw(requestParameters, initOverrides); + return await response.value(); + } +} diff --git a/packages/composition-openapi/src/generated/apis/MediaTransportApi.ts b/packages/composition-openapi/src/generated/apis/MediaTransportApi.ts new file mode 100644 index 00000000..7642fd11 --- /dev/null +++ b/packages/composition-openapi/src/generated/apis/MediaTransportApi.ts @@ -0,0 +1,195 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import * as runtime from '../runtime'; +import { type ApiError, ApiErrorFromJSON, ApiErrorToJSON } from '../models/ApiError'; + +export interface WhepOfferRequest { + compositionId: string; + outputId: string; + body: string; +} + +export interface WhipOfferRequest { + compositionId: string; + inputId: string; + body: string; +} + +/** + * + */ +export class MediaTransportApi extends runtime.BaseAPI { + /** + * Creates request options for whepOffer without sending the request + */ + async whepOfferRequestOpts(requestParameters: WhepOfferRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling whepOffer().' + ); + } + + if (requestParameters['outputId'] == null) { + throw new runtime.RequiredError( + 'outputId', + 'Required parameter "outputId" was null or undefined when calling whepOffer().' + ); + } + + if (requestParameters['body'] == null) { + throw new runtime.RequiredError( + 'body', + 'Required parameter "body" was null or undefined when calling whepOffer().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/sdp'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/whep/{output_id}`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{output_id}', encodeURIComponent(String(requestParameters['outputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: requestParameters['body'] as any, + }; + } + + /** + * Play an output over WHEP + */ + async whepOfferRaw( + requestParameters: WhepOfferRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.whepOfferRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + if (this.isJsonMime(response.headers.get('content-type'))) { + return new runtime.JSONApiResponse(response); + } else { + return new runtime.TextApiResponse(response) as any; + } + } + + /** + * Play an output over WHEP + */ + async whepOffer( + requestParameters: WhepOfferRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.whepOfferRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for whipOffer without sending the request + */ + async whipOfferRequestOpts(requestParameters: WhipOfferRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling whipOffer().' + ); + } + + if (requestParameters['inputId'] == null) { + throw new runtime.RequiredError( + 'inputId', + 'Required parameter "inputId" was null or undefined when calling whipOffer().' + ); + } + + if (requestParameters['body'] == null) { + throw new runtime.RequiredError( + 'body', + 'Required parameter "body" was null or undefined when calling whipOffer().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/sdp'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/whip/{input_id}`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{input_id}', encodeURIComponent(String(requestParameters['inputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: requestParameters['body'] as any, + }; + } + + /** + * Publish to an input over WHIP + */ + async whipOfferRaw( + requestParameters: WhipOfferRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.whipOfferRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + if (this.isJsonMime(response.headers.get('content-type'))) { + return new runtime.JSONApiResponse(response); + } else { + return new runtime.TextApiResponse(response) as any; + } + } + + /** + * Publish to an input over WHIP + */ + async whipOffer( + requestParameters: WhipOfferRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.whipOfferRaw(requestParameters, initOverrides); + return await response.value(); + } +} diff --git a/packages/composition-openapi/src/generated/apis/OutputsApi.ts b/packages/composition-openapi/src/generated/apis/OutputsApi.ts new file mode 100644 index 00000000..537279f6 --- /dev/null +++ b/packages/composition-openapi/src/generated/apis/OutputsApi.ts @@ -0,0 +1,464 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import * as runtime from '../runtime'; +import { type ApiError, ApiErrorFromJSON, ApiErrorToJSON } from '../models/ApiError'; +import { type RegisterOutput, RegisterOutputFromJSON, RegisterOutputToJSON } from '../models/RegisterOutput'; +import { type UnregisterOutput, UnregisterOutputFromJSON, UnregisterOutputToJSON } from '../models/UnregisterOutput'; +import { + type UpdateOutputRequest, + UpdateOutputRequestFromJSON, + UpdateOutputRequestToJSON, +} from '../models/UpdateOutputRequest'; + +export interface RegisterOutputRequest { + compositionId: string; + outputId: string; + registerOutput: RegisterOutput; +} + +export interface RegisterTemplateOutputRequest { + compositionId: string; + outputId: string; + config: RegisterOutput; + template: Blob; +} + +export interface RequestKeyframeRequest { + compositionId: string; + outputId: string; +} + +export interface UnregisterOutputRequest { + compositionId: string; + outputId: string; + unregisterOutput: UnregisterOutput; +} + +export interface UpdateOutputOperationRequest { + compositionId: string; + outputId: string; + updateOutputRequest: UpdateOutputRequest; +} + +/** + * + */ +export class OutputsApi extends runtime.BaseAPI { + /** + * Creates request options for registerOutput without sending the request + */ + async registerOutputRequestOpts(requestParameters: RegisterOutputRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling registerOutput().' + ); + } + + if (requestParameters['outputId'] == null) { + throw new runtime.RequiredError( + 'outputId', + 'Required parameter "outputId" was null or undefined when calling registerOutput().' + ); + } + + if (requestParameters['registerOutput'] == null) { + throw new runtime.RequiredError( + 'registerOutput', + 'Required parameter "registerOutput" was null or undefined when calling registerOutput().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/output/{output_id}/register`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{output_id}', encodeURIComponent(String(requestParameters['outputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: RegisterOutputToJSON(requestParameters['registerOutput']), + }; + } + + /** + * Register an output + */ + async registerOutputRaw( + requestParameters: RegisterOutputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.registerOutputRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Register an output + */ + async registerOutput( + requestParameters: RegisterOutputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.registerOutputRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for registerTemplateOutput without sending the request + */ + async registerTemplateOutputRequestOpts( + requestParameters: RegisterTemplateOutputRequest + ): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling registerTemplateOutput().' + ); + } + + if (requestParameters['outputId'] == null) { + throw new runtime.RequiredError( + 'outputId', + 'Required parameter "outputId" was null or undefined when calling registerTemplateOutput().' + ); + } + + if (requestParameters['config'] == null) { + throw new runtime.RequiredError( + 'config', + 'Required parameter "config" was null or undefined when calling registerTemplateOutput().' + ); + } + + if (requestParameters['template'] == null) { + throw new runtime.RequiredError( + 'template', + 'Required parameter "template" was null or undefined when calling registerTemplateOutput().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + const consumes: runtime.Consume[] = [{ contentType: 'multipart/form-data' }]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + + if (requestParameters['config'] != null) { + formParams.append( + 'config', + new Blob([JSON.stringify(RegisterOutputToJSON(requestParameters['config']))], { type: 'application/json' }) + ); + } + + if (requestParameters['template'] != null) { + formParams.append('template', requestParameters['template'] as any); + } + + let urlPath = `/api/composition/{composition_id}/output/{output_id}/template`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{output_id}', encodeURIComponent(String(requestParameters['outputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: formParams, + }; + } + + /** + * Register a templated output + */ + async registerTemplateOutputRaw( + requestParameters: RegisterTemplateOutputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.registerTemplateOutputRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Register a templated output + */ + async registerTemplateOutput( + requestParameters: RegisterTemplateOutputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.registerTemplateOutputRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for requestKeyframe without sending the request + */ + async requestKeyframeRequestOpts(requestParameters: RequestKeyframeRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling requestKeyframe().' + ); + } + + if (requestParameters['outputId'] == null) { + throw new runtime.RequiredError( + 'outputId', + 'Required parameter "outputId" was null or undefined when calling requestKeyframe().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/output/{output_id}/request_keyframe`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{output_id}', encodeURIComponent(String(requestParameters['outputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + }; + } + + /** + * Request a keyframe + */ + async requestKeyframeRaw( + requestParameters: RequestKeyframeRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.requestKeyframeRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Request a keyframe + */ + async requestKeyframe( + requestParameters: RequestKeyframeRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.requestKeyframeRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for unregisterOutput without sending the request + */ + async unregisterOutputRequestOpts(requestParameters: UnregisterOutputRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling unregisterOutput().' + ); + } + + if (requestParameters['outputId'] == null) { + throw new runtime.RequiredError( + 'outputId', + 'Required parameter "outputId" was null or undefined when calling unregisterOutput().' + ); + } + + if (requestParameters['unregisterOutput'] == null) { + throw new runtime.RequiredError( + 'unregisterOutput', + 'Required parameter "unregisterOutput" was null or undefined when calling unregisterOutput().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/output/{output_id}/unregister`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{output_id}', encodeURIComponent(String(requestParameters['outputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: UnregisterOutputToJSON(requestParameters['unregisterOutput']), + }; + } + + /** + * Unregister an output + */ + async unregisterOutputRaw( + requestParameters: UnregisterOutputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.unregisterOutputRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Unregister an output + */ + async unregisterOutput( + requestParameters: UnregisterOutputRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.unregisterOutputRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for updateOutput without sending the request + */ + async updateOutputRequestOpts(requestParameters: UpdateOutputOperationRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling updateOutput().' + ); + } + + if (requestParameters['outputId'] == null) { + throw new runtime.RequiredError( + 'outputId', + 'Required parameter "outputId" was null or undefined when calling updateOutput().' + ); + } + + if (requestParameters['updateOutputRequest'] == null) { + throw new runtime.RequiredError( + 'updateOutputRequest', + 'Required parameter "updateOutputRequest" was null or undefined when calling updateOutput().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/output/{output_id}/update`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{output_id}', encodeURIComponent(String(requestParameters['outputId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: UpdateOutputRequestToJSON(requestParameters['updateOutputRequest']), + }; + } + + /** + * Update an output\'s scene + */ + async updateOutputRaw( + requestParameters: UpdateOutputOperationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.updateOutputRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Update an output\'s scene + */ + async updateOutput( + requestParameters: UpdateOutputOperationRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.updateOutputRaw(requestParameters, initOverrides); + return await response.value(); + } +} diff --git a/packages/composition-openapi/src/generated/apis/RenderersApi.ts b/packages/composition-openapi/src/generated/apis/RenderersApi.ts new file mode 100644 index 00000000..69a795c8 --- /dev/null +++ b/packages/composition-openapi/src/generated/apis/RenderersApi.ts @@ -0,0 +1,282 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import * as runtime from '../runtime'; +import { type ApiError, ApiErrorFromJSON, ApiErrorToJSON } from '../models/ApiError'; +import { type ImageSpec, ImageSpecFromJSON, ImageSpecToJSON } from '../models/ImageSpec'; +import { + type UnregisterRenderer, + UnregisterRendererFromJSON, + UnregisterRendererToJSON, +} from '../models/UnregisterRenderer'; + +export interface RegisterFontRequest { + compositionId: string; + font: Blob; +} + +export interface RegisterImageRequest { + compositionId: string; + imageId: string; + imageSpec: ImageSpec; +} + +export interface UnregisterImageRequest { + compositionId: string; + imageId: string; + unregisterRenderer: UnregisterRenderer; +} + +/** + * + */ +export class RenderersApi extends runtime.BaseAPI { + /** + * Creates request options for registerFont without sending the request + */ + async registerFontRequestOpts(requestParameters: RegisterFontRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling registerFont().' + ); + } + + if (requestParameters['font'] == null) { + throw new runtime.RequiredError( + 'font', + 'Required parameter "font" was null or undefined when calling registerFont().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + const consumes: runtime.Consume[] = [{ contentType: 'multipart/form-data' }]; + // @ts-ignore: canConsumeForm may be unused + const canConsumeForm = runtime.canConsumeForm(consumes); + + let formParams: { append(param: string, value: any): any }; + let useForm = false; + // use FormData to transmit files using content-type "multipart/form-data" + useForm = canConsumeForm; + if (useForm) { + formParams = new FormData(); + } else { + formParams = new URLSearchParams(); + } + + if (requestParameters['font'] != null) { + formParams.append('font', requestParameters['font'] as any); + } + + let urlPath = `/api/composition/{composition_id}/font/register`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: formParams, + }; + } + + /** + * Register a font + */ + async registerFontRaw( + requestParameters: RegisterFontRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.registerFontRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Register a font + */ + async registerFont( + requestParameters: RegisterFontRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.registerFontRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for registerImage without sending the request + */ + async registerImageRequestOpts(requestParameters: RegisterImageRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling registerImage().' + ); + } + + if (requestParameters['imageId'] == null) { + throw new runtime.RequiredError( + 'imageId', + 'Required parameter "imageId" was null or undefined when calling registerImage().' + ); + } + + if (requestParameters['imageSpec'] == null) { + throw new runtime.RequiredError( + 'imageSpec', + 'Required parameter "imageSpec" was null or undefined when calling registerImage().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/image/{image_id}/register`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{image_id}', encodeURIComponent(String(requestParameters['imageId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: ImageSpecToJSON(requestParameters['imageSpec']), + }; + } + + /** + * Register an image + */ + async registerImageRaw( + requestParameters: RegisterImageRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.registerImageRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Register an image + */ + async registerImage( + requestParameters: RegisterImageRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.registerImageRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * Creates request options for unregisterImage without sending the request + */ + async unregisterImageRequestOpts(requestParameters: UnregisterImageRequest): Promise { + if (requestParameters['compositionId'] == null) { + throw new runtime.RequiredError( + 'compositionId', + 'Required parameter "compositionId" was null or undefined when calling unregisterImage().' + ); + } + + if (requestParameters['imageId'] == null) { + throw new runtime.RequiredError( + 'imageId', + 'Required parameter "imageId" was null or undefined when calling unregisterImage().' + ); + } + + if (requestParameters['unregisterRenderer'] == null) { + throw new runtime.RequiredError( + 'unregisterRenderer', + 'Required parameter "unregisterRenderer" was null or undefined when calling unregisterImage().' + ); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.accessToken) { + const token = this.configuration.accessToken; + const tokenString = await token('BearerAuth', []); + + if (tokenString) { + headerParameters['Authorization'] = `Bearer ${tokenString}`; + } + } + + let urlPath = `/api/composition/{composition_id}/image/{image_id}/unregister`; + urlPath = urlPath.replace('{composition_id}', encodeURIComponent(String(requestParameters['compositionId']))); + urlPath = urlPath.replace('{image_id}', encodeURIComponent(String(requestParameters['imageId']))); + + return { + path: urlPath, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: UnregisterRendererToJSON(requestParameters['unregisterRenderer']), + }; + } + + /** + * Unregister an image + */ + async unregisterImageRaw( + requestParameters: UnregisterImageRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise> { + const requestOptions = await this.unregisterImageRequestOpts(requestParameters); + const response = await this.request(requestOptions, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Unregister an image + */ + async unregisterImage( + requestParameters: UnregisterImageRequest, + initOverrides?: RequestInit | runtime.InitOverrideFunction + ): Promise { + const response = await this.unregisterImageRaw(requestParameters, initOverrides); + return await response.value(); + } +} diff --git a/packages/composition-openapi/src/generated/apis/index.ts b/packages/composition-openapi/src/generated/apis/index.ts new file mode 100644 index 00000000..c099c6e5 --- /dev/null +++ b/packages/composition-openapi/src/generated/apis/index.ts @@ -0,0 +1,8 @@ +/* tslint:disable */ +/* eslint-disable */ +export * from './CompositionsApi'; +export * from './EventsApi'; +export * from './InputsApi'; +export * from './MediaTransportApi'; +export * from './OutputsApi'; +export * from './RenderersApi'; diff --git a/packages/composition-openapi/src/generated/index.ts b/packages/composition-openapi/src/generated/index.ts new file mode 100644 index 00000000..bebe8bbb --- /dev/null +++ b/packages/composition-openapi/src/generated/index.ts @@ -0,0 +1,5 @@ +/* tslint:disable */ +/* eslint-disable */ +export * from './runtime'; +export * from './apis/index'; +export * from './models/index'; diff --git a/packages/composition-openapi/src/generated/models/ApiError.ts b/packages/composition-openapi/src/generated/models/ApiError.ts new file mode 100644 index 00000000..979457f5 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/ApiError.ts @@ -0,0 +1,63 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface ApiError + */ +export interface ApiError { + /** + * + * @type {string} + * @memberof ApiError + */ + message: string; +} + +/** + * Check if a given object implements the ApiError interface. + */ +export function instanceOfApiError(value: object): value is ApiError { + if (!('message' in value) || value['message'] === undefined) return false; + return true; +} + +export function ApiErrorFromJSON(json: any): ApiError { + return ApiErrorFromJSONTyped(json, false); +} + +export function ApiErrorFromJSONTyped(json: any, ignoreDiscriminator: boolean): ApiError { + if (json == null) { + return json; + } + return { + message: json['message'], + }; +} + +export function ApiErrorToJSON(json: any): ApiError { + return ApiErrorToJSONTyped(json, false); +} + +export function ApiErrorToJSONTyped(value?: ApiError | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + message: value['message'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/AudioChannels.ts b/packages/composition-openapi/src/generated/models/AudioChannels.ts new file mode 100644 index 00000000..0a43e08c --- /dev/null +++ b/packages/composition-openapi/src/generated/models/AudioChannels.ts @@ -0,0 +1,50 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const AudioChannels = { + Mono: 'mono', + Stereo: 'stereo', +} as const; +export type AudioChannels = (typeof AudioChannels)[keyof typeof AudioChannels]; + +export function instanceOfAudioChannels(value: any): boolean { + for (const key in AudioChannels) { + if (Object.prototype.hasOwnProperty.call(AudioChannels, key)) { + if (AudioChannels[key as keyof typeof AudioChannels] === value) { + return true; + } + } + } + return false; +} + +export function AudioChannelsFromJSON(json: any): AudioChannels { + return AudioChannelsFromJSONTyped(json, false); +} + +export function AudioChannelsFromJSONTyped(json: any, ignoreDiscriminator: boolean): AudioChannels { + return json as AudioChannels; +} + +export function AudioChannelsToJSON(value?: AudioChannels | null): any { + return value as any; +} + +export function AudioChannelsToJSONTyped(value: any, ignoreDiscriminator: boolean): AudioChannels { + return value as AudioChannels; +} diff --git a/packages/composition-openapi/src/generated/models/AudioMixingStrategy.ts b/packages/composition-openapi/src/generated/models/AudioMixingStrategy.ts new file mode 100644 index 00000000..b17fbe92 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/AudioMixingStrategy.ts @@ -0,0 +1,50 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const AudioMixingStrategy = { + SumClip: 'sum_clip', + SumScale: 'sum_scale', +} as const; +export type AudioMixingStrategy = (typeof AudioMixingStrategy)[keyof typeof AudioMixingStrategy]; + +export function instanceOfAudioMixingStrategy(value: any): boolean { + for (const key in AudioMixingStrategy) { + if (Object.prototype.hasOwnProperty.call(AudioMixingStrategy, key)) { + if (AudioMixingStrategy[key as keyof typeof AudioMixingStrategy] === value) { + return true; + } + } + } + return false; +} + +export function AudioMixingStrategyFromJSON(json: any): AudioMixingStrategy { + return AudioMixingStrategyFromJSONTyped(json, false); +} + +export function AudioMixingStrategyFromJSONTyped(json: any, ignoreDiscriminator: boolean): AudioMixingStrategy { + return json as AudioMixingStrategy; +} + +export function AudioMixingStrategyToJSON(value?: AudioMixingStrategy | null): any { + return value as any; +} + +export function AudioMixingStrategyToJSONTyped(value: any, ignoreDiscriminator: boolean): AudioMixingStrategy { + return value as AudioMixingStrategy; +} diff --git a/packages/composition-openapi/src/generated/models/AudioScene.ts b/packages/composition-openapi/src/generated/models/AudioScene.ts new file mode 100644 index 00000000..e557aeca --- /dev/null +++ b/packages/composition-openapi/src/generated/models/AudioScene.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { AudioSceneInput } from './AudioSceneInput'; +import { + AudioSceneInputFromJSON, + AudioSceneInputFromJSONTyped, + AudioSceneInputToJSON, + AudioSceneInputToJSONTyped, +} from './AudioSceneInput'; + +/** + * + * @export + * @interface AudioScene + */ +export interface AudioScene { + /** + * + * @type {Array} + * @memberof AudioScene + */ + inputs: Array; +} + +/** + * Check if a given object implements the AudioScene interface. + */ +export function instanceOfAudioScene(value: object): value is AudioScene { + if (!('inputs' in value) || value['inputs'] === undefined) return false; + return true; +} + +export function AudioSceneFromJSON(json: any): AudioScene { + return AudioSceneFromJSONTyped(json, false); +} + +export function AudioSceneFromJSONTyped(json: any, ignoreDiscriminator: boolean): AudioScene { + if (json == null) { + return json; + } + return { + inputs: (json['inputs'] as Array).map(AudioSceneInputFromJSON), + }; +} + +export function AudioSceneToJSON(json: any): AudioScene { + return AudioSceneToJSONTyped(json, false); +} + +export function AudioSceneToJSONTyped(value?: AudioScene | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + inputs: (value['inputs'] as Array).map(AudioSceneInputToJSON), + }; +} diff --git a/packages/composition-openapi/src/generated/models/AudioSceneInput.ts b/packages/composition-openapi/src/generated/models/AudioSceneInput.ts new file mode 100644 index 00000000..7a32622d --- /dev/null +++ b/packages/composition-openapi/src/generated/models/AudioSceneInput.ts @@ -0,0 +1,76 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface AudioSceneInput + */ +export interface AudioSceneInput { + /** + * + * @type {string} + * @memberof AudioSceneInput + */ + inputId: string; + /** + * (**default=`1.0`**) float in `[0, 2]` range representing input volume + * @type {number} + * @memberof AudioSceneInput + */ + volume?: number | null; +} + +/** + * Check if a given object implements the AudioSceneInput interface. + */ +export function instanceOfAudioSceneInput(value: object): value is AudioSceneInput { + if ( + (!('inputId' in (value as Record)) && !('input_id' in (value as Record))) || + ((value as Record)['inputId'] === undefined && + (value as Record)['input_id'] === undefined) + ) + return false; + return true; +} + +export function AudioSceneInputFromJSON(json: any): AudioSceneInput { + return AudioSceneInputFromJSONTyped(json, false); +} + +export function AudioSceneInputFromJSONTyped(json: any, ignoreDiscriminator: boolean): AudioSceneInput { + if (json == null) { + return json; + } + return { + inputId: json['input_id'], + volume: json['volume'] === undefined ? undefined : json['volume'] === null ? null : json['volume'], + }; +} + +export function AudioSceneInputToJSON(json: any): AudioSceneInput { + return AudioSceneInputToJSONTyped(json, false); +} + +export function AudioSceneInputToJSONTyped(value?: AudioSceneInput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + input_id: value['inputId'], + volume: value['volume'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/AverageAndMaxBitrate.ts b/packages/composition-openapi/src/generated/models/AverageAndMaxBitrate.ts new file mode 100644 index 00000000..7a606041 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/AverageAndMaxBitrate.ts @@ -0,0 +1,86 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface AverageAndMaxBitrate + */ +export interface AverageAndMaxBitrate { + /** + * Average bitrate measured in bits/second. Encoder will try to keep the bitrate around the provided average, + * but may temporarily increase it to the provided max bitrate. + * @type {number} + * @memberof AverageAndMaxBitrate + */ + averageBitrate: number; + /** + * Max bitrate measured in bits/second. + * @type {number} + * @memberof AverageAndMaxBitrate + */ + maxBitrate: number; +} + +/** + * Check if a given object implements the AverageAndMaxBitrate interface. + */ +export function instanceOfAverageAndMaxBitrate(value: object): value is AverageAndMaxBitrate { + if ( + (!('averageBitrate' in (value as Record)) && !('average_bitrate' in (value as Record))) || + ((value as Record)['averageBitrate'] === undefined && + (value as Record)['average_bitrate'] === undefined) + ) + return false; + if ( + (!('maxBitrate' in (value as Record)) && !('max_bitrate' in (value as Record))) || + ((value as Record)['maxBitrate'] === undefined && + (value as Record)['max_bitrate'] === undefined) + ) + return false; + return true; +} + +export function AverageAndMaxBitrateFromJSON(json: any): AverageAndMaxBitrate { + return AverageAndMaxBitrateFromJSONTyped(json, false); +} + +export function AverageAndMaxBitrateFromJSONTyped(json: any, ignoreDiscriminator: boolean): AverageAndMaxBitrate { + if (json == null) { + return json; + } + return { + averageBitrate: json['average_bitrate'], + maxBitrate: json['max_bitrate'], + }; +} + +export function AverageAndMaxBitrateToJSON(json: any): AverageAndMaxBitrate { + return AverageAndMaxBitrateToJSONTyped(json, false); +} + +export function AverageAndMaxBitrateToJSONTyped( + value?: AverageAndMaxBitrate | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + average_bitrate: value['averageBitrate'], + max_bitrate: value['maxBitrate'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/BoxShadow.ts b/packages/composition-openapi/src/generated/models/BoxShadow.ts new file mode 100644 index 00000000..a6b7f103 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/BoxShadow.ts @@ -0,0 +1,87 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface BoxShadow + */ +export interface BoxShadow { + /** + * + * @type {number} + * @memberof BoxShadow + */ + offsetX?: number | null; + /** + * + * @type {number} + * @memberof BoxShadow + */ + offsetY?: number | null; + /** + * + * @type {string} + * @memberof BoxShadow + */ + color?: string | null; + /** + * + * @type {number} + * @memberof BoxShadow + */ + blurRadius?: number | null; +} + +/** + * Check if a given object implements the BoxShadow interface. + */ +export function instanceOfBoxShadow(value: object): value is BoxShadow { + return true; +} + +export function BoxShadowFromJSON(json: any): BoxShadow { + return BoxShadowFromJSONTyped(json, false); +} + +export function BoxShadowFromJSONTyped(json: any, ignoreDiscriminator: boolean): BoxShadow { + if (json == null) { + return json; + } + return { + offsetX: json['offset_x'] === undefined ? undefined : json['offset_x'] === null ? null : json['offset_x'], + offsetY: json['offset_y'] === undefined ? undefined : json['offset_y'] === null ? null : json['offset_y'], + color: json['color'] === undefined ? undefined : json['color'] === null ? null : json['color'], + blurRadius: + json['blur_radius'] === undefined ? undefined : json['blur_radius'] === null ? null : json['blur_radius'], + }; +} + +export function BoxShadowToJSON(json: any): BoxShadow { + return BoxShadowToJSONTyped(json, false); +} + +export function BoxShadowToJSONTyped(value?: BoxShadow | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + offset_x: value['offsetX'], + offset_y: value['offsetY'], + color: value['color'], + blur_radius: value['blurRadius'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/Component.ts b/packages/composition-openapi/src/generated/models/Component.ts new file mode 100644 index 00000000..63014fa7 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Component.ts @@ -0,0 +1,97 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { Image } from './Image'; +import { instanceOfImage, ImageFromJSON, ImageFromJSONTyped, ImageToJSON } from './Image'; +import type { InputStream } from './InputStream'; +import { instanceOfInputStream, InputStreamFromJSON, InputStreamFromJSONTyped, InputStreamToJSON } from './InputStream'; +import type { Rescaler } from './Rescaler'; +import { instanceOfRescaler, RescalerFromJSON, RescalerFromJSONTyped, RescalerToJSON } from './Rescaler'; +import type { Text } from './Text'; +import { instanceOfText, TextFromJSON, TextFromJSONTyped, TextToJSON } from './Text'; +import type { Tiles } from './Tiles'; +import { instanceOfTiles, TilesFromJSON, TilesFromJSONTyped, TilesToJSON } from './Tiles'; +import type { View } from './View'; +import { instanceOfView, ViewFromJSON, ViewFromJSONTyped, ViewToJSON } from './View'; + +/** + * @type Component + * + * @export + */ +export type Component = Image | InputStream | Rescaler | Text | Tiles | View; + +export function ComponentFromJSON(json: any): Component { + return ComponentFromJSONTyped(json, false); +} + +export function ComponentFromJSONTyped(json: any, ignoreDiscriminator: boolean): Component { + if (json == null) { + return json; + } + if (typeof json !== 'object') { + return json; + } + if (instanceOfImage(json)) { + return ImageFromJSONTyped(json, true); + } + if (instanceOfInputStream(json)) { + return InputStreamFromJSONTyped(json, true); + } + if (instanceOfRescaler(json)) { + return RescalerFromJSONTyped(json, true); + } + if (instanceOfText(json)) { + return TextFromJSONTyped(json, true); + } + if (instanceOfTiles(json)) { + return TilesFromJSONTyped(json, true); + } + if (instanceOfView(json)) { + return ViewFromJSONTyped(json, true); + } + return {} as any; +} + +export function ComponentToJSON(json: any): any { + return ComponentToJSONTyped(json, false); +} + +export function ComponentToJSONTyped(value?: Component | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + if (typeof value !== 'object') { + return value; + } + if (instanceOfImage(value)) { + return ImageToJSON(value as Image); + } + if (instanceOfInputStream(value)) { + return InputStreamToJSON(value as InputStream); + } + if (instanceOfRescaler(value)) { + return RescalerToJSON(value as Rescaler); + } + if (instanceOfText(value)) { + return TextToJSON(value as Text); + } + if (instanceOfTiles(value)) { + return TilesToJSON(value as Tiles); + } + if (instanceOfView(value)) { + return ViewToJSON(value as View); + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/CompositionCreatedResponse.ts b/packages/composition-openapi/src/generated/models/CompositionCreatedResponse.ts new file mode 100644 index 00000000..fd74928d --- /dev/null +++ b/packages/composition-openapi/src/generated/models/CompositionCreatedResponse.ts @@ -0,0 +1,87 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface CompositionCreatedResponse + */ +export interface CompositionCreatedResponse { + /** + * + * @type {string} + * @memberof CompositionCreatedResponse + */ + compositionId: string; + /** + * + * @type {string} + * @memberof CompositionCreatedResponse + */ + apiUrl: string; +} + +/** + * Check if a given object implements the CompositionCreatedResponse interface. + */ +export function instanceOfCompositionCreatedResponse(value: object): value is CompositionCreatedResponse { + if ( + (!('compositionId' in (value as Record)) && !('composition_id' in (value as Record))) || + ((value as Record)['compositionId'] === undefined && + (value as Record)['composition_id'] === undefined) + ) + return false; + if ( + (!('apiUrl' in (value as Record)) && !('api_url' in (value as Record))) || + ((value as Record)['apiUrl'] === undefined && (value as Record)['api_url'] === undefined) + ) + return false; + return true; +} + +export function CompositionCreatedResponseFromJSON(json: any): CompositionCreatedResponse { + return CompositionCreatedResponseFromJSONTyped(json, false); +} + +export function CompositionCreatedResponseFromJSONTyped( + json: any, + ignoreDiscriminator: boolean +): CompositionCreatedResponse { + if (json == null) { + return json; + } + return { + compositionId: json['composition_id'], + apiUrl: json['api_url'], + }; +} + +export function CompositionCreatedResponseToJSON(json: any): CompositionCreatedResponse { + return CompositionCreatedResponseToJSONTyped(json, false); +} + +export function CompositionCreatedResponseToJSONTyped( + value?: CompositionCreatedResponse | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + composition_id: value['compositionId'], + api_url: value['apiUrl'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/CreateCompositionRequest.ts b/packages/composition-openapi/src/generated/models/CreateCompositionRequest.ts new file mode 100644 index 00000000..dceeb153 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/CreateCompositionRequest.ts @@ -0,0 +1,80 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface CreateCompositionRequest + */ +export interface CreateCompositionRequest { + /** + * If true, outputs will immediately start producing audio and video. + * If false, call `POST /api/composition/{composition_id}/start` to start the composition. + * @type {boolean} + * @memberof CreateCompositionRequest + */ + autostart?: boolean; + /** + * If true (default), the composition will be cleaned up after 5 minutes when all **inputs** + * have zero bitrate, regardless of output bitrate. This prevents circular liveness when + * composition output is sent to a stream. + * If false, cleanup only triggers when both inputs and outputs have zero bitrate. + * @type {boolean} + * @memberof CreateCompositionRequest + */ + cleanupWithoutInputs?: boolean; +} + +/** + * Check if a given object implements the CreateCompositionRequest interface. + */ +export function instanceOfCreateCompositionRequest(value: object): value is CreateCompositionRequest { + return true; +} + +export function CreateCompositionRequestFromJSON(json: any): CreateCompositionRequest { + return CreateCompositionRequestFromJSONTyped(json, false); +} + +export function CreateCompositionRequestFromJSONTyped( + json: any, + ignoreDiscriminator: boolean +): CreateCompositionRequest { + if (json == null) { + return json; + } + return { + autostart: json['autostart'] == null ? undefined : json['autostart'], + cleanupWithoutInputs: json['cleanup_without_inputs'] == null ? undefined : json['cleanup_without_inputs'], + }; +} + +export function CreateCompositionRequestToJSON(json: any): CreateCompositionRequest { + return CreateCompositionRequestToJSONTyped(json, false); +} + +export function CreateCompositionRequestToJSONTyped( + value?: CreateCompositionRequest | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + autostart: value['autostart'], + cleanup_without_inputs: value['cleanupWithoutInputs'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/EasingFunction.ts b/packages/composition-openapi/src/generated/models/EasingFunction.ts new file mode 100644 index 00000000..e5f2f794 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/EasingFunction.ts @@ -0,0 +1,92 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { EasingFunctionBounce } from './EasingFunctionBounce'; +import { + instanceOfEasingFunctionBounce, + EasingFunctionBounceFromJSON, + EasingFunctionBounceFromJSONTyped, + EasingFunctionBounceToJSON, +} from './EasingFunctionBounce'; +import type { EasingFunctionCubicBezier } from './EasingFunctionCubicBezier'; +import { + instanceOfEasingFunctionCubicBezier, + EasingFunctionCubicBezierFromJSON, + EasingFunctionCubicBezierFromJSONTyped, + EasingFunctionCubicBezierToJSON, +} from './EasingFunctionCubicBezier'; +import type { EasingFunctionLinear } from './EasingFunctionLinear'; +import { + instanceOfEasingFunctionLinear, + EasingFunctionLinearFromJSON, + EasingFunctionLinearFromJSONTyped, + EasingFunctionLinearToJSON, +} from './EasingFunctionLinear'; + +/** + * @type EasingFunction + * Easing functions are used to interpolate between two values over time. + * + * Custom easing functions can be implemented with cubic Bézier. + * The control points are defined with `points` field by providing four numerical values: `x1`, `y1`, `x2` and `y2`. The `x1` and `x2` values have to be in the range `[0; 1]`. The cubic Bézier result is clamped to the range `[0; 1]`. + * You can find example control point configurations [here](https://easings.net/). + * @export + */ +export type EasingFunction = EasingFunctionBounce | EasingFunctionCubicBezier | EasingFunctionLinear; + +export function EasingFunctionFromJSON(json: any): EasingFunction { + return EasingFunctionFromJSONTyped(json, false); +} + +export function EasingFunctionFromJSONTyped(json: any, ignoreDiscriminator: boolean): EasingFunction { + if (json == null) { + return json; + } + if (typeof json !== 'object') { + return json; + } + if (instanceOfEasingFunctionBounce(json)) { + return EasingFunctionBounceFromJSONTyped(json, true); + } + if (instanceOfEasingFunctionCubicBezier(json)) { + return EasingFunctionCubicBezierFromJSONTyped(json, true); + } + if (instanceOfEasingFunctionLinear(json)) { + return EasingFunctionLinearFromJSONTyped(json, true); + } + return {} as any; +} + +export function EasingFunctionToJSON(json: any): any { + return EasingFunctionToJSONTyped(json, false); +} + +export function EasingFunctionToJSONTyped(value?: EasingFunction | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + if (typeof value !== 'object') { + return value; + } + if (instanceOfEasingFunctionBounce(value)) { + return EasingFunctionBounceToJSON(value as EasingFunctionBounce); + } + if (instanceOfEasingFunctionCubicBezier(value)) { + return EasingFunctionCubicBezierToJSON(value as EasingFunctionCubicBezier); + } + if (instanceOfEasingFunctionLinear(value)) { + return EasingFunctionLinearToJSON(value as EasingFunctionLinear); + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/EasingFunctionBounce.ts b/packages/composition-openapi/src/generated/models/EasingFunctionBounce.ts new file mode 100644 index 00000000..b05633c3 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/EasingFunctionBounce.ts @@ -0,0 +1,86 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface EasingFunctionBounce + */ +export interface EasingFunctionBounce { + /** + * + * @type {EasingFunctionBounceFunctionNameEnum} + * @memberof EasingFunctionBounce + */ + functionName: EasingFunctionBounceFunctionNameEnum; +} + +/** + * @export + */ +export const EasingFunctionBounceFunctionNameEnum = { + Bounce: 'bounce', +} as const; +export type EasingFunctionBounceFunctionNameEnum = + (typeof EasingFunctionBounceFunctionNameEnum)[keyof typeof EasingFunctionBounceFunctionNameEnum]; + +/** + * Check if a given object implements the EasingFunctionBounce interface. + */ +export function instanceOfEasingFunctionBounce(value: object): value is EasingFunctionBounce { + if ( + (!('functionName' in (value as Record)) && !('function_name' in (value as Record))) || + ((value as Record)['functionName'] === undefined && + (value as Record)['function_name'] === undefined) + ) + return false; + if ( + (value as Record)['functionName'] !== 'bounce' && + (value as Record)['function_name'] !== 'bounce' + ) + return false; + + return true; +} + +export function EasingFunctionBounceFromJSON(json: any): EasingFunctionBounce { + return EasingFunctionBounceFromJSONTyped(json, false); +} + +export function EasingFunctionBounceFromJSONTyped(json: any, ignoreDiscriminator: boolean): EasingFunctionBounce { + if (json == null) { + return json; + } + return { + functionName: json['function_name'], + }; +} + +export function EasingFunctionBounceToJSON(json: any): EasingFunctionBounce { + return EasingFunctionBounceToJSONTyped(json, false); +} + +export function EasingFunctionBounceToJSONTyped( + value?: EasingFunctionBounce | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + function_name: value['functionName'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/EasingFunctionCubicBezier.ts b/packages/composition-openapi/src/generated/models/EasingFunctionCubicBezier.ts new file mode 100644 index 00000000..e58d0889 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/EasingFunctionCubicBezier.ts @@ -0,0 +1,98 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface EasingFunctionCubicBezier + */ +export interface EasingFunctionCubicBezier { + /** + * + * @type {Array} + * @memberof EasingFunctionCubicBezier + */ + points: Array; + /** + * + * @type {EasingFunctionCubicBezierFunctionNameEnum} + * @memberof EasingFunctionCubicBezier + */ + functionName: EasingFunctionCubicBezierFunctionNameEnum; +} + +/** + * @export + */ +export const EasingFunctionCubicBezierFunctionNameEnum = { + CubicBezier: 'cubic_bezier', +} as const; +export type EasingFunctionCubicBezierFunctionNameEnum = + (typeof EasingFunctionCubicBezierFunctionNameEnum)[keyof typeof EasingFunctionCubicBezierFunctionNameEnum]; + +/** + * Check if a given object implements the EasingFunctionCubicBezier interface. + */ +export function instanceOfEasingFunctionCubicBezier(value: object): value is EasingFunctionCubicBezier { + if (!('points' in value) || value['points'] === undefined) return false; + if ( + (!('functionName' in (value as Record)) && !('function_name' in (value as Record))) || + ((value as Record)['functionName'] === undefined && + (value as Record)['function_name'] === undefined) + ) + return false; + if ( + (value as Record)['functionName'] !== 'cubic_bezier' && + (value as Record)['function_name'] !== 'cubic_bezier' + ) + return false; + + return true; +} + +export function EasingFunctionCubicBezierFromJSON(json: any): EasingFunctionCubicBezier { + return EasingFunctionCubicBezierFromJSONTyped(json, false); +} + +export function EasingFunctionCubicBezierFromJSONTyped( + json: any, + ignoreDiscriminator: boolean +): EasingFunctionCubicBezier { + if (json == null) { + return json; + } + return { + points: json['points'], + functionName: json['function_name'], + }; +} + +export function EasingFunctionCubicBezierToJSON(json: any): EasingFunctionCubicBezier { + return EasingFunctionCubicBezierToJSONTyped(json, false); +} + +export function EasingFunctionCubicBezierToJSONTyped( + value?: EasingFunctionCubicBezier | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + points: value['points'], + function_name: value['functionName'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/EasingFunctionLinear.ts b/packages/composition-openapi/src/generated/models/EasingFunctionLinear.ts new file mode 100644 index 00000000..45a33225 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/EasingFunctionLinear.ts @@ -0,0 +1,86 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface EasingFunctionLinear + */ +export interface EasingFunctionLinear { + /** + * + * @type {EasingFunctionLinearFunctionNameEnum} + * @memberof EasingFunctionLinear + */ + functionName: EasingFunctionLinearFunctionNameEnum; +} + +/** + * @export + */ +export const EasingFunctionLinearFunctionNameEnum = { + Linear: 'linear', +} as const; +export type EasingFunctionLinearFunctionNameEnum = + (typeof EasingFunctionLinearFunctionNameEnum)[keyof typeof EasingFunctionLinearFunctionNameEnum]; + +/** + * Check if a given object implements the EasingFunctionLinear interface. + */ +export function instanceOfEasingFunctionLinear(value: object): value is EasingFunctionLinear { + if ( + (!('functionName' in (value as Record)) && !('function_name' in (value as Record))) || + ((value as Record)['functionName'] === undefined && + (value as Record)['function_name'] === undefined) + ) + return false; + if ( + (value as Record)['functionName'] !== 'linear' && + (value as Record)['function_name'] !== 'linear' + ) + return false; + + return true; +} + +export function EasingFunctionLinearFromJSON(json: any): EasingFunctionLinear { + return EasingFunctionLinearFromJSONTyped(json, false); +} + +export function EasingFunctionLinearFromJSONTyped(json: any, ignoreDiscriminator: boolean): EasingFunctionLinear { + if (json == null) { + return json; + } + return { + functionName: json['function_name'], + }; +} + +export function EasingFunctionLinearToJSON(json: any): EasingFunctionLinear { + return EasingFunctionLinearToJSONTyped(json, false); +} + +export function EasingFunctionLinearToJSONTyped( + value?: EasingFunctionLinear | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + function_name: value['functionName'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/FontUpload.ts b/packages/composition-openapi/src/generated/models/FontUpload.ts new file mode 100644 index 00000000..c658cc55 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/FontUpload.ts @@ -0,0 +1,63 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface FontUpload + */ +export interface FontUpload { + /** + * + * @type {Blob} + * @memberof FontUpload + */ + font: Blob; +} + +/** + * Check if a given object implements the FontUpload interface. + */ +export function instanceOfFontUpload(value: object): value is FontUpload { + if (!('font' in value) || value['font'] === undefined) return false; + return true; +} + +export function FontUploadFromJSON(json: any): FontUpload { + return FontUploadFromJSONTyped(json, false); +} + +export function FontUploadFromJSONTyped(json: any, ignoreDiscriminator: boolean): FontUpload { + if (json == null) { + return json; + } + return { + font: json['font'], + }; +} + +export function FontUploadToJSON(json: any): FontUpload { + return FontUploadToJSONTyped(json, false); +} + +export function FontUploadToJSONTyped(value?: FontUpload | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + font: value['font'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/Framerate.ts b/packages/composition-openapi/src/generated/models/Framerate.ts new file mode 100644 index 00000000..021eecfb --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Framerate.ts @@ -0,0 +1,54 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * @type Framerate + * + * @export + */ +export type Framerate = number | string; + +export function FramerateFromJSON(json: any): Framerate { + return FramerateFromJSONTyped(json, false); +} + +export function FramerateFromJSONTyped(json: any, ignoreDiscriminator: boolean): Framerate { + if (json == null) { + return json; + } + if (typeof json === 'string') { + return json; + } + if (typeof json === 'number') { + return json; + } + return {} as any; +} + +export function FramerateToJSON(json: any): any { + return FramerateToJSONTyped(json, false); +} + +export function FramerateToJSONTyped(value?: Framerate | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + if (typeof value === 'string') { + return value; + } + if (typeof value === 'number') { + return value; + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/H264EncoderPreset.ts b/packages/composition-openapi/src/generated/models/H264EncoderPreset.ts new file mode 100644 index 00000000..42b61054 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/H264EncoderPreset.ts @@ -0,0 +1,58 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const H264EncoderPreset = { + Ultrafast: 'ultrafast', + Superfast: 'superfast', + Veryfast: 'veryfast', + Faster: 'faster', + Fast: 'fast', + Medium: 'medium', + Slow: 'slow', + Slower: 'slower', + Veryslow: 'veryslow', + Placebo: 'placebo', +} as const; +export type H264EncoderPreset = (typeof H264EncoderPreset)[keyof typeof H264EncoderPreset]; + +export function instanceOfH264EncoderPreset(value: any): boolean { + for (const key in H264EncoderPreset) { + if (Object.prototype.hasOwnProperty.call(H264EncoderPreset, key)) { + if (H264EncoderPreset[key as keyof typeof H264EncoderPreset] === value) { + return true; + } + } + } + return false; +} + +export function H264EncoderPresetFromJSON(json: any): H264EncoderPreset { + return H264EncoderPresetFromJSONTyped(json, false); +} + +export function H264EncoderPresetFromJSONTyped(json: any, ignoreDiscriminator: boolean): H264EncoderPreset { + return json as H264EncoderPreset; +} + +export function H264EncoderPresetToJSON(value?: H264EncoderPreset | null): any { + return value as any; +} + +export function H264EncoderPresetToJSONTyped(value: any, ignoreDiscriminator: boolean): H264EncoderPreset { + return value as H264EncoderPreset; +} diff --git a/packages/composition-openapi/src/generated/models/HorizontalAlign.ts b/packages/composition-openapi/src/generated/models/HorizontalAlign.ts new file mode 100644 index 00000000..c55a71e2 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/HorizontalAlign.ts @@ -0,0 +1,52 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const HorizontalAlign = { + Left: 'left', + Right: 'right', + Justified: 'justified', + Center: 'center', +} as const; +export type HorizontalAlign = (typeof HorizontalAlign)[keyof typeof HorizontalAlign]; + +export function instanceOfHorizontalAlign(value: any): boolean { + for (const key in HorizontalAlign) { + if (Object.prototype.hasOwnProperty.call(HorizontalAlign, key)) { + if (HorizontalAlign[key as keyof typeof HorizontalAlign] === value) { + return true; + } + } + } + return false; +} + +export function HorizontalAlignFromJSON(json: any): HorizontalAlign { + return HorizontalAlignFromJSONTyped(json, false); +} + +export function HorizontalAlignFromJSONTyped(json: any, ignoreDiscriminator: boolean): HorizontalAlign { + return json as HorizontalAlign; +} + +export function HorizontalAlignToJSON(value?: HorizontalAlign | null): any { + return value as any; +} + +export function HorizontalAlignToJSONTyped(value: any, ignoreDiscriminator: boolean): HorizontalAlign { + return value as HorizontalAlign; +} diff --git a/packages/composition-openapi/src/generated/models/Image.ts b/packages/composition-openapi/src/generated/models/Image.ts new file mode 100644 index 00000000..3181cce1 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Image.ts @@ -0,0 +1,113 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface Image + */ +export interface Image { + /** + * Id of a component. + * @type {string} + * @memberof Image + */ + id?: string | null; + /** + * Id of an image. It identifies an image registered using a `register image` request. + * @type {string} + * @memberof Image + */ + imageId: string; + /** + * Width of the image in pixels. + * If `height` is not explicitly provided, the image will automatically adjust its height to maintain its original aspect ratio relative to the width. + * @type {number} + * @memberof Image + */ + width?: number | null; + /** + * Height of the image in pixels. + * If `width` is not explicitly provided, the image will automatically adjust its width to maintain its original aspect ratio relative to the height. + * @type {number} + * @memberof Image + */ + height?: number | null; + /** + * + * @type {ImageTypeEnum} + * @memberof Image + */ + type: ImageTypeEnum; +} + +/** + * @export + */ +export const ImageTypeEnum = { + Image: 'image', +} as const; +export type ImageTypeEnum = (typeof ImageTypeEnum)[keyof typeof ImageTypeEnum]; + +/** + * Check if a given object implements the Image interface. + */ +export function instanceOfImage(value: object): value is Image { + if ( + (!('imageId' in (value as Record)) && !('image_id' in (value as Record))) || + ((value as Record)['imageId'] === undefined && + (value as Record)['image_id'] === undefined) + ) + return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'image') return false; + + return true; +} + +export function ImageFromJSON(json: any): Image { + return ImageFromJSONTyped(json, false); +} + +export function ImageFromJSONTyped(json: any, ignoreDiscriminator: boolean): Image { + if (json == null) { + return json; + } + return { + id: json['id'] === undefined ? undefined : json['id'] === null ? null : json['id'], + imageId: json['image_id'], + width: json['width'] === undefined ? undefined : json['width'] === null ? null : json['width'], + height: json['height'] === undefined ? undefined : json['height'] === null ? null : json['height'], + type: json['type'], + }; +} + +export function ImageToJSON(json: any): Image { + return ImageToJSONTyped(json, false); +} + +export function ImageToJSONTyped(value?: Image | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + id: value['id'], + image_id: value['imageId'], + width: value['width'], + height: value['height'], + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/ImageSpec.ts b/packages/composition-openapi/src/generated/models/ImageSpec.ts new file mode 100644 index 00000000..6fecaf3c --- /dev/null +++ b/packages/composition-openapi/src/generated/models/ImageSpec.ts @@ -0,0 +1,114 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { ImageSpecAuto } from './ImageSpecAuto'; +import { + instanceOfImageSpecAuto, + ImageSpecAutoFromJSON, + ImageSpecAutoFromJSONTyped, + ImageSpecAutoToJSON, +} from './ImageSpecAuto'; +import type { ImageSpecGif } from './ImageSpecGif'; +import { + instanceOfImageSpecGif, + ImageSpecGifFromJSON, + ImageSpecGifFromJSONTyped, + ImageSpecGifToJSON, +} from './ImageSpecGif'; +import type { ImageSpecJpeg } from './ImageSpecJpeg'; +import { + instanceOfImageSpecJpeg, + ImageSpecJpegFromJSON, + ImageSpecJpegFromJSONTyped, + ImageSpecJpegToJSON, +} from './ImageSpecJpeg'; +import type { ImageSpecPng } from './ImageSpecPng'; +import { + instanceOfImageSpecPng, + ImageSpecPngFromJSON, + ImageSpecPngFromJSONTyped, + ImageSpecPngToJSON, +} from './ImageSpecPng'; +import type { ImageSpecSvg } from './ImageSpecSvg'; +import { + instanceOfImageSpecSvg, + ImageSpecSvgFromJSON, + ImageSpecSvgFromJSONTyped, + ImageSpecSvgToJSON, +} from './ImageSpecSvg'; + +/** + * @type ImageSpec + * + * @export + */ +export type ImageSpec = ImageSpecAuto | ImageSpecGif | ImageSpecJpeg | ImageSpecPng | ImageSpecSvg; + +export function ImageSpecFromJSON(json: any): ImageSpec { + return ImageSpecFromJSONTyped(json, false); +} + +export function ImageSpecFromJSONTyped(json: any, ignoreDiscriminator: boolean): ImageSpec { + if (json == null) { + return json; + } + if (typeof json !== 'object') { + return json; + } + if (instanceOfImageSpecAuto(json)) { + return ImageSpecAutoFromJSONTyped(json, true); + } + if (instanceOfImageSpecGif(json)) { + return ImageSpecGifFromJSONTyped(json, true); + } + if (instanceOfImageSpecJpeg(json)) { + return ImageSpecJpegFromJSONTyped(json, true); + } + if (instanceOfImageSpecPng(json)) { + return ImageSpecPngFromJSONTyped(json, true); + } + if (instanceOfImageSpecSvg(json)) { + return ImageSpecSvgFromJSONTyped(json, true); + } + return {} as any; +} + +export function ImageSpecToJSON(json: any): any { + return ImageSpecToJSONTyped(json, false); +} + +export function ImageSpecToJSONTyped(value?: ImageSpec | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + if (typeof value !== 'object') { + return value; + } + if (instanceOfImageSpecAuto(value)) { + return ImageSpecAutoToJSON(value as ImageSpecAuto); + } + if (instanceOfImageSpecGif(value)) { + return ImageSpecGifToJSON(value as ImageSpecGif); + } + if (instanceOfImageSpecJpeg(value)) { + return ImageSpecJpegToJSON(value as ImageSpecJpeg); + } + if (instanceOfImageSpecPng(value)) { + return ImageSpecPngToJSON(value as ImageSpecPng); + } + if (instanceOfImageSpecSvg(value)) { + return ImageSpecSvgToJSON(value as ImageSpecSvg); + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/ImageSpecAuto.ts b/packages/composition-openapi/src/generated/models/ImageSpecAuto.ts new file mode 100644 index 00000000..cd6b1957 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/ImageSpecAuto.ts @@ -0,0 +1,88 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface ImageSpecAuto + */ +export interface ImageSpecAuto { + /** + * + * @type {string} + * @memberof ImageSpecAuto + */ + url: string; + /** + * + * @type {ImageSpecAutoAssetTypeEnum} + * @memberof ImageSpecAuto + */ + assetType: ImageSpecAutoAssetTypeEnum; +} + +/** + * @export + */ +export const ImageSpecAutoAssetTypeEnum = { + Auto: 'auto', +} as const; +export type ImageSpecAutoAssetTypeEnum = (typeof ImageSpecAutoAssetTypeEnum)[keyof typeof ImageSpecAutoAssetTypeEnum]; + +/** + * Check if a given object implements the ImageSpecAuto interface. + */ +export function instanceOfImageSpecAuto(value: object): value is ImageSpecAuto { + if (!('url' in value) || value['url'] === undefined) return false; + if ( + (!('assetType' in (value as Record)) && !('asset_type' in (value as Record))) || + ((value as Record)['assetType'] === undefined && + (value as Record)['asset_type'] === undefined) + ) + return false; + if ((value as Record)['assetType'] !== 'auto' && (value as Record)['asset_type'] !== 'auto') + return false; + + return true; +} + +export function ImageSpecAutoFromJSON(json: any): ImageSpecAuto { + return ImageSpecAutoFromJSONTyped(json, false); +} + +export function ImageSpecAutoFromJSONTyped(json: any, ignoreDiscriminator: boolean): ImageSpecAuto { + if (json == null) { + return json; + } + return { + url: json['url'], + assetType: json['asset_type'], + }; +} + +export function ImageSpecAutoToJSON(json: any): ImageSpecAuto { + return ImageSpecAutoToJSONTyped(json, false); +} + +export function ImageSpecAutoToJSONTyped(value?: ImageSpecAuto | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + url: value['url'], + asset_type: value['assetType'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/ImageSpecGif.ts b/packages/composition-openapi/src/generated/models/ImageSpecGif.ts new file mode 100644 index 00000000..f60762e5 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/ImageSpecGif.ts @@ -0,0 +1,88 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface ImageSpecGif + */ +export interface ImageSpecGif { + /** + * + * @type {string} + * @memberof ImageSpecGif + */ + url: string; + /** + * + * @type {ImageSpecGifAssetTypeEnum} + * @memberof ImageSpecGif + */ + assetType: ImageSpecGifAssetTypeEnum; +} + +/** + * @export + */ +export const ImageSpecGifAssetTypeEnum = { + Gif: 'gif', +} as const; +export type ImageSpecGifAssetTypeEnum = (typeof ImageSpecGifAssetTypeEnum)[keyof typeof ImageSpecGifAssetTypeEnum]; + +/** + * Check if a given object implements the ImageSpecGif interface. + */ +export function instanceOfImageSpecGif(value: object): value is ImageSpecGif { + if (!('url' in value) || value['url'] === undefined) return false; + if ( + (!('assetType' in (value as Record)) && !('asset_type' in (value as Record))) || + ((value as Record)['assetType'] === undefined && + (value as Record)['asset_type'] === undefined) + ) + return false; + if ((value as Record)['assetType'] !== 'gif' && (value as Record)['asset_type'] !== 'gif') + return false; + + return true; +} + +export function ImageSpecGifFromJSON(json: any): ImageSpecGif { + return ImageSpecGifFromJSONTyped(json, false); +} + +export function ImageSpecGifFromJSONTyped(json: any, ignoreDiscriminator: boolean): ImageSpecGif { + if (json == null) { + return json; + } + return { + url: json['url'], + assetType: json['asset_type'], + }; +} + +export function ImageSpecGifToJSON(json: any): ImageSpecGif { + return ImageSpecGifToJSONTyped(json, false); +} + +export function ImageSpecGifToJSONTyped(value?: ImageSpecGif | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + url: value['url'], + asset_type: value['assetType'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/ImageSpecJpeg.ts b/packages/composition-openapi/src/generated/models/ImageSpecJpeg.ts new file mode 100644 index 00000000..f7d1045f --- /dev/null +++ b/packages/composition-openapi/src/generated/models/ImageSpecJpeg.ts @@ -0,0 +1,88 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface ImageSpecJpeg + */ +export interface ImageSpecJpeg { + /** + * + * @type {string} + * @memberof ImageSpecJpeg + */ + url: string; + /** + * + * @type {ImageSpecJpegAssetTypeEnum} + * @memberof ImageSpecJpeg + */ + assetType: ImageSpecJpegAssetTypeEnum; +} + +/** + * @export + */ +export const ImageSpecJpegAssetTypeEnum = { + Jpeg: 'jpeg', +} as const; +export type ImageSpecJpegAssetTypeEnum = (typeof ImageSpecJpegAssetTypeEnum)[keyof typeof ImageSpecJpegAssetTypeEnum]; + +/** + * Check if a given object implements the ImageSpecJpeg interface. + */ +export function instanceOfImageSpecJpeg(value: object): value is ImageSpecJpeg { + if (!('url' in value) || value['url'] === undefined) return false; + if ( + (!('assetType' in (value as Record)) && !('asset_type' in (value as Record))) || + ((value as Record)['assetType'] === undefined && + (value as Record)['asset_type'] === undefined) + ) + return false; + if ((value as Record)['assetType'] !== 'jpeg' && (value as Record)['asset_type'] !== 'jpeg') + return false; + + return true; +} + +export function ImageSpecJpegFromJSON(json: any): ImageSpecJpeg { + return ImageSpecJpegFromJSONTyped(json, false); +} + +export function ImageSpecJpegFromJSONTyped(json: any, ignoreDiscriminator: boolean): ImageSpecJpeg { + if (json == null) { + return json; + } + return { + url: json['url'], + assetType: json['asset_type'], + }; +} + +export function ImageSpecJpegToJSON(json: any): ImageSpecJpeg { + return ImageSpecJpegToJSONTyped(json, false); +} + +export function ImageSpecJpegToJSONTyped(value?: ImageSpecJpeg | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + url: value['url'], + asset_type: value['assetType'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/ImageSpecPng.ts b/packages/composition-openapi/src/generated/models/ImageSpecPng.ts new file mode 100644 index 00000000..32ed75d4 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/ImageSpecPng.ts @@ -0,0 +1,88 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface ImageSpecPng + */ +export interface ImageSpecPng { + /** + * + * @type {string} + * @memberof ImageSpecPng + */ + url: string; + /** + * + * @type {ImageSpecPngAssetTypeEnum} + * @memberof ImageSpecPng + */ + assetType: ImageSpecPngAssetTypeEnum; +} + +/** + * @export + */ +export const ImageSpecPngAssetTypeEnum = { + Png: 'png', +} as const; +export type ImageSpecPngAssetTypeEnum = (typeof ImageSpecPngAssetTypeEnum)[keyof typeof ImageSpecPngAssetTypeEnum]; + +/** + * Check if a given object implements the ImageSpecPng interface. + */ +export function instanceOfImageSpecPng(value: object): value is ImageSpecPng { + if (!('url' in value) || value['url'] === undefined) return false; + if ( + (!('assetType' in (value as Record)) && !('asset_type' in (value as Record))) || + ((value as Record)['assetType'] === undefined && + (value as Record)['asset_type'] === undefined) + ) + return false; + if ((value as Record)['assetType'] !== 'png' && (value as Record)['asset_type'] !== 'png') + return false; + + return true; +} + +export function ImageSpecPngFromJSON(json: any): ImageSpecPng { + return ImageSpecPngFromJSONTyped(json, false); +} + +export function ImageSpecPngFromJSONTyped(json: any, ignoreDiscriminator: boolean): ImageSpecPng { + if (json == null) { + return json; + } + return { + url: json['url'], + assetType: json['asset_type'], + }; +} + +export function ImageSpecPngToJSON(json: any): ImageSpecPng { + return ImageSpecPngToJSONTyped(json, false); +} + +export function ImageSpecPngToJSONTyped(value?: ImageSpecPng | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + url: value['url'], + asset_type: value['assetType'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/ImageSpecSvg.ts b/packages/composition-openapi/src/generated/models/ImageSpecSvg.ts new file mode 100644 index 00000000..dffc4929 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/ImageSpecSvg.ts @@ -0,0 +1,104 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { Resolution } from './Resolution'; +import { ResolutionFromJSON, ResolutionFromJSONTyped, ResolutionToJSON, ResolutionToJSONTyped } from './Resolution'; + +/** + * + * @export + * @interface ImageSpecSvg + */ +export interface ImageSpecSvg { + /** + * + * @type {string} + * @memberof ImageSpecSvg + */ + url: string; + /** + * + * @type {Resolution} + * @memberof ImageSpecSvg + */ + resolution?: Resolution | null; + /** + * + * @type {ImageSpecSvgAssetTypeEnum} + * @memberof ImageSpecSvg + */ + assetType: ImageSpecSvgAssetTypeEnum; +} + +/** + * @export + */ +export const ImageSpecSvgAssetTypeEnum = { + Svg: 'svg', +} as const; +export type ImageSpecSvgAssetTypeEnum = (typeof ImageSpecSvgAssetTypeEnum)[keyof typeof ImageSpecSvgAssetTypeEnum]; + +/** + * Check if a given object implements the ImageSpecSvg interface. + */ +export function instanceOfImageSpecSvg(value: object): value is ImageSpecSvg { + if (!('url' in value) || value['url'] === undefined) return false; + if ( + (!('assetType' in (value as Record)) && !('asset_type' in (value as Record))) || + ((value as Record)['assetType'] === undefined && + (value as Record)['asset_type'] === undefined) + ) + return false; + if ((value as Record)['assetType'] !== 'svg' && (value as Record)['asset_type'] !== 'svg') + return false; + + return true; +} + +export function ImageSpecSvgFromJSON(json: any): ImageSpecSvg { + return ImageSpecSvgFromJSONTyped(json, false); +} + +export function ImageSpecSvgFromJSONTyped(json: any, ignoreDiscriminator: boolean): ImageSpecSvg { + if (json == null) { + return json; + } + return { + url: json['url'], + resolution: + json['resolution'] === undefined + ? undefined + : json['resolution'] === null + ? null + : ResolutionFromJSON(json['resolution']), + assetType: json['asset_type'], + }; +} + +export function ImageSpecSvgToJSON(json: any): ImageSpecSvg { + return ImageSpecSvgToJSONTyped(json, false); +} + +export function ImageSpecSvgToJSONTyped(value?: ImageSpecSvg | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + url: value['url'], + resolution: ResolutionToJSON(value['resolution']), + asset_type: value['assetType'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/InputStream.ts b/packages/composition-openapi/src/generated/models/InputStream.ts new file mode 100644 index 00000000..b17ecc58 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/InputStream.ts @@ -0,0 +1,95 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface InputStream + */ +export interface InputStream { + /** + * Id of a component. + * @type {string} + * @memberof InputStream + */ + id?: string | null; + /** + * Id of an input. It identifies a stream registered using a `RegisterInputStream` request. + * @type {string} + * @memberof InputStream + */ + inputId: string; + /** + * + * @type {InputStreamTypeEnum} + * @memberof InputStream + */ + type: InputStreamTypeEnum; +} + +/** + * @export + */ +export const InputStreamTypeEnum = { + InputStream: 'input_stream', +} as const; +export type InputStreamTypeEnum = (typeof InputStreamTypeEnum)[keyof typeof InputStreamTypeEnum]; + +/** + * Check if a given object implements the InputStream interface. + */ +export function instanceOfInputStream(value: object): value is InputStream { + if ( + (!('inputId' in (value as Record)) && !('input_id' in (value as Record))) || + ((value as Record)['inputId'] === undefined && + (value as Record)['input_id'] === undefined) + ) + return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'input_stream') return false; + + return true; +} + +export function InputStreamFromJSON(json: any): InputStream { + return InputStreamFromJSONTyped(json, false); +} + +export function InputStreamFromJSONTyped(json: any, ignoreDiscriminator: boolean): InputStream { + if (json == null) { + return json; + } + return { + id: json['id'] === undefined ? undefined : json['id'] === null ? null : json['id'], + inputId: json['input_id'], + type: json['type'], + }; +} + +export function InputStreamToJSON(json: any): InputStream { + return InputStreamToJSONTyped(json, false); +} + +export function InputStreamToJSONTyped(value?: InputStream | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + id: value['id'], + input_id: value['inputId'], + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/Interpolation.ts b/packages/composition-openapi/src/generated/models/Interpolation.ts new file mode 100644 index 00000000..6702e1cb --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Interpolation.ts @@ -0,0 +1,50 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const Interpolation = { + Linear: 'linear', + Spring: 'spring', +} as const; +export type Interpolation = (typeof Interpolation)[keyof typeof Interpolation]; + +export function instanceOfInterpolation(value: any): boolean { + for (const key in Interpolation) { + if (Object.prototype.hasOwnProperty.call(Interpolation, key)) { + if (Interpolation[key as keyof typeof Interpolation] === value) { + return true; + } + } + } + return false; +} + +export function InterpolationFromJSON(json: any): Interpolation { + return InterpolationFromJSONTyped(json, false); +} + +export function InterpolationFromJSONTyped(json: any, ignoreDiscriminator: boolean): Interpolation { + return json as Interpolation; +} + +export function InterpolationToJSON(value?: Interpolation | null): any { + return value as any; +} + +export function InterpolationToJSONTyped(value: any, ignoreDiscriminator: boolean): Interpolation { + return value as Interpolation; +} diff --git a/packages/composition-openapi/src/generated/models/Mp4Input.ts b/packages/composition-openapi/src/generated/models/Mp4Input.ts new file mode 100644 index 00000000..635e50ef --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Mp4Input.ts @@ -0,0 +1,90 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * Input stream from an MP4 file. + * @export + * @interface Mp4Input + */ +export interface Mp4Input { + /** + * URL of the MP4 file. + * @type {string} + * @memberof Mp4Input + */ + url: string; + /** + * (**default=`false`**) If input should be played in the loop. Added in v0.4.0 + * @type {boolean} + * @memberof Mp4Input + */ + loop?: boolean | null; + /** + * + * @type {Mp4InputTypeEnum} + * @memberof Mp4Input + */ + type: Mp4InputTypeEnum; +} + +/** + * @export + */ +export const Mp4InputTypeEnum = { + Mp4: 'mp4', +} as const; +export type Mp4InputTypeEnum = (typeof Mp4InputTypeEnum)[keyof typeof Mp4InputTypeEnum]; + +/** + * Check if a given object implements the Mp4Input interface. + */ +export function instanceOfMp4Input(value: object): value is Mp4Input { + if (!('url' in value) || value['url'] === undefined) return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'mp4') return false; + + return true; +} + +export function Mp4InputFromJSON(json: any): Mp4Input { + return Mp4InputFromJSONTyped(json, false); +} + +export function Mp4InputFromJSONTyped(json: any, ignoreDiscriminator: boolean): Mp4Input { + if (json == null) { + return json; + } + return { + url: json['url'], + loop: json['loop'] === undefined ? undefined : json['loop'] === null ? null : json['loop'], + type: json['type'], + }; +} + +export function Mp4InputToJSON(json: any): Mp4Input { + return Mp4InputToJSONTyped(json, false); +} + +export function Mp4InputToJSONTyped(value?: Mp4Input | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + url: value['url'], + loop: value['loop'], + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/OpusEncoderPreset.ts b/packages/composition-openapi/src/generated/models/OpusEncoderPreset.ts new file mode 100644 index 00000000..00154c94 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/OpusEncoderPreset.ts @@ -0,0 +1,51 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const OpusEncoderPreset = { + Quality: 'quality', + Voip: 'voip', + LowestLatency: 'lowest_latency', +} as const; +export type OpusEncoderPreset = (typeof OpusEncoderPreset)[keyof typeof OpusEncoderPreset]; + +export function instanceOfOpusEncoderPreset(value: any): boolean { + for (const key in OpusEncoderPreset) { + if (Object.prototype.hasOwnProperty.call(OpusEncoderPreset, key)) { + if (OpusEncoderPreset[key as keyof typeof OpusEncoderPreset] === value) { + return true; + } + } + } + return false; +} + +export function OpusEncoderPresetFromJSON(json: any): OpusEncoderPreset { + return OpusEncoderPresetFromJSONTyped(json, false); +} + +export function OpusEncoderPresetFromJSONTyped(json: any, ignoreDiscriminator: boolean): OpusEncoderPreset { + return json as OpusEncoderPreset; +} + +export function OpusEncoderPresetToJSON(value?: OpusEncoderPreset | null): any { + return value as any; +} + +export function OpusEncoderPresetToJSONTyped(value: any, ignoreDiscriminator: boolean): OpusEncoderPreset { + return value as OpusEncoderPreset; +} diff --git a/packages/composition-openapi/src/generated/models/OutputEndCondition.ts b/packages/composition-openapi/src/generated/models/OutputEndCondition.ts new file mode 100644 index 00000000..a1ecf66d --- /dev/null +++ b/packages/composition-openapi/src/generated/models/OutputEndCondition.ts @@ -0,0 +1,94 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * This type defines when end of an input stream should trigger end of the output stream. Only one of those fields can be set at the time. + * Unless specified otherwise the input stream is considered finished/ended when: + * - TCP connection was dropped/closed. + * - RTCP Goodbye packet (`BYE`) was received. + * - Mp4 track has ended. + * - Input was unregistered already (or never registered). + * @export + * @interface OutputEndCondition + */ +export interface OutputEndCondition { + /** + * Terminate output stream if any of the input streams from the list are finished. + * @type {Array} + * @memberof OutputEndCondition + */ + anyOf?: Array | null; + /** + * Terminate output stream if all the input streams from the list are finished. + * @type {Array} + * @memberof OutputEndCondition + */ + allOf?: Array | null; + /** + * Terminate output stream if any of the input streams ends. This includes streams added after the output was registered. In particular, output stream will **not be** terminated if no inputs were ever connected. + * @type {boolean} + * @memberof OutputEndCondition + */ + anyInput?: boolean | null; + /** + * Terminate output stream if all the input streams finish. In particular, output stream will **be** terminated if no inputs were ever connected. + * @type {boolean} + * @memberof OutputEndCondition + */ + allInputs?: boolean | null; +} + +/** + * Check if a given object implements the OutputEndCondition interface. + */ +export function instanceOfOutputEndCondition(value: object): value is OutputEndCondition { + return true; +} + +export function OutputEndConditionFromJSON(json: any): OutputEndCondition { + return OutputEndConditionFromJSONTyped(json, false); +} + +export function OutputEndConditionFromJSONTyped(json: any, ignoreDiscriminator: boolean): OutputEndCondition { + if (json == null) { + return json; + } + return { + anyOf: json['any_of'] === undefined ? undefined : json['any_of'] === null ? null : json['any_of'], + allOf: json['all_of'] === undefined ? undefined : json['all_of'] === null ? null : json['all_of'], + anyInput: json['any_input'] === undefined ? undefined : json['any_input'] === null ? null : json['any_input'], + allInputs: json['all_inputs'] === undefined ? undefined : json['all_inputs'] === null ? null : json['all_inputs'], + }; +} + +export function OutputEndConditionToJSON(json: any): OutputEndCondition { + return OutputEndConditionToJSONTyped(json, false); +} + +export function OutputEndConditionToJSONTyped( + value?: OutputEndCondition | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + any_of: value['anyOf'], + all_of: value['allOf'], + any_input: value['anyInput'], + all_inputs: value['allInputs'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/OutputRtmpClientAudioOptions.ts b/packages/composition-openapi/src/generated/models/OutputRtmpClientAudioOptions.ts new file mode 100644 index 00000000..29291d8b --- /dev/null +++ b/packages/composition-openapi/src/generated/models/OutputRtmpClientAudioOptions.ts @@ -0,0 +1,132 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { AudioChannels } from './AudioChannels'; +import { + AudioChannelsFromJSON, + AudioChannelsFromJSONTyped, + AudioChannelsToJSON, + AudioChannelsToJSONTyped, +} from './AudioChannels'; +import type { AudioMixingStrategy } from './AudioMixingStrategy'; +import { + AudioMixingStrategyFromJSON, + AudioMixingStrategyFromJSONTyped, + AudioMixingStrategyToJSON, + AudioMixingStrategyToJSONTyped, +} from './AudioMixingStrategy'; +import type { AudioScene } from './AudioScene'; +import { AudioSceneFromJSON, AudioSceneFromJSONTyped, AudioSceneToJSON, AudioSceneToJSONTyped } from './AudioScene'; +import type { OutputEndCondition } from './OutputEndCondition'; +import { + OutputEndConditionFromJSON, + OutputEndConditionFromJSONTyped, + OutputEndConditionToJSON, + OutputEndConditionToJSONTyped, +} from './OutputEndCondition'; + +/** + * + * @export + * @interface OutputRtmpClientAudioOptions + */ +export interface OutputRtmpClientAudioOptions { + /** + * (**default="sum_clip"**) Specifies how audio should be mixed. + * @type {AudioMixingStrategy} + * @memberof OutputRtmpClientAudioOptions + */ + mixingStrategy?: AudioMixingStrategy | null; + /** + * Condition for termination of the output stream based on the input streams states. If output includes both audio and video streams, then EOS needs to be sent for every type. + * @type {OutputEndCondition} + * @memberof OutputRtmpClientAudioOptions + */ + sendEosWhen?: OutputEndCondition | null; + /** + * Channels configuration. + * @type {AudioChannels} + * @memberof OutputRtmpClientAudioOptions + */ + channels?: AudioChannels | null; + /** + * Initial audio mixer configuration for output. + * @type {AudioScene} + * @memberof OutputRtmpClientAudioOptions + */ + initial: AudioScene; +} + +/** + * Check if a given object implements the OutputRtmpClientAudioOptions interface. + */ +export function instanceOfOutputRtmpClientAudioOptions(value: object): value is OutputRtmpClientAudioOptions { + if (!('initial' in value) || value['initial'] === undefined) return false; + return true; +} + +export function OutputRtmpClientAudioOptionsFromJSON(json: any): OutputRtmpClientAudioOptions { + return OutputRtmpClientAudioOptionsFromJSONTyped(json, false); +} + +export function OutputRtmpClientAudioOptionsFromJSONTyped( + json: any, + ignoreDiscriminator: boolean +): OutputRtmpClientAudioOptions { + if (json == null) { + return json; + } + return { + mixingStrategy: + json['mixing_strategy'] === undefined + ? undefined + : json['mixing_strategy'] === null + ? null + : AudioMixingStrategyFromJSON(json['mixing_strategy']), + sendEosWhen: + json['send_eos_when'] === undefined + ? undefined + : json['send_eos_when'] === null + ? null + : OutputEndConditionFromJSON(json['send_eos_when']), + channels: + json['channels'] === undefined + ? undefined + : json['channels'] === null + ? null + : AudioChannelsFromJSON(json['channels']), + initial: AudioSceneFromJSON(json['initial']), + }; +} + +export function OutputRtmpClientAudioOptionsToJSON(json: any): OutputRtmpClientAudioOptions { + return OutputRtmpClientAudioOptionsToJSONTyped(json, false); +} + +export function OutputRtmpClientAudioOptionsToJSONTyped( + value?: OutputRtmpClientAudioOptions | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + mixing_strategy: AudioMixingStrategyToJSON(value['mixingStrategy']), + send_eos_when: OutputEndConditionToJSON(value['sendEosWhen']), + channels: AudioChannelsToJSON(value['channels']), + initial: AudioSceneToJSON(value['initial']), + }; +} diff --git a/packages/composition-openapi/src/generated/models/OutputRtmpClientVideoOptions.ts b/packages/composition-openapi/src/generated/models/OutputRtmpClientVideoOptions.ts new file mode 100644 index 00000000..6a409e2a --- /dev/null +++ b/packages/composition-openapi/src/generated/models/OutputRtmpClientVideoOptions.ts @@ -0,0 +1,103 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { VideoScene } from './VideoScene'; +import { VideoSceneFromJSON, VideoSceneFromJSONTyped, VideoSceneToJSON, VideoSceneToJSONTyped } from './VideoScene'; +import type { OutputEndCondition } from './OutputEndCondition'; +import { + OutputEndConditionFromJSON, + OutputEndConditionFromJSONTyped, + OutputEndConditionToJSON, + OutputEndConditionToJSONTyped, +} from './OutputEndCondition'; +import type { Resolution } from './Resolution'; +import { ResolutionFromJSON, ResolutionFromJSONTyped, ResolutionToJSON, ResolutionToJSONTyped } from './Resolution'; + +/** + * + * @export + * @interface OutputRtmpClientVideoOptions + */ +export interface OutputRtmpClientVideoOptions { + /** + * Output resolution in pixels. + * @type {Resolution} + * @memberof OutputRtmpClientVideoOptions + */ + resolution: Resolution; + /** + * Condition for termination of the output stream based on the input streams states. If output includes both audio and video streams, then EOS needs to be sent for every type. + * @type {OutputEndCondition} + * @memberof OutputRtmpClientVideoOptions + */ + sendEosWhen?: OutputEndCondition | null; + /** + * Root of a component tree/scene that should be rendered for the output. Use `update_output` request to update this value after registration. Learn more. + * @type {VideoScene} + * @memberof OutputRtmpClientVideoOptions + */ + initial: VideoScene; +} + +/** + * Check if a given object implements the OutputRtmpClientVideoOptions interface. + */ +export function instanceOfOutputRtmpClientVideoOptions(value: object): value is OutputRtmpClientVideoOptions { + if (!('resolution' in value) || value['resolution'] === undefined) return false; + if (!('initial' in value) || value['initial'] === undefined) return false; + return true; +} + +export function OutputRtmpClientVideoOptionsFromJSON(json: any): OutputRtmpClientVideoOptions { + return OutputRtmpClientVideoOptionsFromJSONTyped(json, false); +} + +export function OutputRtmpClientVideoOptionsFromJSONTyped( + json: any, + ignoreDiscriminator: boolean +): OutputRtmpClientVideoOptions { + if (json == null) { + return json; + } + return { + resolution: ResolutionFromJSON(json['resolution']), + sendEosWhen: + json['send_eos_when'] === undefined + ? undefined + : json['send_eos_when'] === null + ? null + : OutputEndConditionFromJSON(json['send_eos_when']), + initial: VideoSceneFromJSON(json['initial']), + }; +} + +export function OutputRtmpClientVideoOptionsToJSON(json: any): OutputRtmpClientVideoOptions { + return OutputRtmpClientVideoOptionsToJSONTyped(json, false); +} + +export function OutputRtmpClientVideoOptionsToJSONTyped( + value?: OutputRtmpClientVideoOptions | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + resolution: ResolutionToJSON(value['resolution']), + send_eos_when: OutputEndConditionToJSON(value['sendEosWhen']), + initial: VideoSceneToJSON(value['initial']), + }; +} diff --git a/packages/composition-openapi/src/generated/models/OutputWhipAudioOptions.ts b/packages/composition-openapi/src/generated/models/OutputWhipAudioOptions.ts new file mode 100644 index 00000000..4e681e9c --- /dev/null +++ b/packages/composition-openapi/src/generated/models/OutputWhipAudioOptions.ts @@ -0,0 +1,152 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { WhipAudioEncoderOptions } from './WhipAudioEncoderOptions'; +import { + WhipAudioEncoderOptionsFromJSON, + WhipAudioEncoderOptionsFromJSONTyped, + WhipAudioEncoderOptionsToJSON, + WhipAudioEncoderOptionsToJSONTyped, +} from './WhipAudioEncoderOptions'; +import type { AudioChannels } from './AudioChannels'; +import { + AudioChannelsFromJSON, + AudioChannelsFromJSONTyped, + AudioChannelsToJSON, + AudioChannelsToJSONTyped, +} from './AudioChannels'; +import type { AudioMixingStrategy } from './AudioMixingStrategy'; +import { + AudioMixingStrategyFromJSON, + AudioMixingStrategyFromJSONTyped, + AudioMixingStrategyToJSON, + AudioMixingStrategyToJSONTyped, +} from './AudioMixingStrategy'; +import type { AudioScene } from './AudioScene'; +import { AudioSceneFromJSON, AudioSceneFromJSONTyped, AudioSceneToJSON, AudioSceneToJSONTyped } from './AudioScene'; +import type { OutputEndCondition } from './OutputEndCondition'; +import { + OutputEndConditionFromJSON, + OutputEndConditionFromJSONTyped, + OutputEndConditionToJSON, + OutputEndConditionToJSONTyped, +} from './OutputEndCondition'; + +/** + * + * @export + * @interface OutputWhipAudioOptions + */ +export interface OutputWhipAudioOptions { + /** + * (**default="sum_clip"**) Specifies how audio should be mixed. + * @type {AudioMixingStrategy} + * @memberof OutputWhipAudioOptions + */ + mixingStrategy?: AudioMixingStrategy | null; + /** + * Condition for termination of output stream based on the input streams states. + * @type {OutputEndCondition} + * @memberof OutputWhipAudioOptions + */ + sendEosWhen?: OutputEndCondition | null; + /** + * Specifies channels configuration. + * @type {AudioChannels} + * @memberof OutputWhipAudioOptions + */ + channels?: AudioChannels | null; + /** + * Codec preferences list. + * @type {Array} + * @memberof OutputWhipAudioOptions + */ + encoderPreferences?: Array | null; + /** + * Initial audio mixer configuration for output. + * @type {AudioScene} + * @memberof OutputWhipAudioOptions + */ + initial: AudioScene; +} + +/** + * Check if a given object implements the OutputWhipAudioOptions interface. + */ +export function instanceOfOutputWhipAudioOptions(value: object): value is OutputWhipAudioOptions { + if (!('initial' in value) || value['initial'] === undefined) return false; + return true; +} + +export function OutputWhipAudioOptionsFromJSON(json: any): OutputWhipAudioOptions { + return OutputWhipAudioOptionsFromJSONTyped(json, false); +} + +export function OutputWhipAudioOptionsFromJSONTyped(json: any, ignoreDiscriminator: boolean): OutputWhipAudioOptions { + if (json == null) { + return json; + } + return { + mixingStrategy: + json['mixing_strategy'] === undefined + ? undefined + : json['mixing_strategy'] === null + ? null + : AudioMixingStrategyFromJSON(json['mixing_strategy']), + sendEosWhen: + json['send_eos_when'] === undefined + ? undefined + : json['send_eos_when'] === null + ? null + : OutputEndConditionFromJSON(json['send_eos_when']), + channels: + json['channels'] === undefined + ? undefined + : json['channels'] === null + ? null + : AudioChannelsFromJSON(json['channels']), + encoderPreferences: + json['encoder_preferences'] === undefined + ? undefined + : json['encoder_preferences'] === null + ? null + : (json['encoder_preferences'] as Array).map(WhipAudioEncoderOptionsFromJSON), + initial: AudioSceneFromJSON(json['initial']), + }; +} + +export function OutputWhipAudioOptionsToJSON(json: any): OutputWhipAudioOptions { + return OutputWhipAudioOptionsToJSONTyped(json, false); +} + +export function OutputWhipAudioOptionsToJSONTyped( + value?: OutputWhipAudioOptions | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + mixing_strategy: AudioMixingStrategyToJSON(value['mixingStrategy']), + send_eos_when: OutputEndConditionToJSON(value['sendEosWhen']), + channels: AudioChannelsToJSON(value['channels']), + encoder_preferences: + value['encoderPreferences'] == null + ? undefined + : (value['encoderPreferences'] as Array).map(WhipAudioEncoderOptionsToJSON), + initial: AudioSceneToJSON(value['initial']), + }; +} diff --git a/packages/composition-openapi/src/generated/models/OutputWhipVideoOptions.ts b/packages/composition-openapi/src/generated/models/OutputWhipVideoOptions.ts new file mode 100644 index 00000000..1d961729 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/OutputWhipVideoOptions.ts @@ -0,0 +1,100 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { VideoScene } from './VideoScene'; +import { VideoSceneFromJSON, VideoSceneFromJSONTyped, VideoSceneToJSON, VideoSceneToJSONTyped } from './VideoScene'; +import type { OutputEndCondition } from './OutputEndCondition'; +import { + OutputEndConditionFromJSON, + OutputEndConditionFromJSONTyped, + OutputEndConditionToJSON, + OutputEndConditionToJSONTyped, +} from './OutputEndCondition'; +import type { Resolution } from './Resolution'; +import { ResolutionFromJSON, ResolutionFromJSONTyped, ResolutionToJSON, ResolutionToJSONTyped } from './Resolution'; + +/** + * + * @export + * @interface OutputWhipVideoOptions + */ +export interface OutputWhipVideoOptions { + /** + * Output resolution in pixels. + * @type {Resolution} + * @memberof OutputWhipVideoOptions + */ + resolution: Resolution; + /** + * Defines when output stream should end if some of the input streams are finished. If output includes both audio and video streams, then EOS needs to be sent on both. + * @type {OutputEndCondition} + * @memberof OutputWhipVideoOptions + */ + sendEosWhen?: OutputEndCondition | null; + /** + * Root of a component tree/scene that should be rendered for the output. + * @type {VideoScene} + * @memberof OutputWhipVideoOptions + */ + initial: VideoScene; +} + +/** + * Check if a given object implements the OutputWhipVideoOptions interface. + */ +export function instanceOfOutputWhipVideoOptions(value: object): value is OutputWhipVideoOptions { + if (!('resolution' in value) || value['resolution'] === undefined) return false; + if (!('initial' in value) || value['initial'] === undefined) return false; + return true; +} + +export function OutputWhipVideoOptionsFromJSON(json: any): OutputWhipVideoOptions { + return OutputWhipVideoOptionsFromJSONTyped(json, false); +} + +export function OutputWhipVideoOptionsFromJSONTyped(json: any, ignoreDiscriminator: boolean): OutputWhipVideoOptions { + if (json == null) { + return json; + } + return { + resolution: ResolutionFromJSON(json['resolution']), + sendEosWhen: + json['send_eos_when'] === undefined + ? undefined + : json['send_eos_when'] === null + ? null + : OutputEndConditionFromJSON(json['send_eos_when']), + initial: VideoSceneFromJSON(json['initial']), + }; +} + +export function OutputWhipVideoOptionsToJSON(json: any): OutputWhipVideoOptions { + return OutputWhipVideoOptionsToJSONTyped(json, false); +} + +export function OutputWhipVideoOptionsToJSONTyped( + value?: OutputWhipVideoOptions | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + resolution: ResolutionToJSON(value['resolution']), + send_eos_when: OutputEndConditionToJSON(value['sendEosWhen']), + initial: VideoSceneToJSON(value['initial']), + }; +} diff --git a/packages/composition-openapi/src/generated/models/Overflow.ts b/packages/composition-openapi/src/generated/models/Overflow.ts new file mode 100644 index 00000000..853b6f5e --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Overflow.ts @@ -0,0 +1,51 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const Overflow = { + Visible: 'visible', + Hidden: 'hidden', + Fit: 'fit', +} as const; +export type Overflow = (typeof Overflow)[keyof typeof Overflow]; + +export function instanceOfOverflow(value: any): boolean { + for (const key in Overflow) { + if (Object.prototype.hasOwnProperty.call(Overflow, key)) { + if (Overflow[key as keyof typeof Overflow] === value) { + return true; + } + } + } + return false; +} + +export function OverflowFromJSON(json: any): Overflow { + return OverflowFromJSONTyped(json, false); +} + +export function OverflowFromJSONTyped(json: any, ignoreDiscriminator: boolean): Overflow { + return json as Overflow; +} + +export function OverflowToJSON(value?: Overflow | null): any { + return value as any; +} + +export function OverflowToJSONTyped(value: any, ignoreDiscriminator: boolean): Overflow { + return value as Overflow; +} diff --git a/packages/composition-openapi/src/generated/models/PixelFormat.ts b/packages/composition-openapi/src/generated/models/PixelFormat.ts new file mode 100644 index 00000000..d7a1990d --- /dev/null +++ b/packages/composition-openapi/src/generated/models/PixelFormat.ts @@ -0,0 +1,51 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const PixelFormat = { + Yuv420p: 'yuv420p', + Yuv422p: 'yuv422p', + Yuv444p: 'yuv444p', +} as const; +export type PixelFormat = (typeof PixelFormat)[keyof typeof PixelFormat]; + +export function instanceOfPixelFormat(value: any): boolean { + for (const key in PixelFormat) { + if (Object.prototype.hasOwnProperty.call(PixelFormat, key)) { + if (PixelFormat[key as keyof typeof PixelFormat] === value) { + return true; + } + } + } + return false; +} + +export function PixelFormatFromJSON(json: any): PixelFormat { + return PixelFormatFromJSONTyped(json, false); +} + +export function PixelFormatFromJSONTyped(json: any, ignoreDiscriminator: boolean): PixelFormat { + return json as PixelFormat; +} + +export function PixelFormatToJSON(value?: PixelFormat | null): any { + return value as any; +} + +export function PixelFormatToJSONTyped(value: any, ignoreDiscriminator: boolean): PixelFormat { + return value as PixelFormat; +} diff --git a/packages/composition-openapi/src/generated/models/PortOrPortRange.ts b/packages/composition-openapi/src/generated/models/PortOrPortRange.ts new file mode 100644 index 00000000..6415b44d --- /dev/null +++ b/packages/composition-openapi/src/generated/models/PortOrPortRange.ts @@ -0,0 +1,54 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * @type PortOrPortRange + * + * @export + */ +export type PortOrPortRange = number | string; + +export function PortOrPortRangeFromJSON(json: any): PortOrPortRange { + return PortOrPortRangeFromJSONTyped(json, false); +} + +export function PortOrPortRangeFromJSONTyped(json: any, ignoreDiscriminator: boolean): PortOrPortRange { + if (json == null) { + return json; + } + if (typeof json === 'string') { + return json; + } + if (typeof json === 'number') { + return json; + } + return {} as any; +} + +export function PortOrPortRangeToJSON(json: any): any { + return PortOrPortRangeToJSONTyped(json, false); +} + +export function PortOrPortRangeToJSONTyped(value?: PortOrPortRange | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + if (typeof value === 'string') { + return value; + } + if (typeof value === 'number') { + return value; + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/RegisterInput.ts b/packages/composition-openapi/src/generated/models/RegisterInput.ts new file mode 100644 index 00000000..ad2f143b --- /dev/null +++ b/packages/composition-openapi/src/generated/models/RegisterInput.ts @@ -0,0 +1,81 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { Mp4Input } from './Mp4Input'; +import { instanceOfMp4Input, Mp4InputFromJSON, Mp4InputFromJSONTyped, Mp4InputToJSON } from './Mp4Input'; +import type { RtmpInput } from './RtmpInput'; +import { instanceOfRtmpInput, RtmpInputFromJSON, RtmpInputFromJSONTyped, RtmpInputToJSON } from './RtmpInput'; +import type { WhepInput } from './WhepInput'; +import { instanceOfWhepInput, WhepInputFromJSON, WhepInputFromJSONTyped, WhepInputToJSON } from './WhepInput'; +import type { WhipInput } from './WhipInput'; +import { instanceOfWhipInput, WhipInputFromJSON, WhipInputFromJSONTyped, WhipInputToJSON } from './WhipInput'; + +/** + * @type RegisterInput + * + * @export + */ +export type RegisterInput = Mp4Input | RtmpInput | WhepInput | WhipInput; + +export function RegisterInputFromJSON(json: any): RegisterInput { + return RegisterInputFromJSONTyped(json, false); +} + +export function RegisterInputFromJSONTyped(json: any, ignoreDiscriminator: boolean): RegisterInput { + if (json == null) { + return json; + } + if (typeof json !== 'object') { + return json; + } + if (instanceOfMp4Input(json)) { + return Mp4InputFromJSONTyped(json, true); + } + if (instanceOfRtmpInput(json)) { + return RtmpInputFromJSONTyped(json, true); + } + if (instanceOfWhepInput(json)) { + return WhepInputFromJSONTyped(json, true); + } + if (instanceOfWhipInput(json)) { + return WhipInputFromJSONTyped(json, true); + } + return {} as any; +} + +export function RegisterInputToJSON(json: any): any { + return RegisterInputToJSONTyped(json, false); +} + +export function RegisterInputToJSONTyped(value?: RegisterInput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + if (typeof value !== 'object') { + return value; + } + if (instanceOfMp4Input(value)) { + return Mp4InputToJSON(value as Mp4Input); + } + if (instanceOfRtmpInput(value)) { + return RtmpInputToJSON(value as RtmpInput); + } + if (instanceOfWhepInput(value)) { + return WhepInputToJSON(value as WhepInput); + } + if (instanceOfWhipInput(value)) { + return WhipInputToJSON(value as WhipInput); + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/RegisterInputResponse.ts b/packages/composition-openapi/src/generated/models/RegisterInputResponse.ts new file mode 100644 index 00000000..febbebac --- /dev/null +++ b/packages/composition-openapi/src/generated/models/RegisterInputResponse.ts @@ -0,0 +1,113 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface RegisterInputResponse + */ +export interface RegisterInputResponse { + /** + * + * @type {string} + * @memberof RegisterInputResponse + */ + bearerToken?: string | null; + /** + * + * @type {string} + * @memberof RegisterInputResponse + */ + endpointRoute?: string | null; + /** + * + * @type {number} + * @memberof RegisterInputResponse + */ + videoDurationMs?: number | null; + /** + * + * @type {number} + * @memberof RegisterInputResponse + */ + audioDurationMs?: number | null; + /** + * + * @type {number} + * @memberof RegisterInputResponse + */ + port?: number | null; +} + +/** + * Check if a given object implements the RegisterInputResponse interface. + */ +export function instanceOfRegisterInputResponse(value: object): value is RegisterInputResponse { + return true; +} + +export function RegisterInputResponseFromJSON(json: any): RegisterInputResponse { + return RegisterInputResponseFromJSONTyped(json, false); +} + +export function RegisterInputResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): RegisterInputResponse { + if (json == null) { + return json; + } + return { + bearerToken: + json['bearer_token'] === undefined ? undefined : json['bearer_token'] === null ? null : json['bearer_token'], + endpointRoute: + json['endpoint_route'] === undefined + ? undefined + : json['endpoint_route'] === null + ? null + : json['endpoint_route'], + videoDurationMs: + json['video_duration_ms'] === undefined + ? undefined + : json['video_duration_ms'] === null + ? null + : json['video_duration_ms'], + audioDurationMs: + json['audio_duration_ms'] === undefined + ? undefined + : json['audio_duration_ms'] === null + ? null + : json['audio_duration_ms'], + port: json['port'] === undefined ? undefined : json['port'] === null ? null : json['port'], + }; +} + +export function RegisterInputResponseToJSON(json: any): RegisterInputResponse { + return RegisterInputResponseToJSONTyped(json, false); +} + +export function RegisterInputResponseToJSONTyped( + value?: RegisterInputResponse | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + bearer_token: value['bearerToken'], + endpoint_route: value['endpointRoute'], + video_duration_ms: value['videoDurationMs'], + audio_duration_ms: value['audioDurationMs'], + port: value['port'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/RegisterOutput.ts b/packages/composition-openapi/src/generated/models/RegisterOutput.ts new file mode 100644 index 00000000..bfd0bb98 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/RegisterOutput.ts @@ -0,0 +1,65 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { RtmpOutput } from './RtmpOutput'; +import { instanceOfRtmpOutput, RtmpOutputFromJSON, RtmpOutputFromJSONTyped, RtmpOutputToJSON } from './RtmpOutput'; +import type { WhipOutput } from './WhipOutput'; +import { instanceOfWhipOutput, WhipOutputFromJSON, WhipOutputFromJSONTyped, WhipOutputToJSON } from './WhipOutput'; + +/** + * @type RegisterOutput + * + * @export + */ +export type RegisterOutput = RtmpOutput | WhipOutput; + +export function RegisterOutputFromJSON(json: any): RegisterOutput { + return RegisterOutputFromJSONTyped(json, false); +} + +export function RegisterOutputFromJSONTyped(json: any, ignoreDiscriminator: boolean): RegisterOutput { + if (json == null) { + return json; + } + if (typeof json !== 'object') { + return json; + } + if (instanceOfRtmpOutput(json)) { + return RtmpOutputFromJSONTyped(json, true); + } + if (instanceOfWhipOutput(json)) { + return WhipOutputFromJSONTyped(json, true); + } + return {} as any; +} + +export function RegisterOutputToJSON(json: any): any { + return RegisterOutputToJSONTyped(json, false); +} + +export function RegisterOutputToJSONTyped(value?: RegisterOutput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + if (typeof value !== 'object') { + return value; + } + if (instanceOfRtmpOutput(value)) { + return RtmpOutputToJSON(value as RtmpOutput); + } + if (instanceOfWhipOutput(value)) { + return WhipOutputToJSON(value as WhipOutput); + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/RegisterTemplateOutput.ts b/packages/composition-openapi/src/generated/models/RegisterTemplateOutput.ts new file mode 100644 index 00000000..ff2f0f02 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/RegisterTemplateOutput.ts @@ -0,0 +1,83 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { RegisterOutput } from './RegisterOutput'; +import { + RegisterOutputFromJSON, + RegisterOutputFromJSONTyped, + RegisterOutputToJSON, + RegisterOutputToJSONTyped, +} from './RegisterOutput'; + +/** + * + * @export + * @interface RegisterTemplateOutput + */ +export interface RegisterTemplateOutput { + /** + * + * @type {RegisterOutput} + * @memberof RegisterTemplateOutput + */ + config: RegisterOutput; + /** + * + * @type {Blob} + * @memberof RegisterTemplateOutput + */ + template: Blob; +} + +/** + * Check if a given object implements the RegisterTemplateOutput interface. + */ +export function instanceOfRegisterTemplateOutput(value: object): value is RegisterTemplateOutput { + if (!('config' in value) || value['config'] === undefined) return false; + if (!('template' in value) || value['template'] === undefined) return false; + return true; +} + +export function RegisterTemplateOutputFromJSON(json: any): RegisterTemplateOutput { + return RegisterTemplateOutputFromJSONTyped(json, false); +} + +export function RegisterTemplateOutputFromJSONTyped(json: any, ignoreDiscriminator: boolean): RegisterTemplateOutput { + if (json == null) { + return json; + } + return { + config: RegisterOutputFromJSON(json['config']), + template: json['template'], + }; +} + +export function RegisterTemplateOutputToJSON(json: any): RegisterTemplateOutput { + return RegisterTemplateOutputToJSONTyped(json, false); +} + +export function RegisterTemplateOutputToJSONTyped( + value?: RegisterTemplateOutput | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + config: RegisterOutputToJSON(value['config']), + template: value['template'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/RescaleMode.ts b/packages/composition-openapi/src/generated/models/RescaleMode.ts new file mode 100644 index 00000000..bcf03705 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/RescaleMode.ts @@ -0,0 +1,50 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const RescaleMode = { + Fit: 'fit', + Fill: 'fill', +} as const; +export type RescaleMode = (typeof RescaleMode)[keyof typeof RescaleMode]; + +export function instanceOfRescaleMode(value: any): boolean { + for (const key in RescaleMode) { + if (Object.prototype.hasOwnProperty.call(RescaleMode, key)) { + if (RescaleMode[key as keyof typeof RescaleMode] === value) { + return true; + } + } + } + return false; +} + +export function RescaleModeFromJSON(json: any): RescaleMode { + return RescaleModeFromJSONTyped(json, false); +} + +export function RescaleModeFromJSONTyped(json: any, ignoreDiscriminator: boolean): RescaleMode { + return json as RescaleMode; +} + +export function RescaleModeToJSON(value?: RescaleMode | null): any { + return value as any; +} + +export function RescaleModeToJSONTyped(value: any, ignoreDiscriminator: boolean): RescaleMode { + return value as RescaleMode; +} diff --git a/packages/composition-openapi/src/generated/models/Rescaler.ts b/packages/composition-openapi/src/generated/models/Rescaler.ts new file mode 100644 index 00000000..bdbb30ca --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Rescaler.ts @@ -0,0 +1,278 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { RescaleMode } from './RescaleMode'; +import { + RescaleModeFromJSON, + RescaleModeFromJSONTyped, + RescaleModeToJSON, + RescaleModeToJSONTyped, +} from './RescaleMode'; +import type { VerticalAlign } from './VerticalAlign'; +import { + VerticalAlignFromJSON, + VerticalAlignFromJSONTyped, + VerticalAlignToJSON, + VerticalAlignToJSONTyped, +} from './VerticalAlign'; +import type { BoxShadow } from './BoxShadow'; +import { BoxShadowFromJSON, BoxShadowFromJSONTyped, BoxShadowToJSON, BoxShadowToJSONTyped } from './BoxShadow'; +import type { HorizontalAlign } from './HorizontalAlign'; +import { + HorizontalAlignFromJSON, + HorizontalAlignFromJSONTyped, + HorizontalAlignToJSON, + HorizontalAlignToJSONTyped, +} from './HorizontalAlign'; +import type { Transition } from './Transition'; +import { TransitionFromJSON, TransitionFromJSONTyped, TransitionToJSON, TransitionToJSONTyped } from './Transition'; +import type { Component } from './Component'; +import { ComponentFromJSON, ComponentFromJSONTyped, ComponentToJSON, ComponentToJSONTyped } from './Component'; + +/** + * + * @export + * @interface Rescaler + */ +export interface Rescaler { + /** + * Id of a component. + * @type {string} + * @memberof Rescaler + */ + id?: string | null; + /** + * List of component's children. + * @type {Component} + * @memberof Rescaler + */ + child: Component; + /** + * (**default=`"fit"`**) Resize mode: + * @type {RescaleMode} + * @memberof Rescaler + */ + mode?: RescaleMode | null; + /** + * (**default=`"center"`**) Horizontal alignment. + * @type {HorizontalAlign} + * @memberof Rescaler + */ + horizontalAlign?: HorizontalAlign | null; + /** + * (**default=`"center"`**) Vertical alignment. + * @type {VerticalAlign} + * @memberof Rescaler + */ + verticalAlign?: VerticalAlign | null; + /** + * Width of a component in pixels (without a border). Exact behavior might be different + * based on the parent component: + * - If the parent component is a layout, check sections "Absolute positioning" and "Static + * positioning" of that component. + * - If the parent component is not a layout, then this field is required. + * @type {number} + * @memberof Rescaler + */ + width?: number | null; + /** + * Height of a component in pixels (without a border). Exact behavior might be different + * based on the parent component: + * - If the parent component is a layout, check sections "Absolute positioning" and "Static + * positioning" of that component. + * - If the parent component is not a layout, then this field is required. + * @type {number} + * @memberof Rescaler + */ + height?: number | null; + /** + * Distance in pixels between this component's top edge and its parent's top edge (including a border). + * If this field is defined, then the component will ignore a layout defined by its parent. + * @type {number} + * @memberof Rescaler + */ + top?: number | null; + /** + * Distance in pixels between this component's left edge and its parent's left edge (including a border). + * If this field is defined, this element will be absolutely positioned, instead of being + * laid out by its parent. + * @type {number} + * @memberof Rescaler + */ + left?: number | null; + /** + * Distance in pixels between the bottom edge of this component and the bottom edge of its + * parent (including a border). If this field is defined, this element will be absolutely + * positioned, instead of being laid out by its parent. + * @type {number} + * @memberof Rescaler + */ + bottom?: number | null; + /** + * Distance in pixels between this component's right edge and its parent's right edge. + * If this field is defined, this element will be absolutely positioned, instead of being + * laid out by its parent. + * @type {number} + * @memberof Rescaler + */ + right?: number | null; + /** + * Rotation of a component in degrees. If this field is defined, this element will be + * absolutely positioned, instead of being laid out by its parent. + * @type {number} + * @memberof Rescaler + */ + rotation?: number | null; + /** + * Defines how this component will behave during a scene update. This will only have an + * effect if the previous scene already contained a `Rescaler` component with the same id. + * @type {Transition} + * @memberof Rescaler + */ + transition?: Transition | null; + /** + * (**default=`0.0`**) Radius of a rounded corner. + * @type {number} + * @memberof Rescaler + */ + borderRadius?: number | null; + /** + * (**default=`0.0`**) Border width. + * @type {number} + * @memberof Rescaler + */ + borderWidth?: number | null; + /** + * (**default=`"#00000000"`**) Border color in a `"#RRGGBBAA"` format. + * @type {string} + * @memberof Rescaler + */ + borderColor?: string | null; + /** + * List of box shadows. + * @type {Array} + * @memberof Rescaler + */ + boxShadow?: Array | null; + /** + * + * @type {RescalerTypeEnum} + * @memberof Rescaler + */ + type: RescalerTypeEnum; +} + +/** + * @export + */ +export const RescalerTypeEnum = { + Rescaler: 'rescaler', +} as const; +export type RescalerTypeEnum = (typeof RescalerTypeEnum)[keyof typeof RescalerTypeEnum]; + +/** + * Check if a given object implements the Rescaler interface. + */ +export function instanceOfRescaler(value: object): value is Rescaler { + if (!('child' in value) || value['child'] === undefined) return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'rescaler') return false; + + return true; +} + +export function RescalerFromJSON(json: any): Rescaler { + return RescalerFromJSONTyped(json, false); +} + +export function RescalerFromJSONTyped(json: any, ignoreDiscriminator: boolean): Rescaler { + if (json == null) { + return json; + } + return { + id: json['id'] === undefined ? undefined : json['id'] === null ? null : json['id'], + child: ComponentFromJSON(json['child']), + mode: json['mode'] === undefined ? undefined : json['mode'] === null ? null : RescaleModeFromJSON(json['mode']), + horizontalAlign: + json['horizontal_align'] === undefined + ? undefined + : json['horizontal_align'] === null + ? null + : HorizontalAlignFromJSON(json['horizontal_align']), + verticalAlign: + json['vertical_align'] === undefined + ? undefined + : json['vertical_align'] === null + ? null + : VerticalAlignFromJSON(json['vertical_align']), + width: json['width'] === undefined ? undefined : json['width'] === null ? null : json['width'], + height: json['height'] === undefined ? undefined : json['height'] === null ? null : json['height'], + top: json['top'] === undefined ? undefined : json['top'] === null ? null : json['top'], + left: json['left'] === undefined ? undefined : json['left'] === null ? null : json['left'], + bottom: json['bottom'] === undefined ? undefined : json['bottom'] === null ? null : json['bottom'], + right: json['right'] === undefined ? undefined : json['right'] === null ? null : json['right'], + rotation: json['rotation'] === undefined ? undefined : json['rotation'] === null ? null : json['rotation'], + transition: + json['transition'] === undefined + ? undefined + : json['transition'] === null + ? null + : TransitionFromJSON(json['transition']), + borderRadius: + json['border_radius'] === undefined ? undefined : json['border_radius'] === null ? null : json['border_radius'], + borderWidth: + json['border_width'] === undefined ? undefined : json['border_width'] === null ? null : json['border_width'], + borderColor: + json['border_color'] === undefined ? undefined : json['border_color'] === null ? null : json['border_color'], + boxShadow: + json['box_shadow'] === undefined + ? undefined + : json['box_shadow'] === null + ? null + : (json['box_shadow'] as Array).map(BoxShadowFromJSON), + type: json['type'], + }; +} + +export function RescalerToJSON(json: any): Rescaler { + return RescalerToJSONTyped(json, false); +} + +export function RescalerToJSONTyped(value?: Rescaler | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + id: value['id'], + child: ComponentToJSON(value['child']), + mode: RescaleModeToJSON(value['mode']), + horizontal_align: HorizontalAlignToJSON(value['horizontalAlign']), + vertical_align: VerticalAlignToJSON(value['verticalAlign']), + width: value['width'], + height: value['height'], + top: value['top'], + left: value['left'], + bottom: value['bottom'], + right: value['right'], + rotation: value['rotation'], + transition: TransitionToJSON(value['transition']), + border_radius: value['borderRadius'], + border_width: value['borderWidth'], + border_color: value['borderColor'], + box_shadow: value['boxShadow'] == null ? undefined : (value['boxShadow'] as Array).map(BoxShadowToJSON), + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/Resolution.ts b/packages/composition-openapi/src/generated/models/Resolution.ts new file mode 100644 index 00000000..973d070e --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Resolution.ts @@ -0,0 +1,72 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface Resolution + */ +export interface Resolution { + /** + * Width in pixels. + * @type {number} + * @memberof Resolution + */ + width: number; + /** + * Height in pixels. + * @type {number} + * @memberof Resolution + */ + height: number; +} + +/** + * Check if a given object implements the Resolution interface. + */ +export function instanceOfResolution(value: object): value is Resolution { + if (!('width' in value) || value['width'] === undefined) return false; + if (!('height' in value) || value['height'] === undefined) return false; + return true; +} + +export function ResolutionFromJSON(json: any): Resolution { + return ResolutionFromJSONTyped(json, false); +} + +export function ResolutionFromJSONTyped(json: any, ignoreDiscriminator: boolean): Resolution { + if (json == null) { + return json; + } + return { + width: json['width'], + height: json['height'], + }; +} + +export function ResolutionToJSON(json: any): Resolution { + return ResolutionToJSONTyped(json, false); +} + +export function ResolutionToJSONTyped(value?: Resolution | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + width: value['width'], + height: value['height'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/RtmpInput.ts b/packages/composition-openapi/src/generated/models/RtmpInput.ts new file mode 100644 index 00000000..8dc6c0f4 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/RtmpInput.ts @@ -0,0 +1,89 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface RtmpInput + */ +export interface RtmpInput { + /** + * The RTMP stream key. + * This is the path segment of the RTMP stream URL that Smelter listens on for incoming streams. + * Format: `rtmp://:/` + * @type {string} + * @memberof RtmpInput + */ + streamKey: string; + /** + * + * @type {RtmpInputTypeEnum} + * @memberof RtmpInput + */ + type: RtmpInputTypeEnum; +} + +/** + * @export + */ +export const RtmpInputTypeEnum = { + RtmpServer: 'rtmp_server', +} as const; +export type RtmpInputTypeEnum = (typeof RtmpInputTypeEnum)[keyof typeof RtmpInputTypeEnum]; + +/** + * Check if a given object implements the RtmpInput interface. + */ +export function instanceOfRtmpInput(value: object): value is RtmpInput { + if ( + (!('streamKey' in (value as Record)) && !('stream_key' in (value as Record))) || + ((value as Record)['streamKey'] === undefined && + (value as Record)['stream_key'] === undefined) + ) + return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'rtmp_server') return false; + + return true; +} + +export function RtmpInputFromJSON(json: any): RtmpInput { + return RtmpInputFromJSONTyped(json, false); +} + +export function RtmpInputFromJSONTyped(json: any, ignoreDiscriminator: boolean): RtmpInput { + if (json == null) { + return json; + } + return { + streamKey: json['stream_key'], + type: json['type'], + }; +} + +export function RtmpInputToJSON(json: any): RtmpInput { + return RtmpInputToJSONTyped(json, false); +} + +export function RtmpInputToJSONTyped(value?: RtmpInput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + stream_key: value['streamKey'], + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/RtmpOutput.ts b/packages/composition-openapi/src/generated/models/RtmpOutput.ts new file mode 100644 index 00000000..6d3f663b --- /dev/null +++ b/packages/composition-openapi/src/generated/models/RtmpOutput.ts @@ -0,0 +1,123 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { OutputRtmpClientVideoOptions } from './OutputRtmpClientVideoOptions'; +import { + OutputRtmpClientVideoOptionsFromJSON, + OutputRtmpClientVideoOptionsFromJSONTyped, + OutputRtmpClientVideoOptionsToJSON, + OutputRtmpClientVideoOptionsToJSONTyped, +} from './OutputRtmpClientVideoOptions'; +import type { OutputRtmpClientAudioOptions } from './OutputRtmpClientAudioOptions'; +import { + OutputRtmpClientAudioOptionsFromJSON, + OutputRtmpClientAudioOptionsFromJSONTyped, + OutputRtmpClientAudioOptionsToJSON, + OutputRtmpClientAudioOptionsToJSONTyped, +} from './OutputRtmpClientAudioOptions'; + +/** + * + * @export + * @interface RtmpOutput + */ +export interface RtmpOutput { + /** + * RTMP endpoint url. + * @type {string} + * @memberof RtmpOutput + */ + url: string; + /** + * Video stream configuration. + * @type {OutputRtmpClientVideoOptions} + * @memberof RtmpOutput + */ + video?: OutputRtmpClientVideoOptions | null; + /** + * Audio stream configuration. + * @type {OutputRtmpClientAudioOptions} + * @memberof RtmpOutput + */ + audio?: OutputRtmpClientAudioOptions | null; + /** + * + * @type {RtmpOutputTypeEnum} + * @memberof RtmpOutput + */ + type: RtmpOutputTypeEnum; +} + +/** + * @export + */ +export const RtmpOutputTypeEnum = { + RtmpClient: 'rtmp_client', +} as const; +export type RtmpOutputTypeEnum = (typeof RtmpOutputTypeEnum)[keyof typeof RtmpOutputTypeEnum]; + +/** + * Check if a given object implements the RtmpOutput interface. + */ +export function instanceOfRtmpOutput(value: object): value is RtmpOutput { + if (!('url' in value) || value['url'] === undefined) return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'rtmp_client') return false; + + return true; +} + +export function RtmpOutputFromJSON(json: any): RtmpOutput { + return RtmpOutputFromJSONTyped(json, false); +} + +export function RtmpOutputFromJSONTyped(json: any, ignoreDiscriminator: boolean): RtmpOutput { + if (json == null) { + return json; + } + return { + url: json['url'], + video: + json['video'] === undefined + ? undefined + : json['video'] === null + ? null + : OutputRtmpClientVideoOptionsFromJSON(json['video']), + audio: + json['audio'] === undefined + ? undefined + : json['audio'] === null + ? null + : OutputRtmpClientAudioOptionsFromJSON(json['audio']), + type: json['type'], + }; +} + +export function RtmpOutputToJSON(json: any): RtmpOutput { + return RtmpOutputToJSONTyped(json, false); +} + +export function RtmpOutputToJSONTyped(value?: RtmpOutput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + url: value['url'], + video: OutputRtmpClientVideoOptionsToJSON(value['video']), + audio: OutputRtmpClientAudioOptionsToJSON(value['audio']), + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/SendCompositionEventRequest.ts b/packages/composition-openapi/src/generated/models/SendCompositionEventRequest.ts new file mode 100644 index 00000000..565966f5 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/SendCompositionEventRequest.ts @@ -0,0 +1,82 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface SendCompositionEventRequest + */ +export interface SendCompositionEventRequest { + /** + * Name of the event delivered to the composition's templates. + * @type {string} + * @memberof SendCompositionEventRequest + */ + eventName: string; + /** + * + * @type {any} + * @memberof SendCompositionEventRequest + */ + data?: any | null; +} + +/** + * Check if a given object implements the SendCompositionEventRequest interface. + */ +export function instanceOfSendCompositionEventRequest(value: object): value is SendCompositionEventRequest { + if ( + (!('eventName' in (value as Record)) && !('event_name' in (value as Record))) || + ((value as Record)['eventName'] === undefined && + (value as Record)['event_name'] === undefined) + ) + return false; + return true; +} + +export function SendCompositionEventRequestFromJSON(json: any): SendCompositionEventRequest { + return SendCompositionEventRequestFromJSONTyped(json, false); +} + +export function SendCompositionEventRequestFromJSONTyped( + json: any, + ignoreDiscriminator: boolean +): SendCompositionEventRequest { + if (json == null) { + return json; + } + return { + eventName: json['event_name'], + data: json['data'] === undefined ? undefined : json['data'] === null ? null : json['data'], + }; +} + +export function SendCompositionEventRequestToJSON(json: any): SendCompositionEventRequest { + return SendCompositionEventRequestToJSONTyped(json, false); +} + +export function SendCompositionEventRequestToJSONTyped( + value?: SendCompositionEventRequest | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + event_name: value['eventName'], + data: value['data'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/Text.ts b/packages/composition-openapi/src/generated/models/Text.ts new file mode 100644 index 00000000..e8d53245 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Text.ts @@ -0,0 +1,234 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { TextStyle } from './TextStyle'; +import { TextStyleFromJSON, TextStyleFromJSONTyped, TextStyleToJSON, TextStyleToJSONTyped } from './TextStyle'; +import type { HorizontalAlign } from './HorizontalAlign'; +import { + HorizontalAlignFromJSON, + HorizontalAlignFromJSONTyped, + HorizontalAlignToJSON, + HorizontalAlignToJSONTyped, +} from './HorizontalAlign'; +import type { TextWeight } from './TextWeight'; +import { TextWeightFromJSON, TextWeightFromJSONTyped, TextWeightToJSON, TextWeightToJSONTyped } from './TextWeight'; +import type { TextWrapMode } from './TextWrapMode'; +import { + TextWrapModeFromJSON, + TextWrapModeFromJSONTyped, + TextWrapModeToJSON, + TextWrapModeToJSONTyped, +} from './TextWrapMode'; + +/** + * + * @export + * @interface Text + */ +export interface Text { + /** + * Id of a component. + * @type {string} + * @memberof Text + */ + id?: string | null; + /** + * Text that will be rendered. + * @type {string} + * @memberof Text + */ + text: string; + /** + * Width of a texture that text will be rendered on. If not provided, the resulting texture + * will be sized based on the defined text but limited to `max_width` value. + * @type {number} + * @memberof Text + */ + width?: number | null; + /** + * Height of a texture that text will be rendered on. If not provided, the resulting texture + * will be sized based on the defined text but limited to `max_height` value. + * It's an error to provide `height` if `width` is not defined. + * @type {number} + * @memberof Text + */ + height?: number | null; + /** + * (**default=`7682`**) Maximal `width`. Limits the width of the texture that the text will be rendered on. + * Value is ignored if `width` is defined. + * @type {number} + * @memberof Text + */ + maxWidth?: number | null; + /** + * (**default=`4320`**) Maximal `height`. Limits the height of the texture that the text will be rendered on. + * Value is ignored if height is defined. + * @type {number} + * @memberof Text + */ + maxHeight?: number | null; + /** + * Font size in pixels. + * @type {number} + * @memberof Text + */ + fontSize: number; + /** + * Distance between lines in pixels. Defaults to the value of the `font_size` property. + * @type {number} + * @memberof Text + */ + lineHeight?: number | null; + /** + * (**default=`"#FFFFFFFF"`**) Font color in `#RRGGBBAA` format. + * @type {string} + * @memberof Text + */ + color?: string | null; + /** + * (**default=`"#00000000"`**) Background color in `#RRGGBBAA` format. + * @type {string} + * @memberof Text + */ + backgroundColor?: string | null; + /** + * (**default=`"Verdana"`**) Font family. Provide [family-name](https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#family-name-value) + * for a specific font. "generic-family" values like e.g. "sans-serif" will not work. + * @type {string} + * @memberof Text + */ + fontFamily?: string | null; + /** + * (**default=`"normal"`**) Font style. The selected font needs to support the specified style. + * @type {TextStyle} + * @memberof Text + */ + style?: TextStyle | null; + /** + * (**default=`"left"`**) Text align. + * @type {HorizontalAlign} + * @memberof Text + */ + align?: HorizontalAlign | null; + /** + * (**default=`"none"`**) Text wrapping options. + * @type {TextWrapMode} + * @memberof Text + */ + wrap?: TextWrapMode | null; + /** + * (**default=`"normal"`**) Font weight. The selected font needs to support the specified weight. + * @type {TextWeight} + * @memberof Text + */ + weight?: TextWeight | null; + /** + * + * @type {TextTypeEnum} + * @memberof Text + */ + type: TextTypeEnum; +} + +/** + * @export + */ +export const TextTypeEnum = { + Text: 'text', +} as const; +export type TextTypeEnum = (typeof TextTypeEnum)[keyof typeof TextTypeEnum]; + +/** + * Check if a given object implements the Text interface. + */ +export function instanceOfText(value: object): value is Text { + if (!('text' in value) || value['text'] === undefined) return false; + if ( + (!('fontSize' in (value as Record)) && !('font_size' in (value as Record))) || + ((value as Record)['fontSize'] === undefined && + (value as Record)['font_size'] === undefined) + ) + return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'text') return false; + + return true; +} + +export function TextFromJSON(json: any): Text { + return TextFromJSONTyped(json, false); +} + +export function TextFromJSONTyped(json: any, ignoreDiscriminator: boolean): Text { + if (json == null) { + return json; + } + return { + id: json['id'] === undefined ? undefined : json['id'] === null ? null : json['id'], + text: json['text'], + width: json['width'] === undefined ? undefined : json['width'] === null ? null : json['width'], + height: json['height'] === undefined ? undefined : json['height'] === null ? null : json['height'], + maxWidth: json['max_width'] === undefined ? undefined : json['max_width'] === null ? null : json['max_width'], + maxHeight: json['max_height'] === undefined ? undefined : json['max_height'] === null ? null : json['max_height'], + fontSize: json['font_size'], + lineHeight: + json['line_height'] === undefined ? undefined : json['line_height'] === null ? null : json['line_height'], + color: json['color'] === undefined ? undefined : json['color'] === null ? null : json['color'], + backgroundColor: + json['background_color'] === undefined + ? undefined + : json['background_color'] === null + ? null + : json['background_color'], + fontFamily: + json['font_family'] === undefined ? undefined : json['font_family'] === null ? null : json['font_family'], + style: json['style'] === undefined ? undefined : json['style'] === null ? null : TextStyleFromJSON(json['style']), + align: + json['align'] === undefined ? undefined : json['align'] === null ? null : HorizontalAlignFromJSON(json['align']), + wrap: json['wrap'] === undefined ? undefined : json['wrap'] === null ? null : TextWrapModeFromJSON(json['wrap']), + weight: + json['weight'] === undefined ? undefined : json['weight'] === null ? null : TextWeightFromJSON(json['weight']), + type: json['type'], + }; +} + +export function TextToJSON(json: any): Text { + return TextToJSONTyped(json, false); +} + +export function TextToJSONTyped(value?: Text | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + id: value['id'], + text: value['text'], + width: value['width'], + height: value['height'], + max_width: value['maxWidth'], + max_height: value['maxHeight'], + font_size: value['fontSize'], + line_height: value['lineHeight'], + color: value['color'], + background_color: value['backgroundColor'], + font_family: value['fontFamily'], + style: TextStyleToJSON(value['style']), + align: HorizontalAlignToJSON(value['align']), + wrap: TextWrapModeToJSON(value['wrap']), + weight: TextWeightToJSON(value['weight']), + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/TextStyle.ts b/packages/composition-openapi/src/generated/models/TextStyle.ts new file mode 100644 index 00000000..bcb357ac --- /dev/null +++ b/packages/composition-openapi/src/generated/models/TextStyle.ts @@ -0,0 +1,51 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const TextStyle = { + Normal: 'normal', + Italic: 'italic', + Oblique: 'oblique', +} as const; +export type TextStyle = (typeof TextStyle)[keyof typeof TextStyle]; + +export function instanceOfTextStyle(value: any): boolean { + for (const key in TextStyle) { + if (Object.prototype.hasOwnProperty.call(TextStyle, key)) { + if (TextStyle[key as keyof typeof TextStyle] === value) { + return true; + } + } + } + return false; +} + +export function TextStyleFromJSON(json: any): TextStyle { + return TextStyleFromJSONTyped(json, false); +} + +export function TextStyleFromJSONTyped(json: any, ignoreDiscriminator: boolean): TextStyle { + return json as TextStyle; +} + +export function TextStyleToJSON(value?: TextStyle | null): any { + return value as any; +} + +export function TextStyleToJSONTyped(value: any, ignoreDiscriminator: boolean): TextStyle { + return value as TextStyle; +} diff --git a/packages/composition-openapi/src/generated/models/TextWeight.ts b/packages/composition-openapi/src/generated/models/TextWeight.ts new file mode 100644 index 00000000..8b26eaf8 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/TextWeight.ts @@ -0,0 +1,57 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * Font weight, based on the [OpenType specification](https://learn.microsoft.com/en-gb/typography/opentype/spec/os2#usweightclass). + * @export + */ +export const TextWeight = { + Thin: 'thin', + ExtraLight: 'extra_light', + Light: 'light', + Normal: 'normal', + Medium: 'medium', + SemiBold: 'semi_bold', + Bold: 'bold', + ExtraBold: 'extra_bold', + Black: 'black', +} as const; +export type TextWeight = (typeof TextWeight)[keyof typeof TextWeight]; + +export function instanceOfTextWeight(value: any): boolean { + for (const key in TextWeight) { + if (Object.prototype.hasOwnProperty.call(TextWeight, key)) { + if (TextWeight[key as keyof typeof TextWeight] === value) { + return true; + } + } + } + return false; +} + +export function TextWeightFromJSON(json: any): TextWeight { + return TextWeightFromJSONTyped(json, false); +} + +export function TextWeightFromJSONTyped(json: any, ignoreDiscriminator: boolean): TextWeight { + return json as TextWeight; +} + +export function TextWeightToJSON(value?: TextWeight | null): any { + return value as any; +} + +export function TextWeightToJSONTyped(value: any, ignoreDiscriminator: boolean): TextWeight { + return value as TextWeight; +} diff --git a/packages/composition-openapi/src/generated/models/TextWrapMode.ts b/packages/composition-openapi/src/generated/models/TextWrapMode.ts new file mode 100644 index 00000000..6eae4ba2 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/TextWrapMode.ts @@ -0,0 +1,51 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const TextWrapMode = { + None: 'none', + Glyph: 'glyph', + Word: 'word', +} as const; +export type TextWrapMode = (typeof TextWrapMode)[keyof typeof TextWrapMode]; + +export function instanceOfTextWrapMode(value: any): boolean { + for (const key in TextWrapMode) { + if (Object.prototype.hasOwnProperty.call(TextWrapMode, key)) { + if (TextWrapMode[key as keyof typeof TextWrapMode] === value) { + return true; + } + } + } + return false; +} + +export function TextWrapModeFromJSON(json: any): TextWrapMode { + return TextWrapModeFromJSONTyped(json, false); +} + +export function TextWrapModeFromJSONTyped(json: any, ignoreDiscriminator: boolean): TextWrapMode { + return json as TextWrapMode; +} + +export function TextWrapModeToJSON(value?: TextWrapMode | null): any { + return value as any; +} + +export function TextWrapModeToJSONTyped(value: any, ignoreDiscriminator: boolean): TextWrapMode { + return value as TextWrapMode; +} diff --git a/packages/composition-openapi/src/generated/models/Tiles.ts b/packages/composition-openapi/src/generated/models/Tiles.ts new file mode 100644 index 00000000..19dd9a68 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Tiles.ts @@ -0,0 +1,219 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { VerticalAlign } from './VerticalAlign'; +import { + VerticalAlignFromJSON, + VerticalAlignFromJSONTyped, + VerticalAlignToJSON, + VerticalAlignToJSONTyped, +} from './VerticalAlign'; +import type { HorizontalAlign } from './HorizontalAlign'; +import { + HorizontalAlignFromJSON, + HorizontalAlignFromJSONTyped, + HorizontalAlignToJSON, + HorizontalAlignToJSONTyped, +} from './HorizontalAlign'; +import type { Transition } from './Transition'; +import { TransitionFromJSON, TransitionFromJSONTyped, TransitionToJSON, TransitionToJSONTyped } from './Transition'; +import type { Component } from './Component'; +import { ComponentFromJSON, ComponentFromJSONTyped, ComponentToJSON, ComponentToJSONTyped } from './Component'; + +/** + * + * @export + * @interface Tiles + */ +export interface Tiles { + /** + * Id of a component. + * @type {string} + * @memberof Tiles + */ + id?: string | null; + /** + * List of component's children. + * @type {Array} + * @memberof Tiles + */ + children?: Array | null; + /** + * Width of a component in pixels. Exact behavior might be different based on the parent + * component: + * - If the parent component is a layout, check sections "Absolute positioning" and "Static + * positioning" of that component. + * - If the parent component is not a layout, then this field is required. + * @type {number} + * @memberof Tiles + */ + width?: number | null; + /** + * Height of a component in pixels. Exact behavior might be different based on the parent + * component: + * - If the parent component is a layout, check sections "Absolute positioning" and "Static + * positioning" of that component. + * - If the parent component is not a layout, then this field is required. + * @type {number} + * @memberof Tiles + */ + height?: number | null; + /** + * (**default=`"#00000000"`**) Background color in a `"#RRGGBBAA"` format. + * @type {string} + * @memberof Tiles + */ + backgroundColor?: string | null; + /** + * (**default=`"16:9"`**) Aspect ratio of a tile in `"W:H"` format, where W and H are integers. + * @type {string} + * @memberof Tiles + */ + tileAspectRatio?: string | null; + /** + * (**default=`0`**) Margin of each tile in pixels. + * @type {number} + * @memberof Tiles + */ + margin?: number | null; + /** + * (**default=`0`**) Padding on each tile in pixels. + * @type {number} + * @memberof Tiles + */ + padding?: number | null; + /** + * (**default=`"center"`**) Horizontal alignment of tiles. + * @type {HorizontalAlign} + * @memberof Tiles + */ + horizontalAlign?: HorizontalAlign | null; + /** + * (**default=`"center"`**) Vertical alignment of tiles. + * @type {VerticalAlign} + * @memberof Tiles + */ + verticalAlign?: VerticalAlign | null; + /** + * Defines how this component will behave during a scene update. This will only have an + * effect if the previous scene already contained a `Tiles` component with the same id. + * @type {Transition} + * @memberof Tiles + */ + transition?: Transition | null; + /** + * + * @type {TilesTypeEnum} + * @memberof Tiles + */ + type: TilesTypeEnum; +} + +/** + * @export + */ +export const TilesTypeEnum = { + Tiles: 'tiles', +} as const; +export type TilesTypeEnum = (typeof TilesTypeEnum)[keyof typeof TilesTypeEnum]; + +/** + * Check if a given object implements the Tiles interface. + */ +export function instanceOfTiles(value: object): value is Tiles { + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'tiles') return false; + + return true; +} + +export function TilesFromJSON(json: any): Tiles { + return TilesFromJSONTyped(json, false); +} + +export function TilesFromJSONTyped(json: any, ignoreDiscriminator: boolean): Tiles { + if (json == null) { + return json; + } + return { + id: json['id'] === undefined ? undefined : json['id'] === null ? null : json['id'], + children: + json['children'] === undefined + ? undefined + : json['children'] === null + ? null + : (json['children'] as Array).map(ComponentFromJSON), + width: json['width'] === undefined ? undefined : json['width'] === null ? null : json['width'], + height: json['height'] === undefined ? undefined : json['height'] === null ? null : json['height'], + backgroundColor: + json['background_color'] === undefined + ? undefined + : json['background_color'] === null + ? null + : json['background_color'], + tileAspectRatio: + json['tile_aspect_ratio'] === undefined + ? undefined + : json['tile_aspect_ratio'] === null + ? null + : json['tile_aspect_ratio'], + margin: json['margin'] === undefined ? undefined : json['margin'] === null ? null : json['margin'], + padding: json['padding'] === undefined ? undefined : json['padding'] === null ? null : json['padding'], + horizontalAlign: + json['horizontal_align'] === undefined + ? undefined + : json['horizontal_align'] === null + ? null + : HorizontalAlignFromJSON(json['horizontal_align']), + verticalAlign: + json['vertical_align'] === undefined + ? undefined + : json['vertical_align'] === null + ? null + : VerticalAlignFromJSON(json['vertical_align']), + transition: + json['transition'] === undefined + ? undefined + : json['transition'] === null + ? null + : TransitionFromJSON(json['transition']), + type: json['type'], + }; +} + +export function TilesToJSON(json: any): Tiles { + return TilesToJSONTyped(json, false); +} + +export function TilesToJSONTyped(value?: Tiles | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + id: value['id'], + children: value['children'] == null ? undefined : (value['children'] as Array).map(ComponentToJSON), + width: value['width'], + height: value['height'], + background_color: value['backgroundColor'], + tile_aspect_ratio: value['tileAspectRatio'], + margin: value['margin'], + padding: value['padding'], + horizontal_align: HorizontalAlignToJSON(value['horizontalAlign']), + vertical_align: VerticalAlignToJSON(value['verticalAlign']), + transition: TransitionToJSON(value['transition']), + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/Transition.ts b/packages/composition-openapi/src/generated/models/Transition.ts new file mode 100644 index 00000000..8c70d899 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/Transition.ts @@ -0,0 +1,103 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { EasingFunction } from './EasingFunction'; +import { + EasingFunctionFromJSON, + EasingFunctionFromJSONTyped, + EasingFunctionToJSON, + EasingFunctionToJSONTyped, +} from './EasingFunction'; + +/** + * + * @export + * @interface Transition + */ +export interface Transition { + /** + * Duration of a transition in milliseconds. + * @type {number} + * @memberof Transition + */ + durationMs: number; + /** + * (**default=`"linear"`**) Easing function to be used for the transition. + * @type {EasingFunction} + * @memberof Transition + */ + easingFunction?: EasingFunction | null; + /** + * (**default=`false`**) On scene update, if there is already a transition in progress, + * it will be interrupted and the new transition will start from the current state. + * @type {boolean} + * @memberof Transition + */ + shouldInterrupt?: boolean | null; +} + +/** + * Check if a given object implements the Transition interface. + */ +export function instanceOfTransition(value: object): value is Transition { + if ( + (!('durationMs' in (value as Record)) && !('duration_ms' in (value as Record))) || + ((value as Record)['durationMs'] === undefined && + (value as Record)['duration_ms'] === undefined) + ) + return false; + return true; +} + +export function TransitionFromJSON(json: any): Transition { + return TransitionFromJSONTyped(json, false); +} + +export function TransitionFromJSONTyped(json: any, ignoreDiscriminator: boolean): Transition { + if (json == null) { + return json; + } + return { + durationMs: json['duration_ms'], + easingFunction: + json['easing_function'] === undefined + ? undefined + : json['easing_function'] === null + ? null + : EasingFunctionFromJSON(json['easing_function']), + shouldInterrupt: + json['should_interrupt'] === undefined + ? undefined + : json['should_interrupt'] === null + ? null + : json['should_interrupt'], + }; +} + +export function TransitionToJSON(json: any): Transition { + return TransitionToJSONTyped(json, false); +} + +export function TransitionToJSONTyped(value?: Transition | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + duration_ms: value['durationMs'], + easing_function: EasingFunctionToJSON(value['easingFunction']), + should_interrupt: value['shouldInterrupt'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/TransportProtocol.ts b/packages/composition-openapi/src/generated/models/TransportProtocol.ts new file mode 100644 index 00000000..e08374fc --- /dev/null +++ b/packages/composition-openapi/src/generated/models/TransportProtocol.ts @@ -0,0 +1,50 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const TransportProtocol = { + Udp: 'udp', + TcpServer: 'tcp_server', +} as const; +export type TransportProtocol = (typeof TransportProtocol)[keyof typeof TransportProtocol]; + +export function instanceOfTransportProtocol(value: any): boolean { + for (const key in TransportProtocol) { + if (Object.prototype.hasOwnProperty.call(TransportProtocol, key)) { + if (TransportProtocol[key as keyof typeof TransportProtocol] === value) { + return true; + } + } + } + return false; +} + +export function TransportProtocolFromJSON(json: any): TransportProtocol { + return TransportProtocolFromJSONTyped(json, false); +} + +export function TransportProtocolFromJSONTyped(json: any, ignoreDiscriminator: boolean): TransportProtocol { + return json as TransportProtocol; +} + +export function TransportProtocolToJSON(value?: TransportProtocol | null): any { + return value as any; +} + +export function TransportProtocolToJSONTyped(value: any, ignoreDiscriminator: boolean): TransportProtocol { + return value as TransportProtocol; +} diff --git a/packages/composition-openapi/src/generated/models/UnregisterInput.ts b/packages/composition-openapi/src/generated/models/UnregisterInput.ts new file mode 100644 index 00000000..7855fce4 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/UnregisterInput.ts @@ -0,0 +1,68 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface UnregisterInput + */ +export interface UnregisterInput { + /** + * Time in milliseconds when this request should be applied. Value `0` represents + * time of the start request. + * @type {number} + * @memberof UnregisterInput + */ + scheduleTimeMs?: number | null; +} + +/** + * Check if a given object implements the UnregisterInput interface. + */ +export function instanceOfUnregisterInput(value: object): value is UnregisterInput { + return true; +} + +export function UnregisterInputFromJSON(json: any): UnregisterInput { + return UnregisterInputFromJSONTyped(json, false); +} + +export function UnregisterInputFromJSONTyped(json: any, ignoreDiscriminator: boolean): UnregisterInput { + if (json == null) { + return json; + } + return { + scheduleTimeMs: + json['schedule_time_ms'] === undefined + ? undefined + : json['schedule_time_ms'] === null + ? null + : json['schedule_time_ms'], + }; +} + +export function UnregisterInputToJSON(json: any): UnregisterInput { + return UnregisterInputToJSONTyped(json, false); +} + +export function UnregisterInputToJSONTyped(value?: UnregisterInput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + schedule_time_ms: value['scheduleTimeMs'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/UnregisterOutput.ts b/packages/composition-openapi/src/generated/models/UnregisterOutput.ts new file mode 100644 index 00000000..a20f7402 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/UnregisterOutput.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface UnregisterOutput + */ +export interface UnregisterOutput { + /** + * Time in milliseconds when this request should be applied. Value `0` represents + * time of the start request. + * @type {number} + * @memberof UnregisterOutput + */ + scheduleTimeMs?: number | null; +} + +/** + * Check if a given object implements the UnregisterOutput interface. + */ +export function instanceOfUnregisterOutput(value: object): value is UnregisterOutput { + return true; +} + +export function UnregisterOutputFromJSON(json: any): UnregisterOutput { + return UnregisterOutputFromJSONTyped(json, false); +} + +export function UnregisterOutputFromJSONTyped(json: any, ignoreDiscriminator: boolean): UnregisterOutput { + if (json == null) { + return json; + } + return { + scheduleTimeMs: + json['schedule_time_ms'] === undefined + ? undefined + : json['schedule_time_ms'] === null + ? null + : json['schedule_time_ms'], + }; +} + +export function UnregisterOutputToJSON(json: any): UnregisterOutput { + return UnregisterOutputToJSONTyped(json, false); +} + +export function UnregisterOutputToJSONTyped( + value?: UnregisterOutput | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + schedule_time_ms: value['scheduleTimeMs'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/UnregisterRenderer.ts b/packages/composition-openapi/src/generated/models/UnregisterRenderer.ts new file mode 100644 index 00000000..3b128b81 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/UnregisterRenderer.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface UnregisterRenderer + */ +export interface UnregisterRenderer { + /** + * Time in milliseconds when this request should be applied. Value `0` represents + * time of the start request. + * @type {number} + * @memberof UnregisterRenderer + */ + scheduleTimeMs?: number | null; +} + +/** + * Check if a given object implements the UnregisterRenderer interface. + */ +export function instanceOfUnregisterRenderer(value: object): value is UnregisterRenderer { + return true; +} + +export function UnregisterRendererFromJSON(json: any): UnregisterRenderer { + return UnregisterRendererFromJSONTyped(json, false); +} + +export function UnregisterRendererFromJSONTyped(json: any, ignoreDiscriminator: boolean): UnregisterRenderer { + if (json == null) { + return json; + } + return { + scheduleTimeMs: + json['schedule_time_ms'] === undefined + ? undefined + : json['schedule_time_ms'] === null + ? null + : json['schedule_time_ms'], + }; +} + +export function UnregisterRendererToJSON(json: any): UnregisterRenderer { + return UnregisterRendererToJSONTyped(json, false); +} + +export function UnregisterRendererToJSONTyped( + value?: UnregisterRenderer | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + schedule_time_ms: value['scheduleTimeMs'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/UpdateOutputRequest.ts b/packages/composition-openapi/src/generated/models/UpdateOutputRequest.ts new file mode 100644 index 00000000..5215aafb --- /dev/null +++ b/packages/composition-openapi/src/generated/models/UpdateOutputRequest.ts @@ -0,0 +1,91 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { VideoScene } from './VideoScene'; +import { VideoSceneFromJSON, VideoSceneFromJSONTyped, VideoSceneToJSON, VideoSceneToJSONTyped } from './VideoScene'; +import type { AudioScene } from './AudioScene'; +import { AudioSceneFromJSON, AudioSceneFromJSONTyped, AudioSceneToJSON, AudioSceneToJSONTyped } from './AudioScene'; + +/** + * + * @export + * @interface UpdateOutputRequest + */ +export interface UpdateOutputRequest { + /** + * + * @type {VideoScene} + * @memberof UpdateOutputRequest + */ + video?: VideoScene | null; + /** + * + * @type {AudioScene} + * @memberof UpdateOutputRequest + */ + audio?: AudioScene | null; + /** + * + * @type {number} + * @memberof UpdateOutputRequest + */ + scheduleTimeMs?: number | null; +} + +/** + * Check if a given object implements the UpdateOutputRequest interface. + */ +export function instanceOfUpdateOutputRequest(value: object): value is UpdateOutputRequest { + return true; +} + +export function UpdateOutputRequestFromJSON(json: any): UpdateOutputRequest { + return UpdateOutputRequestFromJSONTyped(json, false); +} + +export function UpdateOutputRequestFromJSONTyped(json: any, ignoreDiscriminator: boolean): UpdateOutputRequest { + if (json == null) { + return json; + } + return { + video: json['video'] === undefined ? undefined : json['video'] === null ? null : VideoSceneFromJSON(json['video']), + audio: json['audio'] === undefined ? undefined : json['audio'] === null ? null : AudioSceneFromJSON(json['audio']), + scheduleTimeMs: + json['schedule_time_ms'] === undefined + ? undefined + : json['schedule_time_ms'] === null + ? null + : json['schedule_time_ms'], + }; +} + +export function UpdateOutputRequestToJSON(json: any): UpdateOutputRequest { + return UpdateOutputRequestToJSONTyped(json, false); +} + +export function UpdateOutputRequestToJSONTyped( + value?: UpdateOutputRequest | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + video: VideoSceneToJSON(value['video']), + audio: AudioSceneToJSON(value['audio']), + schedule_time_ms: value['scheduleTimeMs'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/VerticalAlign.ts b/packages/composition-openapi/src/generated/models/VerticalAlign.ts new file mode 100644 index 00000000..8a581ecf --- /dev/null +++ b/packages/composition-openapi/src/generated/models/VerticalAlign.ts @@ -0,0 +1,52 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const VerticalAlign = { + Top: 'top', + Center: 'center', + Bottom: 'bottom', + Justified: 'justified', +} as const; +export type VerticalAlign = (typeof VerticalAlign)[keyof typeof VerticalAlign]; + +export function instanceOfVerticalAlign(value: any): boolean { + for (const key in VerticalAlign) { + if (Object.prototype.hasOwnProperty.call(VerticalAlign, key)) { + if (VerticalAlign[key as keyof typeof VerticalAlign] === value) { + return true; + } + } + } + return false; +} + +export function VerticalAlignFromJSON(json: any): VerticalAlign { + return VerticalAlignFromJSONTyped(json, false); +} + +export function VerticalAlignFromJSONTyped(json: any, ignoreDiscriminator: boolean): VerticalAlign { + return json as VerticalAlign; +} + +export function VerticalAlignToJSON(value?: VerticalAlign | null): any { + return value as any; +} + +export function VerticalAlignToJSONTyped(value: any, ignoreDiscriminator: boolean): VerticalAlign { + return value as VerticalAlign; +} diff --git a/packages/composition-openapi/src/generated/models/VideoEncoderBitrate.ts b/packages/composition-openapi/src/generated/models/VideoEncoderBitrate.ts new file mode 100644 index 00000000..712b4729 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/VideoEncoderBitrate.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { AverageAndMaxBitrate } from './AverageAndMaxBitrate'; +import { + instanceOfAverageAndMaxBitrate, + AverageAndMaxBitrateFromJSON, + AverageAndMaxBitrateFromJSONTyped, + AverageAndMaxBitrateToJSON, +} from './AverageAndMaxBitrate'; + +/** + * @type VideoEncoderBitrate + * + * @export + */ +export type VideoEncoderBitrate = AverageAndMaxBitrate | number; + +export function VideoEncoderBitrateFromJSON(json: any): VideoEncoderBitrate { + return VideoEncoderBitrateFromJSONTyped(json, false); +} + +export function VideoEncoderBitrateFromJSONTyped(json: any, ignoreDiscriminator: boolean): VideoEncoderBitrate { + if (json == null) { + return json; + } + if (typeof json !== 'object') { + return json; + } + if (instanceOfAverageAndMaxBitrate(json)) { + return AverageAndMaxBitrateFromJSONTyped(json, true); + } + if (typeof json === 'number') { + return json; + } + return {} as any; +} + +export function VideoEncoderBitrateToJSON(json: any): any { + return VideoEncoderBitrateToJSONTyped(json, false); +} + +export function VideoEncoderBitrateToJSONTyped( + value?: VideoEncoderBitrate | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + if (typeof value !== 'object') { + return value; + } + if (instanceOfAverageAndMaxBitrate(value)) { + return AverageAndMaxBitrateToJSON(value as AverageAndMaxBitrate); + } + if (typeof value === 'number') { + return value; + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/VideoScene.ts b/packages/composition-openapi/src/generated/models/VideoScene.ts new file mode 100644 index 00000000..4e859694 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/VideoScene.ts @@ -0,0 +1,66 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { Component } from './Component'; +import { ComponentFromJSON, ComponentFromJSONTyped, ComponentToJSON, ComponentToJSONTyped } from './Component'; + +/** + * + * @export + * @interface VideoScene + */ +export interface VideoScene { + /** + * + * @type {Component} + * @memberof VideoScene + */ + root: Component; +} + +/** + * Check if a given object implements the VideoScene interface. + */ +export function instanceOfVideoScene(value: object): value is VideoScene { + if (!('root' in value) || value['root'] === undefined) return false; + return true; +} + +export function VideoSceneFromJSON(json: any): VideoScene { + return VideoSceneFromJSONTyped(json, false); +} + +export function VideoSceneFromJSONTyped(json: any, ignoreDiscriminator: boolean): VideoScene { + if (json == null) { + return json; + } + return { + root: ComponentFromJSON(json['root']), + }; +} + +export function VideoSceneToJSON(json: any): VideoScene { + return VideoSceneToJSONTyped(json, false); +} + +export function VideoSceneToJSONTyped(value?: VideoScene | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + root: ComponentToJSON(value['root']), + }; +} diff --git a/packages/composition-openapi/src/generated/models/View.ts b/packages/composition-openapi/src/generated/models/View.ts new file mode 100644 index 00000000..5ba89b47 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/View.ts @@ -0,0 +1,349 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { BoxShadow } from './BoxShadow'; +import { BoxShadowFromJSON, BoxShadowFromJSONTyped, BoxShadowToJSON, BoxShadowToJSONTyped } from './BoxShadow'; +import type { Transition } from './Transition'; +import { TransitionFromJSON, TransitionFromJSONTyped, TransitionToJSON, TransitionToJSONTyped } from './Transition'; +import type { ViewDirection } from './ViewDirection'; +import { + ViewDirectionFromJSON, + ViewDirectionFromJSONTyped, + ViewDirectionToJSON, + ViewDirectionToJSONTyped, +} from './ViewDirection'; +import type { Component } from './Component'; +import { ComponentFromJSON, ComponentFromJSONTyped, ComponentToJSON, ComponentToJSONTyped } from './Component'; +import type { Overflow } from './Overflow'; +import { OverflowFromJSON, OverflowFromJSONTyped, OverflowToJSON, OverflowToJSONTyped } from './Overflow'; + +/** + * + * @export + * @interface View + */ +export interface View { + /** + * Id of a component. + * @type {string} + * @memberof View + */ + id?: string | null; + /** + * List of component's children. + * @type {Array} + * @memberof View + */ + children?: Array | null; + /** + * Width of a component in pixels (without a border). Exact behavior might be different + * based on the parent component: + * - If the parent component is a layout, check sections "Absolute positioning" and "Static + * positioning" of that component. + * - If the parent component is not a layout, then this field is required. + * @type {number} + * @memberof View + */ + width?: number | null; + /** + * Height of a component in pixels (without a border). Exact behavior might be different + * based on the parent component: + * - If the parent component is a layout, check sections "Absolute positioning" and "Static + * positioning" of that component. + * - If the parent component is not a layout, then this field is required. + * @type {number} + * @memberof View + */ + height?: number | null; + /** + * Direction defines how static children are positioned inside a View component. + * @type {ViewDirection} + * @memberof View + */ + direction?: ViewDirection | null; + /** + * Distance in pixels between this component's top edge and its parent's top edge (including a border). + * If this field is defined, then the component will ignore a layout defined by its parent. + * @type {number} + * @memberof View + */ + top?: number | null; + /** + * Distance in pixels between this component's left edge and its parent's left edge (including a border). + * If this field is defined, this element will be absolutely positioned, instead of being + * laid out by its parent. + * @type {number} + * @memberof View + */ + left?: number | null; + /** + * Distance in pixels between the bottom edge of this component and the bottom edge of its + * parent (including a border). If this field is defined, this element will be absolutely + * positioned, instead of being laid out by its parent. + * @type {number} + * @memberof View + */ + bottom?: number | null; + /** + * Distance in pixels between this component's right edge and its parent's right edge. + * If this field is defined, this element will be absolutely positioned, instead of being + * laid out by its parent. + * @type {number} + * @memberof View + */ + right?: number | null; + /** + * Rotation of a component in degrees. If this field is defined, this element will be + * absolutely positioned, instead of being laid out by its parent. + * @type {number} + * @memberof View + */ + rotation?: number | null; + /** + * Defines how this component will behave during a scene update. This will only have an + * effect if the previous scene already contained a `View` component with the same id. + * @type {Transition} + * @memberof View + */ + transition?: Transition | null; + /** + * (**default=`"hidden"`**) Controls what happens to content that is too big to fit into an area. + * @type {Overflow} + * @memberof View + */ + overflow?: Overflow | null; + /** + * (**default=`"#00000000"`**) Background color in a `"#RRGGBBAA"` format. + * @type {string} + * @memberof View + */ + backgroundColor?: string | null; + /** + * (**default=`0.0`**) Radius of a rounded corner. + * @type {number} + * @memberof View + */ + borderRadius?: number | null; + /** + * (**default=`0.0`**) Border width. + * @type {number} + * @memberof View + */ + borderWidth?: number | null; + /** + * (**default=`"#00000000"`**) Border color in a `"#RRGGBBAA"` format. + * @type {string} + * @memberof View + */ + borderColor?: string | null; + /** + * List of box shadows. + * @type {Array} + * @memberof View + */ + boxShadow?: Array | null; + /** + * (**default=`0.0`**) Padding for all sides of the component. + * @type {number} + * @memberof View + */ + padding?: number | null; + /** + * (**default=`0.0`**) Padding for the top and bottom of the component. + * @type {number} + * @memberof View + */ + paddingVertical?: number | null; + /** + * (**default=`0.0`**) Padding for the left and right of the component. + * @type {number} + * @memberof View + */ + paddingHorizontal?: number | null; + /** + * (**default=`0.0`**) Padding on top side in pixels. + * @type {number} + * @memberof View + */ + paddingTop?: number | null; + /** + * (**default=`0.0`**) Padding on right side in pixels. + * @type {number} + * @memberof View + */ + paddingRight?: number | null; + /** + * (**default=`0.0`**) Padding on bottom side in pixels. + * @type {number} + * @memberof View + */ + paddingBottom?: number | null; + /** + * (**default=`0.0`**) Padding on left side in pixels. + * @type {number} + * @memberof View + */ + paddingLeft?: number | null; + /** + * + * @type {ViewTypeEnum} + * @memberof View + */ + type: ViewTypeEnum; +} + +/** + * @export + */ +export const ViewTypeEnum = { + View: 'view', +} as const; +export type ViewTypeEnum = (typeof ViewTypeEnum)[keyof typeof ViewTypeEnum]; + +/** + * Check if a given object implements the View interface. + */ +export function instanceOfView(value: object): value is View { + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'view') return false; + + return true; +} + +export function ViewFromJSON(json: any): View { + return ViewFromJSONTyped(json, false); +} + +export function ViewFromJSONTyped(json: any, ignoreDiscriminator: boolean): View { + if (json == null) { + return json; + } + return { + id: json['id'] === undefined ? undefined : json['id'] === null ? null : json['id'], + children: + json['children'] === undefined + ? undefined + : json['children'] === null + ? null + : (json['children'] as Array).map(ComponentFromJSON), + width: json['width'] === undefined ? undefined : json['width'] === null ? null : json['width'], + height: json['height'] === undefined ? undefined : json['height'] === null ? null : json['height'], + direction: + json['direction'] === undefined + ? undefined + : json['direction'] === null + ? null + : ViewDirectionFromJSON(json['direction']), + top: json['top'] === undefined ? undefined : json['top'] === null ? null : json['top'], + left: json['left'] === undefined ? undefined : json['left'] === null ? null : json['left'], + bottom: json['bottom'] === undefined ? undefined : json['bottom'] === null ? null : json['bottom'], + right: json['right'] === undefined ? undefined : json['right'] === null ? null : json['right'], + rotation: json['rotation'] === undefined ? undefined : json['rotation'] === null ? null : json['rotation'], + transition: + json['transition'] === undefined + ? undefined + : json['transition'] === null + ? null + : TransitionFromJSON(json['transition']), + overflow: + json['overflow'] === undefined + ? undefined + : json['overflow'] === null + ? null + : OverflowFromJSON(json['overflow']), + backgroundColor: + json['background_color'] === undefined + ? undefined + : json['background_color'] === null + ? null + : json['background_color'], + borderRadius: + json['border_radius'] === undefined ? undefined : json['border_radius'] === null ? null : json['border_radius'], + borderWidth: + json['border_width'] === undefined ? undefined : json['border_width'] === null ? null : json['border_width'], + borderColor: + json['border_color'] === undefined ? undefined : json['border_color'] === null ? null : json['border_color'], + boxShadow: + json['box_shadow'] === undefined + ? undefined + : json['box_shadow'] === null + ? null + : (json['box_shadow'] as Array).map(BoxShadowFromJSON), + padding: json['padding'] === undefined ? undefined : json['padding'] === null ? null : json['padding'], + paddingVertical: + json['padding_vertical'] === undefined + ? undefined + : json['padding_vertical'] === null + ? null + : json['padding_vertical'], + paddingHorizontal: + json['padding_horizontal'] === undefined + ? undefined + : json['padding_horizontal'] === null + ? null + : json['padding_horizontal'], + paddingTop: + json['padding_top'] === undefined ? undefined : json['padding_top'] === null ? null : json['padding_top'], + paddingRight: + json['padding_right'] === undefined ? undefined : json['padding_right'] === null ? null : json['padding_right'], + paddingBottom: + json['padding_bottom'] === undefined + ? undefined + : json['padding_bottom'] === null + ? null + : json['padding_bottom'], + paddingLeft: + json['padding_left'] === undefined ? undefined : json['padding_left'] === null ? null : json['padding_left'], + type: json['type'], + }; +} + +export function ViewToJSON(json: any): View { + return ViewToJSONTyped(json, false); +} + +export function ViewToJSONTyped(value?: View | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + id: value['id'], + children: value['children'] == null ? undefined : (value['children'] as Array).map(ComponentToJSON), + width: value['width'], + height: value['height'], + direction: ViewDirectionToJSON(value['direction']), + top: value['top'], + left: value['left'], + bottom: value['bottom'], + right: value['right'], + rotation: value['rotation'], + transition: TransitionToJSON(value['transition']), + overflow: OverflowToJSON(value['overflow']), + background_color: value['backgroundColor'], + border_radius: value['borderRadius'], + border_width: value['borderWidth'], + border_color: value['borderColor'], + box_shadow: value['boxShadow'] == null ? undefined : (value['boxShadow'] as Array).map(BoxShadowToJSON), + padding: value['padding'], + padding_vertical: value['paddingVertical'], + padding_horizontal: value['paddingHorizontal'], + padding_top: value['paddingTop'], + padding_right: value['paddingRight'], + padding_bottom: value['paddingBottom'], + padding_left: value['paddingLeft'], + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/ViewDirection.ts b/packages/composition-openapi/src/generated/models/ViewDirection.ts new file mode 100644 index 00000000..481fcea7 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/ViewDirection.ts @@ -0,0 +1,50 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const ViewDirection = { + Row: 'row', + Column: 'column', +} as const; +export type ViewDirection = (typeof ViewDirection)[keyof typeof ViewDirection]; + +export function instanceOfViewDirection(value: any): boolean { + for (const key in ViewDirection) { + if (Object.prototype.hasOwnProperty.call(ViewDirection, key)) { + if (ViewDirection[key as keyof typeof ViewDirection] === value) { + return true; + } + } + } + return false; +} + +export function ViewDirectionFromJSON(json: any): ViewDirection { + return ViewDirectionFromJSONTyped(json, false); +} + +export function ViewDirectionFromJSONTyped(json: any, ignoreDiscriminator: boolean): ViewDirection { + return json as ViewDirection; +} + +export function ViewDirectionToJSON(value?: ViewDirection | null): any { + return value as any; +} + +export function ViewDirectionToJSONTyped(value: any, ignoreDiscriminator: boolean): ViewDirection { + return value as ViewDirection; +} diff --git a/packages/composition-openapi/src/generated/models/WhepInput.ts b/packages/composition-openapi/src/generated/models/WhepInput.ts new file mode 100644 index 00000000..af37599a --- /dev/null +++ b/packages/composition-openapi/src/generated/models/WhepInput.ts @@ -0,0 +1,105 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface WhepInput + */ +export interface WhepInput { + /** + * WHEP server endpoint URL + * @type {string} + * @memberof WhepInput + */ + endpointUrl: string; + /** + * Optional Bearer token for auth + * @type {string} + * @memberof WhepInput + */ + bearerToken?: string | null; + /** + * If `true`, requests a h264-encoded video track. + * If not provided, it defaults to `true` + * @type {boolean} + * @memberof WhepInput + */ + video?: boolean | null; + /** + * + * @type {WhepInputTypeEnum} + * @memberof WhepInput + */ + type: WhepInputTypeEnum; +} + +/** + * @export + */ +export const WhepInputTypeEnum = { + WhepClient: 'whep_client', +} as const; +export type WhepInputTypeEnum = (typeof WhepInputTypeEnum)[keyof typeof WhepInputTypeEnum]; + +/** + * Check if a given object implements the WhepInput interface. + */ +export function instanceOfWhepInput(value: object): value is WhepInput { + if ( + (!('endpointUrl' in (value as Record)) && !('endpoint_url' in (value as Record))) || + ((value as Record)['endpointUrl'] === undefined && + (value as Record)['endpoint_url'] === undefined) + ) + return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'whep_client') return false; + + return true; +} + +export function WhepInputFromJSON(json: any): WhepInput { + return WhepInputFromJSONTyped(json, false); +} + +export function WhepInputFromJSONTyped(json: any, ignoreDiscriminator: boolean): WhepInput { + if (json == null) { + return json; + } + return { + endpointUrl: json['endpoint_url'], + bearerToken: + json['bearer_token'] === undefined ? undefined : json['bearer_token'] === null ? null : json['bearer_token'], + video: json['video'] === undefined ? undefined : json['video'] === null ? null : json['video'], + type: json['type'], + }; +} + +export function WhepInputToJSON(json: any): WhepInput { + return WhepInputToJSONTyped(json, false); +} + +export function WhepInputToJSONTyped(value?: WhepInput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + endpoint_url: value['endpointUrl'], + bearer_token: value['bearerToken'], + video: value['video'], + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptions.ts b/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptions.ts new file mode 100644 index 00000000..a3da49d7 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptions.ts @@ -0,0 +1,78 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import type { WhipAudioEncoderOptionsAny } from './WhipAudioEncoderOptionsAny'; +import { + instanceOfWhipAudioEncoderOptionsAny, + WhipAudioEncoderOptionsAnyFromJSON, + WhipAudioEncoderOptionsAnyFromJSONTyped, + WhipAudioEncoderOptionsAnyToJSON, +} from './WhipAudioEncoderOptionsAny'; +import type { WhipAudioEncoderOptionsOpus } from './WhipAudioEncoderOptionsOpus'; +import { + instanceOfWhipAudioEncoderOptionsOpus, + WhipAudioEncoderOptionsOpusFromJSON, + WhipAudioEncoderOptionsOpusFromJSONTyped, + WhipAudioEncoderOptionsOpusToJSON, +} from './WhipAudioEncoderOptionsOpus'; + +/** + * @type WhipAudioEncoderOptions + * + * @export + */ +export type WhipAudioEncoderOptions = WhipAudioEncoderOptionsAny | WhipAudioEncoderOptionsOpus; + +export function WhipAudioEncoderOptionsFromJSON(json: any): WhipAudioEncoderOptions { + return WhipAudioEncoderOptionsFromJSONTyped(json, false); +} + +export function WhipAudioEncoderOptionsFromJSONTyped(json: any, ignoreDiscriminator: boolean): WhipAudioEncoderOptions { + if (json == null) { + return json; + } + if (typeof json !== 'object') { + return json; + } + if (instanceOfWhipAudioEncoderOptionsAny(json)) { + return WhipAudioEncoderOptionsAnyFromJSONTyped(json, true); + } + if (instanceOfWhipAudioEncoderOptionsOpus(json)) { + return WhipAudioEncoderOptionsOpusFromJSONTyped(json, true); + } + return {} as any; +} + +export function WhipAudioEncoderOptionsToJSON(json: any): any { + return WhipAudioEncoderOptionsToJSONTyped(json, false); +} + +export function WhipAudioEncoderOptionsToJSONTyped( + value?: WhipAudioEncoderOptions | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + if (typeof value !== 'object') { + return value; + } + if (instanceOfWhipAudioEncoderOptionsAny(value)) { + return WhipAudioEncoderOptionsAnyToJSON(value as WhipAudioEncoderOptionsAny); + } + if (instanceOfWhipAudioEncoderOptionsOpus(value)) { + return WhipAudioEncoderOptionsOpusToJSON(value as WhipAudioEncoderOptionsOpus); + } + return {}; +} diff --git a/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptionsAny.ts b/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptionsAny.ts new file mode 100644 index 00000000..4dca3437 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptionsAny.ts @@ -0,0 +1,80 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface WhipAudioEncoderOptionsAny + */ +export interface WhipAudioEncoderOptionsAny { + /** + * + * @type {WhipAudioEncoderOptionsAnyTypeEnum} + * @memberof WhipAudioEncoderOptionsAny + */ + type: WhipAudioEncoderOptionsAnyTypeEnum; +} + +/** + * @export + */ +export const WhipAudioEncoderOptionsAnyTypeEnum = { + Any: 'any', +} as const; +export type WhipAudioEncoderOptionsAnyTypeEnum = + (typeof WhipAudioEncoderOptionsAnyTypeEnum)[keyof typeof WhipAudioEncoderOptionsAnyTypeEnum]; + +/** + * Check if a given object implements the WhipAudioEncoderOptionsAny interface. + */ +export function instanceOfWhipAudioEncoderOptionsAny(value: object): value is WhipAudioEncoderOptionsAny { + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'any') return false; + + return true; +} + +export function WhipAudioEncoderOptionsAnyFromJSON(json: any): WhipAudioEncoderOptionsAny { + return WhipAudioEncoderOptionsAnyFromJSONTyped(json, false); +} + +export function WhipAudioEncoderOptionsAnyFromJSONTyped( + json: any, + ignoreDiscriminator: boolean +): WhipAudioEncoderOptionsAny { + if (json == null) { + return json; + } + return { + type: json['type'], + }; +} + +export function WhipAudioEncoderOptionsAnyToJSON(json: any): WhipAudioEncoderOptionsAny { + return WhipAudioEncoderOptionsAnyToJSONTyped(json, false); +} + +export function WhipAudioEncoderOptionsAnyToJSONTyped( + value?: WhipAudioEncoderOptionsAny | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptionsOpus.ts b/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptionsOpus.ts new file mode 100644 index 00000000..077be7e9 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/WhipAudioEncoderOptionsOpus.ts @@ -0,0 +1,123 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { OpusEncoderPreset } from './OpusEncoderPreset'; +import { + OpusEncoderPresetFromJSON, + OpusEncoderPresetFromJSONTyped, + OpusEncoderPresetToJSON, + OpusEncoderPresetToJSONTyped, +} from './OpusEncoderPreset'; + +/** + * + * @export + * @interface WhipAudioEncoderOptionsOpus + */ +export interface WhipAudioEncoderOptionsOpus { + /** + * (**default="voip"**) Specifies preset for audio output encoder. + * @type {OpusEncoderPreset} + * @memberof WhipAudioEncoderOptionsOpus + */ + preset?: OpusEncoderPreset | null; + /** + * (**default=`48000`**) Sample rate. Allowed values: [8000, 16000, 24000, 48000]. + * @type {number} + * @memberof WhipAudioEncoderOptionsOpus + */ + sampleRate?: number | null; + /** + * (**default=`false`**) Specifies if forward error correction (FEC) should be used. + * @type {boolean} + * @memberof WhipAudioEncoderOptionsOpus + */ + forwardErrorCorrection?: boolean | null; + /** + * + * @type {WhipAudioEncoderOptionsOpusTypeEnum} + * @memberof WhipAudioEncoderOptionsOpus + */ + type: WhipAudioEncoderOptionsOpusTypeEnum; +} + +/** + * @export + */ +export const WhipAudioEncoderOptionsOpusTypeEnum = { + Opus: 'opus', +} as const; +export type WhipAudioEncoderOptionsOpusTypeEnum = + (typeof WhipAudioEncoderOptionsOpusTypeEnum)[keyof typeof WhipAudioEncoderOptionsOpusTypeEnum]; + +/** + * Check if a given object implements the WhipAudioEncoderOptionsOpus interface. + */ +export function instanceOfWhipAudioEncoderOptionsOpus(value: object): value is WhipAudioEncoderOptionsOpus { + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'opus') return false; + + return true; +} + +export function WhipAudioEncoderOptionsOpusFromJSON(json: any): WhipAudioEncoderOptionsOpus { + return WhipAudioEncoderOptionsOpusFromJSONTyped(json, false); +} + +export function WhipAudioEncoderOptionsOpusFromJSONTyped( + json: any, + ignoreDiscriminator: boolean +): WhipAudioEncoderOptionsOpus { + if (json == null) { + return json; + } + return { + preset: + json['preset'] === undefined + ? undefined + : json['preset'] === null + ? null + : OpusEncoderPresetFromJSON(json['preset']), + sampleRate: + json['sample_rate'] === undefined ? undefined : json['sample_rate'] === null ? null : json['sample_rate'], + forwardErrorCorrection: + json['forward_error_correction'] === undefined + ? undefined + : json['forward_error_correction'] === null + ? null + : json['forward_error_correction'], + type: json['type'], + }; +} + +export function WhipAudioEncoderOptionsOpusToJSON(json: any): WhipAudioEncoderOptionsOpus { + return WhipAudioEncoderOptionsOpusToJSONTyped(json, false); +} + +export function WhipAudioEncoderOptionsOpusToJSONTyped( + value?: WhipAudioEncoderOptionsOpus | null, + ignoreDiscriminator: boolean = false +): any { + if (value == null) { + return value; + } + + return { + preset: OpusEncoderPresetToJSON(value['preset']), + sample_rate: value['sampleRate'], + forward_error_correction: value['forwardErrorCorrection'], + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/WhipInput.ts b/packages/composition-openapi/src/generated/models/WhipInput.ts new file mode 100644 index 00000000..deac0010 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/WhipInput.ts @@ -0,0 +1,92 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface WhipInput + */ +export interface WhipInput { + /** + * Token used for authentication in WHIP protocol. If not provided, the random value + * will be generated and returned in the response. + * @type {string} + * @memberof WhipInput + */ + bearerToken?: string | null; + /** + * If `true`, accepts a h264-encoded video track. + * If not provided, it defaults to `true` + * @type {boolean} + * @memberof WhipInput + */ + video?: boolean | null; + /** + * + * @type {WhipInputTypeEnum} + * @memberof WhipInput + */ + type: WhipInputTypeEnum; +} + +/** + * @export + */ +export const WhipInputTypeEnum = { + WhipServer: 'whip_server', +} as const; +export type WhipInputTypeEnum = (typeof WhipInputTypeEnum)[keyof typeof WhipInputTypeEnum]; + +/** + * Check if a given object implements the WhipInput interface. + */ +export function instanceOfWhipInput(value: object): value is WhipInput { + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'whip_server') return false; + + return true; +} + +export function WhipInputFromJSON(json: any): WhipInput { + return WhipInputFromJSONTyped(json, false); +} + +export function WhipInputFromJSONTyped(json: any, ignoreDiscriminator: boolean): WhipInput { + if (json == null) { + return json; + } + return { + bearerToken: + json['bearer_token'] === undefined ? undefined : json['bearer_token'] === null ? null : json['bearer_token'], + video: json['video'] === undefined ? undefined : json['video'] === null ? null : json['video'], + type: json['type'], + }; +} + +export function WhipInputToJSON(json: any): WhipInput { + return WhipInputToJSONTyped(json, false); +} + +export function WhipInputToJSONTyped(value?: WhipInput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + bearer_token: value['bearerToken'], + video: value['video'], + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/WhipOutput.ts b/packages/composition-openapi/src/generated/models/WhipOutput.ts new file mode 100644 index 00000000..93bfe866 --- /dev/null +++ b/packages/composition-openapi/src/generated/models/WhipOutput.ts @@ -0,0 +1,137 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +import type { OutputWhipVideoOptions } from './OutputWhipVideoOptions'; +import { + OutputWhipVideoOptionsFromJSON, + OutputWhipVideoOptionsFromJSONTyped, + OutputWhipVideoOptionsToJSON, + OutputWhipVideoOptionsToJSONTyped, +} from './OutputWhipVideoOptions'; +import type { OutputWhipAudioOptions } from './OutputWhipAudioOptions'; +import { + OutputWhipAudioOptionsFromJSON, + OutputWhipAudioOptionsFromJSONTyped, + OutputWhipAudioOptionsToJSON, + OutputWhipAudioOptionsToJSONTyped, +} from './OutputWhipAudioOptions'; + +/** + * + * @export + * @interface WhipOutput + */ +export interface WhipOutput { + /** + * WHIP server endpoint + * @type {string} + * @memberof WhipOutput + */ + endpointUrl: string; + /** + * + * @type {string} + * @memberof WhipOutput + */ + bearerToken?: string | null; + /** + * Video track configuration. + * @type {OutputWhipVideoOptions} + * @memberof WhipOutput + */ + video?: OutputWhipVideoOptions | null; + /** + * Audio track configuration. + * @type {OutputWhipAudioOptions} + * @memberof WhipOutput + */ + audio?: OutputWhipAudioOptions | null; + /** + * + * @type {WhipOutputTypeEnum} + * @memberof WhipOutput + */ + type: WhipOutputTypeEnum; +} + +/** + * @export + */ +export const WhipOutputTypeEnum = { + WhipClient: 'whip_client', +} as const; +export type WhipOutputTypeEnum = (typeof WhipOutputTypeEnum)[keyof typeof WhipOutputTypeEnum]; + +/** + * Check if a given object implements the WhipOutput interface. + */ +export function instanceOfWhipOutput(value: object): value is WhipOutput { + if ( + (!('endpointUrl' in (value as Record)) && !('endpoint_url' in (value as Record))) || + ((value as Record)['endpointUrl'] === undefined && + (value as Record)['endpoint_url'] === undefined) + ) + return false; + if (!('type' in value) || value['type'] === undefined) return false; + if (value['type'] !== 'whip_client') return false; + + return true; +} + +export function WhipOutputFromJSON(json: any): WhipOutput { + return WhipOutputFromJSONTyped(json, false); +} + +export function WhipOutputFromJSONTyped(json: any, ignoreDiscriminator: boolean): WhipOutput { + if (json == null) { + return json; + } + return { + endpointUrl: json['endpoint_url'], + bearerToken: + json['bearer_token'] === undefined ? undefined : json['bearer_token'] === null ? null : json['bearer_token'], + video: + json['video'] === undefined + ? undefined + : json['video'] === null + ? null + : OutputWhipVideoOptionsFromJSON(json['video']), + audio: + json['audio'] === undefined + ? undefined + : json['audio'] === null + ? null + : OutputWhipAudioOptionsFromJSON(json['audio']), + type: json['type'], + }; +} + +export function WhipOutputToJSON(json: any): WhipOutput { + return WhipOutputToJSONTyped(json, false); +} + +export function WhipOutputToJSONTyped(value?: WhipOutput | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + endpoint_url: value['endpointUrl'], + bearer_token: value['bearerToken'], + video: OutputWhipVideoOptionsToJSON(value['video']), + audio: OutputWhipAudioOptionsToJSON(value['audio']), + type: value['type'], + }; +} diff --git a/packages/composition-openapi/src/generated/models/index.ts b/packages/composition-openapi/src/generated/models/index.ts new file mode 100644 index 00000000..aed3fb3c --- /dev/null +++ b/packages/composition-openapi/src/generated/models/index.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/* eslint-disable */ +export * from './ApiError'; +export * from './AudioChannels'; +export * from './AudioMixingStrategy'; +export * from './AudioScene'; +export * from './AudioSceneInput'; +export * from './AverageAndMaxBitrate'; +export * from './BoxShadow'; +export * from './Component'; +export * from './CompositionCreatedResponse'; +export * from './CreateCompositionRequest'; +export * from './EasingFunction'; +export * from './EasingFunctionBounce'; +export * from './EasingFunctionCubicBezier'; +export * from './EasingFunctionLinear'; +export * from './FontUpload'; +export * from './Framerate'; +export * from './H264EncoderPreset'; +export * from './HorizontalAlign'; +export * from './Image'; +export * from './ImageSpec'; +export * from './ImageSpecAuto'; +export * from './ImageSpecGif'; +export * from './ImageSpecJpeg'; +export * from './ImageSpecPng'; +export * from './ImageSpecSvg'; +export * from './InputStream'; +export * from './Interpolation'; +export * from './Mp4Input'; +export * from './OpusEncoderPreset'; +export * from './OutputEndCondition'; +export * from './OutputRtmpClientAudioOptions'; +export * from './OutputRtmpClientVideoOptions'; +export * from './OutputWhipAudioOptions'; +export * from './OutputWhipVideoOptions'; +export * from './Overflow'; +export * from './PixelFormat'; +export * from './PortOrPortRange'; +export * from './RegisterInput'; +export * from './RegisterInputResponse'; +export * from './RegisterOutput'; +export * from './RegisterTemplateOutput'; +export * from './RescaleMode'; +export * from './Rescaler'; +export * from './Resolution'; +export * from './RtmpInput'; +export * from './RtmpOutput'; +export * from './SendCompositionEventRequest'; +export * from './Text'; +export * from './TextStyle'; +export * from './TextWeight'; +export * from './TextWrapMode'; +export * from './Tiles'; +export * from './Transition'; +export * from './TransportProtocol'; +export * from './UnregisterInput'; +export * from './UnregisterOutput'; +export * from './UnregisterRenderer'; +export * from './UpdateOutputRequest'; +export * from './VerticalAlign'; +export * from './VideoEncoderBitrate'; +export * from './VideoScene'; +export * from './View'; +export * from './ViewDirection'; +export * from './WhepInput'; +export * from './WhipAudioEncoderOptions'; +export * from './WhipAudioEncoderOptionsAny'; +export * from './WhipAudioEncoderOptionsOpus'; +export * from './WhipInput'; +export * from './WhipOutput'; diff --git a/packages/composition-openapi/src/generated/runtime.ts b/packages/composition-openapi/src/generated/runtime.ts new file mode 100644 index 00000000..cf8f9f39 --- /dev/null +++ b/packages/composition-openapi/src/generated/runtime.ts @@ -0,0 +1,497 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Composition API + * Real-time video compositing + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +export const BASE_PATH = 'https://rtc.fishjam.io'.replace(/\/+$/, ''); + +export interface ConfigurationParameters { + basePath?: string; // override base path + fetchApi?: FetchAPI; // override for fetch implementation + middleware?: Middleware[]; // middleware to apply before/after fetch requests + queryParamsStringify?: (params: HTTPQuery) => string; // stringify function for query strings + username?: string; // parameter for basic security + password?: string; // parameter for basic security + apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + headers?: HTTPHeaders; //header params we want to use on every request + credentials?: RequestCredentials; //value for the credentials param we want to use on each request +} + +export class Configuration { + constructor(private configuration: ConfigurationParameters = {}) {} + + set config(configuration: Configuration) { + this.configuration = configuration; + } + + get basePath(): string { + return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH; + } + + get fetchApi(): FetchAPI | undefined { + return this.configuration.fetchApi; + } + + get middleware(): Middleware[] { + return this.configuration.middleware || []; + } + + get queryParamsStringify(): (params: HTTPQuery) => string { + return this.configuration.queryParamsStringify || querystring; + } + + get username(): string | undefined { + return this.configuration.username; + } + + get password(): string | undefined { + return this.configuration.password; + } + + get apiKey(): ((name: string) => string | Promise) | undefined { + const apiKey = this.configuration.apiKey; + if (apiKey) { + return typeof apiKey === 'function' ? apiKey : () => apiKey; + } + return undefined; + } + + get accessToken(): ((name?: string, scopes?: string[]) => string | Promise) | undefined { + const accessToken = this.configuration.accessToken; + if (accessToken) { + return typeof accessToken === 'function' ? accessToken : async () => accessToken; + } + return undefined; + } + + get headers(): HTTPHeaders | undefined { + return this.configuration.headers; + } + + get credentials(): RequestCredentials | undefined { + return this.configuration.credentials; + } +} + +export const DefaultConfig = new Configuration(); + +/** + * This is the base class for all generated API classes. + */ +export class BaseAPI { + private static readonly jsonRegex = /^(:?application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$/i; + private middleware: Middleware[]; + + constructor(protected configuration = DefaultConfig) { + this.middleware = configuration.middleware; + } + + withMiddleware(this: T, ...middlewares: Middleware[]) { + const next = this.clone(); + next.middleware = next.middleware.concat(...middlewares); + return next; + } + + withPreMiddleware(this: T, ...preMiddlewares: Array) { + const middlewares = preMiddlewares.map((pre) => ({ pre })); + return this.withMiddleware(...middlewares); + } + + withPostMiddleware(this: T, ...postMiddlewares: Array) { + const middlewares = postMiddlewares.map((post) => ({ post })); + return this.withMiddleware(...middlewares); + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + protected isJsonMime(mime: string | null | undefined): boolean { + if (!mime) { + return false; + } + return BaseAPI.jsonRegex.test(mime); + } + + protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + const { url, init } = await this.createFetchParams(context, initOverrides); + const response = await this.fetchApi(url, init); + if (response && response.status >= 200 && response.status < 300) { + return response; + } + throw new ResponseError(response, 'Response returned an error code'); + } + + private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + let url = this.configuration.basePath + context.path; + if (context.query !== undefined && Object.keys(context.query).length !== 0) { + // only add the querystring to the URL if there are query parameters. + // this is done to avoid urls ending with a "?" character which buggy webservers + // do not handle correctly sometimes. + url += '?' + this.configuration.queryParamsStringify(context.query); + } + + const headers = Object.assign({}, this.configuration.headers, context.headers); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); + + const initOverrideFn = typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; + + const initParams = { + method: context.method, + headers, + body: context.body, + credentials: this.configuration.credentials, + }; + + const overriddenInit: RequestInit = { + ...initParams, + ...(await initOverrideFn({ + init: initParams, + context, + })), + }; + + let body: any; + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { + body = overriddenInit.body; + } else if (this.isJsonMime(headers['Content-Type'])) { + body = JSON.stringify(overriddenInit.body); + } else { + body = overriddenInit.body; + } + + const init: RequestInit = { + ...overriddenInit, + body, + }; + + return { url, init }; + } + + private fetchApi = async (url: string, init: RequestInit) => { + let fetchParams = { url, init }; + for (const middleware of this.middleware) { + if (middleware.pre) { + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; + } + } + let response: Response | undefined = undefined; + try { + response = await (this.configuration.fetchApi || fetch)(fetchParams.url, fetchParams.init); + } catch (e) { + for (const middleware of this.middleware) { + if (middleware.onError) { + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; + } + } + if (response === undefined) { + if (e instanceof Error) { + throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + } else { + throw e; + } + } + } + for (const middleware of this.middleware) { + if (middleware.post) { + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; + } + } + return response; + }; + + /** + * Create a shallow clone of `this` by constructing a new instance + * and then shallow cloning data members. + */ + private clone(this: T): T { + const constructor = this.constructor as any; + const next = new constructor(this.configuration); + next.middleware = this.middleware.slice(); + return next; + } +} + +function isBlob(value: any): value is Blob { + return typeof Blob !== 'undefined' && value instanceof Blob; +} + +function isFormData(value: any): value is FormData { + return typeof FormData !== 'undefined' && value instanceof FormData; +} + +export class ResponseError extends Error { + override name: 'ResponseError' = 'ResponseError'; + constructor( + public response: Response, + msg?: string + ) { + super(msg); + + // restore prototype chain + const actualProto = new.target.prototype; + if (Object.setPrototypeOf) { + Object.setPrototypeOf(this, actualProto); + } + } +} + +export class FetchError extends Error { + override name: 'FetchError' = 'FetchError'; + constructor( + public cause: Error, + msg?: string + ) { + super(msg); + + // restore prototype chain + const actualProto = new.target.prototype; + if (Object.setPrototypeOf) { + Object.setPrototypeOf(this, actualProto); + } + } +} + +export class RequiredError extends Error { + override name: 'RequiredError' = 'RequiredError'; + constructor( + public field: string, + msg?: string + ) { + super(msg); + + // restore prototype chain + const actualProto = new.target.prototype; + if (Object.setPrototypeOf) { + Object.setPrototypeOf(this, actualProto); + } + } +} + +export const COLLECTION_FORMATS = { + csv: ',', + ssv: ' ', + tsv: '\t', + pipes: '|', +}; + +export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; + +export type Json = any; +export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; +export type HTTPHeaders = { [key: string]: string }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; +export type HTTPBody = Json | FormData | URLSearchParams; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; +}; +export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; + +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; + +export interface FetchParams { + url: string; + init: RequestInit; +} + +export interface RequestOpts { + path: string; + method: HTTPMethod; + headers: HTTPHeaders; + query?: HTTPQuery; + body?: HTTPBody; +} + +export function querystring(params: HTTPQuery, prefix: string = ''): string { + return Object.keys(params) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) + .join('&'); +} + +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '' +): string { + const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); + if (value instanceof Array) { + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) + .join(`&${encodeURIComponent(fullKey)}=`); + return `${encodeURIComponent(fullKey)}=${multiValue}`; + } + if (value instanceof Set) { + const valueAsArray = Array.from(value); + return querystringSingleKey(key, valueAsArray, keyPrefix); + } + if (value instanceof Date) { + return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`; + } + if (value instanceof Object) { + return querystring(value as HTTPQuery, fullKey); + } + return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`; +} + +export function exists(json: any, key: string) { + const value = json[key]; + return value !== null && value !== undefined; +} + +export function mapValues(data: any, fn: (item: any) => any) { + const result: { [key: string]: any } = {}; + for (const key of Object.keys(data)) { + result[key] = fn(data[key]); + } + return result; +} + +// Pass-through serializer for `any`-typed properties in form data. See #1877. +export function anyToJSON(value: any): any { + return value; +} + +export function canConsumeForm(consumes: Consume[]): boolean { + for (const consume of consumes) { + if (consume.contentType?.startsWith('multipart/form-data') == true) { + return true; + } + } + return false; +} + +export interface Consume { + contentType: string; +} + +export interface RequestContext { + fetch: FetchAPI; + url: string; + init: RequestInit; +} + +export interface ResponseContext { + fetch: FetchAPI; + url: string; + init: RequestInit; + response: Response; +} + +export interface ErrorContext { + fetch: FetchAPI; + url: string; + init: RequestInit; + error: unknown; + response?: Response; +} + +export interface Middleware { + pre?(context: RequestContext): Promise; + post?(context: ResponseContext): Promise; + onError?(context: ErrorContext): Promise; +} + +export interface ApiResponse { + raw: Response; + value(): Promise; +} + +export interface ResponseTransformer { + (json: any): T; +} + +export class JSONApiResponse { + constructor( + public raw: Response, + private transformer: ResponseTransformer = (jsonValue: any) => jsonValue + ) {} + + async value(): Promise { + return this.transformer(await this.raw.json()); + } +} + +export class VoidApiResponse { + constructor(public raw: Response) {} + + async value(): Promise { + return undefined; + } +} + +export class BlobApiResponse { + constructor(public raw: Response) {} + + async value(): Promise { + return await this.raw.blob(); + } +} + +export class TextApiResponse { + constructor(public raw: Response) {} + + async value(): Promise { + return await this.raw.text(); + } +} diff --git a/packages/composition-openapi/src/index.ts b/packages/composition-openapi/src/index.ts new file mode 100644 index 00000000..69e4e4eb --- /dev/null +++ b/packages/composition-openapi/src/index.ts @@ -0,0 +1 @@ +export * from './generated'; diff --git a/packages/composition-openapi/tsconfig.json b/packages/composition-openapi/tsconfig.json new file mode 100644 index 00000000..fd152b94 --- /dev/null +++ b/packages/composition-openapi/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "moduleResolution": "node", + "outDir": "dist/", + }, + "include": ["./src"], +} \ No newline at end of file From db878346464b362ef39f141cb0af45ba305a3d9b Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 21 Aug 2026 16:57:43 +0200 Subject: [PATCH 02/15] Bundle composition-openapi into the SDK --- packages/js-server-sdk/package.json | 2 + yarn.lock | 81 +++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/packages/js-server-sdk/package.json b/packages/js-server-sdk/package.json index 63b346bc..3f697cb0 100644 --- a/packages/js-server-sdk/package.json +++ b/packages/js-server-sdk/package.json @@ -51,6 +51,7 @@ "src/proto.ts" ], "noExternal": [ + "composition-openapi", "fishjam-openapi", "fishjam-proto" ], @@ -76,6 +77,7 @@ } }, "devDependencies": { + "@fishjam-cloud/composition-openapi": "workspace:*", "@fishjam-cloud/fishjam-openapi": "workspace:*", "@fishjam-cloud/fishjam-proto": "workspace:*", "@openapitools/openapi-generator-cli": "^2.18.4", diff --git a/yarn.lock b/yarn.lock index 56b9b769..56bdf4ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1747,7 +1747,7 @@ __metadata: languageName: node linkType: hard -"@fishjam-cloud/composition-cli@workspace:packages/composition-cli": +"@fishjam-cloud/composition-cli@workspace:*, @fishjam-cloud/composition-cli@workspace:packages/composition-cli": version: 0.0.0-use.local resolution: "@fishjam-cloud/composition-cli@workspace:packages/composition-cli" dependencies: @@ -1766,7 +1766,16 @@ __metadata: languageName: unknown linkType: soft -"@fishjam-cloud/composition@workspace:packages/composition": +"@fishjam-cloud/composition-openapi@workspace:*, @fishjam-cloud/composition-openapi@workspace:packages/composition-openapi": + version: 0.0.0-use.local + resolution: "@fishjam-cloud/composition-openapi@workspace:packages/composition-openapi" + dependencies: + "@openapitools/openapi-generator-cli": "npm:^2.18.4" + tsup: "npm:^8.4.0" + languageName: unknown + linkType: soft + +"@fishjam-cloud/composition@workspace:*, @fishjam-cloud/composition@workspace:packages/composition": version: 0.0.0-use.local resolution: "@fishjam-cloud/composition@workspace:packages/composition" dependencies: @@ -1808,6 +1817,7 @@ __metadata: version: 0.0.0-use.local resolution: "@fishjam-cloud/js-server-sdk@workspace:packages/js-server-sdk" dependencies: + "@fishjam-cloud/composition-openapi": "workspace:*" "@fishjam-cloud/fishjam-openapi": "workspace:*" "@fishjam-cloud/fishjam-proto": "workspace:*" "@openapitools/openapi-generator-cli": "npm:^2.18.4" @@ -1866,6 +1876,15 @@ __metadata: languageName: node linkType: hard +"@hono/node-server@npm:^1.13.0": + version: 1.19.17 + resolution: "@hono/node-server@npm:1.19.17" + peerDependencies: + hono: ^4 + checksum: 10c0/e77907e3b5db8ab68ed4f297ad84807bfdd698636408de86ab8d36dab4658504ac4c0ed9d9436bc272a0172b9b7a5a4b578532e0b5baf97674c7b420cb5cff4b + languageName: node + linkType: hard + "@humanfs/core@npm:^0.19.1": version: 0.19.1 resolution: "@humanfs/core@npm:0.19.1" @@ -2671,6 +2690,15 @@ __metadata: languageName: node linkType: hard +"@swmansion/smelter@npm:0.3.0": + version: 0.3.0 + resolution: "@swmansion/smelter@npm:0.3.0" + peerDependencies: + react: "*" + checksum: 10c0/3d40fda353193fe3bae3b9fe13e146e654613ce817a6b8e0c12c924e3a7361d49b99a0e1bfa9a0c768aa461524dabcc5fe37da993c4ea110458c77ed4edd98b0 + languageName: node + linkType: hard + "@tootallnate/quickjs-emscripten@npm:^0.23.0": version: 0.23.0 resolution: "@tootallnate/quickjs-emscripten@npm:0.23.0" @@ -2834,7 +2862,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^18": +"@types/react@npm:^18, @types/react@npm:^18.3.0": version: 18.3.31 resolution: "@types/react@npm:18.3.31" dependencies: @@ -3870,6 +3898,24 @@ __metadata: languageName: node linkType: hard +"composition-demo@workspace:examples/composition": + version: 0.0.0-use.local + resolution: "composition-demo@workspace:examples/composition" + dependencies: + "@fishjam-cloud/composition": "workspace:*" + "@fishjam-cloud/composition-cli": "workspace:*" + "@fishjam-cloud/js-server-sdk": "workspace:*" + "@hono/node-server": "npm:^1.13.0" + "@swmansion/smelter": "npm:0.3.0" + "@types/node": "npm:^22.13.16" + "@types/react": "npm:^18.3.0" + hono: "npm:^4.6.0" + prettier: "npm:^3.6.2" + react: "npm:^18.3.1" + typescript: "npm:^5.9.3" + languageName: unknown + linkType: soft + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -5823,6 +5869,13 @@ __metadata: languageName: node linkType: hard +"hono@npm:^4.6.0": + version: 4.13.3 + resolution: "hono@npm:4.13.3" + checksum: 10c0/51ab0e8f2f769e806c7e2d6d0e1577643fa35e442250ffe4cc69cffa4a276aad5d2db4edc15ab2210ae0ef478638e44937d8b3e2eded313a05793bc219239c4b + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" @@ -6104,7 +6157,7 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^4.0.0": +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed @@ -6396,6 +6449,17 @@ __metadata: languageName: node linkType: hard +"loose-envify@npm:^1.1.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: "npm:^3.0.0 || ^4.0.0" + bin: + loose-envify: cli.js + checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e + languageName: node + linkType: hard + "loupe@npm:^3.1.0, loupe@npm:^3.1.4": version: 3.2.1 resolution: "loupe@npm:3.2.1" @@ -7393,6 +7457,15 @@ __metadata: languageName: node linkType: hard +"react@npm:^18.3.1": + version: 18.3.1 + resolution: "react@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10c0/283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3 + languageName: node + linkType: hard + "react@npm:^19.0.0": version: 19.2.7 resolution: "react@npm:19.2.7" From 9e3d7f6bd9554deafc8ddd15501d5b69979b43b2 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 21 Aug 2026 16:57:44 +0200 Subject: [PATCH 03/15] Add CompositionClient --- packages/js-server-sdk/src/composition.ts | 363 ++++++++++++++++++ .../js-server-sdk/src/exceptions/index.ts | 8 + .../js-server-sdk/src/exceptions/mapper.ts | 25 +- packages/js-server-sdk/src/index.ts | 61 +++ packages/js-server-sdk/src/types.ts | 67 +++- packages/js-server-sdk/src/utils.ts | 18 +- 6 files changed, 534 insertions(+), 8 deletions(-) create mode 100644 packages/js-server-sdk/src/composition.ts diff --git a/packages/js-server-sdk/src/composition.ts b/packages/js-server-sdk/src/composition.ts new file mode 100644 index 00000000..f8ee15cb --- /dev/null +++ b/packages/js-server-sdk/src/composition.ts @@ -0,0 +1,363 @@ +import { + Configuration, + CompositionsApi, + EventsApi, + InputsApi, + OutputsApi, + RenderersApi, + type CreateCompositionRequest, + type ImageSpec, + type Mp4Input, + type RegisterInput, + type RegisterInputResponse, + type RegisterOutput, + type SendCompositionEventRequest, + type UnregisterInput, + type UnregisterOutput, + type UnregisterRenderer, + type RtmpInput, + type RtmpOutput, + type UpdateOutputRequest, + type WhepInput, + type WhipInput, + type WhipOutput, +} from '@fishjam-cloud/composition-openapi'; +import { UnknownException } from './exceptions'; +import { mapException } from './exceptions/mapper'; +import type { + Composition, + CompositionConfig, + CompositionId, + InputId, + Mp4InputDurations, + OutputId, + RendererId, + RtmpInputPort, + WhipInputTarget, +} from './types'; +import { getCompositionUrl, toBlob } from './utils'; + +/** + * Client class that allows to manage compositions, the real-time video compositing sessions + * of a Fishjam App. It requires the management token that can be retrieved from the Fishjam + * Dashboard, the same one used by {@link FishjamClient}. + * + * Example usage: + * ``` + * const compositionClient = new CompositionClient({ + * managementToken: fastify.config.FISHJAM_MANAGEMENT_TOKEN, + * }); + * ``` + * @category Client + */ +export class CompositionClient { + private readonly compositionsApi: CompositionsApi; + private readonly eventsApi: EventsApi; + private readonly inputsApi: InputsApi; + private readonly outputsApi: OutputsApi; + private readonly renderersApi: RenderersApi; + private readonly baseUrl: string; + + constructor(config: CompositionConfig) { + this.baseUrl = getCompositionUrl(config); + + const apiConfig = new Configuration({ + basePath: this.baseUrl, + headers: { Authorization: `Bearer ${config.managementToken}` }, + }); + + this.compositionsApi = new CompositionsApi(apiConfig); + this.eventsApi = new EventsApi(apiConfig); + this.inputsApi = new InputsApi(apiConfig); + this.outputsApi = new OutputsApi(apiConfig); + this.renderersApi = new RenderersApi(apiConfig); + } + + /** + * Create a new composition. Inputs registered on it are composed into the scenes its outputs render. + */ + async createComposition(config: CreateCompositionRequest = {}): Promise { + try { + return (await this.compositionsApi.createComposition({ createCompositionRequest: config })) as Composition; + } catch (error) { + throw await mapException(error); + } + } + + /** + * The address of a composition, as other services refer to it. Fishjam needs it to forward a + * room's tracks with {@link FishjamClient.forwardRoomTracks}. + */ + compositionUrl(compositionId: CompositionId): string { + return new URL(`/api/composition/${compositionId}`, this.baseUrl).href; + } + + /** + * Start a composition created with `autostart` disabled. Its outputs begin producing audio and video. + */ + async startComposition(compositionId: CompositionId): Promise { + try { + await this.compositionsApi.start({ compositionId }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Reset a composition, tearing down its scene while keeping the composition itself alive. + */ + async resetComposition(compositionId: CompositionId): Promise { + try { + await this.compositionsApi.reset({ compositionId }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Delete an existing composition. Its inputs and outputs are torn down with it. + */ + async deleteComposition(compositionId: CompositionId): Promise { + try { + await this.compositionsApi.deleteComposition({ compositionId }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Register a media source on a composition. Prefer the variant methods, such as + * {@link CompositionClient.registerWhipInput}, which return what that input type produces. + */ + async registerInput( + compositionId: CompositionId, + inputId: InputId, + input: RegisterInput + ): Promise { + try { + return await this.inputsApi.registerInput({ compositionId, inputId, registerInput: input }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Register an input that a WHIP publisher pushes media into. + * @returns the address and token to publish with, see {@link WhipInputTarget} + */ + async registerWhipInput( + compositionId: CompositionId, + inputId: InputId, + options: Omit = {} + ): Promise { + const { bearerToken, endpointRoute } = await this.registerInput(compositionId, inputId, { + ...options, + type: 'whip_server', + }); + + const token = bearerToken ?? options.bearerToken; + if (!token) { + throw new UnknownException({ + message: `Registering WHIP input "${inputId}" returned no bearer token, so it cannot be published to`, + }); + } + + const route = endpointRoute ?? `/whip/${encodeURIComponent(inputId)}`; + return { url: `${this.compositionUrl(compositionId)}${route}`, bearerToken: token }; + } + + /** + * Register an input that pulls media from a WHEP endpoint. + */ + async registerWhepInput( + compositionId: CompositionId, + inputId: InputId, + options: Omit + ): Promise { + await this.registerInput(compositionId, inputId, { ...options, type: 'whep_client' }); + } + + /** + * Register an input that plays an MP4 file. + * @returns how much media the file holds, see {@link Mp4InputDurations} + */ + async registerMp4Input( + compositionId: CompositionId, + inputId: InputId, + options: Omit + ): Promise { + const { videoDurationMs, audioDurationMs } = await this.registerInput(compositionId, inputId, { + ...options, + type: 'mp4', + }); + + return { videoDurationMs: videoDurationMs ?? undefined, audioDurationMs: audioDurationMs ?? undefined }; + } + + /** + * Register an input that an RTMP publisher pushes media into. + * @returns the port the input listens on, when the server assigns one + */ + async registerRtmpInput( + compositionId: CompositionId, + inputId: InputId, + options: Omit + ): Promise { + const { port } = await this.registerInput(compositionId, inputId, { ...options, type: 'rtmp_server' }); + + return { port: port ?? undefined }; + } + + /** + * Unregister an input. Scenes referencing it stop receiving its media. + */ + async unregisterInput(compositionId: CompositionId, inputId: InputId, options: UnregisterInput = {}): Promise { + try { + await this.inputsApi.unregisterInput({ compositionId, inputId, unregisterInput: options }); + } catch (error) { + throw await mapException(error, 'input'); + } + } + + /** + * Register an output, the destination the composed result is sent to, carrying the scene to render. + */ + async registerOutput(compositionId: CompositionId, outputId: OutputId, output: RegisterOutput): Promise { + try { + await this.outputsApi.registerOutput({ compositionId, outputId, registerOutput: output }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Register an output rendering a template bundle, as built by `@fishjam-cloud/composition-cli`. + * The bundle is either a `Blob` or a path to read it from; never pass a path taken from + * untrusted input, since its contents are uploaded. + */ + async registerTemplateOutput( + compositionId: CompositionId, + outputId: OutputId, + config: RegisterOutput, + template: Blob | string + ): Promise { + try { + await this.outputsApi.registerTemplateOutput({ + compositionId, + outputId, + config, + template: await toBlob(template), + }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Register an output sending the composed result to a WHIP endpoint. + */ + async registerWhipOutput( + compositionId: CompositionId, + outputId: OutputId, + options: Omit + ): Promise { + await this.registerOutput(compositionId, outputId, { ...options, type: 'whip_client' }); + } + + /** + * Register an output sending the composed result to an RTMP endpoint. + */ + async registerRtmpOutput( + compositionId: CompositionId, + outputId: OutputId, + options: Omit + ): Promise { + await this.registerOutput(compositionId, outputId, { ...options, type: 'rtmp_client' }); + } + + /** + * Unregister an output. It stops producing audio and video. + */ + async unregisterOutput( + compositionId: CompositionId, + outputId: OutputId, + options: UnregisterOutput = {} + ): Promise { + try { + await this.outputsApi.unregisterOutput({ compositionId, outputId, unregisterOutput: options }); + } catch (error) { + throw await mapException(error, 'output'); + } + } + + /** + * Replace the scene an output renders. + */ + async updateOutput(compositionId: CompositionId, outputId: OutputId, update: UpdateOutputRequest): Promise { + try { + await this.outputsApi.updateOutput({ compositionId, outputId, updateOutputRequest: update }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Ask an output to emit a keyframe, so a viewer joining mid-stream renders a full picture sooner. + */ + async requestKeyframe(compositionId: CompositionId, outputId: OutputId): Promise { + try { + await this.outputsApi.requestKeyframe({ compositionId, outputId }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Register an image that scenes can reference by its renderer ID. + */ + async registerImage(compositionId: CompositionId, imageId: RendererId, image: ImageSpec): Promise { + try { + await this.renderersApi.registerImage({ compositionId, imageId, imageSpec: image }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Register a font that scenes can render text with. The font is either a `Blob` or a path + * to read it from; never pass a path taken from untrusted input, since its contents are uploaded. + */ + async registerFont(compositionId: CompositionId, font: Blob | string): Promise { + try { + await this.renderersApi.registerFont({ compositionId, font: await toBlob(font) }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } + + /** + * Unregister a previously registered image. + */ + async unregisterImage( + compositionId: CompositionId, + imageId: RendererId, + options: UnregisterRenderer = {} + ): Promise { + try { + await this.renderersApi.unregisterImage({ compositionId, imageId, unregisterRenderer: options }); + } catch (error) { + throw await mapException(error, 'renderer'); + } + } + + /** + * Deliver an event to the templates rendered by the composition's outputs. + */ + async sendEvent(compositionId: CompositionId, event: SendCompositionEventRequest): Promise { + try { + await this.eventsApi.sendCompositionEvent({ compositionId, sendCompositionEventRequest: event }); + } catch (error) { + throw await mapException(error, 'composition'); + } + } +} diff --git a/packages/js-server-sdk/src/exceptions/index.ts b/packages/js-server-sdk/src/exceptions/index.ts index c28604dd..26bd62bd 100644 --- a/packages/js-server-sdk/src/exceptions/index.ts +++ b/packages/js-server-sdk/src/exceptions/index.ts @@ -47,6 +47,14 @@ export class PeerNotFoundException extends FishjamBaseException {} export class RecordingNotFoundException extends FishjamBaseException {} +export class CompositionNotFoundException extends FishjamBaseException {} + +export class InputNotFoundException extends FishjamBaseException {} + +export class OutputNotFoundException extends FishjamBaseException {} + +export class RendererNotFoundException extends FishjamBaseException {} + export class ServiceUnavailableException extends FishjamBaseException {} export class QuotaExceededException extends FishjamBaseException {} diff --git a/packages/js-server-sdk/src/exceptions/mapper.ts b/packages/js-server-sdk/src/exceptions/mapper.ts index 74d5f496..79f0c41e 100644 --- a/packages/js-server-sdk/src/exceptions/mapper.ts +++ b/packages/js-server-sdk/src/exceptions/mapper.ts @@ -1,11 +1,19 @@ +import { + ResponseError as CompositionResponseError, + FetchError as CompositionFetchError, +} from '@fishjam-cloud/composition-openapi'; import { ResponseError, FetchError } from '@fishjam-cloud/fishjam-openapi'; import { BadRequestException, + CompositionNotFoundException, FishjamNotFoundException, + InputNotFoundException, InvalidFishjamCredentialsException, + OutputNotFoundException, PeerNotFoundException, QuotaExceededException, RecordingNotFoundException, + RendererNotFoundException, RoomNotFoundException, ServiceUnavailableException, UnauthorizedException, @@ -13,16 +21,24 @@ import { type FishjamExceptionInfo, } from '.'; -type Entity = 'peer' | 'room' | 'credentials' | 'recording'; +type Entity = 'peer' | 'room' | 'credentials' | 'recording' | 'composition' | 'input' | 'output' | 'renderer'; const notFoundException = (info: FishjamExceptionInfo, entity?: Entity) => { switch (entity) { + case 'composition': + return new CompositionNotFoundException(info); case 'credentials': return new InvalidFishjamCredentialsException(info); + case 'input': + return new InputNotFoundException(info); + case 'output': + return new OutputNotFoundException(info); case 'peer': return new PeerNotFoundException(info); case 'recording': return new RecordingNotFoundException(info); + case 'renderer': + return new RendererNotFoundException(info); case 'room': return new RoomNotFoundException(info); default: @@ -31,10 +47,10 @@ const notFoundException = (info: FishjamExceptionInfo, entity?: Entity) => { }; export const mapException = async (error: unknown, entity?: Entity): Promise => { - if (error instanceof FetchError) { + if (error instanceof FetchError || error instanceof CompositionFetchError) { return new UnknownException({ message: error.cause.message, statusCode: 500, details: error.cause.message }); } - if (!(error instanceof ResponseError)) { + if (!(error instanceof ResponseError) && !(error instanceof CompositionResponseError)) { return error; } @@ -43,11 +59,12 @@ export const mapException = async (error: unknown, entity?: Entity): Promise; +/** + * ID of a composition. + * Composition can be created with {@link CompositionClient.createComposition}. + */ +export type CompositionId = Brand; + +/** + * ID of an input registered on a composition with {@link CompositionClient.registerInput}. + */ +export type InputId = Brand; + +/** + * ID of an output registered on a composition with {@link CompositionClient.registerOutput}. + */ +export type OutputId = Brand; + +/** + * ID of a renderer, such as an image registered with {@link CompositionClient.registerImage}. + */ +export type RendererId = Brand; + +export type Composition = Override; + +/** + * Where to publish a WHIP input registered with {@link CompositionClient.registerWhipInput}. + * Hand these to a WHIP publisher, such as `useLivestreamStreamer` in the React client SDK. + */ +export type WhipInputTarget = { + url: string; + bearerToken: string; +}; + +/** + * How much media an MP4 input registered with {@link CompositionClient.registerMp4Input} holds. + */ +export type Mp4InputDurations = { + videoDurationMs?: number; + audioDurationMs?: number; +}; + +/** + * The port an RTMP input registered with {@link CompositionClient.registerRtmpInput} listens on. + */ +export type RtmpInputPort = { + port?: number; +}; + export type Room = { id: RoomId; peers: Peer[]; config: RoomConfig; }; +export type CompositionConfig = { + /** + * Management token is a secret token authorizing to perform actions on your account. + * It is the same token {@link FishjamClient} is configured with. + * Never share this token with anyone. + * Visit https://fishjam.io/app/ to get your Management Token. + */ + managementToken: string; + /** + * Address of the Composition API. Only needs setting when running against a + * deployment other than production. + */ + compositionUrl?: string; +}; + export type FishjamConfig = { - /* + /** * Fishjam ID is a unique identifier for your account and environment. * Visit https://fishjam.io/app/ to get your Fishjam ID. */ fishjamId: string; - /* + /** * Management token is a secret token authorizing to perform actions on your account. * Never share this token with anyone. * Visit https://fishjam.io/app/ to get your Management Token. diff --git a/packages/js-server-sdk/src/utils.ts b/packages/js-server-sdk/src/utils.ts index b20f6733..20f6cf3e 100644 --- a/packages/js-server-sdk/src/utils.ts +++ b/packages/js-server-sdk/src/utils.ts @@ -1,5 +1,8 @@ +import { readFile } from 'node:fs/promises'; import { MissingFishjamIdException } from './exceptions'; -import type { FishjamConfig } from './types'; +import type { CompositionConfig, FishjamConfig } from './types'; + +const FISHJAM_URL = 'https://fishjam.io'; export const httpToWebsocket = (httpUrl: string) => { const url = new URL(httpUrl); @@ -15,7 +18,7 @@ export const getFishjamUrl = (config: FishjamConfig) => { try { return new URL(config.fishjamId).href; } catch { - return `https://fishjam.io/api/v1/connect/${config.fishjamId}`; + return `${FISHJAM_URL}/api/v1/connect/${config.fishjamId}`; } }; @@ -31,3 +34,14 @@ export const getAgentWebsocketUrl = (config: FishjamConfig, peerWebsocketUrl?: s } return `${httpToWebsocket(getFishjamUrl(config))}${AGENT_SOCKET_PATH}`; }; + +const COMPOSITION_URL = 'https://rtc.fishjam.io'; + +export const getCompositionUrl = (config: CompositionConfig) => + new URL(config.compositionUrl ?? COMPOSITION_URL).origin; + +export const toBlob = async (file: Blob | string): Promise => + typeof file === 'string' ? new Blob([await readFile(file)]) : file; + +export const getLivestreamWhipUrl = (config: FishjamConfig) => + `${new URL(getFishjamUrl(config)).origin}/api/v1/live/api/whip`; From 4cfd96210aa813d08d995f245e7d9561200565fa Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 21 Aug 2026 16:57:44 +0200 Subject: [PATCH 04/15] Test the composition client --- .../js-server-sdk/tests/composition.test.ts | 220 ++++++++++++++++++ .../js-server-sdk/tests/exceptions.test.ts | 15 ++ .../js-server-sdk/tests/fixtures/font.ttf | 1 + 3 files changed, 236 insertions(+) create mode 100644 packages/js-server-sdk/tests/composition.test.ts create mode 100644 packages/js-server-sdk/tests/fixtures/font.ttf diff --git a/packages/js-server-sdk/tests/composition.test.ts b/packages/js-server-sdk/tests/composition.test.ts new file mode 100644 index 00000000..63ec4a28 --- /dev/null +++ b/packages/js-server-sdk/tests/composition.test.ts @@ -0,0 +1,220 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { CompositionClient } from '../src/composition'; +import { InputNotFoundException, RendererNotFoundException, UnknownException } from '../src/exceptions'; +import { getCompositionUrl } from '../src/utils'; +import type { CompositionId, InputId, OutputId } from '../src/types'; + +const COMPOSITION_ID = 'comp-1' as CompositionId; +const INPUT_ID = 'cam' as InputId; +const OUTPUT_ID = 'out-1' as OutputId; + +const client = (compositionUrl?: string) => new CompositionClient({ managementToken: 'token', compositionUrl }); + +const stubFetch = (body: unknown, status = 200) => { + const fetch = vi + .fn() + .mockResolvedValue(new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } })); + vi.stubGlobal('fetch', fetch); + return fetch; +}; + +const requestBody = (fetch: ReturnType) => JSON.parse(fetch.mock.calls[0][1].body as string); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe('getCompositionUrl', () => { + it('defaults to the production Composition API', () => { + expect(getCompositionUrl({ managementToken: 't' })).toBe('https://rtc.fishjam.io'); + }); + + it('uses the configured address when given one', () => { + expect(getCompositionUrl({ managementToken: 't', compositionUrl: 'http://localhost:8000' })).toBe( + 'http://localhost:8000' + ); + }); + + it('keeps the origin only, so paths do not end up doubled', () => { + expect(getCompositionUrl({ managementToken: 't', compositionUrl: 'http://localhost:8000/' })).toBe( + 'http://localhost:8000' + ); + }); +}); + +describe('request serialisation', () => { + it('sends the wire format snake_case while the surface stays camelCase', async () => { + const fetch = stubFetch({}); + await client().registerOutput(COMPOSITION_ID, OUTPUT_ID, { + type: 'whip_client', + endpointUrl: 'https://example.com/whip', + bearerToken: 'wt', + video: { + resolution: { width: 1280, height: 720 }, + initial: { root: { type: 'input_stream', inputId: 'cam' } }, + }, + }); + + expect(requestBody(fetch)).toEqual({ + type: 'whip_client', + endpoint_url: 'https://example.com/whip', + bearer_token: 'wt', + video: { + resolution: { width: 1280, height: 720 }, + initial: { root: { input_id: 'cam', type: 'input_stream' } }, + }, + }); + }); + + it('reads a response back into camelCase', async () => { + stubFetch({ port: 5004 }); + const response = await client().registerInput(COMPOSITION_ID, INPUT_ID, { + type: 'rtmp_server', + streamKey: 'key', + }); + + expect(response).toEqual({ port: 5004 }); + }); +}); + +describe('input variants', () => { + it('resolves the WHIP publishing address from the route the server returned', async () => { + stubFetch({ bearer_token: 'tok', endpoint_route: '/whip/server-chosen-route' }); + const target = await client('http://localhost:8000').registerWhipInput(COMPOSITION_ID, INPUT_ID); + + expect(target).toEqual({ + url: 'http://localhost:8000/api/composition/comp-1/whip/server-chosen-route', + bearerToken: 'tok', + }); + }); + + it('falls back to the conventional WHIP route when the server omits it', async () => { + stubFetch({ bearer_token: 'tok' }); + const target = await client('http://localhost:8000').registerWhipInput(COMPOSITION_ID, INPUT_ID); + + expect(target.url).toBe('http://localhost:8000/api/composition/comp-1/whip/cam'); + }); + + it('keeps a caller-supplied WHIP token', async () => { + stubFetch({ endpoint_route: '/whip/cam' }); + const target = await client().registerWhipInput(COMPOSITION_ID, INPUT_ID, { bearerToken: 'mine' }); + + expect(target.bearerToken).toBe('mine'); + }); + + it('throws when neither the caller nor the server provides a WHIP token', async () => { + stubFetch({ endpoint_route: '/whip/cam' }); + + await expect(client().registerWhipInput(COMPOSITION_ID, INPUT_ID)).rejects.toThrow(UnknownException); + }); + + it('sends the discriminant for each variant', async () => { + const cases = [ + [(c: CompositionClient) => c.registerWhipInput(COMPOSITION_ID, INPUT_ID), 'whip_server'], + [ + (c: CompositionClient) => c.registerWhepInput(COMPOSITION_ID, INPUT_ID, { endpointUrl: 'https://x/whep' }), + 'whep_client', + ], + [(c: CompositionClient) => c.registerMp4Input(COMPOSITION_ID, INPUT_ID, { url: 'https://x/a.mp4' }), 'mp4'], + [(c: CompositionClient) => c.registerRtmpInput(COMPOSITION_ID, INPUT_ID, { streamKey: 'k' }), 'rtmp_server'], + ] as const; + + for (const [register, type] of cases) { + const fetch = stubFetch({ bearer_token: 'tok' }); + await register(client()); + expect(requestBody(fetch).type).toBe(type); + vi.unstubAllGlobals(); + } + }); + + it('returns the durations of an MP4 input', async () => { + stubFetch({ video_duration_ms: 1000, audio_duration_ms: 2000 }); + + await expect(client().registerMp4Input(COMPOSITION_ID, INPUT_ID, { url: 'https://x/a.mp4' })).resolves.toEqual({ + videoDurationMs: 1000, + audioDurationMs: 2000, + }); + }); + + it('returns the port of an RTMP input', async () => { + stubFetch({ port: 5004 }); + + await expect(client().registerRtmpInput(COMPOSITION_ID, INPUT_ID, { streamKey: 'k' })).resolves.toEqual({ + port: 5004, + }); + }); +}); + +describe('output variants', () => { + it('sends the discriminant for each variant', async () => { + const whip = stubFetch({}); + await client().registerWhipOutput(COMPOSITION_ID, OUTPUT_ID, { endpointUrl: 'https://x/whip' }); + expect(requestBody(whip)).toEqual({ endpoint_url: 'https://x/whip', type: 'whip_client' }); + vi.unstubAllGlobals(); + + const rtmp = stubFetch({}); + await client().registerRtmpOutput(COMPOSITION_ID, OUTPUT_ID, { url: 'rtmp://x/live' }); + expect(requestBody(rtmp)).toEqual({ url: 'rtmp://x/live', type: 'rtmp_client' }); + }); +}); + +describe('file uploads', () => { + it('reads a font from a path', async () => { + const fetch = stubFetch({}); + await client().registerFont(COMPOSITION_ID, `${import.meta.dirname}/fixtures/font.ttf`); + + const form = fetch.mock.calls[0][1].body as FormData; + expect(await (form.get('font') as Blob).text()).toBe('font-bytes'); + }); + + it('accepts a Blob as it is', async () => { + const fetch = stubFetch({}); + await client().registerFont(COMPOSITION_ID, new Blob(['inline'])); + + const form = fetch.mock.calls[0][1].body as FormData; + expect(await (form.get('font') as Blob).text()).toBe('inline'); + }); + + it('uploads a template bundle alongside its output config', async () => { + const fetch = stubFetch({}); + await client().registerTemplateOutput( + COMPOSITION_ID, + OUTPUT_ID, + { type: 'whip_client', endpointUrl: 'https://example.com/whip' }, + new Blob(['bundle']) + ); + + const form = fetch.mock.calls[0][1].body as FormData; + expect(await (form.get('template') as Blob).text()).toBe('bundle'); + expect(JSON.parse(await (form.get('config') as Blob).text())).toEqual({ + type: 'whip_client', + endpoint_url: 'https://example.com/whip', + }); + }); +}); + +describe('missing resources', () => { + const notFound = () => { + const fetch = vi.fn().mockResolvedValue( + new Response(JSON.stringify({ message: 'gone' }), { + status: 404, + headers: { 'content-type': 'application/json' }, + }) + ); + vi.stubGlobal('fetch', fetch); + }; + + it('reports a missing input rather than a missing composition', async () => { + notFound(); + + await expect(client().unregisterInput(COMPOSITION_ID, INPUT_ID)).rejects.toBeInstanceOf(InputNotFoundException); + }); + + it('reports a missing image rather than a missing composition', async () => { + notFound(); + + await expect(client().unregisterImage(COMPOSITION_ID, 'logo' as never)).rejects.toBeInstanceOf( + RendererNotFoundException + ); + }); +}); diff --git a/packages/js-server-sdk/tests/exceptions.test.ts b/packages/js-server-sdk/tests/exceptions.test.ts index 0a41bcc7..02f81bc0 100644 --- a/packages/js-server-sdk/tests/exceptions.test.ts +++ b/packages/js-server-sdk/tests/exceptions.test.ts @@ -3,6 +3,10 @@ import { ResponseError, FetchError } from '@fishjam-cloud/fishjam-openapi'; import { mapException } from '../src/exceptions/mapper'; import { BadRequestException, + CompositionNotFoundException, + InputNotFoundException, + OutputNotFoundException, + RendererNotFoundException, FishjamBaseException, FishjamNotFoundException, InvalidFishjamCredentialsException, @@ -17,6 +21,17 @@ import { const responseError = (status: number, body?: Record) => new ResponseError(new Response(body === undefined ? null : JSON.stringify(body), { status })); +describe('mapException entity mapping', () => { + it.each([ + ['composition', CompositionNotFoundException], + ['input', InputNotFoundException], + ['output', OutputNotFoundException], + ['renderer', RendererNotFoundException], + ] as const)('maps a 404 for %s', async (entity, expected) => { + await expect(mapException(responseError(404), entity)).resolves.toBeInstanceOf(expected); + }); +}); + describe('mapException status mapping', () => { it.each([ [400, BadRequestException], diff --git a/packages/js-server-sdk/tests/fixtures/font.ttf b/packages/js-server-sdk/tests/fixtures/font.ttf new file mode 100644 index 00000000..2a843c79 --- /dev/null +++ b/packages/js-server-sdk/tests/fixtures/font.ttf @@ -0,0 +1 @@ +font-bytes \ No newline at end of file From 172736844e9ed29d57636e75a5da43a748249fab Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 21 Aug 2026 16:57:44 +0200 Subject: [PATCH 05/15] Forward a room's tracks into a composition --- packages/js-server-sdk/src/client.ts | 30 ++++++++- .../tests/track_forwarding.test.ts | 65 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 packages/js-server-sdk/tests/track_forwarding.test.ts diff --git a/packages/js-server-sdk/src/client.ts b/packages/js-server-sdk/src/client.ts index ab5f2eff..68ca7258 100644 --- a/packages/js-server-sdk/src/client.ts +++ b/packages/js-server-sdk/src/client.ts @@ -6,6 +6,7 @@ import { RoomConfig, CredentialsApi, StreamersApi, + TrackForwardingsApi, PeerOptionsWebRTC, PeerOptionsVapi, PeerOptionsAgent, @@ -16,7 +17,7 @@ import { } from '@fishjam-cloud/fishjam-openapi'; import type { AgentCallbacks, FishjamConfig, PeerId, Recording, RecordingId, Room, RoomId, Peer } from './types'; import { mapException } from './exceptions/mapper'; -import { getFishjamUrl } from './utils'; +import { getFishjamUrl, getLivestreamWhipUrl } from './utils'; import { FishjamAgent, TrackId } from './agent'; import packageJson from '../package.json'; @@ -32,6 +33,7 @@ export class FishjamClient { private readonly streamerApi: StreamersApi; private readonly credentialsApi: CredentialsApi; private readonly recordingsApi: RecordingsApi; + private readonly trackForwardingsApi: TrackForwardingsApi; private readonly fishjamConfig: FishjamConfig; private deprecationWarningShown: boolean = false; @@ -73,6 +75,7 @@ export class FishjamClient { this.streamerApi = new StreamersApi(apiConfig); this.credentialsApi = new CredentialsApi(apiConfig); this.recordingsApi = new RecordingsApi(apiConfig); + this.trackForwardingsApi = new TrackForwardingsApi(apiConfig); this.fishjamConfig = config; } @@ -283,6 +286,31 @@ export class FishjamClient { } } + /** + * Forwards every track published in the room into a composition, which composes them into + * its outputs. Pass the composition's address, as returned by + * {@link CompositionClient.compositionUrl}. + */ + async forwardRoomTracks(roomId: RoomId, compositionUrl: string): Promise { + try { + await this.trackForwardingsApi.createTrackForwarding({ + roomId, + trackForwarding: { compositionURL: compositionUrl }, + }); + } catch (error) { + throw await mapException(error, 'room'); + } + } + + /** + * Where to publish a livestream, paired with a token from + * {@link FishjamClient.createLivestreamStreamerToken}. A composition reaches viewers by + * sending a WHIP output here. + */ + livestreamWhipUrl(): string { + return getLivestreamWhipUrl(this.fishjamConfig); + } + /** * Creates a livestream viewer token for the given room. * @returns a livestream viewer token diff --git a/packages/js-server-sdk/tests/track_forwarding.test.ts b/packages/js-server-sdk/tests/track_forwarding.test.ts new file mode 100644 index 00000000..5810fc59 --- /dev/null +++ b/packages/js-server-sdk/tests/track_forwarding.test.ts @@ -0,0 +1,65 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { CompositionClient } from '../src/composition'; +import { FishjamClient } from '../src/client'; +import type { CompositionId, RoomId } from '../src/types'; + +const ROOM_ID = 'room-1' as RoomId; +const COMPOSITION_ID = 'comp-1' as CompositionId; + +const stubFetch = () => { + const fetch = vi.fn().mockResolvedValue(new Response(null, { status: 201 })); + vi.stubGlobal('fetch', fetch); + return fetch; +}; + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe('forwardRoomTracks', () => { + it('points fishjam at the composition it should feed', async () => { + const fetch = stubFetch(); + const compositions = new CompositionClient({ managementToken: 't', compositionUrl: 'http://localhost:8000' }); + const fishjam = new FishjamClient({ fishjamId: 'http://localhost:5002', managementToken: 't' }); + + await fishjam.forwardRoomTracks(ROOM_ID, compositions.compositionUrl(COMPOSITION_ID)); + + const [url, init] = fetch.mock.calls[0]; + expect(String(url)).toContain('/room/room-1/track_forwardings'); + expect(init.method).toBe('POST'); + expect(JSON.parse(init.body as string)).toEqual({ + compositionURL: 'http://localhost:8000/api/composition/comp-1', + }); + }); +}); + +describe('compositionUrl', () => { + it('addresses a composition on the configured deployment', () => { + const client = new CompositionClient({ managementToken: 't', compositionUrl: 'http://localhost:8000' }); + + expect(client.compositionUrl(COMPOSITION_ID)).toBe('http://localhost:8000/api/composition/comp-1'); + }); + + it('defaults to the production Composition API', () => { + const client = new CompositionClient({ managementToken: 't' }); + + expect(client.compositionUrl(COMPOSITION_ID)).toBe('https://rtc.fishjam.io/api/composition/comp-1'); + }); +}); + +describe('livestreamWhipUrl', () => { + it('derives the address from a bare Fishjam ID', () => { + const client = new FishjamClient({ fishjamId: 'abc123', managementToken: 't' }); + + expect(client.livestreamWhipUrl()).toBe('https://fishjam.io/api/v1/live/api/whip'); + }); + + it('keeps the host when the Fishjam ID is a full URL', () => { + const client = new FishjamClient({ + fishjamId: 'https://cloud.fishjam.work/api/v1/connect/abc123', + managementToken: 't', + }); + + expect(client.livestreamWhipUrl()).toBe('https://cloud.fishjam.work/api/v1/live/api/whip'); + }); +}); From 8be635a630b8a0bbe86460b8b5ccbfb2a8c153e3 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 21 Aug 2026 16:57:44 +0200 Subject: [PATCH 06/15] Add the composition example --- examples/composition/.env.example | 2 + examples/composition/.gitignore | 3 + examples/composition/README.md | 42 +++ examples/composition/package.json | 31 ++ examples/composition/src/const.ts | 17 ++ examples/composition/src/controllers/peers.ts | 8 + .../composition/src/controllers/viewers.ts | 8 + examples/composition/src/environment.d.ts | 11 + examples/composition/src/index.ts | 69 +++++ .../composition/src/service/composition.ts | 67 +++++ examples/composition/src/service/fishjam.ts | 47 ++++ examples/composition/template/App.tsx | 266 ++++++++++++++++++ examples/composition/template/scene.ts | 23 ++ examples/composition/tsconfig.json | 16 ++ 14 files changed, 610 insertions(+) create mode 100644 examples/composition/.env.example create mode 100644 examples/composition/.gitignore create mode 100644 examples/composition/README.md create mode 100644 examples/composition/package.json create mode 100644 examples/composition/src/const.ts create mode 100644 examples/composition/src/controllers/peers.ts create mode 100644 examples/composition/src/controllers/viewers.ts create mode 100644 examples/composition/src/environment.d.ts create mode 100644 examples/composition/src/index.ts create mode 100644 examples/composition/src/service/composition.ts create mode 100644 examples/composition/src/service/fishjam.ts create mode 100644 examples/composition/template/App.tsx create mode 100644 examples/composition/template/scene.ts create mode 100644 examples/composition/tsconfig.json diff --git a/examples/composition/.env.example b/examples/composition/.env.example new file mode 100644 index 00000000..6ac7225c --- /dev/null +++ b/examples/composition/.env.example @@ -0,0 +1,2 @@ +FISHJAM_ID="" +FISHJAM_TOKEN="" diff --git a/examples/composition/.gitignore b/examples/composition/.gitignore new file mode 100644 index 00000000..e6367a1f --- /dev/null +++ b/examples/composition/.gitignore @@ -0,0 +1,3 @@ +node_modules +.env +dist diff --git a/examples/composition/README.md b/examples/composition/README.md new file mode 100644 index 00000000..7712fd9e --- /dev/null +++ b/examples/composition/README.md @@ -0,0 +1,42 @@ +# Compositions with Fishjam + +This example composes everyone in a Fishjam room into a single video and streams it to livestream viewers. +Peers join a room, their tracks are forwarded into a composition, and a template you can edit decides how +they are laid out. + +## Development + +To start the server you must first copy `.env.example` to `.env`. + +Then you need to set the following variables: + +- `FISHJAM_ID`: your Fishjam ID, which you can get at +- `FISHJAM_TOKEN`: your Fishjam management token, which you can get at +- `COMPOSITION_URL`: only when running against a deployment other than production + +Once you've set up your environment variables, all you need to do is run the following command: + +```bash +yarn dev +``` + +This bundles `template/App.tsx`, creates the room, the livestream and the composition, and then serves peer +and viewer tokens. Requires Node 23 or newer, which runs the TypeScript sources directly. + +When the server is running, you can obtain peer tokens by going to , and a +livestream viewer token from . + +Connect peers with the [fishjam minimal-react example](https://github.com/fishjam-cloud/web-client-sdk/tree/main/examples/react-client) +and watch the composed result with a livestream viewer. Press Ctrl+C to delete the composition and its rooms. + +Press Enter in the terminal to cycle the scene, which sends an event the template reacts to. + +## Editing the template + +`template/App.tsx` is a regular React component rendered by Smelter, using every hook the composition +package offers: `usePeers` lays out whoever is connected, `usePeer` resolves the spotlighted one, +`useSpeakingState` outlines whoever is talking, `useRoom` tells the template the room is linked, and +`eventBus` receives the scene events. Colours come from the Fishjam palette and the text is set in Inter, +uploaded at startup with `registerFont`. + +Change it, restart `yarn dev`, and the new bundle is uploaded with the output. diff --git a/examples/composition/package.json b/examples/composition/package.json new file mode 100644 index 00000000..5b632080 --- /dev/null +++ b/examples/composition/package.json @@ -0,0 +1,31 @@ +{ + "name": "composition-demo", + "version": "0.29.0", + "private": true, + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "format": "prettier --write .", + "typecheck": "tsc", + "build:template": "composition-cli build template/App.tsx --out dist/template.js", + "dev": "yarn build:template && node --env-file-if-exists=.env src/index.ts" + }, + "dependencies": { + "@fishjam-cloud/js-server-sdk": "workspace:*", + "@hono/node-server": "^1.13.0", + "hono": "^4.6.0" + }, + "devDependencies": { + "@fishjam-cloud/composition": "workspace:*", + "@fishjam-cloud/composition-cli": "workspace:*", + "@swmansion/smelter": "0.3.0", + "@types/node": "^22.13.16", + "@types/react": "^18.3.0", + "prettier": "^3.6.2", + "react": "^18.3.1", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=23" + } +} diff --git a/examples/composition/src/const.ts b/examples/composition/src/const.ts new file mode 100644 index 00000000..f6a433b5 --- /dev/null +++ b/examples/composition/src/const.ts @@ -0,0 +1,17 @@ +import type { OutputId, RendererId } from '@fishjam-cloud/js-server-sdk'; + +export const PORT = 3000; + +export const PREVIEW_OUTPUT_ID = 'preview' as OutputId; + +export const FONT_ID = 'inter' as RendererId; + +export const FONT_URL = 'https://raw.githubusercontent.com/google/fonts/main/ofl/inter/Inter%5Bopsz%2Cwght%5D.ttf'; + +export const LOGO_URL = 'https://fishjam.swmansion.com/favicon.svg'; + +export const LOGO_RESOLUTION = { width: 200, height: 200 }; + +export const OUTPUT_RESOLUTION = { width: 1280, height: 720 }; + +export const TEMPLATE_BUNDLE = new URL('../dist/template.js', import.meta.url).pathname; diff --git a/examples/composition/src/controllers/peers.ts b/examples/composition/src/controllers/peers.ts new file mode 100644 index 00000000..4baa9643 --- /dev/null +++ b/examples/composition/src/controllers/peers.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono'; +import type { FishjamService } from '../service/fishjam.ts'; + +export const peerController = (fishjam: FishjamService) => + new Hono().get('/peers', async (c) => { + const { peerToken } = await fishjam.createPeer(); + return c.json({ token: peerToken, fishjamId: process.env.FISHJAM_ID }); + }); diff --git a/examples/composition/src/controllers/viewers.ts b/examples/composition/src/controllers/viewers.ts new file mode 100644 index 00000000..dabae102 --- /dev/null +++ b/examples/composition/src/controllers/viewers.ts @@ -0,0 +1,8 @@ +import { Hono } from 'hono'; +import type { FishjamService } from '../service/fishjam.ts'; + +export const viewerController = (fishjam: FishjamService) => + new Hono().get('/viewer', async (c) => { + const { token } = await fishjam.createViewerToken(); + return c.json({ token, fishjamId: process.env.FISHJAM_ID }); + }); diff --git a/examples/composition/src/environment.d.ts b/examples/composition/src/environment.d.ts new file mode 100644 index 00000000..63cc0665 --- /dev/null +++ b/examples/composition/src/environment.d.ts @@ -0,0 +1,11 @@ +declare global { + namespace NodeJS { + interface ProcessEnv { + FISHJAM_ID: string; + FISHJAM_TOKEN: string; + COMPOSITION_URL?: string; + } + } +} + +export {}; diff --git a/examples/composition/src/index.ts b/examples/composition/src/index.ts new file mode 100644 index 00000000..a05b8822 --- /dev/null +++ b/examples/composition/src/index.ts @@ -0,0 +1,69 @@ +import { serve } from '@hono/node-server'; +import { Hono } from 'hono'; +import { createInterface } from 'node:readline'; +import { PORT } from './const.ts'; +import { peerController } from './controllers/peers.ts'; +import { viewerController } from './controllers/viewers.ts'; +import { CompositionService } from './service/composition.ts'; +import { FishjamService } from './service/fishjam.ts'; + +if (!process.env.FISHJAM_ID || !process.env.FISHJAM_TOKEN) { + throw Error('Environment variables FISHJAM_ID and FISHJAM_TOKEN are required.'); +} + +const fishjam = await FishjamService.create({ + fishjamId: process.env.FISHJAM_ID, + managementToken: process.env.FISHJAM_TOKEN, +}); + +let composition: CompositionService | undefined; + +const cleanup = async () => { + await composition?.cleanup(); + await fishjam.cleanup(); +}; + +try { + composition = await CompositionService.create({ + managementToken: process.env.FISHJAM_TOKEN, + compositionUrl: process.env.COMPOSITION_URL, + }); + + const streamer = await fishjam.createStreamerToken(); + await composition.useFishjamAssets(); + await composition.streamTo(fishjam.livestreamWhipUrl(), streamer.token); + await fishjam.composeRoomInto(composition.url); +} catch (error) { + console.error('failed to start composing:', error); + await cleanup(); + process.exit(1); +} + +console.log(`composing room ${fishjam.roomId} into livestream ${fishjam.livestreamId}`); +console.log('press Enter to change the scene'); + +const scenes = createInterface({ input: process.stdin }); +let sceneIndex = 0; + +scenes.on('line', async () => { + const { layout, background } = await composition!.showScene(++sceneIndex); + console.log(`scene: ${layout} on ${background}`); +}); + +const teardown = () => { + scenes.close(); + cleanup() + .then(() => console.log('\ndeleted the composition and its rooms')) + .catch((error) => console.error('cleanup failed:', error)) + .finally(() => process.exit(0)); +}; + +process.once('SIGINT', teardown); +process.once('SIGTERM', teardown); +scenes.once('SIGINT', teardown); + +const app = new Hono().route('/', peerController(fishjam)).route('/', viewerController(fishjam)); + +serve({ fetch: app.fetch, port: PORT }, ({ port }) => { + console.log(`peer tokens on http://localhost:${port}/peers, viewer token on http://localhost:${port}/viewer`); +}); diff --git a/examples/composition/src/service/composition.ts b/examples/composition/src/service/composition.ts new file mode 100644 index 00000000..b30af4e1 --- /dev/null +++ b/examples/composition/src/service/composition.ts @@ -0,0 +1,67 @@ +import { CompositionClient } from '@fishjam-cloud/js-server-sdk'; +import type { CompositionConfig, CompositionId, RendererId } from '@fishjam-cloud/js-server-sdk'; +import { + FONT_URL, + LOGO_RESOLUTION, + LOGO_URL, + OUTPUT_RESOLUTION, + PREVIEW_OUTPUT_ID, + TEMPLATE_BUNDLE, +} from '../const.ts'; +import { LOGO_ID, SCENES, SCENE_EVENT, type Scene } from '../../template/scene.ts'; + +export class CompositionService { + private readonly compositions: CompositionClient; + readonly compositionId: CompositionId; + + private constructor(compositions: CompositionClient, compositionId: CompositionId) { + this.compositions = compositions; + this.compositionId = compositionId; + } + + static async create(config: CompositionConfig): Promise { + const compositions = new CompositionClient(config); + const { compositionId } = await compositions.createComposition(); + + return new CompositionService(compositions, compositionId); + } + + get url() { + return this.compositions.compositionUrl(this.compositionId); + } + + async useFishjamAssets() { + const font = await fetch(FONT_URL); + await this.compositions.registerFont(this.compositionId, await font.blob()); + await this.compositions.registerImage(this.compositionId, LOGO_ID as RendererId, { + assetType: 'svg', + url: LOGO_URL, + resolution: LOGO_RESOLUTION, + }); + } + + async showScene(index: number): Promise { + const scene = SCENES[index % SCENES.length]; + await this.compositions.sendEvent(this.compositionId, { eventName: SCENE_EVENT, data: scene }); + + return scene; + } + + async streamTo(endpointUrl: string, bearerToken: string) { + await this.compositions.registerTemplateOutput( + this.compositionId, + PREVIEW_OUTPUT_ID, + { + type: 'whip_client', + endpointUrl, + bearerToken, + video: { resolution: OUTPUT_RESOLUTION, initial: { root: { type: 'view' } } }, + }, + TEMPLATE_BUNDLE + ); + } + + async cleanup() { + await this.compositions.deleteComposition(this.compositionId); + } +} diff --git a/examples/composition/src/service/fishjam.ts b/examples/composition/src/service/fishjam.ts new file mode 100644 index 00000000..751404a9 --- /dev/null +++ b/examples/composition/src/service/fishjam.ts @@ -0,0 +1,47 @@ +import { FishjamClient } from '@fishjam-cloud/js-server-sdk'; +import type { FishjamConfig, RoomId } from '@fishjam-cloud/js-server-sdk'; + +export class FishjamService { + private readonly fishjam: FishjamClient; + readonly roomId: RoomId; + readonly livestreamId: RoomId; + + private constructor(fishjam: FishjamClient, roomId: RoomId, livestreamId: RoomId) { + this.fishjam = fishjam; + this.roomId = roomId; + this.livestreamId = livestreamId; + } + + static async create(config: FishjamConfig): Promise { + const fishjam = await FishjamClient.create(config); + const room = await fishjam.createRoom(); + const livestream = await fishjam.createRoom({ roomType: 'livestream' }); + + return new FishjamService(fishjam, room.id, livestream.id); + } + + async createPeer() { + return this.fishjam.createPeer(this.roomId); + } + + async createViewerToken() { + return this.fishjam.createLivestreamViewerToken(this.livestreamId); + } + + async createStreamerToken() { + return this.fishjam.createLivestreamStreamerToken(this.livestreamId); + } + + livestreamWhipUrl() { + return this.fishjam.livestreamWhipUrl(); + } + + async composeRoomInto(compositionUrl: string) { + await this.fishjam.forwardRoomTracks(this.roomId, compositionUrl); + } + + async cleanup() { + await this.fishjam.deleteRoom(this.roomId); + await this.fishjam.deleteRoom(this.livestreamId); + } +} diff --git a/examples/composition/template/App.tsx b/examples/composition/template/App.tsx new file mode 100644 index 00000000..b369dcc2 --- /dev/null +++ b/examples/composition/template/App.tsx @@ -0,0 +1,266 @@ +import { eventBus, usePeer, usePeers, useRoom, useSpeakingState } from '@fishjam-cloud/composition'; +import { Image, InputStream, Rescaler, Text, Tiles, View } from '@swmansion/smelter'; +import { useCallback, useEffect, useState } from 'react'; +import { + FONT_FAMILY, + LOGO_ID, + SCENES, + SCENE_EVENT, + SHADOW_COLOR, + SPEAKING_COLOR, + TICKER_TEXT, + type Scene, +} from './scene.ts'; + +type Camera = { peerId: string; inputId: string }; +type LayoutProps = { cameras: Camera[] }; + +const FRAME = { width: 1280, height: 720 }; +const MARGIN = 48; +const LOGO_SIZE = 72; +const TICKER = { height: 72, fontSize: 28, lineBox: 40, unit: 900, copies: 3, durationMs: 9000 }; +const HEADER_HEIGHT = MARGIN * 2 + LOGO_SIZE; +const STAGE = { top: HEADER_HEIGHT, height: FRAME.height - HEADER_HEIGHT - TICKER.height - MARGIN }; +const TILE_GAPS = { margin: 10, padding: 8 }; +const PIP = { width: 220, height: 124, gap: 14, inset: 18 }; +const MESSAGE = { width: 640, height: 92, fontSize: 34 }; +const LOGO_HOME = { top: MARGIN, left: FRAME.width - MARGIN - LOGO_SIZE }; +function stageWidth(height: number) { + return (height * 16) / 9; +} + +function useScene(): Scene { + const [scene, setScene] = useState(SCENES[0]); + useEffect(() => eventBus.on(SCENE_EVENT, setScene), []); + return scene; +} + +function useTicking(everyMs: number): number { + const [tick, setTick] = useState(0); + + useEffect(() => { + const timer = setInterval(() => setTick((current) => current + 1), everyMs); + return () => clearInterval(timer); + }, [everyMs]); + + return tick; +} + +function CameraTile({ peerId, inputId }: Camera) { + const speaking = useSpeakingState(peerId) === 'speech'; + + return ( + + + + + + ); +} + +function SpeakingProbe({ peerId, onChange }: { peerId: string; onChange: (peerId: string, on: boolean) => void }) { + const speaking = useSpeakingState(peerId) === 'speech'; + useEffect(() => onChange(peerId, speaking), [peerId, speaking, onChange]); + return null; +} + +function MainTile({ peerId }: { peerId: string }) { + const peer = usePeer(peerId); + const stream = peer?.screenShareStream ?? peer?.cameraStream; + + return stream ? : null; +} + +function Logo({ top, left }: { top: number; left: number }) { + return ( + + + + ); +} + +function Ticker({ scene }: { scene: Scene }) { + const [offset, setOffset] = useState({ left: 0, sliding: false }); + + useEffect(() => { + const restart = () => { + setOffset({ left: 0, sliding: false }); + setTimeout(() => setOffset({ left: -TICKER.unit, sliding: true }), 60); + }; + + restart(); + const loop = setInterval(restart, TICKER.durationMs + 200); + return () => clearInterval(loop); + }, []); + + return ( + + + {Array.from({ length: TICKER.copies }, (_, copy) => ( + + {TICKER_TEXT} + + ))} + + + ); +} + +function Message({ scene, text }: { scene: Scene; text: string }) { + const dots = '.'.repeat((useTicking(500) % 3) + 1); + + return ( + + + {`${text}${dots}`} + + + ); +} + +function TilesLayout({ cameras }: LayoutProps) { + return ( + + {cameras.map((camera) => ( + + ))} + + ); +} + +function PipLayout({ cameras }: LayoutProps) { + const [main, ...rest] = cameras; + const width = stageWidth(STAGE.height); + + return ( + + + + {rest.slice(0, 3).map((camera, index) => ( + + + + ))} + + + ); +} + +function SpeakerLayout({ cameras }: LayoutProps) { + const [speaking, setSpeaking] = useState>({}); + const onChange = useCallback( + (peerId: string, on: boolean) => + setSpeaking((state) => (state[peerId] === on ? state : { ...state, [peerId]: on })), + [] + ); + + const main = cameras.find((camera) => speaking[camera.peerId]) ?? cameras[0]; + const rest = cameras.filter((camera) => camera.inputId !== main.inputId); + const mainHeight = rest.length > 0 ? STAGE.height * 0.66 : STAGE.height; + const sideGap = (FRAME.width - stageWidth(mainHeight)) / 2; + + return ( + + {cameras.map((camera) => ( + + ))} + + + + {rest.length > 0 && ( + + {rest.map((camera) => ( + + ))} + + )} + + ); +} + +const LAYOUTS = { tiles: TilesLayout, pip: PipLayout, speaker: SpeakerLayout }; + +export default function App() { + const scene = useScene(); + const room = useRoom(); + const peers = usePeers(); + const cameras = peers.flatMap((peer) => + peer.cameraStream ? [{ peerId: peer.id, inputId: peer.cameraStream.inputId }] : [] + ); + const Layout = LAYOUTS[scene.layout]; + const waiting = !room || cameras.length === 0; + + return ( + + + + + + {waiting ? ( + + ) : ( + + + + )} + + + + ); +} diff --git a/examples/composition/template/scene.ts b/examples/composition/template/scene.ts new file mode 100644 index 00000000..e41ab31b --- /dev/null +++ b/examples/composition/template/scene.ts @@ -0,0 +1,23 @@ +export type Scene = { + layout: 'tiles' | 'speaker' | 'pip'; + background: string; + heading: string; +}; + +const CREAM = '#FCF6E7FF'; +const CORAL = '#ED716DFF'; +const BLUE = '#38B5DCFF'; + +export const SCENES: Scene[] = [ + { layout: 'tiles', background: CREAM, heading: CORAL }, + { layout: 'pip', background: CREAM, heading: CORAL }, + { layout: 'speaker', background: CREAM, heading: CORAL }, +]; + +export const TICKER_TEXT = 'COMPOSITION DEMO /// press Enter to change the scene ///'; + +export const SPEAKING_COLOR = BLUE; +export const SHADOW_COLOR = '#00000026'; +export const FONT_FAMILY = 'Inter'; +export const LOGO_ID = 'fish'; +export const SCENE_EVENT = 'SCENE'; diff --git a/examples/composition/tsconfig.json b/examples/composition/tsconfig.json new file mode 100644 index 00000000..7f2444fd --- /dev/null +++ b/examples/composition/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "types": ["node"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "jsx": "react-jsx" + }, + "include": ["./src", "./template"] +} From 900196f15e0e2e5381ab935da73954c1c7125ddc Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 21 Aug 2026 16:57:44 +0200 Subject: [PATCH 07/15] Teach the spellchecker RTMP --- AGENTS.md | 2 +- spelling.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 08a271fb..3bb06910 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,4 +7,4 @@ Fishjam JavaScript/TypeScript server SDK — a Yarn (Berry, v4) workspace. Node (via nvm) and Corepack/Yarn are pre-installed; the startup script runs `yarn install`. Non-obvious notes: - Use Corepack-managed Yarn; if `yarn` is not found, run `corepack enable` and ensure the nvm Node bin is on `PATH`. -- Validated commands: `yarn build`, `yarn typecheck`, `yarn lint:check` (all pass). There is no unit-test script; the SDK is exercised through consuming repos (e.g. `room-manager`). +- Validated commands: `yarn build`, `yarn typecheck`, `yarn lint:check`, `yarn workspace @fishjam-cloud/js-server-sdk test` (all pass). diff --git a/spelling.txt b/spelling.txt index 4bd92d06..8a23ac73 100644 --- a/spelling.txt +++ b/spelling.txt @@ -107,3 +107,4 @@ Memberof unmutes websocat vapi +RTMP From 9fb8f0ed0e34816500d28586d465349c1ad594c5 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Fri, 21 Aug 2026 17:23:28 +0200 Subject: [PATCH 08/15] Stop advertising a port RTMP inputs never return --- packages/js-server-sdk/src/composition.ts | 11 ++++------- packages/js-server-sdk/src/types.ts | 7 ------- packages/js-server-sdk/tests/composition.test.ts | 8 -------- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/packages/js-server-sdk/src/composition.ts b/packages/js-server-sdk/src/composition.ts index f8ee15cb..fbb5e553 100644 --- a/packages/js-server-sdk/src/composition.ts +++ b/packages/js-server-sdk/src/composition.ts @@ -32,7 +32,6 @@ import type { Mp4InputDurations, OutputId, RendererId, - RtmpInputPort, WhipInputTarget, } from './types'; import { getCompositionUrl, toBlob } from './utils'; @@ -195,17 +194,15 @@ export class CompositionClient { } /** - * Register an input that an RTMP publisher pushes media into. - * @returns the port the input listens on, when the server assigns one + * Register an input that an RTMP publisher pushes media into. The stream key identifies the + * input; the address to publish to belongs to the composition, not to this call. */ async registerRtmpInput( compositionId: CompositionId, inputId: InputId, options: Omit - ): Promise { - const { port } = await this.registerInput(compositionId, inputId, { ...options, type: 'rtmp_server' }); - - return { port: port ?? undefined }; + ): Promise { + await this.registerInput(compositionId, inputId, { ...options, type: 'rtmp_server' }); } /** diff --git a/packages/js-server-sdk/src/types.ts b/packages/js-server-sdk/src/types.ts index b9b8f560..9a181127 100644 --- a/packages/js-server-sdk/src/types.ts +++ b/packages/js-server-sdk/src/types.ts @@ -115,13 +115,6 @@ export type Mp4InputDurations = { audioDurationMs?: number; }; -/** - * The port an RTMP input registered with {@link CompositionClient.registerRtmpInput} listens on. - */ -export type RtmpInputPort = { - port?: number; -}; - export type Room = { id: RoomId; peers: Peer[]; diff --git a/packages/js-server-sdk/tests/composition.test.ts b/packages/js-server-sdk/tests/composition.test.ts index 63ec4a28..41a7a37f 100644 --- a/packages/js-server-sdk/tests/composition.test.ts +++ b/packages/js-server-sdk/tests/composition.test.ts @@ -135,14 +135,6 @@ describe('input variants', () => { audioDurationMs: 2000, }); }); - - it('returns the port of an RTMP input', async () => { - stubFetch({ port: 5004 }); - - await expect(client().registerRtmpInput(COMPOSITION_ID, INPUT_ID, { streamKey: 'k' })).resolves.toEqual({ - port: 5004, - }); - }); }); describe('output variants', () => { From ac3e7cac5c47456309422a1514815285735a17d0 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 24 Aug 2026 11:47:08 +0200 Subject: [PATCH 09/15] Clean up both halves of the example when startup fails --- examples/composition/src/index.ts | 14 +++++++++----- examples/composition/src/service/fishjam.ts | 10 ++++++++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/examples/composition/src/index.ts b/examples/composition/src/index.ts index a05b8822..a875ca7e 100644 --- a/examples/composition/src/index.ts +++ b/examples/composition/src/index.ts @@ -19,8 +19,10 @@ const fishjam = await FishjamService.create({ let composition: CompositionService | undefined; const cleanup = async () => { - await composition?.cleanup(); - await fishjam.cleanup(); + const results = await Promise.allSettled([composition?.cleanup(), fishjam.cleanup()]); + const failure = results.find((result) => result.status === 'rejected'); + + if (failure) throw failure.reason; }; try { @@ -45,9 +47,11 @@ console.log('press Enter to change the scene'); const scenes = createInterface({ input: process.stdin }); let sceneIndex = 0; -scenes.on('line', async () => { - const { layout, background } = await composition!.showScene(++sceneIndex); - console.log(`scene: ${layout} on ${background}`); +scenes.on('line', () => { + composition! + .showScene(++sceneIndex) + .then(({ layout, background }) => console.log(`scene: ${layout} on ${background}`)) + .catch((error) => console.error('failed to change the scene:', error)); }); const teardown = () => { diff --git a/examples/composition/src/service/fishjam.ts b/examples/composition/src/service/fishjam.ts index 751404a9..36aea54e 100644 --- a/examples/composition/src/service/fishjam.ts +++ b/examples/composition/src/service/fishjam.ts @@ -15,9 +15,15 @@ export class FishjamService { static async create(config: FishjamConfig): Promise { const fishjam = await FishjamClient.create(config); const room = await fishjam.createRoom(); - const livestream = await fishjam.createRoom({ roomType: 'livestream' }); - return new FishjamService(fishjam, room.id, livestream.id); + try { + const livestream = await fishjam.createRoom({ roomType: 'livestream' }); + + return new FishjamService(fishjam, room.id, livestream.id); + } catch (error) { + await fishjam.deleteRoom(room.id); + throw error; + } } async createPeer() { From 60f4737831adba5584a567214d0ced0ea7a4e478 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 24 Aug 2026 12:24:01 +0200 Subject: [PATCH 10/15] Give the composition output an audio track --- examples/composition/src/service/composition.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/composition/src/service/composition.ts b/examples/composition/src/service/composition.ts index b30af4e1..01b977e7 100644 --- a/examples/composition/src/service/composition.ts +++ b/examples/composition/src/service/composition.ts @@ -56,6 +56,7 @@ export class CompositionService { endpointUrl, bearerToken, video: { resolution: OUTPUT_RESOLUTION, initial: { root: { type: 'view' } } }, + audio: { initial: { inputs: [] } }, }, TEMPLATE_BUNDLE ); From bb626c4e512ad4d7d6a149166d98a10a0de62d72 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 24 Aug 2026 13:52:31 +0200 Subject: [PATCH 11/15] Say what the example does with the template and the URL --- examples/composition/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/composition/README.md b/examples/composition/README.md index 7712fd9e..a13d3250 100644 --- a/examples/composition/README.md +++ b/examples/composition/README.md @@ -12,7 +12,8 @@ Then you need to set the following variables: - `FISHJAM_ID`: your Fishjam ID, which you can get at - `FISHJAM_TOKEN`: your Fishjam management token, which you can get at -- `COMPOSITION_URL`: only when running against a deployment other than production +- `COMPOSITION_URL`: address of the Composition API, only needed to point the example at something other + than production, such as a local cluster. Leave it unset otherwise. Once you've set up your environment variables, all you need to do is run the following command: @@ -20,8 +21,8 @@ Once you've set up your environment variables, all you need to do is run the fol yarn dev ``` -This bundles `template/App.tsx`, creates the room, the livestream and the composition, and then serves peer -and viewer tokens. Requires Node 23 or newer, which runs the TypeScript sources directly. +This bundles `template/App.tsx` into the template the composition renders, creates the room, the livestream +and the composition, uploads the bundle with the composition's output, and then serves peer and viewer tokens. Requires Node 23 or newer, which runs the TypeScript sources directly. When the server is running, you can obtain peer tokens by going to , and a livestream viewer token from . From 78882feba0680b290409c7d1252a12f6b7f526a4 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 24 Aug 2026 17:09:13 +0200 Subject: [PATCH 12/15] Normalise the WHIP route and name the origin helper for what it returns --- packages/js-server-sdk/src/composition.ts | 12 ++++++---- packages/js-server-sdk/src/utils.ts | 2 +- .../js-server-sdk/tests/composition.test.ts | 24 +++++++++++++++---- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/packages/js-server-sdk/src/composition.ts b/packages/js-server-sdk/src/composition.ts index fbb5e553..d15c7042 100644 --- a/packages/js-server-sdk/src/composition.ts +++ b/packages/js-server-sdk/src/composition.ts @@ -34,7 +34,7 @@ import type { RendererId, WhipInputTarget, } from './types'; -import { getCompositionUrl, toBlob } from './utils'; +import { getCompositionOrigin, toBlob } from './utils'; /** * Client class that allows to manage compositions, the real-time video compositing sessions @@ -58,7 +58,7 @@ export class CompositionClient { private readonly baseUrl: string; constructor(config: CompositionConfig) { - this.baseUrl = getCompositionUrl(config); + this.baseUrl = getCompositionOrigin(config); const apiConfig = new Configuration({ basePath: this.baseUrl, @@ -157,12 +157,14 @@ export class CompositionClient { const token = bearerToken ?? options.bearerToken; if (!token) { throw new UnknownException({ - message: `Registering WHIP input "${inputId}" returned no bearer token, so it cannot be published to`, + message: `Could not obtain a publishing token for input "${inputId}", retry or report it`, }); } - const route = endpointRoute ?? `/whip/${encodeURIComponent(inputId)}`; - return { url: `${this.compositionUrl(compositionId)}${route}`, bearerToken: token }; + const route = endpointRoute || `/whip/${encodeURIComponent(inputId)}`; + const url = `${this.compositionUrl(compositionId)}/${route.replace(/^\//, '')}`; + + return { url, bearerToken: token }; } /** diff --git a/packages/js-server-sdk/src/utils.ts b/packages/js-server-sdk/src/utils.ts index 20f6cf3e..201b2c4a 100644 --- a/packages/js-server-sdk/src/utils.ts +++ b/packages/js-server-sdk/src/utils.ts @@ -37,7 +37,7 @@ export const getAgentWebsocketUrl = (config: FishjamConfig, peerWebsocketUrl?: s const COMPOSITION_URL = 'https://rtc.fishjam.io'; -export const getCompositionUrl = (config: CompositionConfig) => +export const getCompositionOrigin = (config: CompositionConfig) => new URL(config.compositionUrl ?? COMPOSITION_URL).origin; export const toBlob = async (file: Blob | string): Promise => diff --git a/packages/js-server-sdk/tests/composition.test.ts b/packages/js-server-sdk/tests/composition.test.ts index 41a7a37f..889cb1a7 100644 --- a/packages/js-server-sdk/tests/composition.test.ts +++ b/packages/js-server-sdk/tests/composition.test.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { CompositionClient } from '../src/composition'; import { InputNotFoundException, RendererNotFoundException, UnknownException } from '../src/exceptions'; -import { getCompositionUrl } from '../src/utils'; +import { getCompositionOrigin } from '../src/utils'; import type { CompositionId, InputId, OutputId } from '../src/types'; const COMPOSITION_ID = 'comp-1' as CompositionId; @@ -24,19 +24,19 @@ afterEach(() => { vi.unstubAllGlobals(); }); -describe('getCompositionUrl', () => { +describe('getCompositionOrigin', () => { it('defaults to the production Composition API', () => { - expect(getCompositionUrl({ managementToken: 't' })).toBe('https://rtc.fishjam.io'); + expect(getCompositionOrigin({ managementToken: 't' })).toBe('https://rtc.fishjam.io'); }); it('uses the configured address when given one', () => { - expect(getCompositionUrl({ managementToken: 't', compositionUrl: 'http://localhost:8000' })).toBe( + expect(getCompositionOrigin({ managementToken: 't', compositionUrl: 'http://localhost:8000' })).toBe( 'http://localhost:8000' ); }); it('keeps the origin only, so paths do not end up doubled', () => { - expect(getCompositionUrl({ managementToken: 't', compositionUrl: 'http://localhost:8000/' })).toBe( + expect(getCompositionOrigin({ managementToken: 't', compositionUrl: 'http://localhost:8000/' })).toBe( 'http://localhost:8000' ); }); @@ -210,3 +210,17 @@ describe('missing resources', () => { ); }); }); + +describe('WHIP url building', () => { + it.each([ + ['/whip/from-server', 'http://localhost:8000/api/composition/comp-1/whip/from-server'], + ['whip/no-leading-slash', 'http://localhost:8000/api/composition/comp-1/whip/no-leading-slash'], + ['', 'http://localhost:8000/api/composition/comp-1/whip/cam'], + ])('normalises the route %s', async (endpoint_route, expected) => { + stubFetch({ bearer_token: 'tok', endpoint_route }); + + const target = await client('http://localhost:8000').registerWhipInput(COMPOSITION_ID, INPUT_ID); + + expect(target.url).toBe(expected); + }); +}); From 86ce10d204e5d5ec62f1ffe4d2ca4d88dd4d2482 Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 24 Aug 2026 17:36:58 +0200 Subject: [PATCH 13/15] Take the WHIP token from the server response only --- packages/js-server-sdk/src/composition.ts | 5 ++--- packages/js-server-sdk/tests/composition.test.ts | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/js-server-sdk/src/composition.ts b/packages/js-server-sdk/src/composition.ts index d15c7042..37bf164b 100644 --- a/packages/js-server-sdk/src/composition.ts +++ b/packages/js-server-sdk/src/composition.ts @@ -154,8 +154,7 @@ export class CompositionClient { type: 'whip_server', }); - const token = bearerToken ?? options.bearerToken; - if (!token) { + if (!bearerToken) { throw new UnknownException({ message: `Could not obtain a publishing token for input "${inputId}", retry or report it`, }); @@ -164,7 +163,7 @@ export class CompositionClient { const route = endpointRoute || `/whip/${encodeURIComponent(inputId)}`; const url = `${this.compositionUrl(compositionId)}/${route.replace(/^\//, '')}`; - return { url, bearerToken: token }; + return { url, bearerToken }; } /** diff --git a/packages/js-server-sdk/tests/composition.test.ts b/packages/js-server-sdk/tests/composition.test.ts index 889cb1a7..330911bf 100644 --- a/packages/js-server-sdk/tests/composition.test.ts +++ b/packages/js-server-sdk/tests/composition.test.ts @@ -95,14 +95,14 @@ describe('input variants', () => { expect(target.url).toBe('http://localhost:8000/api/composition/comp-1/whip/cam'); }); - it('keeps a caller-supplied WHIP token', async () => { - stubFetch({ endpoint_route: '/whip/cam' }); + it('returns the token the server echoes for a caller-supplied one', async () => { + stubFetch({ bearer_token: 'mine', endpoint_route: '/whip/cam' }); const target = await client().registerWhipInput(COMPOSITION_ID, INPUT_ID, { bearerToken: 'mine' }); expect(target.bearerToken).toBe('mine'); }); - it('throws when neither the caller nor the server provides a WHIP token', async () => { + it('throws when the server returns no WHIP token', async () => { stubFetch({ endpoint_route: '/whip/cam' }); await expect(client().registerWhipInput(COMPOSITION_ID, INPUT_ID)).rejects.toThrow(UnknownException); From 6c646b03f1122d8bf386feb1faf5f5942b23f1be Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 24 Aug 2026 17:56:56 +0200 Subject: [PATCH 14/15] Take the WHIP fallback path from the generated client --- packages/js-server-sdk/src/composition.ts | 17 +++++++++++++++-- .../js-server-sdk/tests/composition.test.ts | 10 ++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/js-server-sdk/src/composition.ts b/packages/js-server-sdk/src/composition.ts index 37bf164b..874e676a 100644 --- a/packages/js-server-sdk/src/composition.ts +++ b/packages/js-server-sdk/src/composition.ts @@ -3,6 +3,7 @@ import { CompositionsApi, EventsApi, InputsApi, + MediaTransportApi, OutputsApi, RenderersApi, type CreateCompositionRequest, @@ -53,6 +54,7 @@ export class CompositionClient { private readonly compositionsApi: CompositionsApi; private readonly eventsApi: EventsApi; private readonly inputsApi: InputsApi; + private readonly mediaTransportApi: MediaTransportApi; private readonly outputsApi: OutputsApi; private readonly renderersApi: RenderersApi; private readonly baseUrl: string; @@ -68,6 +70,7 @@ export class CompositionClient { this.compositionsApi = new CompositionsApi(apiConfig); this.eventsApi = new EventsApi(apiConfig); this.inputsApi = new InputsApi(apiConfig); + this.mediaTransportApi = new MediaTransportApi(apiConfig); this.outputsApi = new OutputsApi(apiConfig); this.renderersApi = new RenderersApi(apiConfig); } @@ -160,12 +163,22 @@ export class CompositionClient { }); } - const route = endpointRoute || `/whip/${encodeURIComponent(inputId)}`; - const url = `${this.compositionUrl(compositionId)}/${route.replace(/^\//, '')}`; + const url = endpointRoute + ? `${this.compositionUrl(compositionId)}/${endpointRoute.replace(/^\//, '')}` + : await this.whipPath(compositionId, inputId); return { url, bearerToken }; } + /** + * Where WHIP publishing is served, for servers that do not report the route themselves. + */ + private async whipPath(compositionId: CompositionId, inputId: InputId): Promise { + const { path } = await this.mediaTransportApi.whipOfferRequestOpts({ compositionId, inputId, body: '' }); + + return new URL(path, this.baseUrl).href; + } + /** * Register an input that pulls media from a WHEP endpoint. */ diff --git a/packages/js-server-sdk/tests/composition.test.ts b/packages/js-server-sdk/tests/composition.test.ts index 330911bf..9ff3e7ea 100644 --- a/packages/js-server-sdk/tests/composition.test.ts +++ b/packages/js-server-sdk/tests/composition.test.ts @@ -224,3 +224,13 @@ describe('WHIP url building', () => { expect(target.url).toBe(expected); }); }); + +describe('WHIP url without a server route', () => { + it('falls back to the generated path and encodes the id', async () => { + stubFetch({ bearer_token: 'tok' }); + + const target = await client('http://localhost:8000').registerWhipInput(COMPOSITION_ID, 'odd/id' as InputId); + + expect(target.url).toBe('http://localhost:8000/api/composition/comp-1/whip/odd%2Fid'); + }); +}); From a1b770c2e70b20ff7c4563845ca86653c2fb3f5d Mon Sep 17 00:00:00 2001 From: Bernard Gawor Date: Mon, 24 Aug 2026 18:20:25 +0200 Subject: [PATCH 15/15] Bind the example to loopback and settle both room deletions --- examples/composition/README.md | 4 ++-- examples/composition/src/const.ts | 2 ++ examples/composition/src/index.ts | 6 +++--- examples/composition/src/service/fishjam.ts | 9 +++++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/examples/composition/README.md b/examples/composition/README.md index a13d3250..ee0ac29d 100644 --- a/examples/composition/README.md +++ b/examples/composition/README.md @@ -24,8 +24,8 @@ yarn dev This bundles `template/App.tsx` into the template the composition renders, creates the room, the livestream and the composition, uploads the bundle with the composition's output, and then serves peer and viewer tokens. Requires Node 23 or newer, which runs the TypeScript sources directly. -When the server is running, you can obtain peer tokens by going to , and a -livestream viewer token from . +When the server is running, you can obtain peer tokens by going to , and a +livestream viewer token from . Connect peers with the [fishjam minimal-react example](https://github.com/fishjam-cloud/web-client-sdk/tree/main/examples/react-client) and watch the composed result with a livestream viewer. Press Ctrl+C to delete the composition and its rooms. diff --git a/examples/composition/src/const.ts b/examples/composition/src/const.ts index f6a433b5..f0bfc4a8 100644 --- a/examples/composition/src/const.ts +++ b/examples/composition/src/const.ts @@ -2,6 +2,8 @@ import type { OutputId, RendererId } from '@fishjam-cloud/js-server-sdk'; export const PORT = 3000; +export const HOSTNAME = '127.0.0.1'; + export const PREVIEW_OUTPUT_ID = 'preview' as OutputId; export const FONT_ID = 'inter' as RendererId; diff --git a/examples/composition/src/index.ts b/examples/composition/src/index.ts index a875ca7e..9b34de04 100644 --- a/examples/composition/src/index.ts +++ b/examples/composition/src/index.ts @@ -1,7 +1,7 @@ import { serve } from '@hono/node-server'; import { Hono } from 'hono'; import { createInterface } from 'node:readline'; -import { PORT } from './const.ts'; +import { HOSTNAME, PORT } from './const.ts'; import { peerController } from './controllers/peers.ts'; import { viewerController } from './controllers/viewers.ts'; import { CompositionService } from './service/composition.ts'; @@ -68,6 +68,6 @@ scenes.once('SIGINT', teardown); const app = new Hono().route('/', peerController(fishjam)).route('/', viewerController(fishjam)); -serve({ fetch: app.fetch, port: PORT }, ({ port }) => { - console.log(`peer tokens on http://localhost:${port}/peers, viewer token on http://localhost:${port}/viewer`); +serve({ fetch: app.fetch, port: PORT, hostname: HOSTNAME }, ({ port }) => { + console.log(`peer tokens on http://${HOSTNAME}:${port}/peers, viewer token on http://${HOSTNAME}:${port}/viewer`); }); diff --git a/examples/composition/src/service/fishjam.ts b/examples/composition/src/service/fishjam.ts index 36aea54e..adde6f8a 100644 --- a/examples/composition/src/service/fishjam.ts +++ b/examples/composition/src/service/fishjam.ts @@ -47,7 +47,12 @@ export class FishjamService { } async cleanup() { - await this.fishjam.deleteRoom(this.roomId); - await this.fishjam.deleteRoom(this.livestreamId); + const results = await Promise.allSettled([ + this.fishjam.deleteRoom(this.roomId), + this.fishjam.deleteRoom(this.livestreamId), + ]); + const failure = results.find((result) => result.status === 'rejected'); + + if (failure) throw failure.reason; } }