diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7c12e8fe6a..e6ab01255c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,12 +2,63 @@
## [Unreleased](https://github.com/aklivity/zilla/tree/HEAD)
-[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.67...HEAD)
+[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.68...HEAD)
+
+**Implemented enhancements:**
+
+- Support parameters in KafkaTopicsConfig [\#809](https://github.com/aklivity/zilla/pull/809) ([bmaidics](https://github.com/bmaidics))
+
+**Fixed bugs:**
+
+- SEVERE: Problem adapting object of type class NamespaceConfig to interface jakarta.json.JsonObject in class class NamespaceAdapter [\#796](https://github.com/aklivity/zilla/issues/796)
+- Zilla is validating `env` vars before replacing them. [\#795](https://github.com/aklivity/zilla/issues/795)
+- Basic Docker Compose Setup Clogs CPU With Error Messages [\#722](https://github.com/aklivity/zilla/issues/722)
+
+**Closed issues:**
+
+- Use dedicated env var to enable Incubator features [\#800](https://github.com/aklivity/zilla/issues/800)
+- Support `http` to `kafka` proxy using `openapi.yaml` and `asyncapi.yaml` [\#742](https://github.com/aklivity/zilla/issues/742)
+- Support `mqtt` to `kafka` proxy using `asyncapi.yaml` [\#741](https://github.com/aklivity/zilla/issues/741)
+- Support `openapi` `http` proxy using `openapi.yaml` [\#740](https://github.com/aklivity/zilla/issues/740)
+- Support `asyncapi` `http` proxy using `asyncapi.yaml` [\#739](https://github.com/aklivity/zilla/issues/739)
+- Support `asyncapi` `mqtt` proxy using `asyncapi.yaml` [\#738](https://github.com/aklivity/zilla/issues/738)
+- Support local logging of events caused by external actors [\#679](https://github.com/aklivity/zilla/issues/679)
+
+**Merged pull requests:**
+
+- Asyncapi and Openapi bug fixes [\#826](https://github.com/aklivity/zilla/pull/826) ([akrambek](https://github.com/akrambek))
+- Asyncapi catalog implementation [\#825](https://github.com/aklivity/zilla/pull/825) ([bmaidics](https://github.com/bmaidics))
+- Fix NPE in KafkaSignalStream [\#823](https://github.com/aklivity/zilla/pull/823) ([bmaidics](https://github.com/bmaidics))
+- Fix early flush sending for retained stream [\#822](https://github.com/aklivity/zilla/pull/822) ([bmaidics](https://github.com/bmaidics))
+- Add incubating annotation for stdout exporter [\#819](https://github.com/aklivity/zilla/pull/819) ([jfallows](https://github.com/jfallows))
+- MQTT-Kafka asyncapi proxy [\#818](https://github.com/aklivity/zilla/pull/818) ([bmaidics](https://github.com/bmaidics))
+- Fix kafka client composite resolvedId [\#816](https://github.com/aklivity/zilla/pull/816) ([bmaidics](https://github.com/bmaidics))
+- Use env var to add incubator java option [\#811](https://github.com/aklivity/zilla/pull/811) ([vordimous](https://github.com/vordimous))
+- Support http to kafka proxy using openapi.yaml and asyncapi.yaml [\#810](https://github.com/aklivity/zilla/pull/810) ([akrambek](https://github.com/akrambek))
+- Structured models require `catalog` config [\#807](https://github.com/aklivity/zilla/pull/807) ([aDaemonThread](https://github.com/aDaemonThread))
+- Include qualified vault name on binding [\#806](https://github.com/aklivity/zilla/pull/806) ([jfallows](https://github.com/jfallows))
+- Include config exception cause [\#805](https://github.com/aklivity/zilla/pull/805) ([jfallows](https://github.com/jfallows))
+- Kafka asyncapi client [\#804](https://github.com/aklivity/zilla/pull/804) ([bmaidics](https://github.com/bmaidics))
+- Support k3po ephemeral option [\#801](https://github.com/aklivity/zilla/pull/801) ([akrambek](https://github.com/akrambek))
+- Support asyncapi http proxy using asyncapi.yaml [\#799](https://github.com/aklivity/zilla/pull/799) ([bmaidics](https://github.com/bmaidics))
+- Fix kafka sasl schema validation to support expressions [\#798](https://github.com/aklivity/zilla/pull/798) ([akrambek](https://github.com/akrambek))
+- Zilla is validating env vars before replacing them [\#797](https://github.com/aklivity/zilla/pull/797) ([akrambek](https://github.com/akrambek))
+- Support openapi http proxy using openapi.yaml [\#778](https://github.com/aklivity/zilla/pull/778) ([akrambek](https://github.com/akrambek))
+- Support asyncapi mqtt proxy using asyncapi.yaml [\#764](https://github.com/aklivity/zilla/pull/764) ([bmaidics](https://github.com/bmaidics))
+- Support local logging of events [\#755](https://github.com/aklivity/zilla/pull/755) ([attilakreiner](https://github.com/attilakreiner))
+
+## [0.9.68](https://github.com/aklivity/zilla/tree/0.9.68) (2024-02-13)
+
+[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.67...0.9.68)
**Fixed bugs:**
- Zilla crashes when a large number of MQTT clients connect [\#793](https://github.com/aklivity/zilla/issues/793)
+**Merged pull requests:**
+
+- Require group host and port for `kafka` coordinator-specific streams [\#794](https://github.com/aklivity/zilla/pull/794) ([jfallows](https://github.com/jfallows))
+
## [0.9.67](https://github.com/aklivity/zilla/tree/0.9.67) (2024-02-11)
[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.66...0.9.67)
@@ -15,10 +66,6 @@
**Implemented enhancements:**
- Use `model` and `view` when describing the message type [\#750](https://github.com/aklivity/zilla/issues/750)
-- Support obtaining `protobuf` schemas from `schema registry` for `grpc` services [\#697](https://github.com/aklivity/zilla/issues/697)
-- Support idempotent `mqtt` `qos 2` publish to `kafka` [\#677](https://github.com/aklivity/zilla/issues/677)
-- Detect and inspect invalid messages received [\#676](https://github.com/aklivity/zilla/issues/676)
-- Support incremental validation of fragmented messages sent by client [\#671](https://github.com/aklivity/zilla/issues/671)
- Catalog cache TTL implementation [\#658](https://github.com/aklivity/zilla/pull/658) ([aDaemonThread](https://github.com/aDaemonThread))
**Fixed bugs:**
@@ -31,6 +78,13 @@
- Fix zilla crash when it tries to send flush on retain stream [\#784](https://github.com/aklivity/zilla/pull/784) ([bmaidics](https://github.com/bmaidics))
- Limit sharding to mqtt 5 [\#760](https://github.com/aklivity/zilla/pull/760) ([bmaidics](https://github.com/bmaidics))
+**Closed issues:**
+
+- Support obtaining `protobuf` schemas from `schema registry` for `grpc` services [\#697](https://github.com/aklivity/zilla/issues/697)
+- Support idempotent `mqtt` `qos 2` publish to `kafka` [\#677](https://github.com/aklivity/zilla/issues/677)
+- Detect and inspect invalid messages received [\#676](https://github.com/aklivity/zilla/issues/676)
+- Support incremental validation of fragmented messages sent by client [\#671](https://github.com/aklivity/zilla/issues/671)
+
**Merged pull requests:**
- Simplify TLSv1.3 handshake check [\#792](https://github.com/aklivity/zilla/pull/792) ([jfallows](https://github.com/jfallows))
@@ -65,16 +119,16 @@
[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.65...0.9.66)
-**Implemented enhancements:**
+**Fixed bugs:**
+
+- Schema validation fails before the `${{env.*}}` parameters have been removed [\#583](https://github.com/aklivity/zilla/issues/583)
+
+**Closed issues:**
- Support `openapi` `http` response validation [\#684](https://github.com/aklivity/zilla/issues/684)
- Support `protobuf` conversion to and from `json` for `kafka` messages [\#682](https://github.com/aklivity/zilla/issues/682)
- Support incubator features preview in zilla release docker image [\#670](https://github.com/aklivity/zilla/issues/670)
-**Fixed bugs:**
-
-- Schema validation fails before the `${{env.*}}` parameters have been removed [\#583](https://github.com/aklivity/zilla/issues/583)
-
**Merged pull requests:**
- update license exclude path to include both zpmw files [\#759](https://github.com/aklivity/zilla/pull/759) ([vordimous](https://github.com/vordimous))
@@ -90,10 +144,6 @@
**Implemented enhancements:**
-- Support `avro` conversion to and from `json` for `kafka` messages [\#681](https://github.com/aklivity/zilla/issues/681)
-- Support observability of zilla engine internal streams [\#678](https://github.com/aklivity/zilla/issues/678)
-- Simplify configuration of multiple protocols on different tcp ports [\#669](https://github.com/aklivity/zilla/issues/669)
-- Simplify kafka client bootstrap server names and ports config [\#619](https://github.com/aklivity/zilla/issues/619)
- MQTT publish QoS 2 as Kafka produce with acks in\_sync\_replicas and idempotent `producerId` [\#605](https://github.com/aklivity/zilla/issues/605)
- Add the option to route by `port` in the `tls` binding [\#564](https://github.com/aklivity/zilla/issues/564)
- Support outbound message transformation from `protobuf` to `json` [\#458](https://github.com/aklivity/zilla/issues/458)
@@ -124,6 +174,10 @@
**Closed issues:**
- Prototype composite binding support with nested namespaces [\#685](https://github.com/aklivity/zilla/issues/685)
+- Support `avro` conversion to and from `json` for `kafka` messages [\#681](https://github.com/aklivity/zilla/issues/681)
+- Support observability of zilla engine internal streams [\#678](https://github.com/aklivity/zilla/issues/678)
+- Simplify configuration of multiple protocols on different tcp ports [\#669](https://github.com/aklivity/zilla/issues/669)
+- Simplify kafka client bootstrap server names and ports config [\#619](https://github.com/aklivity/zilla/issues/619)
- Build has been failed in local [\#229](https://github.com/aklivity/zilla/issues/229)
**Merged pull requests:**
diff --git a/build/flyweight-maven-plugin/pom.xml b/build/flyweight-maven-plugin/pom.xml
index f87405e06b..fad482be76 100644
--- a/build/flyweight-maven-plugin/pom.xml
+++ b/build/flyweight-maven-plugin/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
build
- 0.9.68
+ 0.9.69
../pom.xml
diff --git a/build/pom.xml b/build/pom.xml
index 26db82e124..9287417e6b 100644
--- a/build/pom.xml
+++ b/build/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.68
+ 0.9.69
../pom.xml
diff --git a/cloud/docker-image/pom.xml b/cloud/docker-image/pom.xml
index 320d2634ef..801505b541 100644
--- a/cloud/docker-image/pom.xml
+++ b/cloud/docker-image/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
cloud
- 0.9.68
+ 0.9.69
../pom.xml
@@ -43,6 +43,24 @@
${project.version}
runtime
+
+ ${project.groupId}
+ binding-asyncapi
+ ${project.version}
+ runtime
+
+
+ ${project.groupId}
+ binding-openapi
+ ${project.version}
+ runtime
+
+
+ ${project.groupId}
+ binding-openapi-asyncapi
+ ${project.version}
+ runtime
+
${project.groupId}
binding-echo
@@ -223,6 +241,12 @@
${project.version}
runtime
+
+ ${project.groupId}
+ exporter-stdout
+ ${project.version}
+ runtime
+
${project.groupId}
metrics-stream
diff --git a/cloud/docker-image/src/main/docker/zpm.json.template b/cloud/docker-image/src/main/docker/zpm.json.template
index 427e9b3f99..790c062053 100644
--- a/cloud/docker-image/src/main/docker/zpm.json.template
+++ b/cloud/docker-image/src/main/docker/zpm.json.template
@@ -14,6 +14,7 @@
"dependencies":
[
"io.aklivity.zilla:binding-amqp",
+ "io.aklivity.zilla:binding-asyncapi",
"io.aklivity.zilla:binding-echo",
"io.aklivity.zilla:binding-fan",
"io.aklivity.zilla:binding-filesystem",
@@ -26,6 +27,8 @@
"io.aklivity.zilla:binding-kafka",
"io.aklivity.zilla:binding-mqtt",
"io.aklivity.zilla:binding-mqtt-kafka",
+ "io.aklivity.zilla:binding-openapi",
+ "io.aklivity.zilla:binding-openapi-asyncapi",
"io.aklivity.zilla:binding-proxy",
"io.aklivity.zilla:binding-sse",
"io.aklivity.zilla:binding-sse-kafka",
@@ -43,8 +46,9 @@
"io.aklivity.zilla:command-stop",
"io.aklivity.zilla:command-tune",
"io.aklivity.zilla:engine",
- "io.aklivity.zilla:exporter-prometheus",
"io.aklivity.zilla:exporter-otlp",
+ "io.aklivity.zilla:exporter-prometheus",
+ "io.aklivity.zilla:exporter-stdout",
"io.aklivity.zilla:guard-jwt",
"io.aklivity.zilla:metrics-stream",
"io.aklivity.zilla:metrics-http",
diff --git a/cloud/helm-chart/pom.xml b/cloud/helm-chart/pom.xml
index 93117c23e6..19fe35c8f9 100644
--- a/cloud/helm-chart/pom.xml
+++ b/cloud/helm-chart/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
cloud
- 0.9.68
+ 0.9.69
../pom.xml
diff --git a/cloud/pom.xml b/cloud/pom.xml
index e84cfbd44c..be5d7b7ede 100644
--- a/cloud/pom.xml
+++ b/cloud/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.68
+ 0.9.69
../pom.xml
diff --git a/conf/pom.xml b/conf/pom.xml
index 1b22c2510b..a4e6729542 100644
--- a/conf/pom.xml
+++ b/conf/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.68
+ 0.9.69
../pom.xml
diff --git a/incubator/binding-amqp.spec/pom.xml b/incubator/binding-amqp.spec/pom.xml
index a68b6467df..f502c6e2ef 100644
--- a/incubator/binding-amqp.spec/pom.xml
+++ b/incubator/binding-amqp.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.68
+ 0.9.69
../pom.xml
diff --git a/incubator/binding-amqp/pom.xml b/incubator/binding-amqp/pom.xml
index 6133d94f01..7841077e88 100644
--- a/incubator/binding-amqp/pom.xml
+++ b/incubator/binding-amqp/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.68
+ 0.9.69
../pom.xml
diff --git a/incubator/binding-asyncapi.spec/COPYRIGHT b/incubator/binding-asyncapi.spec/COPYRIGHT
new file mode 100644
index 0000000000..8b1b7215ef
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/COPYRIGHT
@@ -0,0 +1,13 @@
+Copyright ${copyrightYears} Aklivity Inc.
+
+Aklivity licenses this file to you 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/incubator/binding-asyncapi.spec/LICENSE b/incubator/binding-asyncapi.spec/LICENSE
new file mode 100644
index 0000000000..8dada3edaf
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/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/incubator/binding-asyncapi.spec/NOTICE b/incubator/binding-asyncapi.spec/NOTICE
new file mode 100644
index 0000000000..8ac96c59e7
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/NOTICE
@@ -0,0 +1,28 @@
+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.
+
+This project includes:
+ agrona under The Apache License, Version 2.0
+ ICU4J under Unicode/ICU License
+ Jakarta JSON Processing API under Eclipse Public License 2.0 or GNU General Public License, version 2 with the GNU Classpath Exception
+ org.leadpony.justify under The Apache Software License, Version 2.0
+ zilla::specs::binding-http.spec under The Apache Software License, Version 2.0
+ zilla::specs::binding-kafka.spec under The Apache Software License, Version 2.0
+ zilla::specs::binding-mqtt-kafka.spec under Aklivity Community License Agreement
+ zilla::specs::binding-mqtt.spec under The Apache Software License, Version 2.0
+ zilla::specs::binding-proxy.spec under The Apache Software License, Version 2.0
+ zilla::specs::engine.spec under The Apache Software License, Version 2.0
+
+
+This project also includes code under copyright of the following entities:
+ https://github.com/reaktivity/
diff --git a/incubator/binding-asyncapi.spec/NOTICE.template b/incubator/binding-asyncapi.spec/NOTICE.template
new file mode 100644
index 0000000000..e9ed8f0e7b
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/NOTICE.template
@@ -0,0 +1,18 @@
+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.
+
+This project includes:
+#GENERATED_NOTICES#
+
+This project also includes code under copyright of the following entities:
+ https://github.com/reaktivity/
\ No newline at end of file
diff --git a/incubator/binding-asyncapi.spec/mvnw b/incubator/binding-asyncapi.spec/mvnw
new file mode 100755
index 0000000000..d2f0ea3808
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/incubator/binding-asyncapi.spec/mvnw.cmd b/incubator/binding-asyncapi.spec/mvnw.cmd
new file mode 100644
index 0000000000..b26ab24f03
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/incubator/binding-asyncapi.spec/pom.xml b/incubator/binding-asyncapi.spec/pom.xml
new file mode 100644
index 0000000000..1a20bb45c8
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/pom.xml
@@ -0,0 +1,180 @@
+
+
+
+ 4.0.0
+
+ io.aklivity.zilla
+ incubator
+ 0.9.69
+ ../pom.xml
+
+
+ binding-asyncapi.spec
+ zilla::incubator::binding-asyncapi.spec
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+ 11
+ 11
+ 0.91
+ 0
+
+
+
+
+ org.kaazing
+ k3po.lang
+ provided
+
+
+ ${project.groupId}
+ engine.spec
+ ${project.version}
+
+
+ ${project.groupId}
+ binding-mqtt.spec
+ ${project.version}
+
+
+ ${project.groupId}
+ binding-http.spec
+ ${project.version}
+
+
+ ${project.groupId}
+ binding-kafka.spec
+ ${project.version}
+
+
+ ${project.groupId}
+ binding-mqtt-kafka.spec
+ ${project.version}
+
+
+ junit
+ junit
+ test
+
+
+ org.kaazing
+ k3po.junit
+ test
+
+
+ org.hamcrest
+ hamcrest-library
+ test
+
+
+
+
+
+
+ src/main/resources
+
+
+ src/main/scripts
+
+
+
+
+
+ org.jasig.maven
+ maven-notice-plugin
+
+
+ ${project.groupId}
+ flyweight-maven-plugin
+ ${project.version}
+
+ core http mqtt kafka asyncapi
+ io.aklivity.zilla.specs.binding.asyncapi.internal.types
+
+
+
+
+ validate
+ generate
+
+
+
+
+
+ com.mycila
+ license-maven-plugin
+
+
+ maven-checkstyle-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.moditect
+ moditect-maven-plugin
+
+
+ org.kaazing
+ k3po-maven-plugin
+
+
+ ${project.groupId}
+ engine
+ ${project.version}
+ test-jar
+
+
+ ${project.groupId}
+ engine
+ ${project.version}
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+ io/aklivity/zilla/specs/binding/asyncapi/internal/types/**/*.class
+
+
+
+ BUNDLE
+
+
+ INSTRUCTION
+ COVEREDRATIO
+ ${jacoco.coverage.ratio}
+
+
+ CLASS
+ MISSEDCOUNT
+ ${jacoco.missed.count}
+
+
+
+
+
+
+
+
+
diff --git a/incubator/binding-asyncapi.spec/src/main/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiFunctions.java b/incubator/binding-asyncapi.spec/src/main/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiFunctions.java
new file mode 100644
index 0000000000..440d91d71c
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiFunctions.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi;
+
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+import org.agrona.DirectBuffer;
+import org.agrona.MutableDirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.kaazing.k3po.lang.el.BytesMatcher;
+import org.kaazing.k3po.lang.el.Function;
+import org.kaazing.k3po.lang.el.spi.FunctionMapperSpi;
+
+import io.aklivity.zilla.specs.binding.asyncapi.internal.types.OctetsFW;
+import io.aklivity.zilla.specs.binding.asyncapi.internal.types.stream.AsyncapiBeginExFW;
+
+public final class AsyncapiFunctions
+{
+ @Function
+ public static AsyncapiBeginExBuilder beginEx()
+ {
+ return new AsyncapiBeginExBuilder();
+ }
+
+ @Function
+ public static AsyncapiBeginExMatcherBuilder matchBeginEx()
+ {
+ return new AsyncapiBeginExMatcherBuilder();
+ }
+
+ public static final class AsyncapiBeginExBuilder
+ {
+ private final AsyncapiBeginExFW.Builder beginExRW;
+
+ private AsyncapiBeginExBuilder()
+ {
+ MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[1024 * 8]);
+ this.beginExRW = new AsyncapiBeginExFW.Builder().wrap(writeBuffer, 0, writeBuffer.capacity());
+ }
+
+ public AsyncapiBeginExBuilder typeId(
+ int typeId)
+ {
+ beginExRW.typeId(typeId);
+ return this;
+ }
+
+ public AsyncapiBeginExBuilder apiId(
+ long apiId)
+ {
+ beginExRW.apiId(apiId);
+ return this;
+ }
+
+ public AsyncapiBeginExBuilder operationId(
+ String operationId)
+ {
+ beginExRW.operationId(operationId);
+ return this;
+ }
+
+ public AsyncapiBeginExBuilder extension(
+ byte[] extension)
+ {
+ beginExRW.extension(e -> e.set(extension));
+ return this;
+ }
+
+ public byte[] build()
+ {
+ final AsyncapiBeginExFW beginEx = beginExRW.build();
+ final byte[] array = new byte[beginEx.sizeof()];
+ beginEx.buffer().getBytes(beginEx.offset(), array);
+ return array;
+ }
+ }
+
+ public static final class AsyncapiBeginExMatcherBuilder
+ {
+ private final DirectBuffer bufferRO = new UnsafeBuffer();
+
+ private final AsyncapiBeginExFW beginExRO = new AsyncapiBeginExFW();
+
+ private Integer typeId;
+ private long apiId;
+ private String operationId;
+ private OctetsFW.Builder extensionRW;
+
+ public AsyncapiBeginExMatcherBuilder typeId(
+ int typeId)
+ {
+ this.typeId = typeId;
+ return this;
+ }
+
+ public AsyncapiBeginExMatcherBuilder operationId(
+ String operationId)
+ {
+ this.operationId = operationId;
+ return this;
+ }
+
+ public AsyncapiBeginExMatcherBuilder apiId(
+ long apiId)
+ {
+ this.apiId = apiId;
+ return this;
+ }
+
+ public AsyncapiBeginExMatcherBuilder extension(
+ byte[] extension)
+ {
+ assert extensionRW == null;
+ extensionRW = new OctetsFW.Builder().wrap(new UnsafeBuffer(new byte[1024]), 0, 1024);
+
+ extensionRW.set(Objects.requireNonNullElseGet(extension, () -> new byte[] {}));
+
+ return this;
+ }
+
+ public BytesMatcher build()
+ {
+ return typeId != null ? this::match : buf -> null;
+ }
+
+ private AsyncapiBeginExFW match(
+ ByteBuffer byteBuf) throws Exception
+ {
+ if (!byteBuf.hasRemaining())
+ {
+ return null;
+ }
+
+ bufferRO.wrap(byteBuf);
+ final AsyncapiBeginExFW beginEx = beginExRO.tryWrap(bufferRO, byteBuf.position(), byteBuf.limit());
+
+ if (beginEx != null &&
+ matchTypeId(beginEx) &&
+ matchApiId(beginEx) &&
+ matchOperationId(beginEx) &&
+ matchExtension(beginEx))
+ {
+ byteBuf.position(byteBuf.position() + beginEx.sizeof());
+ return beginEx;
+ }
+ throw new Exception(beginEx.toString());
+ }
+
+ private boolean matchTypeId(
+ AsyncapiBeginExFW beginEx)
+ {
+ return typeId == beginEx.typeId();
+ }
+
+ private boolean matchApiId(
+ AsyncapiBeginExFW beginEx)
+ {
+ return apiId == beginEx.apiId();
+ }
+
+ private boolean matchOperationId(
+ AsyncapiBeginExFW beginEx)
+ {
+ return operationId == null || operationId.equals(beginEx.operationId().asString());
+ }
+
+ private boolean matchExtension(
+ final AsyncapiBeginExFW beginEx)
+ {
+ return extensionRW == null || extensionRW.build().equals(beginEx.extension());
+ }
+ }
+
+ private AsyncapiFunctions()
+ {
+ // utility
+ }
+
+ public static class Mapper extends FunctionMapperSpi.Reflective
+ {
+ public Mapper()
+ {
+ super(AsyncapiFunctions.class);
+ }
+
+ @Override
+ public String getPrefixName()
+ {
+ return "asyncapi";
+ }
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/main/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiSpecs.java b/incubator/binding-asyncapi.spec/src/main/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiSpecs.java
new file mode 100644
index 0000000000..262fc5de9c
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiSpecs.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi;
+
+public final class AsyncapiSpecs
+{
+ private AsyncapiSpecs()
+ {
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/main/moditect/module-info.java b/incubator/binding-asyncapi.spec/src/main/moditect/module-info.java
new file mode 100644
index 0000000000..187284829c
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/moditect/module-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+open module io.aklivity.zilla.specs.binding.asyncapi
+{
+ requires transitive io.aklivity.zilla.specs.engine;
+}
diff --git a/incubator/binding-asyncapi.spec/src/main/resources/META-INF/services/org.kaazing.k3po.lang.el.spi.FunctionMapperSpi b/incubator/binding-asyncapi.spec/src/main/resources/META-INF/services/org.kaazing.k3po.lang.el.spi.FunctionMapperSpi
new file mode 100644
index 0000000000..194c889324
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/resources/META-INF/services/org.kaazing.k3po.lang.el.spi.FunctionMapperSpi
@@ -0,0 +1 @@
+io.aklivity.zilla.specs.binding.asyncapi.AsyncapiFunctions$Mapper
diff --git a/incubator/binding-asyncapi.spec/src/main/resources/META-INF/zilla/asyncapi.idl b/incubator/binding-asyncapi.spec/src/main/resources/META-INF/zilla/asyncapi.idl
new file mode 100644
index 0000000000..22dc7b0946
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/resources/META-INF/zilla/asyncapi.idl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+scope asyncapi
+{
+ scope stream
+ {
+ struct AsyncapiBeginEx extends core::stream::Extension
+ {
+ int64 apiId = 0;
+ string16 operationId = null;
+ octets extension;
+ }
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.http.secure.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.http.secure.yaml
new file mode 100644
index 0000000000..177a2ed8ed
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.http.secure.yaml
@@ -0,0 +1,41 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+vaults:
+ test0:
+ type: test
+bindings:
+ asyncapi0:
+ type: asyncapi
+ kind: client
+ vault: test0
+ options:
+ specs:
+ http_api: http/asyncapi.yaml
+ tcp:
+ host: localhost
+ port:
+ - 7080
+ tls:
+ trust:
+ - serverca
+ trustcacerts: true
+ sni:
+ - http.example.net
+ alpn:
+ - h2
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.http.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.http.yaml
new file mode 100644
index 0000000000..246b0e5dfd
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.http.yaml
@@ -0,0 +1,29 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+bindings:
+ asyncapi0:
+ type: asyncapi
+ kind: client
+ options:
+ specs:
+ http_api: http/asyncapi.yaml
+ tcp:
+ host: localhost
+ port:
+ - 7080
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.kafka.sasl.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.kafka.sasl.yaml
new file mode 100644
index 0000000000..ded9bd7624
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.kafka.sasl.yaml
@@ -0,0 +1,46 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+vaults:
+ test0:
+ type: test
+bindings:
+ asyncapi0:
+ type: asyncapi
+ kind: client
+ vault: test0
+ options:
+ specs:
+ kafka_api: kafka/asyncapi.yaml
+ tcp:
+ host: localhost
+ port:
+ - 9092
+ tls:
+ trust:
+ - serverca
+ trustcacerts: true
+ sni:
+ - kafka.example.net
+ alpn:
+ - kafka
+ kafka:
+ sasl:
+ mechanism: plain
+ username: username
+ password: password
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.kafka.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.kafka.yaml
new file mode 100644
index 0000000000..8719d56e79
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.kafka.yaml
@@ -0,0 +1,29 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+bindings:
+ asyncapi0:
+ type: asyncapi
+ kind: client
+ options:
+ specs:
+ kafka_api: kafka/asyncapi.yaml
+ tcp:
+ host: localhost
+ port:
+ - 9092
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.mqtt.secure.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.mqtt.secure.yaml
new file mode 100644
index 0000000000..ed373d7a29
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.mqtt.secure.yaml
@@ -0,0 +1,41 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+vaults:
+ test0:
+ type: test
+bindings:
+ asyncapi0:
+ type: asyncapi
+ kind: client
+ vault: test0
+ options:
+ specs:
+ mqtt_api: mqtt/asyncapi.yaml
+ tcp:
+ host: localhost
+ port:
+ - 7183
+ tls:
+ trust:
+ - serverca
+ trustcacerts: true
+ sni:
+ - mqtt.example.net
+ alpn:
+ - mqtt
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.mqtt.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.mqtt.yaml
new file mode 100644
index 0000000000..65f9033370
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/client.mqtt.yaml
@@ -0,0 +1,29 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+bindings:
+ asyncapi0:
+ type: asyncapi
+ kind: client
+ options:
+ specs:
+ mqtt_api: mqtt/asyncapi.yaml
+ tcp:
+ host: localhost
+ port:
+ - 7183
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/http/asyncapi.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/http/asyncapi.yaml
new file mode 100644
index 0000000000..5c4b7a0dbe
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/http/asyncapi.yaml
@@ -0,0 +1,96 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+asyncapi: 3.0.0
+info:
+ title: AsyncAPI Petstore
+ license:
+ name: MIT
+ version: 1.0.0
+servers:
+ plain:
+ host: http://localhost:8080
+ protocol: http
+ protocolVersion: '2.0'
+defaultContentType: application/json
+
+channels:
+ pets:
+ address: /pets
+ messages:
+ pet:
+ $ref: '#/components/messages/pet'
+ showPetById:
+ address: /pets/{id}
+ messages:
+ pet:
+ $ref: '#/components/messages/pet'
+
+operations:
+ createPet:
+ action: send
+ bindings:
+ http:
+ method: POST
+ channel:
+ $ref: '#/channels/pets'
+ listPets:
+ action: receive
+ bindings:
+ http:
+ method: GET
+ channel:
+ $ref: '#/channels/pets'
+ getPets:
+ action: receive
+ bindings:
+ http:
+ method: GET
+ query:
+ type: object
+ properties:
+ limit:
+ type: number
+ channel:
+ $ref: '#/channels/showPetById'
+
+components:
+ correlationIds:
+ petsCorrelationId:
+ location: '$message.header#/idempotency-key'
+ schemas:
+ petPayload:
+ type: object
+ properties:
+ id:
+ type: integer
+ minimum: 0
+ description: Pet id.
+ name:
+ type: string
+ description: Pet name.
+ tag:
+ type: string
+ description: Tag.
+ messages:
+ pet:
+ name: Pet
+ title: Pet
+ summary: >-
+ Inform about Pet.
+ contentType: application/json
+ payload:
+ $ref: '#/components/schemas/petPayload'
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/kafka/asyncapi.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/kafka/asyncapi.yaml
new file mode 100644
index 0000000000..1c7b1bf0df
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/kafka/asyncapi.yaml
@@ -0,0 +1,199 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+asyncapi: 3.0.0
+info:
+ title: Streetlights Kafka API
+ version: 1.0.0
+ description: "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n### Check out its awesome features:\n\n* Turn a specific streetlight on/off \U0001F303\n* Dim a specific streetlight \U0001F60E\n* Receive real-time information about environmental lighting conditions \U0001F4C8\n"
+ license:
+ name: Apache 2.0
+ url: 'https://www.apache.org/licenses/LICENSE-2.0'
+defaultContentType: application/json
+servers:
+ scram-connections:
+ host: 'test.mykafkacluster.org:18092'
+ protocol: kafka-secure
+ description: Test broker secured with scramSha256
+ security:
+ - $ref: '#/components/securitySchemes/saslScram'
+ tags:
+ - name: 'env:test-scram'
+ description: >-
+ This environment is meant for running internal tests through
+ scramSha256
+ - name: 'kind:remote'
+ description: This server is a remote server. Not exposed by the application
+ - name: 'visibility:private'
+ description: This resource is private and only available to certain users
+channels:
+ lightingMeasured:
+ address: 'smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured'
+ messages:
+ lightMeasured:
+ $ref: '#/components/messages/lightMeasured'
+ description: The topic on which measured values may be produced and consumed.
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/streetlightId'
+ lightTurnOn:
+ address: 'smartylighting.streetlights.1.0.action.{streetlightId}.turn.on'
+ messages:
+ turnOn:
+ $ref: '#/components/messages/turnOnOff'
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/streetlightId'
+ lightTurnOff:
+ address: 'smartylighting.streetlights.1.0.action.{streetlightId}.turn.off'
+ messages:
+ turnOff:
+ $ref: '#/components/messages/turnOnOff'
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/streetlightId'
+ lightsDim:
+ address: 'smartylighting.streetlights.1.0.action.{streetlightId}.dim'
+ messages:
+ dimLight:
+ $ref: '#/components/messages/dimLight'
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/streetlightId'
+operations:
+ receiveLightMeasurement:
+ action: receive
+ channel:
+ $ref: '#/channels/lightingMeasured'
+ summary: >-
+ Inform about environmental lighting conditions of a particular
+ streetlight.
+ traits:
+ - $ref: '#/components/operationTraits/kafka'
+ messages:
+ - $ref: '#/channels/lightingMeasured/messages/lightMeasured'
+ turnOn:
+ action: send
+ channel:
+ $ref: '#/channels/lightTurnOn'
+ traits:
+ - $ref: '#/components/operationTraits/kafka'
+ messages:
+ - $ref: '#/channels/lightTurnOn/messages/turnOn'
+ turnOff:
+ action: send
+ channel:
+ $ref: '#/channels/lightTurnOff'
+ traits:
+ - $ref: '#/components/operationTraits/kafka'
+ messages:
+ - $ref: '#/channels/lightTurnOff/messages/turnOff'
+ dimLight:
+ action: send
+ channel:
+ $ref: '#/channels/lightsDim'
+ traits:
+ - $ref: '#/components/operationTraits/kafka'
+ messages:
+ - $ref: '#/channels/lightsDim/messages/dimLight'
+components:
+ messages:
+ lightMeasured:
+ name: lightMeasured
+ title: Light measured
+ summary: >-
+ Inform about environmental lighting conditions of a particular
+ streetlight.
+ contentType: application/json
+ traits:
+ - $ref: '#/components/messageTraits/commonHeaders'
+ payload:
+ $ref: '#/components/schemas/lightMeasuredPayload'
+ turnOnOff:
+ name: turnOnOff
+ title: Turn on/off
+ summary: Command a particular streetlight to turn the lights on or off.
+ traits:
+ - $ref: '#/components/messageTraits/commonHeaders'
+ payload:
+ $ref: '#/components/schemas/turnOnOffPayload'
+ dimLight:
+ name: dimLight
+ title: Dim light
+ summary: Command a particular streetlight to dim the lights.
+ traits:
+ - $ref: '#/components/messageTraits/commonHeaders'
+ payload:
+ $ref: '#/components/schemas/dimLightPayload'
+ schemas:
+ lightMeasuredPayload:
+ type: object
+ properties:
+ lumens:
+ type: integer
+ minimum: 0
+ description: Light intensity measured in lumens.
+ sentAt:
+ $ref: '#/components/schemas/sentAt'
+ turnOnOffPayload:
+ type: object
+ properties:
+ command:
+ type: string
+ enum:
+ - 'on'
+ - 'off'
+ description: Whether to turn on or off the light.
+ sentAt:
+ $ref: '#/components/schemas/sentAt'
+ dimLightPayload:
+ type: object
+ properties:
+ percentage:
+ type: integer
+ description: Percentage to which the light should be dimmed to.
+ minimum: 0
+ maximum: 100
+ sentAt:
+ $ref: '#/components/schemas/sentAt'
+ sentAt:
+ type: string
+ format: date-time
+ description: Date and time when the message was sent.
+ securitySchemes:
+ saslScram:
+ type: scramSha256
+ description: Provide your username and password for SASL/SCRAM authentication
+ parameters:
+ streetlightId:
+ description: The ID of the streetlight.
+ messageTraits:
+ commonHeaders:
+ headers:
+ type: object
+ properties:
+ my-app-header:
+ type: integer
+ minimum: 0
+ maximum: 100
+ operationTraits:
+ kafka:
+ bindings:
+ kafka:
+ clientId:
+ type: string
+ enum:
+ - my-app-id
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/kafka/sensor.asyncapi.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/kafka/sensor.asyncapi.yaml
new file mode 100644
index 0000000000..020633da3f
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/kafka/sensor.asyncapi.yaml
@@ -0,0 +1,66 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+asyncapi: 3.0.0
+info:
+ title: Zilla Kafka Proxy
+ version: 1.0.0
+ license:
+ name: Aklivity Community License
+servers:
+ plain:
+ host: localhost:9092
+ protocol: kafka
+
+operations:
+ onSensorData:
+ action: receive
+ channel:
+ $ref: '#/channels/sensorData'
+ toSensorData:
+ action: send
+ channel:
+ $ref: '#/channels/sensorData'
+
+channels:
+ sensorData:
+ description: This channel contains a message for sensors.
+ address: sensors
+ messages:
+ sensorData:
+ $ref: '#/components/messages/sensorData'
+ mqttSessions:
+ description: This channel contains MQTT sessions.
+ address: mqtt-sessions
+ mqttMessages:
+ description: This channel contains MQTT messages.
+ address: mqtt-messages
+ mqttRetained:
+ description: This channel contains MQTT retained messages.
+ address: mqtt-retained
+
+components:
+ messages:
+ sensorData:
+ payload:
+ type: object
+ properties:
+ sensorId:
+ type: integer
+ description: This property describes the id of the sensor
+ message:
+ type: string
+ description: This property describes message of the sensor
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/mqtt/asyncapi.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/mqtt/asyncapi.yaml
new file mode 100644
index 0000000000..7aa9fca2e5
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/mqtt/asyncapi.yaml
@@ -0,0 +1,68 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+asyncapi: 3.0.0
+info:
+ title: Zilla MQTT Proxy
+ version: 1.0.0
+ license:
+ name: Aklivity Community License
+servers:
+ plain:
+ host: mqtt://localhost:1883
+ protocol: mqtt
+defaultContentType: application/json
+
+channels:
+ sensors:
+ address: "sensors/{sensorId}"
+ title: MQTT Topic to produce & consume topic.
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/sensorId'
+ messages:
+ items:
+ $ref: '#/components/messages/item'
+
+operations:
+ sendEvents:
+ action: send
+ channel:
+ $ref: '#/channels/sensors'
+
+ receiveEvents:
+ action: receive
+ channel:
+ $ref: '#/channels/sensors'
+
+components:
+ parameters:
+ sensorId:
+ description: Sensor ID
+ location: $message.header#/id
+ messages:
+ item:
+ name: event
+ title: An event
+ headers:
+ type: object
+ properties:
+ idempotency-key:
+ description: Unique identifier for a given event
+ type: string
+ id:
+ description: Sensor ID
+ type: string
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/proxy.mqtt.kafka.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/proxy.mqtt.kafka.yaml
new file mode 100644
index 0000000000..deb7634692
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/proxy.mqtt.kafka.yaml
@@ -0,0 +1,46 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+bindings:
+ asyncapi_proxy0:
+ type: asyncapi
+ kind: proxy
+ options:
+ specs:
+ mqtt_api: mqtt/asyncapi.yaml
+ kafka_api: kafka/sensor.asyncapi.yaml
+ mqtt_kafka:
+ channels:
+ sessions: mqttSessions
+ retained: mqttRetained
+ messages: mqttMessages
+ routes:
+ - when:
+ - api-id: mqtt_api
+ operation-id: sendEvents
+ exit: asyncapi_kafka0
+ with:
+ api-id: kafka_api
+ operation-id: toSensorData
+ - when:
+ - api-id: mqtt_api
+ operation-id: receiveEvents
+ exit: asyncapi_kafka0
+ with:
+ api-id: kafka_api
+ operation-id: onSensorData
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.secure.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.secure.yaml
new file mode 100644
index 0000000000..a09b6aefd6
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.secure.yaml
@@ -0,0 +1,37 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+vaults:
+ test0:
+ type: test
+bindings:
+ composite0:
+ type: asyncapi
+ kind: server
+ vault: test0
+ options:
+ specs:
+ http_api: http/asyncapi.yaml
+ tls:
+ keys:
+ - localhost
+ sni:
+ - http.example.net
+ alpn:
+ - h2
+ exit: asyncapi0
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.yaml
new file mode 100644
index 0000000000..1bb68c32d3
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.yaml
@@ -0,0 +1,26 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+bindings:
+ composite0:
+ type: asyncapi
+ kind: server
+ options:
+ specs:
+ http_api: http/asyncapi.yaml
+ exit: asyncapi0
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.mqtt.secure.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.mqtt.secure.yaml
new file mode 100644
index 0000000000..80fee3c5dd
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.mqtt.secure.yaml
@@ -0,0 +1,37 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+vaults:
+ test0:
+ type: test
+bindings:
+ composite0:
+ type: asyncapi
+ kind: server
+ vault: test0
+ options:
+ specs:
+ mqtt_api: mqtt/asyncapi.yaml
+ tls:
+ keys:
+ - localhost
+ sni:
+ - mqtt.example.net
+ alpn:
+ - mqtt
+ exit: asyncapi0
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.mqtt.yaml b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.mqtt.yaml
new file mode 100644
index 0000000000..36e41f3429
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.mqtt.yaml
@@ -0,0 +1,26 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+---
+name: test
+bindings:
+ composite0:
+ type: asyncapi
+ kind: server
+ options:
+ specs:
+ mqtt_api: mqtt/asyncapi.yaml
+ exit: asyncapi0
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.2.6.schema.json b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.2.6.schema.json
new file mode 100644
index 0000000000..053cc08f14
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.2.6.schema.json
@@ -0,0 +1,3229 @@
+{
+ "$id": "http://asyncapi.com/definitions/2.6.0/asyncapi.json",
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "title": "AsyncAPI 2.6.0 schema.",
+ "type": "object",
+ "required": [
+ "asyncapi",
+ "info",
+ "channels"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "asyncapi": {
+ "type": "string",
+ "enum": [
+ "2.6.0"
+ ],
+ "description": "The AsyncAPI specification version of this document."
+ },
+ "id": {
+ "type": "string",
+ "description": "A unique id representing the application.",
+ "format": "uri"
+ },
+ "info": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/info.json"
+ },
+ "servers": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/servers.json"
+ },
+ "defaultContentType": {
+ "type": "string"
+ },
+ "channels": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/channels.json"
+ },
+ "components": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/components.json"
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/tag.json"
+ },
+ "uniqueItems": true
+ },
+ "externalDocs": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/externalDocs.json"
+ }
+ },
+ "definitions": {
+ "http://asyncapi.com/definitions/2.6.0/specificationExtension.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json",
+ "description": "Any property starting with x- is valid.",
+ "additionalProperties": true,
+ "additionalItems": true
+ },
+ "http://asyncapi.com/definitions/2.6.0/info.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/info.json",
+ "type": "object",
+ "description": "The object provides metadata about the API. The metadata can be used by the clients if needed.",
+ "required": [
+ "version",
+ "title"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A unique and precise title of the API."
+ },
+ "version": {
+ "type": "string",
+ "description": "A semantic version number of the API."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the API. Should be different from the title. CommonMark is allowed."
+ },
+ "termsOfService": {
+ "type": "string",
+ "description": "A URL to the Terms of Service for the API. MUST be in the format of a URL.",
+ "format": "uri"
+ },
+ "contact": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/contact.json"
+ },
+ "license": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/license.json"
+ }
+ },
+ "examples": [
+ {
+ "title": "AsyncAPI Sample App",
+ "description": "This is a sample server.",
+ "termsOfService": "https://asyncapi.org/terms/",
+ "contact": {
+ "name": "API Support",
+ "url": "https://www.example.com/support",
+ "email": "support@example.com"
+ },
+ "license": {
+ "name": "Apache 2.0",
+ "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/contact.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/contact.json",
+ "type": "object",
+ "description": "Contact information for the exposed API.",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The identifying name of the contact person/organization."
+ },
+ "url": {
+ "type": "string",
+ "description": "The URL pointing to the contact information.",
+ "format": "uri"
+ },
+ "email": {
+ "type": "string",
+ "description": "The email address of the contact person/organization.",
+ "format": "email"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "examples": [
+ {
+ "name": "API Support",
+ "url": "https://www.example.com/support",
+ "email": "support@example.com"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/license.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/license.json",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "description": "License information for the exposed API.",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the license type. It's encouraged to use an OSI compatible license."
+ },
+ "url": {
+ "type": "string",
+ "description": "The URL pointing to the license.",
+ "format": "uri"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "examples": [
+ {
+ "name": "Apache 2.0",
+ "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/servers.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/servers.json",
+ "description": "The Servers Object is a map of Server Objects.",
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/server.json"
+ }
+ ]
+ },
+ "examples": [
+ {
+ "development": {
+ "url": "development.gigantic-server.com",
+ "description": "Development server",
+ "protocol": "amqp",
+ "protocolVersion": "0.9.1",
+ "tags": [
+ {
+ "name": "env:development",
+ "description": "This environment is meant for developers to run their own tests"
+ }
+ ]
+ },
+ "staging": {
+ "url": "staging.gigantic-server.com",
+ "description": "Staging server",
+ "protocol": "amqp",
+ "protocolVersion": "0.9.1",
+ "tags": [
+ {
+ "name": "env:staging",
+ "description": "This environment is a replica of the production environment"
+ }
+ ]
+ },
+ "production": {
+ "url": "api.gigantic-server.com",
+ "description": "Production server",
+ "protocol": "amqp",
+ "protocolVersion": "0.9.1",
+ "tags": [
+ {
+ "name": "env:production",
+ "description": "This environment is the live environment available for final users"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/Reference.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/Reference.json",
+ "type": "object",
+ "required": [
+ "$ref"
+ ],
+ "properties": {
+ "$ref": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/ReferenceObject.json"
+ }
+ }
+ },
+ "http://asyncapi.com/definitions/2.6.0/ReferenceObject.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/ReferenceObject.json",
+ "type": "string",
+ "description": "A simple object to allow referencing other components in the specification, internally and externally.",
+ "format": "uri-reference",
+ "examples": [
+ {
+ "$ref": "#/components/schemas/Pet"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/server.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/server.json",
+ "type": "object",
+ "description": "An object representing a message broker, a server or any other kind of computer program capable of sending and/or receiving data",
+ "required": [
+ "url",
+ "protocol"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "url": {
+ "type": "string",
+ "description": "A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the AsyncAPI document is being served."
+ },
+ "description": {
+ "type": "string",
+ "description": "An optional string describing the host designated by the URL. CommonMark syntax MAY be used for rich text representation."
+ },
+ "protocol": {
+ "type": "string",
+ "description": "The protocol this URL supports for connection. Supported protocol include, but are not limited to: amqp, amqps, http, https, ibmmq, jms, kafka, kafka-secure, anypointmq, mqtt, secure-mqtt, solace, stomp, stomps, ws, wss, mercure, googlepubsub."
+ },
+ "protocolVersion": {
+ "type": "string",
+ "description": "The version of the protocol used for connection. For instance: AMQP 0.9.1, HTTP 2.0, Kafka 1.0.0, etc."
+ },
+ "variables": {
+ "description": "A map between a variable name and its value. The value is used for substitution in the server's URL template.",
+ "$ref": "http://asyncapi.com/definitions/2.6.0/serverVariables.json"
+ },
+ "security": {
+ "type": "array",
+ "description": "A declaration of which security mechanisms can be used with this server. The list of values includes alternative security requirement objects that can be used. ",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/SecurityRequirement.json"
+ }
+ },
+ "bindings": {
+ "description": "A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the server.",
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ },
+ "tags": {
+ "type": "array",
+ "description": "A list of tags for logical grouping and categorization of servers.",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/tag.json"
+ },
+ "uniqueItems": true
+ }
+ },
+ "examples": [
+ {
+ "url": "development.gigantic-server.com",
+ "description": "Development server",
+ "protocol": "kafka",
+ "protocolVersion": "1.0.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/serverVariables.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/serverVariables.json",
+ "type": "object",
+ "description": "A map between a variable name and its value. The value is used for substitution in the server's URL template.",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/serverVariable.json"
+ }
+ ]
+ }
+ },
+ "http://asyncapi.com/definitions/2.6.0/serverVariable.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/serverVariable.json",
+ "type": "object",
+ "description": "An object representing a Server Variable for server URL template substitution.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "enum": {
+ "type": "array",
+ "description": "An enumeration of string values to be used if the substitution options are from a limited set.",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true
+ },
+ "default": {
+ "type": "string",
+ "description": "The default value to use for substitution, and to send, if an alternate value is not supplied."
+ },
+ "description": {
+ "type": "string",
+ "description": "An optional description for the server variable. "
+ },
+ "examples": {
+ "type": "array",
+ "description": "An array of examples of the server variable.",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "http://asyncapi.com/definitions/2.6.0/SecurityRequirement.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/SecurityRequirement.json",
+ "type": "object",
+ "description": "Lists of the required security schemes that can be used to execute an operation",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true
+ },
+ "examples": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/bindingsObject.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json",
+ "type": "object",
+ "description": "Map describing protocol-specific definitions for a server.",
+ "additionalProperties": true,
+ "properties": {
+ "http": {},
+ "ws": {},
+ "amqp": {},
+ "amqp1": {},
+ "mqtt": {},
+ "mqtt5": {},
+ "kafka": {},
+ "anypointmq": {},
+ "nats": {},
+ "jms": {},
+ "sns": {},
+ "sqs": {},
+ "stomp": {},
+ "redis": {},
+ "ibmmq": {},
+ "solace": {},
+ "googlepubsub": {},
+ "pulsar": {}
+ }
+ },
+ "http://asyncapi.com/definitions/2.6.0/tag.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/tag.json",
+ "type": "object",
+ "description": "Allows adding meta data to a single tag.",
+ "additionalProperties": false,
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the tag."
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for the tag."
+ },
+ "externalDocs": {
+ "description": "Additional external documentation for this tag.",
+ "$ref": "http://asyncapi.com/definitions/2.6.0/externalDocs.json"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "examples": [
+ {
+ "name": "user",
+ "description": "User-related messages"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/externalDocs.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/externalDocs.json",
+ "type": "object",
+ "additionalProperties": false,
+ "description": "Allows referencing an external resource for extended documentation.",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "description": {
+ "type": "string",
+ "description": "A short description of the target documentation."
+ },
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "The URL for the target documentation. This MUST be in the form of an absolute URL."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "examples": [
+ {
+ "description": "Find more info here",
+ "url": "https://example.com"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/channels.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/channels.json",
+ "type": "object",
+ "description": "Holds the relative paths to the individual channel and their operations. Channel paths are relative to servers.",
+ "propertyNames": {
+ "type": "string",
+ "format": "uri-template",
+ "minLength": 1
+ },
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/channelItem.json"
+ },
+ "examples": [
+ {
+ "user/signedup": {
+ "subscribe": {
+ "message": {
+ "$ref": "#/components/messages/userSignedUp"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/channelItem.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/channelItem.json",
+ "type": "object",
+ "description": "Describes the operations available on a single channel.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "$ref": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/ReferenceObject.json"
+ },
+ "parameters": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/parameters.json"
+ },
+ "description": {
+ "type": "string",
+ "description": "A description of the channel."
+ },
+ "servers": {
+ "type": "array",
+ "description": "The names of the servers on which this channel is available. If absent or empty then this channel must be available on all servers.",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true
+ },
+ "publish": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/operation.json"
+ },
+ "subscribe": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/operation.json"
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "bindings": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ }
+ },
+ "examples": [
+ {
+ "description": "This channel is used to exchange messages about users signing up",
+ "subscribe": {
+ "summary": "A user signed up.",
+ "message": {
+ "description": "A longer description of the message",
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/user"
+ },
+ "signup": {
+ "$ref": "#/components/schemas/signup"
+ }
+ }
+ }
+ }
+ },
+ "bindings": {
+ "amqp": {
+ "is": "queue",
+ "queue": {
+ "exclusive": true
+ }
+ }
+ }
+ },
+ {
+ "subscribe": {
+ "message": {
+ "oneOf": [
+ {
+ "$ref": "#/components/messages/signup"
+ },
+ {
+ "$ref": "#/components/messages/login"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "description": "This application publishes WebUICommand messages to an AMQP queue on RabbitMQ brokers in the Staging and Production environments.",
+ "servers": [
+ "rabbitmqBrokerInProd",
+ "rabbitmqBrokerInStaging"
+ ],
+ "subscribe": {
+ "message": {
+ "$ref": "#/components/messages/WebUICommand"
+ }
+ },
+ "bindings": {
+ "amqp": {
+ "is": "queue"
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/parameters.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/parameters.json",
+ "type": "object",
+ "description": "JSON objects describing reusable channel parameters.",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/parameter.json"
+ }
+ ]
+ },
+ "examples": [
+ {
+ "user/{userId}/signup": {
+ "parameters": {
+ "userId": {
+ "description": "Id of the user.",
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
+ "subscribe": {
+ "message": {
+ "$ref": "#/components/messages/userSignedUp"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/parameter.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/parameter.json",
+ "description": "Describes a parameter included in a channel name.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "description": {
+ "type": "string",
+ "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed."
+ },
+ "schema": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ "location": {
+ "type": "string",
+ "description": "A runtime expression that specifies the location of the parameter value",
+ "pattern": "^\\$message\\.(header|payload)#(\\/(([^\\/~])|(~[01]))*)*"
+ }
+ },
+ "examples": [
+ {
+ "user/{userId}/signup": {
+ "parameters": {
+ "userId": {
+ "description": "Id of the user.",
+ "schema": {
+ "type": "string"
+ },
+ "location": "$message.payload#/user/id"
+ }
+ },
+ "subscribe": {
+ "message": {
+ "$ref": "#/components/messages/userSignedUp"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/schema.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/schema.json",
+ "description": "The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays.",
+ "allOf": [
+ {
+ "$ref": "http://json-schema.org/draft-07/schema#"
+ },
+ {
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ {
+ "type": "boolean"
+ }
+ ],
+ "default": {}
+ },
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ }
+ }
+ ],
+ "default": {}
+ },
+ "allOf": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ }
+ },
+ "oneOf": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ }
+ },
+ "anyOf": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ }
+ },
+ "not": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ "properties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ "default": {}
+ },
+ "patternProperties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ "default": {}
+ },
+ "propertyNames": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ "contains": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ "discriminator": {
+ "type": "string",
+ "description": "Adds support for polymorphism. The discriminator is the schema property name that is used to differentiate between other schema that inherit this schema. "
+ },
+ "externalDocs": {
+ "description": "Additional external documentation for this schema.",
+ "$ref": "http://asyncapi.com/definitions/2.6.0/externalDocs.json"
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false,
+ "description": "Specifies that a schema is deprecated and SHOULD be transitioned out of usage"
+ }
+ }
+ }
+ ],
+ "examples": [
+ {
+ "type": "string",
+ "format": "email"
+ },
+ {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "address": {
+ "$ref": "#/components/schemas/Address"
+ },
+ "age": {
+ "type": "integer",
+ "format": "int32",
+ "minimum": 0
+ }
+ }
+ }
+ ]
+ },
+ "http://json-schema.org/draft-07/schema": {
+ "$id": "http://json-schema.org/draft-07/schema",
+ "title": "Core schema meta-schema",
+ "definitions": {
+ "schemaArray": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#"
+ }
+ },
+ "nonNegativeInteger": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "nonNegativeIntegerDefault0": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/nonNegativeInteger"
+ },
+ {
+ "default": 0
+ }
+ ]
+ },
+ "simpleTypes": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "null",
+ "number",
+ "object",
+ "string"
+ ]
+ },
+ "stringArray": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "default": []
+ }
+ },
+ "type": [
+ "object",
+ "boolean"
+ ],
+ "properties": {
+ "$id": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "$schema": {
+ "type": "string",
+ "format": "uri"
+ },
+ "$ref": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "$comment": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "default": true,
+ "readOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "writeOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "examples": {
+ "type": "array",
+ "items": true
+ },
+ "multipleOf": {
+ "type": "number",
+ "exclusiveMinimum": 0
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "exclusiveMaximum": {
+ "type": "number"
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "exclusiveMinimum": {
+ "type": "number"
+ },
+ "maxLength": {
+ "$ref": "#/definitions/nonNegativeInteger"
+ },
+ "minLength": {
+ "$ref": "#/definitions/nonNegativeIntegerDefault0"
+ },
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "additionalItems": {
+ "$ref": "#"
+ },
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/schemaArray"
+ }
+ ],
+ "default": true
+ },
+ "maxItems": {
+ "$ref": "#/definitions/nonNegativeInteger"
+ },
+ "minItems": {
+ "$ref": "#/definitions/nonNegativeIntegerDefault0"
+ },
+ "uniqueItems": {
+ "type": "boolean",
+ "default": false
+ },
+ "contains": {
+ "$ref": "#"
+ },
+ "maxProperties": {
+ "$ref": "#/definitions/nonNegativeInteger"
+ },
+ "minProperties": {
+ "$ref": "#/definitions/nonNegativeIntegerDefault0"
+ },
+ "required": {
+ "$ref": "#/definitions/stringArray"
+ },
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "definitions": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "default": {}
+ },
+ "properties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "default": {}
+ },
+ "patternProperties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "propertyNames": {
+ "format": "regex"
+ },
+ "default": {}
+ },
+ "dependencies": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/stringArray"
+ }
+ ]
+ }
+ },
+ "propertyNames": {
+ "$ref": "#"
+ },
+ "const": true,
+ "enum": {
+ "type": "array",
+ "items": true,
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "type": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/simpleTypes"
+ },
+ {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/simpleTypes"
+ },
+ "minItems": 1,
+ "uniqueItems": true
+ }
+ ]
+ },
+ "format": {
+ "type": "string"
+ },
+ "contentMediaType": {
+ "type": "string"
+ },
+ "contentEncoding": {
+ "type": "string"
+ },
+ "if": {
+ "$ref": "#"
+ },
+ "then": {
+ "$ref": "#"
+ },
+ "else": {
+ "$ref": "#"
+ },
+ "allOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "anyOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "oneOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "not": {
+ "$ref": "#"
+ }
+ },
+ "default": true
+ },
+ "http://asyncapi.com/definitions/2.6.0/operation.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/operation.json",
+ "type": "object",
+ "description": "Describes a publish or a subscribe operation. This provides a place to document how and why messages are sent and received.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "traits": {
+ "type": "array",
+ "description": "A list of traits to apply to the operation object.",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/operationTrait.json"
+ }
+ ]
+ }
+ },
+ "summary": {
+ "type": "string",
+ "description": "A short summary of what the operation is about."
+ },
+ "description": {
+ "type": "string",
+ "description": "A verbose explanation of the operation."
+ },
+ "security": {
+ "type": "array",
+ "description": "A declaration of which security mechanisms are associated with this operation.",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/SecurityRequirement.json"
+ }
+ },
+ "tags": {
+ "type": "array",
+ "description": "A list of tags for logical grouping and categorization of operations.",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/tag.json"
+ },
+ "uniqueItems": true
+ },
+ "externalDocs": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/externalDocs.json"
+ },
+ "operationId": {
+ "type": "string"
+ },
+ "bindings": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ },
+ "message": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/message.json"
+ }
+ },
+ "examples": [
+ {
+ "user/signedup": {
+ "subscribe": {
+ "message": {
+ "$ref": "#/components/messages/userSignedUp"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/operationTrait.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/operationTrait.json",
+ "type": "object",
+ "description": "Describes a trait that MAY be applied to an Operation Object.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "summary": {
+ "type": "string",
+ "description": "A short summary of what the operation is about."
+ },
+ "description": {
+ "type": "string",
+ "description": "A verbose explanation of the operation."
+ },
+ "tags": {
+ "type": "array",
+ "description": "A list of tags for logical grouping and categorization of operations.",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/tag.json"
+ },
+ "uniqueItems": true
+ },
+ "externalDocs": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/externalDocs.json"
+ },
+ "operationId": {
+ "type": "string",
+ "description": "Unique string used to identify the operation. The id MUST be unique among all operations described in the API."
+ },
+ "security": {
+ "type": "array",
+ "description": "A declaration of which security mechanisms are associated with this operation. ",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/SecurityRequirement.json"
+ }
+ },
+ "bindings": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ }
+ },
+ "examples": [
+ {
+ "bindings": {
+ "amqp": {
+ "ack": false
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/message.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/message.json",
+ "description": "Describes a message received on a given channel and operation.",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "oneOf": [
+ {
+ "type": "object",
+ "required": [
+ "oneOf"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "oneOf": {
+ "type": "array",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/message.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "schemaFormat": {
+ "type": "string"
+ },
+ "contentType": {
+ "type": "string"
+ },
+ "headers": {
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "object"
+ }
+ }
+ }
+ ]
+ },
+ "messageId": {
+ "type": "string"
+ },
+ "payload": {},
+ "correlationId": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/correlationId.json"
+ }
+ ]
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/tag.json"
+ },
+ "uniqueItems": true
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the message."
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the message."
+ },
+ "title": {
+ "type": "string",
+ "description": "A human-friendly title for the message."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the message. CommonMark is allowed."
+ },
+ "externalDocs": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/externalDocs.json"
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "examples": {
+ "type": "array",
+ "description": "List of examples.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [
+ {
+ "required": [
+ "payload"
+ ]
+ },
+ {
+ "required": [
+ "headers"
+ ]
+ }
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Machine readable name of the message example."
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the message example."
+ },
+ "headers": {
+ "type": "object",
+ "description": "Schema definition of the application headers."
+ },
+ "payload": {
+ "description": "Definition of the message payload. It can be of any type"
+ }
+ }
+ }
+ },
+ "bindings": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ },
+ "traits": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/messageTrait.json"
+ }
+ ]
+ }
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "not": {
+ "required": [
+ "schemaFormat"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "payload": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "schemaFormat"
+ ],
+ "properties": {
+ "schemaFormat": {
+ "enum": [
+ "application/vnd.aai.asyncapi;version=2.0.0",
+ "application/vnd.aai.asyncapi+json;version=2.0.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.0.0",
+ "application/vnd.aai.asyncapi;version=2.1.0",
+ "application/vnd.aai.asyncapi+json;version=2.1.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.1.0",
+ "application/vnd.aai.asyncapi;version=2.2.0",
+ "application/vnd.aai.asyncapi+json;version=2.2.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.2.0",
+ "application/vnd.aai.asyncapi;version=2.3.0",
+ "application/vnd.aai.asyncapi+json;version=2.3.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.3.0",
+ "application/vnd.aai.asyncapi;version=2.4.0",
+ "application/vnd.aai.asyncapi+json;version=2.4.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.4.0",
+ "application/vnd.aai.asyncapi;version=2.5.0",
+ "application/vnd.aai.asyncapi+json;version=2.5.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.5.0",
+ "application/vnd.aai.asyncapi;version=2.6.0",
+ "application/vnd.aai.asyncapi+json;version=2.6.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.6.0"
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "payload": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "schemaFormat"
+ ],
+ "properties": {
+ "schemaFormat": {
+ "enum": [
+ "application/schema+json;version=draft-07",
+ "application/schema+yaml;version=draft-07"
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "payload": {
+ "$ref": "http://json-schema.org/draft-07/schema"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "schemaFormat"
+ ],
+ "properties": {
+ "schemaFormat": {
+ "enum": [
+ "application/vnd.oai.openapi;version=3.0.0",
+ "application/vnd.oai.openapi+json;version=3.0.0",
+ "application/vnd.oai.openapi+yaml;version=3.0.0"
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "payload": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/openapiSchema_3_0.json"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "schemaFormat"
+ ],
+ "properties": {
+ "schemaFormat": {
+ "enum": [
+ "application/vnd.apache.avro;version=1.9.0",
+ "application/vnd.apache.avro+json;version=1.9.0",
+ "application/vnd.apache.avro+yaml;version=1.9.0"
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "payload": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/avroSchema_v1.json"
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "examples": [
+ {
+ "messageId": "userSignup",
+ "name": "UserSignup",
+ "title": "User signup",
+ "summary": "Action to sign a user up.",
+ "description": "A longer description",
+ "contentType": "application/json",
+ "tags": [
+ {
+ "name": "user"
+ },
+ {
+ "name": "signup"
+ },
+ {
+ "name": "register"
+ }
+ ],
+ "headers": {
+ "type": "object",
+ "properties": {
+ "correlationId": {
+ "description": "Correlation ID set by application",
+ "type": "string"
+ },
+ "applicationInstanceId": {
+ "description": "Unique identifier for a given instance of the publishing application",
+ "type": "string"
+ }
+ }
+ },
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/userCreate"
+ },
+ "signup": {
+ "$ref": "#/components/schemas/signup"
+ }
+ }
+ },
+ "correlationId": {
+ "description": "Default Correlation ID",
+ "location": "$message.header#/correlationId"
+ },
+ "traits": [
+ {
+ "$ref": "#/components/messageTraits/commonHeaders"
+ }
+ ],
+ "examples": [
+ {
+ "name": "SimpleSignup",
+ "summary": "A simple UserSignup example message",
+ "headers": {
+ "correlationId": "my-correlation-id",
+ "applicationInstanceId": "myInstanceId"
+ },
+ "payload": {
+ "user": {
+ "someUserKey": "someUserValue"
+ },
+ "signup": {
+ "someSignupKey": "someSignupValue"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "messageId": "userSignup",
+ "name": "UserSignup",
+ "title": "User signup",
+ "summary": "Action to sign a user up.",
+ "description": "A longer description",
+ "tags": [
+ {
+ "name": "user"
+ },
+ {
+ "name": "signup"
+ },
+ {
+ "name": "register"
+ }
+ ],
+ "schemaFormat": "application/vnd.apache.avro+json;version=1.9.0",
+ "payload": {
+ "$ref": "path/to/user-create.avsc#/UserCreate"
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/correlationId.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/correlationId.json",
+ "type": "object",
+ "description": "An object that specifies an identifier at design time that can used for message tracing and correlation.",
+ "required": [
+ "location"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "description": {
+ "type": "string",
+ "description": "A optional description of the correlation ID. GitHub Flavored Markdown is allowed."
+ },
+ "location": {
+ "type": "string",
+ "description": "A runtime expression that specifies the location of the correlation ID",
+ "pattern": "^\\$message\\.(header|payload)#(\\/(([^\\/~])|(~[01]))*)*"
+ }
+ },
+ "examples": [
+ {
+ "description": "Default Correlation ID",
+ "location": "$message.header#/correlationId"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/messageTrait.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/messageTrait.json",
+ "type": "object",
+ "description": "Describes a trait that MAY be applied to a Message Object.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "schemaFormat": {
+ "type": "string",
+ "description": "A string containing the name of the schema format/language used to define the message payload."
+ },
+ "contentType": {
+ "type": "string",
+ "description": "The content type to use when encoding/decoding a message's payload."
+ },
+ "headers": {
+ "description": "Schema definition of the application headers.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "object"
+ }
+ }
+ }
+ ]
+ },
+ "messageId": {
+ "type": "string",
+ "description": "Unique string used to identify the message. The id MUST be unique among all messages described in the API."
+ },
+ "correlationId": {
+ "description": "Definition of the correlation ID used for message tracing or matching.",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/correlationId.json"
+ }
+ ]
+ },
+ "tags": {
+ "type": "array",
+ "description": "A list of tags for logical grouping and categorization of messages.",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/tag.json"
+ },
+ "uniqueItems": true
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the message."
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the message."
+ },
+ "title": {
+ "type": "string",
+ "description": "A human-friendly title for the message."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the message. CommonMark is allowed."
+ },
+ "externalDocs": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/externalDocs.json"
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "examples": {
+ "type": "array",
+ "description": "List of examples.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [
+ {
+ "required": [
+ "payload"
+ ]
+ },
+ {
+ "required": [
+ "headers"
+ ]
+ }
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Machine readable name of the message example."
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the message example."
+ },
+ "headers": {
+ "type": "object",
+ "description": "Schema definition of the application headers."
+ },
+ "payload": {
+ "description": "Definition of the message payload. It can be of any type"
+ }
+ }
+ }
+ },
+ "bindings": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ }
+ },
+ "examples": [
+ {
+ "schemaFormat": "application/vnd.apache.avro+json;version=1.9.0",
+ "contentType": "application/json"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/openapiSchema_3_0.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/openapiSchema_3_0.json",
+ "type": "object",
+ "definitions": {
+ "ExternalDocumentation": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri-reference"
+ }
+ },
+ "patternProperties": {
+ "^x-": {}
+ },
+ "additionalProperties": false
+ },
+ "Discriminator": {
+ "type": "object",
+ "required": [
+ "propertyName"
+ ],
+ "properties": {
+ "propertyName": {
+ "type": "string"
+ },
+ "mapping": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "Reference": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ],
+ "patternProperties": {
+ "^\\$ref$": {
+ "type": "string",
+ "format": "uri-reference"
+ }
+ }
+ },
+ "XML": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "namespace": {
+ "type": "string",
+ "format": "uri"
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "attribute": {
+ "type": "boolean",
+ "default": false
+ },
+ "wrapped": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "patternProperties": {
+ "^x-": {}
+ },
+ "additionalProperties": false
+ }
+ },
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "multipleOf": {
+ "type": "number",
+ "exclusiveMinimum": 0
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "exclusiveMaximum": {
+ "type": "boolean",
+ "default": false
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "exclusiveMinimum": {
+ "type": "boolean",
+ "default": false
+ },
+ "maxLength": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minLength": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "maxItems": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minItems": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "uniqueItems": {
+ "type": "boolean",
+ "default": false
+ },
+ "maxProperties": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minProperties": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "required": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "enum": {
+ "type": "array",
+ "items": true,
+ "minItems": 1,
+ "uniqueItems": false
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string"
+ ]
+ },
+ "not": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "allOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "oneOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "anyOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "properties": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "type": "boolean"
+ }
+ ],
+ "default": true
+ },
+ "description": {
+ "type": "string"
+ },
+ "format": {
+ "type": "string"
+ },
+ "default": true,
+ "nullable": {
+ "type": "boolean",
+ "default": false
+ },
+ "discriminator": {
+ "$ref": "#/definitions/Discriminator"
+ },
+ "readOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "writeOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "example": true,
+ "externalDocs": {
+ "$ref": "#/definitions/ExternalDocumentation"
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "xml": {
+ "$ref": "#/definitions/XML"
+ }
+ },
+ "patternProperties": {
+ "^x-": true
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/2.6.0/avroSchema_v1.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/avroSchema_v1.json",
+ "definitions": {
+ "avroSchema": {
+ "title": "Avro Schema",
+ "description": "Root Schema",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/types"
+ }
+ ]
+ },
+ "types": {
+ "title": "Avro Types",
+ "description": "Allowed Avro types",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/primitiveType"
+ },
+ {
+ "$ref": "#/definitions/primitiveTypeWithMetadata"
+ },
+ {
+ "$ref": "#/definitions/customTypeReference"
+ },
+ {
+ "$ref": "#/definitions/avroRecord"
+ },
+ {
+ "$ref": "#/definitions/avroEnum"
+ },
+ {
+ "$ref": "#/definitions/avroArray"
+ },
+ {
+ "$ref": "#/definitions/avroMap"
+ },
+ {
+ "$ref": "#/definitions/avroFixed"
+ },
+ {
+ "$ref": "#/definitions/avroUnion"
+ }
+ ]
+ },
+ "primitiveType": {
+ "title": "Primitive Type",
+ "description": "Basic type primitives.",
+ "type": "string",
+ "enum": [
+ "null",
+ "boolean",
+ "int",
+ "long",
+ "float",
+ "double",
+ "bytes",
+ "string"
+ ]
+ },
+ "primitiveTypeWithMetadata": {
+ "title": "Primitive Type With Metadata",
+ "description": "A primitive type with metadata attached.",
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/definitions/primitiveType"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "customTypeReference": {
+ "title": "Custom Type",
+ "description": "Reference to a ComplexType",
+ "not": {
+ "$ref": "#/definitions/primitiveType"
+ },
+ "type": "string",
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*$"
+ },
+ "avroUnion": {
+ "title": "Union",
+ "description": "A Union of types",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/avroSchema"
+ },
+ "minItems": 1
+ },
+ "avroField": {
+ "title": "Field",
+ "description": "A field within a Record",
+ "type": "object",
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "type": {
+ "$ref": "#/definitions/types"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "default": true,
+ "order": {
+ "enum": [
+ "ascending",
+ "descending",
+ "ignore"
+ ]
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ }
+ },
+ "required": [
+ "name",
+ "type"
+ ]
+ },
+ "avroRecord": {
+ "title": "Record",
+ "description": "A Record",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "record"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "fields": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/avroField"
+ }
+ }
+ },
+ "required": [
+ "type",
+ "name",
+ "fields"
+ ]
+ },
+ "avroEnum": {
+ "title": "Enum",
+ "description": "An enumeration",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "enum"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "symbols": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ }
+ },
+ "required": [
+ "type",
+ "name",
+ "symbols"
+ ]
+ },
+ "avroArray": {
+ "title": "Array",
+ "description": "An array",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "array"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "items": {
+ "$ref": "#/definitions/types"
+ }
+ },
+ "required": [
+ "type",
+ "items"
+ ]
+ },
+ "avroMap": {
+ "title": "Map",
+ "description": "A map of values",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "map"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "values": {
+ "$ref": "#/definitions/types"
+ }
+ },
+ "required": [
+ "type",
+ "values"
+ ]
+ },
+ "avroFixed": {
+ "title": "Fixed",
+ "description": "A fixed sized array of bytes",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "fixed"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "size": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "type",
+ "name",
+ "size"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
+ },
+ "namespace": {
+ "type": "string",
+ "pattern": "^([A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*)*$"
+ }
+ },
+ "description": "Json-Schema definition for Avro AVSC files.",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/avroSchema"
+ }
+ ],
+ "title": "Avro Schema Definition"
+ },
+ "http://asyncapi.com/definitions/2.6.0/components.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/components.json",
+ "type": "object",
+ "description": "Holds a set of reusable objects for different aspects of the AsyncAPI specification. All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "schemas": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schemas.json"
+ },
+ "servers": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/servers.json"
+ },
+ "channels": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/channels.json"
+ },
+ "serverVariables": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/serverVariables.json"
+ },
+ "messages": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/messages.json"
+ },
+ "securitySchemes": {
+ "type": "object",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/SecurityScheme.json"
+ }
+ ]
+ }
+ }
+ },
+ "parameters": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/parameters.json"
+ },
+ "correlationIds": {
+ "type": "object",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/correlationId.json"
+ }
+ ]
+ }
+ }
+ },
+ "operationTraits": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/operationTrait.json"
+ }
+ },
+ "messageTraits": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/messageTrait.json"
+ }
+ },
+ "serverBindings": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ }
+ },
+ "channelBindings": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ }
+ },
+ "operationBindings": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ }
+ },
+ "messageBindings": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/bindingsObject.json"
+ }
+ }
+ },
+ "examples": [
+ {
+ "components": {
+ "schemas": {
+ "Category": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ },
+ "Tag": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "servers": {
+ "development": {
+ "url": "{stage}.gigantic-server.com:{port}",
+ "description": "Development server",
+ "protocol": "amqp",
+ "protocolVersion": "0.9.1",
+ "variables": {
+ "stage": {
+ "$ref": "#/components/serverVariables/stage"
+ },
+ "port": {
+ "$ref": "#/components/serverVariables/port"
+ }
+ }
+ }
+ },
+ "serverVariables": {
+ "stage": {
+ "default": "demo",
+ "description": "This value is assigned by the service provider, in this example `gigantic-server.com`"
+ },
+ "port": {
+ "enum": [
+ "8883",
+ "8884"
+ ],
+ "default": "8883"
+ }
+ },
+ "channels": {
+ "user/signedup": {
+ "subscribe": {
+ "message": {
+ "$ref": "#/components/messages/userSignUp"
+ }
+ }
+ }
+ },
+ "messages": {
+ "userSignUp": {
+ "summary": "Action to sign a user up.",
+ "description": "Multiline description of what this action does.\nHere you have another line.\n",
+ "tags": [
+ {
+ "name": "user"
+ },
+ {
+ "name": "signup"
+ }
+ ],
+ "headers": {
+ "type": "object",
+ "properties": {
+ "applicationInstanceId": {
+ "description": "Unique identifier for a given instance of the publishing application",
+ "type": "string"
+ }
+ }
+ },
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/userCreate"
+ },
+ "signup": {
+ "$ref": "#/components/schemas/signup"
+ }
+ }
+ }
+ }
+ },
+ "parameters": {
+ "userId": {
+ "description": "Id of the user.",
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
+ "correlationIds": {
+ "default": {
+ "description": "Default Correlation ID",
+ "location": "$message.header#/correlationId"
+ }
+ },
+ "messageTraits": {
+ "commonHeaders": {
+ "headers": {
+ "type": "object",
+ "properties": {
+ "my-app-header": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/schemas.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/schemas.json",
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/schema.json"
+ },
+ "description": "JSON objects describing schemas the API uses."
+ },
+ "http://asyncapi.com/definitions/2.6.0/messages.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/messages.json",
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/message.json"
+ },
+ "description": "JSON objects describing the messages being consumed and produced by the API."
+ },
+ "http://asyncapi.com/definitions/2.6.0/SecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/SecurityScheme.json",
+ "description": "Defines a security scheme that can be used by the operations.",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/userPassword.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/apiKey.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/X509.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/symmetricEncryption.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/asymmetricEncryption.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/HTTPSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/oauth2Flows.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/openIdConnect.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/SaslSecurityScheme.json"
+ }
+ ],
+ "examples": [
+ {
+ "type": "userPassword"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/userPassword.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/userPassword.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme. ",
+ "enum": [
+ "userPassword"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "userPassword"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/apiKey.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/apiKey.json",
+ "type": "object",
+ "required": [
+ "type",
+ "in"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "apiKey"
+ ]
+ },
+ "in": {
+ "type": "string",
+ "description": "The location of the API key. ",
+ "enum": [
+ "user",
+ "password"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "apiKey",
+ "in": "user"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/X509.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/X509.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "X509"
+ ],
+ "description": "The type of the security scheme."
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "X509"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/symmetricEncryption.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/symmetricEncryption.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "symmetricEncryption"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "symmetricEncryption"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/asymmetricEncryption.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/asymmetricEncryption.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "asymmetricEncryption"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/2.6.0/HTTPSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/HTTPSecurityScheme.json",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/NonBearerHTTPSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/BearerHTTPSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/APIKeyHTTPSecurityScheme.json"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/NonBearerHTTPSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/NonBearerHTTPSecurityScheme.json",
+ "not": {
+ "type": "object",
+ "properties": {
+ "scheme": {
+ "type": "string",
+ "description": "A short description for security scheme.",
+ "enum": [
+ "bearer"
+ ]
+ }
+ }
+ },
+ "type": "object",
+ "required": [
+ "scheme",
+ "type"
+ ],
+ "properties": {
+ "scheme": {
+ "type": "string",
+ "description": "The name of the HTTP Authorization scheme to be used in the Authorization header as defined in RFC7235."
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ },
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme. ",
+ "enum": [
+ "http"
+ ]
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/2.6.0/BearerHTTPSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/BearerHTTPSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type",
+ "scheme"
+ ],
+ "properties": {
+ "scheme": {
+ "type": "string",
+ "description": "The name of the HTTP Authorization scheme to be used in the Authorization header as defined in RFC7235.",
+ "enum": [
+ "bearer"
+ ]
+ },
+ "bearerFormat": {
+ "type": "string",
+ "description": "A hint to the client to identify how the bearer token is formatted."
+ },
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme. ",
+ "enum": [
+ "http"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/2.6.0/APIKeyHTTPSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/APIKeyHTTPSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "in"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme. ",
+ "enum": [
+ "httpApiKey"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "The name of the header, query or cookie parameter to be used."
+ },
+ "in": {
+ "type": "string",
+ "description": "The location of the API key. ",
+ "enum": [
+ "header",
+ "query",
+ "cookie"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "httpApiKey",
+ "name": "api_key",
+ "in": "header"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/oauth2Flows.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/oauth2Flows.json",
+ "type": "object",
+ "description": "Allows configuration of the supported OAuth Flows.",
+ "required": [
+ "type",
+ "flows"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "A short description for security scheme.",
+ "enum": [
+ "oauth2"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ },
+ "flows": {
+ "type": "object",
+ "properties": {
+ "implicit": {
+ "description": "Configuration for the OAuth Implicit flow.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/oauth2Flow.json"
+ },
+ {
+ "required": [
+ "authorizationUrl",
+ "scopes"
+ ]
+ },
+ {
+ "not": {
+ "required": [
+ "tokenUrl"
+ ]
+ }
+ }
+ ]
+ },
+ "password": {
+ "description": "Configuration for the OAuth Resource Owner Protected Credentials flow.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/oauth2Flow.json"
+ },
+ {
+ "required": [
+ "tokenUrl",
+ "scopes"
+ ]
+ },
+ {
+ "not": {
+ "required": [
+ "authorizationUrl"
+ ]
+ }
+ }
+ ]
+ },
+ "clientCredentials": {
+ "description": "Configuration for the OAuth Client Credentials flow.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/oauth2Flow.json"
+ },
+ {
+ "required": [
+ "tokenUrl",
+ "scopes"
+ ]
+ },
+ {
+ "not": {
+ "required": [
+ "authorizationUrl"
+ ]
+ }
+ }
+ ]
+ },
+ "authorizationCode": {
+ "description": "Configuration for the OAuth Authorization Code flow.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/oauth2Flow.json"
+ },
+ {
+ "required": [
+ "authorizationUrl",
+ "tokenUrl",
+ "scopes"
+ ]
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ }
+ },
+ "http://asyncapi.com/definitions/2.6.0/oauth2Flow.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/oauth2Flow.json",
+ "type": "object",
+ "description": "Configuration details for a supported OAuth Flow",
+ "properties": {
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "The authorization URL to be used for this flow. This MUST be in the form of an absolute URL."
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "The token URL to be used for this flow. This MUST be in the form of an absolute URL."
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "The URL to be used for obtaining refresh tokens. This MUST be in the form of an absolute URL."
+ },
+ "scopes": {
+ "description": "The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it.",
+ "$ref": "http://asyncapi.com/definitions/2.6.0/oauth2Scopes.json"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "oauth2",
+ "flows": {
+ "implicit": {
+ "authorizationUrl": "https://example.com/api/oauth/dialog",
+ "scopes": {
+ "write:pets": "modify pets in your account",
+ "read:pets": "read your pets"
+ }
+ },
+ "authorizationCode": {
+ "authorizationUrl": "https://example.com/api/oauth/dialog",
+ "tokenUrl": "https://example.com/api/oauth/token",
+ "scopes": {
+ "write:pets": "modify pets in your account",
+ "read:pets": "read your pets"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/oauth2Scopes.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/oauth2Scopes.json",
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "http://asyncapi.com/definitions/2.6.0/openIdConnect.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/openIdConnect.json",
+ "type": "object",
+ "required": [
+ "type",
+ "openIdConnectUrl"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "openIdConnect"
+ ]
+ },
+ "description": {
+ "type": "string"
+ },
+ "openIdConnectUrl": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/2.6.0/SaslSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/SaslSecurityScheme.json",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/SaslPlainSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/SaslScramSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/SaslGssapiSecurityScheme.json"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/SaslPlainSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/SaslPlainSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme. Valid values",
+ "enum": [
+ "plain"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "scramSha512"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/SaslScramSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/SaslScramSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "scramSha256",
+ "scramSha512"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "scramSha512"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/2.6.0/SaslGssapiSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/2.6.0/SaslGssapiSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "gssapi"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/2.6.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "scramSha512"
+ }
+ ]
+ }
+ },
+ "description": "!!Auto generated!! \n Do not manually edit. "
+}
\ No newline at end of file
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.3.0.schema.json b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.3.0.schema.json
new file mode 100644
index 0000000000..ed16148dc0
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.3.0.schema.json
@@ -0,0 +1,8746 @@
+{
+ "$id": "http://asyncapi.com/definitions/3.0.0/asyncapi.json",
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "title": "AsyncAPI 3.0.0 schema.",
+ "type": "object",
+ "required": [
+ "asyncapi",
+ "info"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "asyncapi": {
+ "type": "string",
+ "const": "3.0.0",
+ "description": "The AsyncAPI specification version of this document."
+ },
+ "id": {
+ "type": "string",
+ "description": "A unique id representing the application.",
+ "format": "uri"
+ },
+ "info": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/info.json"
+ },
+ "servers": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/servers.json"
+ },
+ "defaultContentType": {
+ "type": "string",
+ "description": "Default content type to use when encoding/decoding a message's payload."
+ },
+ "channels": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/channels.json"
+ },
+ "operations": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operations.json"
+ },
+ "components": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/components.json"
+ }
+ },
+ "definitions": {
+ "http://asyncapi.com/definitions/3.0.0/specificationExtension.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json",
+ "description": "Any property starting with x- is valid.",
+ "additionalProperties": true,
+ "additionalItems": true
+ },
+ "http://asyncapi.com/definitions/3.0.0/info.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/info.json",
+ "type": "object",
+ "description": "The object provides metadata about the API. The metadata can be used by the clients if needed.",
+ "required": [
+ "version",
+ "title"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A unique and precise title of the API."
+ },
+ "version": {
+ "type": "string",
+ "description": "A semantic version number of the API."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the API. Should be different from the title. CommonMark is allowed."
+ },
+ "termsOfService": {
+ "type": "string",
+ "description": "A URL to the Terms of Service for the API. MUST be in the format of a URL.",
+ "format": "uri"
+ },
+ "contact": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/contact.json"
+ },
+ "license": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/license.json"
+ },
+ "tags": {
+ "type": "array",
+ "description": "A list of tags for application API documentation control. Tags can be used for logical grouping of applications.",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/tag.json"
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "externalDocs": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ }
+ },
+ "examples": [
+ {
+ "title": "AsyncAPI Sample App",
+ "version": "1.0.1",
+ "description": "This is a sample app.",
+ "termsOfService": "https://asyncapi.org/terms/",
+ "contact": {
+ "name": "API Support",
+ "url": "https://www.asyncapi.org/support",
+ "email": "support@asyncapi.org"
+ },
+ "license": {
+ "name": "Apache 2.0",
+ "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
+ },
+ "externalDocs": {
+ "description": "Find more info here",
+ "url": "https://www.asyncapi.org"
+ },
+ "tags": [
+ {
+ "name": "e-commerce"
+ }
+ ]
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/contact.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/contact.json",
+ "type": "object",
+ "description": "Contact information for the exposed API.",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The identifying name of the contact person/organization."
+ },
+ "url": {
+ "type": "string",
+ "description": "The URL pointing to the contact information.",
+ "format": "uri"
+ },
+ "email": {
+ "type": "string",
+ "description": "The email address of the contact person/organization.",
+ "format": "email"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "examples": [
+ {
+ "name": "API Support",
+ "url": "https://www.example.com/support",
+ "email": "support@example.com"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/license.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/license.json",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the license type. It's encouraged to use an OSI compatible license."
+ },
+ "url": {
+ "type": "string",
+ "description": "The URL pointing to the license.",
+ "format": "uri"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "examples": [
+ {
+ "name": "Apache 2.0",
+ "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/Reference.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/Reference.json",
+ "type": "object",
+ "description": "A simple object to allow referencing other components in the specification, internally and externally.",
+ "required": [
+ "$ref"
+ ],
+ "properties": {
+ "$ref": {
+ "description": "The reference string.",
+ "$ref": "http://asyncapi.com/definitions/3.0.0/ReferenceObject.json"
+ }
+ },
+ "examples": [
+ {
+ "$ref": "#/components/schemas/Pet"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/ReferenceObject.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/ReferenceObject.json",
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "http://asyncapi.com/definitions/3.0.0/tag.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/tag.json",
+ "type": "object",
+ "description": "Allows adding metadata to a single tag.",
+ "additionalProperties": false,
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the tag."
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for the tag. CommonMark syntax can be used for rich text representation."
+ },
+ "externalDocs": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "examples": [
+ {
+ "name": "user",
+ "description": "User-related messages"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/externalDocs.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/externalDocs.json",
+ "type": "object",
+ "additionalProperties": false,
+ "description": "Allows referencing an external resource for extended documentation.",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "description": {
+ "type": "string",
+ "description": "A short description of the target documentation. CommonMark syntax can be used for rich text representation."
+ },
+ "url": {
+ "type": "string",
+ "description": "The URL for the target documentation. This MUST be in the form of an absolute URL.",
+ "format": "uri"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "examples": [
+ {
+ "description": "Find more info here",
+ "url": "https://example.com"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/servers.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/servers.json",
+ "description": "An object representing multiple servers.",
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/server.json"
+ }
+ ]
+ },
+ "examples": [
+ {
+ "development": {
+ "host": "localhost:5672",
+ "description": "Development AMQP broker.",
+ "protocol": "amqp",
+ "protocolVersion": "0-9-1",
+ "tags": [
+ {
+ "name": "env:development",
+ "description": "This environment is meant for developers to run their own tests."
+ }
+ ]
+ },
+ "staging": {
+ "host": "rabbitmq-staging.in.mycompany.com:5672",
+ "description": "RabbitMQ broker for the staging environment.",
+ "protocol": "amqp",
+ "protocolVersion": "0-9-1",
+ "tags": [
+ {
+ "name": "env:staging",
+ "description": "This environment is a replica of the production environment."
+ }
+ ]
+ },
+ "production": {
+ "host": "rabbitmq.in.mycompany.com:5672",
+ "description": "RabbitMQ broker for the production environment.",
+ "protocol": "amqp",
+ "protocolVersion": "0-9-1",
+ "tags": [
+ {
+ "name": "env:production",
+ "description": "This environment is the live environment available for final users."
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/server.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/server.json",
+ "type": "object",
+ "description": "An object representing a message broker, a server or any other kind of computer program capable of sending and/or receiving data.",
+ "required": [
+ "host",
+ "protocol"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "host": {
+ "type": "string",
+ "description": "The server host name. It MAY include the port. This field supports Server Variables. Variable substitutions will be made when a variable is named in {braces}."
+ },
+ "pathname": {
+ "type": "string",
+ "description": "The path to a resource in the host. This field supports Server Variables. Variable substitutions will be made when a variable is named in {braces}."
+ },
+ "title": {
+ "type": "string",
+ "description": "A human-friendly title for the server."
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the server."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the server. CommonMark is allowed."
+ },
+ "protocol": {
+ "type": "string",
+ "description": "The protocol this server supports for connection."
+ },
+ "protocolVersion": {
+ "type": "string",
+ "description": "An optional string describing the server. CommonMark syntax MAY be used for rich text representation."
+ },
+ "variables": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/serverVariables.json"
+ },
+ "security": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/securityRequirements.json"
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/tag.json"
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "externalDocs": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ },
+ "bindings": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/serverBindingsObject.json"
+ }
+ ]
+ }
+ },
+ "examples": [
+ {
+ "host": "kafka.in.mycompany.com:9092",
+ "description": "Production Kafka broker.",
+ "protocol": "kafka",
+ "protocolVersion": "3.2"
+ },
+ {
+ "host": "rabbitmq.in.mycompany.com:5672",
+ "pathname": "/production",
+ "protocol": "amqp",
+ "description": "Production RabbitMQ broker (uses the `production` vhost)."
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/serverVariables.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/serverVariables.json",
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/serverVariable.json"
+ }
+ ]
+ }
+ },
+ "http://asyncapi.com/definitions/3.0.0/serverVariable.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/serverVariable.json",
+ "type": "object",
+ "description": "An object representing a Server Variable for server URL template substitution.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "enum": {
+ "type": "array",
+ "description": "An enumeration of string values to be used if the substitution options are from a limited set.",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true
+ },
+ "default": {
+ "type": "string",
+ "description": "The default value to use for substitution, and to send, if an alternate value is not supplied."
+ },
+ "description": {
+ "type": "string",
+ "description": "An optional description for the server variable. CommonMark syntax MAY be used for rich text representation."
+ },
+ "examples": {
+ "type": "array",
+ "description": "An array of examples of the server variable.",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "examples": [
+ {
+ "host": "rabbitmq.in.mycompany.com:5672",
+ "pathname": "/{env}",
+ "protocol": "amqp",
+ "description": "RabbitMQ broker. Use the `env` variable to point to either `production` or `staging`.",
+ "variables": {
+ "env": {
+ "description": "Environment to connect to. It can be either `production` or `staging`.",
+ "enum": [
+ "production",
+ "staging"
+ ]
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/securityRequirements.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/securityRequirements.json",
+ "description": "An array representing security requirements.",
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/SecurityScheme.json"
+ }
+ ]
+ }
+ },
+ "http://asyncapi.com/definitions/3.0.0/SecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/SecurityScheme.json",
+ "description": "Defines a security scheme that can be used by the operations.",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/userPassword.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/apiKey.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/X509.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/symmetricEncryption.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/asymmetricEncryption.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/HTTPSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/oauth2Flows.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/openIdConnect.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/SaslSecurityScheme.json"
+ }
+ ],
+ "examples": [
+ {
+ "type": "userPassword"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/userPassword.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/userPassword.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "userPassword"
+ ]
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "userPassword"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/apiKey.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/apiKey.json",
+ "type": "object",
+ "required": [
+ "type",
+ "in"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme",
+ "enum": [
+ "apiKey"
+ ]
+ },
+ "in": {
+ "type": "string",
+ "description": " The location of the API key.",
+ "enum": [
+ "user",
+ "password"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme. CommonMark syntax MAY be used for rich text representation."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "apiKey",
+ "in": "user"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/X509.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/X509.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "X509"
+ ]
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "X509"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/symmetricEncryption.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/symmetricEncryption.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "symmetricEncryption"
+ ]
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "symmetricEncryption"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/asymmetricEncryption.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/asymmetricEncryption.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "asymmetricEncryption"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/3.0.0/HTTPSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/HTTPSecurityScheme.json",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/NonBearerHTTPSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/BearerHTTPSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/APIKeyHTTPSecurityScheme.json"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/NonBearerHTTPSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/NonBearerHTTPSecurityScheme.json",
+ "not": {
+ "type": "object",
+ "properties": {
+ "scheme": {
+ "type": "string",
+ "description": "A short description for security scheme.",
+ "enum": [
+ "bearer"
+ ]
+ }
+ }
+ },
+ "type": "object",
+ "required": [
+ "scheme",
+ "type"
+ ],
+ "properties": {
+ "scheme": {
+ "type": "string",
+ "description": "The name of the HTTP Authorization scheme to be used in the Authorization header as defined in RFC7235."
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ },
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "http"
+ ]
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/3.0.0/BearerHTTPSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/BearerHTTPSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type",
+ "scheme"
+ ],
+ "properties": {
+ "scheme": {
+ "type": "string",
+ "description": "The name of the HTTP Authorization scheme to be used in the Authorization header as defined in RFC7235.",
+ "enum": [
+ "bearer"
+ ]
+ },
+ "bearerFormat": {
+ "type": "string",
+ "description": "A hint to the client to identify how the bearer token is formatted. Bearer tokens are usually generated by an authorization server, so this information is primarily for documentation purposes."
+ },
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "http"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme. CommonMark syntax MAY be used for rich text representation."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/3.0.0/APIKeyHTTPSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/APIKeyHTTPSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "in"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "httpApiKey"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "The name of the header, query or cookie parameter to be used."
+ },
+ "in": {
+ "type": "string",
+ "description": "The location of the API key",
+ "enum": [
+ "header",
+ "query",
+ "cookie"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme. CommonMark syntax MAY be used for rich text representation."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "httpApiKey",
+ "name": "api_key",
+ "in": "header"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/oauth2Flows.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/oauth2Flows.json",
+ "type": "object",
+ "description": "Allows configuration of the supported OAuth Flows.",
+ "required": [
+ "type",
+ "flows"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "oauth2"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ },
+ "flows": {
+ "type": "object",
+ "properties": {
+ "implicit": {
+ "description": "Configuration for the OAuth Implicit flow.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/oauth2Flow.json"
+ },
+ {
+ "required": [
+ "authorizationUrl",
+ "availableScopes"
+ ]
+ },
+ {
+ "not": {
+ "required": [
+ "tokenUrl"
+ ]
+ }
+ }
+ ]
+ },
+ "password": {
+ "description": "Configuration for the OAuth Resource Owner Protected Credentials flow.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/oauth2Flow.json"
+ },
+ {
+ "required": [
+ "tokenUrl",
+ "availableScopes"
+ ]
+ },
+ {
+ "not": {
+ "required": [
+ "authorizationUrl"
+ ]
+ }
+ }
+ ]
+ },
+ "clientCredentials": {
+ "description": "Configuration for the OAuth Client Credentials flow.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/oauth2Flow.json"
+ },
+ {
+ "required": [
+ "tokenUrl",
+ "availableScopes"
+ ]
+ },
+ {
+ "not": {
+ "required": [
+ "authorizationUrl"
+ ]
+ }
+ }
+ ]
+ },
+ "authorizationCode": {
+ "description": "Configuration for the OAuth Authorization Code flow.",
+ "allOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/oauth2Flow.json"
+ },
+ {
+ "required": [
+ "authorizationUrl",
+ "tokenUrl",
+ "availableScopes"
+ ]
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "scopes": {
+ "type": "array",
+ "description": "List of the needed scope names.",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ }
+ },
+ "http://asyncapi.com/definitions/3.0.0/oauth2Flow.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/oauth2Flow.json",
+ "type": "object",
+ "description": "Configuration details for a supported OAuth Flow",
+ "properties": {
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "The authorization URL to be used for this flow. This MUST be in the form of an absolute URL."
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "The token URL to be used for this flow. This MUST be in the form of an absolute URL."
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "The URL to be used for obtaining refresh tokens. This MUST be in the form of an absolute URL."
+ },
+ "availableScopes": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/oauth2Scopes.json",
+ "description": "The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "authorizationUrl": "https://example.com/api/oauth/dialog",
+ "tokenUrl": "https://example.com/api/oauth/token",
+ "availableScopes": {
+ "write:pets": "modify pets in your account",
+ "read:pets": "read your pets"
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/oauth2Scopes.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/oauth2Scopes.json",
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "http://asyncapi.com/definitions/3.0.0/openIdConnect.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/openIdConnect.json",
+ "type": "object",
+ "required": [
+ "type",
+ "openIdConnectUrl"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "openIdConnect"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme. CommonMark syntax MAY be used for rich text representation."
+ },
+ "openIdConnectUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of an absolute URL."
+ },
+ "scopes": {
+ "type": "array",
+ "description": "List of the needed scope names. An empty array means no scopes are needed.",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/3.0.0/SaslSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/SaslSecurityScheme.json",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/SaslPlainSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/SaslScramSecurityScheme.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/SaslGssapiSecurityScheme.json"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/SaslPlainSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/SaslPlainSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme. Valid values",
+ "enum": [
+ "plain"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "scramSha512"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/SaslScramSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/SaslScramSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "scramSha256",
+ "scramSha512"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "scramSha512"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/SaslGssapiSecurityScheme.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/SaslGssapiSecurityScheme.json",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of the security scheme.",
+ "enum": [
+ "gssapi"
+ ]
+ },
+ "description": {
+ "type": "string",
+ "description": "A short description for security scheme."
+ }
+ },
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "type": "scramSha512"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/serverBindingsObject.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/serverBindingsObject.json",
+ "type": "object",
+ "description": "Map describing protocol-specific definitions for a server.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "http": {},
+ "ws": {},
+ "amqp": {},
+ "amqp1": {},
+ "mqtt": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/mqtt/0.2.0/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/mqtt/0.2.0/server.json"
+ }
+ }
+ ]
+ },
+ "kafka": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.4.0",
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.4.0/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.4.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.4.0/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.3.0/server.json"
+ }
+ }
+ ]
+ },
+ "anypointmq": {},
+ "nats": {},
+ "jms": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.0.1"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/jms/0.0.1/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.0.1"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/jms/0.0.1/server.json"
+ }
+ }
+ ]
+ },
+ "sns": {},
+ "sqs": {},
+ "stomp": {},
+ "redis": {},
+ "ibmmq": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/ibmmq/0.1.0/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/ibmmq/0.1.0/server.json"
+ }
+ }
+ ]
+ },
+ "solace": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.4.0",
+ "0.3.0",
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/solace/0.4.0/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.4.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/solace/0.4.0/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/solace/0.3.0/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/solace/0.2.0/server.json"
+ }
+ }
+ ]
+ },
+ "googlepubsub": {},
+ "pulsar": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/pulsar/0.1.0/server.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/pulsar/0.1.0/server.json"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "http://asyncapi.com/bindings/mqtt/0.2.0/server.json": {
+ "$id": "http://asyncapi.com/bindings/mqtt/0.2.0/server.json",
+ "title": "Server Schema",
+ "description": "This object contains information about the server representation in MQTT.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "clientId": {
+ "type": "string",
+ "description": "The client identifier."
+ },
+ "cleanSession": {
+ "type": "boolean",
+ "description": "Whether to create a persistent connection or not. When 'false', the connection will be persistent. This is called clean start in MQTTv5."
+ },
+ "lastWill": {
+ "type": "object",
+ "description": "Last Will and Testament configuration.",
+ "properties": {
+ "topic": {
+ "type": "string",
+ "description": "The topic where the Last Will and Testament message will be sent."
+ },
+ "qos": {
+ "type": "integer",
+ "enum": [
+ 0,
+ 1,
+ 2
+ ],
+ "description": "Defines how hard the broker/client will try to ensure that the Last Will and Testament message is received. Its value MUST be either 0, 1 or 2."
+ },
+ "message": {
+ "type": "string",
+ "description": "Last Will message."
+ },
+ "retain": {
+ "type": "boolean",
+ "description": "Whether the broker should retain the Last Will and Testament message or not."
+ }
+ }
+ },
+ "keepAlive": {
+ "type": "integer",
+ "description": "Interval in seconds of the longest period of time the broker and the client can endure without sending a message."
+ },
+ "sessionExpiryInterval": {
+ "oneOf": [
+ {
+ "type": "integer",
+ "minimum": 0
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ ],
+ "description": "Interval time in seconds or a Schema Object containing the definition of the interval. The broker maintains a session for a disconnected client until this interval expires."
+ },
+ "maximumPacketSize": {
+ "oneOf": [
+ {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 4294967295
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ ],
+ "description": "Number of bytes or a Schema Object representing the Maximum Packet Size the Client is willing to accept."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "clientId": "guest",
+ "cleanSession": true,
+ "lastWill": {
+ "topic": "/last-wills",
+ "qos": 2,
+ "message": "Guest gone offline.",
+ "retain": false
+ },
+ "keepAlive": 60,
+ "sessionExpiryInterval": 120,
+ "maximumPacketSize": 1024,
+ "bindingVersion": "0.2.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/schema.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is a superset of the JSON Schema Specification Draft 07. The empty schema (which allows any instance to validate) MAY be represented by the boolean value true and a schema which allows no instance to validate MAY be represented by the boolean value false.",
+ "allOf": [
+ {
+ "$ref": "http://json-schema.org/draft-07/schema#"
+ },
+ {
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "type": "boolean"
+ }
+ ],
+ "default": {}
+ },
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ }
+ }
+ ],
+ "default": {}
+ },
+ "allOf": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ }
+ },
+ "oneOf": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ }
+ },
+ "anyOf": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ }
+ },
+ "not": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ "properties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ "default": {}
+ },
+ "patternProperties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ "default": {}
+ },
+ "propertyNames": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ "contains": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ "discriminator": {
+ "type": "string",
+ "description": "Adds support for polymorphism. The discriminator is the schema property name that is used to differentiate between other schema that inherit this schema. The property name used MUST be defined at this schema and it MUST be in the required property list. When used, the value MUST be the name of this schema or any schema that inherits it. See Composition and Inheritance for more details."
+ },
+ "externalDocs": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ },
+ "deprecated": {
+ "type": "boolean",
+ "description": "Specifies that a schema is deprecated and SHOULD be transitioned out of usage. Default value is false.",
+ "default": false
+ }
+ }
+ }
+ ]
+ },
+ "http://json-schema.org/draft-07/schema": {
+ "$id": "http://json-schema.org/draft-07/schema",
+ "title": "Core schema meta-schema",
+ "definitions": {
+ "schemaArray": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#"
+ }
+ },
+ "nonNegativeInteger": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "nonNegativeIntegerDefault0": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/nonNegativeInteger"
+ },
+ {
+ "default": 0
+ }
+ ]
+ },
+ "simpleTypes": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "null",
+ "number",
+ "object",
+ "string"
+ ]
+ },
+ "stringArray": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true,
+ "default": []
+ }
+ },
+ "type": [
+ "object",
+ "boolean"
+ ],
+ "properties": {
+ "$id": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "$schema": {
+ "type": "string",
+ "format": "uri"
+ },
+ "$ref": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "$comment": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "default": true,
+ "readOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "writeOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "examples": {
+ "type": "array",
+ "items": true
+ },
+ "multipleOf": {
+ "type": "number",
+ "exclusiveMinimum": 0
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "exclusiveMaximum": {
+ "type": "number"
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "exclusiveMinimum": {
+ "type": "number"
+ },
+ "maxLength": {
+ "$ref": "#/definitions/nonNegativeInteger"
+ },
+ "minLength": {
+ "$ref": "#/definitions/nonNegativeIntegerDefault0"
+ },
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "additionalItems": {
+ "$ref": "#"
+ },
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/schemaArray"
+ }
+ ],
+ "default": true
+ },
+ "maxItems": {
+ "$ref": "#/definitions/nonNegativeInteger"
+ },
+ "minItems": {
+ "$ref": "#/definitions/nonNegativeIntegerDefault0"
+ },
+ "uniqueItems": {
+ "type": "boolean",
+ "default": false
+ },
+ "contains": {
+ "$ref": "#"
+ },
+ "maxProperties": {
+ "$ref": "#/definitions/nonNegativeInteger"
+ },
+ "minProperties": {
+ "$ref": "#/definitions/nonNegativeIntegerDefault0"
+ },
+ "required": {
+ "$ref": "#/definitions/stringArray"
+ },
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "definitions": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "default": {}
+ },
+ "properties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "default": {}
+ },
+ "patternProperties": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "propertyNames": {
+ "format": "regex"
+ },
+ "default": {}
+ },
+ "dependencies": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/stringArray"
+ }
+ ]
+ }
+ },
+ "propertyNames": {
+ "$ref": "#"
+ },
+ "const": true,
+ "enum": {
+ "type": "array",
+ "items": true,
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "type": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/simpleTypes"
+ },
+ {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/simpleTypes"
+ },
+ "minItems": 1,
+ "uniqueItems": true
+ }
+ ]
+ },
+ "format": {
+ "type": "string"
+ },
+ "contentMediaType": {
+ "type": "string"
+ },
+ "contentEncoding": {
+ "type": "string"
+ },
+ "if": {
+ "$ref": "#"
+ },
+ "then": {
+ "$ref": "#"
+ },
+ "else": {
+ "$ref": "#"
+ },
+ "allOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "anyOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "oneOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "not": {
+ "$ref": "#"
+ }
+ },
+ "default": true
+ },
+ "http://asyncapi.com/bindings/kafka/0.4.0/server.json": {
+ "$id": "http://asyncapi.com/bindings/kafka/0.4.0/server.json",
+ "title": "Server Schema",
+ "description": "This object contains server connection information to a Kafka broker. This object contains additional information not possible to represent within the core AsyncAPI specification.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "schemaRegistryUrl": {
+ "type": "string",
+ "description": "API URL for the Schema Registry used when producing Kafka messages (if a Schema Registry was used)."
+ },
+ "schemaRegistryVendor": {
+ "type": "string",
+ "description": "The vendor of the Schema Registry and Kafka serdes library that should be used."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.4.0"
+ ],
+ "description": "The version of this binding."
+ }
+ },
+ "examples": [
+ {
+ "schemaRegistryUrl": "https://my-schema-registry.com",
+ "schemaRegistryVendor": "confluent",
+ "bindingVersion": "0.4.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/kafka/0.3.0/server.json": {
+ "$id": "http://asyncapi.com/bindings/kafka/0.3.0/server.json",
+ "title": "Server Schema",
+ "description": "This object contains server connection information to a Kafka broker. This object contains additional information not possible to represent within the core AsyncAPI specification.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "schemaRegistryUrl": {
+ "type": "string",
+ "description": "API URL for the Schema Registry used when producing Kafka messages (if a Schema Registry was used)."
+ },
+ "schemaRegistryVendor": {
+ "type": "string",
+ "description": "The vendor of the Schema Registry and Kafka serdes library that should be used."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding."
+ }
+ },
+ "examples": [
+ {
+ "schemaRegistryUrl": "https://my-schema-registry.com",
+ "schemaRegistryVendor": "confluent",
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/jms/0.0.1/server.json": {
+ "$id": "http://asyncapi.com/bindings/jms/0.0.1/server.json",
+ "title": "Server Schema",
+ "description": "This object contains configuration for describing a JMS broker as an AsyncAPI server. This objects only contains configuration that can not be provided in the AsyncAPI standard server object.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "required": [
+ "jmsConnectionFactory"
+ ],
+ "properties": {
+ "jmsConnectionFactory": {
+ "type": "string",
+ "description": "The classname of the ConnectionFactory implementation for the JMS Provider."
+ },
+ "properties": {
+ "type": "array",
+ "items": {
+ "$ref": "http://asyncapi.com/bindings/jms/0.0.1/server.json#/definitions/property"
+ },
+ "description": "Additional properties to set on the JMS ConnectionFactory implementation for the JMS Provider."
+ },
+ "clientID": {
+ "type": "string",
+ "description": "A client identifier for applications that use this JMS connection factory. If the Client ID Policy is set to 'Restricted' (the default), then configuring a Client ID on the ConnectionFactory prevents more than one JMS client from using a connection from this factory."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.0.1"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "definitions": {
+ "property": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of a property"
+ },
+ "value": {
+ "type": [
+ "string",
+ "boolean",
+ "number",
+ "null"
+ ],
+ "description": "The name of a property"
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "jmsConnectionFactory": "org.apache.activemq.ActiveMQConnectionFactory",
+ "properties": [
+ {
+ "name": "disableTimeStampsByDefault",
+ "value": false
+ }
+ ],
+ "clientID": "my-application-1",
+ "bindingVersion": "0.0.1"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/ibmmq/0.1.0/server.json": {
+ "$id": "http://asyncapi.com/bindings/ibmmq/0.1.0/server.json",
+ "title": "IBM MQ server bindings object",
+ "description": "This object contains server connection information about the IBM MQ server, referred to as an IBM MQ queue manager. This object contains additional connectivity information not possible to represent within the core AsyncAPI specification.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "groupId": {
+ "type": "string",
+ "description": "Defines a logical group of IBM MQ server objects. This is necessary to specify multi-endpoint configurations used in high availability deployments. If omitted, the server object is not part of a group."
+ },
+ "ccdtQueueManagerName": {
+ "type": "string",
+ "default": "*",
+ "description": "The name of the IBM MQ queue manager to bind to in the CCDT file."
+ },
+ "cipherSpec": {
+ "type": "string",
+ "description": "The recommended cipher specification used to establish a TLS connection between the client and the IBM MQ queue manager. More information on SSL/TLS cipher specifications supported by IBM MQ can be found on this page in the IBM MQ Knowledge Center."
+ },
+ "multiEndpointServer": {
+ "type": "boolean",
+ "default": false,
+ "description": "If 'multiEndpointServer' is 'true' then multiple connections can be workload balanced and applications should not make assumptions as to where messages are processed. Where message ordering, or affinity to specific message resources is necessary, a single endpoint ('multiEndpointServer' = 'false') may be required."
+ },
+ "heartBeatInterval": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999999,
+ "default": 300,
+ "description": "The recommended value (in seconds) for the heartbeat sent to the queue manager during periods of inactivity. A value of zero means that no heart beats are sent. A value of 1 means that the client will use the value defined by the queue manager. More information on heart beat interval can be found on this page in the IBM MQ Knowledge Center."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0"
+ ],
+ "description": "The version of this binding."
+ }
+ },
+ "examples": [
+ {
+ "groupId": "PRODCLSTR1",
+ "cipherSpec": "ANY_TLS12_OR_HIGHER",
+ "bindingVersion": "0.1.0"
+ },
+ {
+ "groupId": "PRODCLSTR1",
+ "bindingVersion": "0.1.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/solace/0.4.0/server.json": {
+ "$id": "http://asyncapi.com/bindings/solace/0.4.0/server.json",
+ "title": "Solace server bindings object",
+ "description": "This object contains server connection information about the Solace broker. This object contains additional connectivity information not possible to represent within the core AsyncAPI specification.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "msgVpn": {
+ "type": "string",
+ "description": "The name of the Virtual Private Network to connect to on the Solace broker."
+ },
+ "clientName": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 160,
+ "description": "A unique client name to use to register to the appliance. If specified, it must be a valid Topic name, and a maximum of 160 bytes in length when encoded as UTF-8."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.4.0"
+ ],
+ "description": "The version of this binding."
+ }
+ },
+ "examples": [
+ {
+ "msgVpn": "ProdVPN",
+ "bindingVersion": "0.4.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/solace/0.3.0/server.json": {
+ "$id": "http://asyncapi.com/bindings/solace/0.3.0/server.json",
+ "title": "Solace server bindings object",
+ "description": "This object contains server connection information about the Solace broker. This object contains additional connectivity information not possible to represent within the core AsyncAPI specification.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "msgVpn": {
+ "type": "string",
+ "description": "The name of the Virtual Private Network to connect to on the Solace broker."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding."
+ }
+ },
+ "examples": [
+ {
+ "msgVpn": "ProdVPN",
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/solace/0.2.0/server.json": {
+ "$id": "http://asyncapi.com/bindings/solace/0.2.0/server.json",
+ "title": "Solace server bindings object",
+ "description": "This object contains server connection information about the Solace broker. This object contains additional connectivity information not possible to represent within the core AsyncAPI specification.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "msvVpn": {
+ "type": "string",
+ "description": "The name of the Virtual Private Network to connect to on the Solace broker."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding."
+ }
+ },
+ "examples": [
+ {
+ "msgVpn": "ProdVPN",
+ "bindingVersion": "0.2.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/pulsar/0.1.0/server.json": {
+ "$id": "http://asyncapi.com/bindings/pulsar/0.1.0/server.json",
+ "title": "Server Schema",
+ "description": "This object contains server information of Pulsar broker, which covers cluster and tenant admin configuration. This object contains additional information not possible to represent within the core AsyncAPI specification.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "tenant": {
+ "type": "string",
+ "description": "The pulsar tenant. If omitted, 'public' MUST be assumed."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "tenant": "contoso",
+ "bindingVersion": "0.1.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/channels.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/channels.json",
+ "type": "object",
+ "description": "An object containing all the Channel Object definitions the Application MUST use during runtime.",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/channel.json"
+ }
+ ]
+ },
+ "examples": [
+ {
+ "userSignedUp": {
+ "address": "user.signedup",
+ "messages": {
+ "userSignedUp": {
+ "$ref": "#/components/messages/userSignedUp"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/channel.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/channel.json",
+ "type": "object",
+ "description": "Describes a shared communication channel.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "address": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "An optional string representation of this channel's address. The address is typically the \"topic name\", \"routing key\", \"event type\", or \"path\". When `null` or absent, it MUST be interpreted as unknown. This is useful when the address is generated dynamically at runtime or can't be known upfront. It MAY contain Channel Address Expressions."
+ },
+ "messages": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/channelMessages.json"
+ },
+ "parameters": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/parameters.json"
+ },
+ "title": {
+ "type": "string",
+ "description": "A human-friendly title for the channel."
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the channel."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the channel. CommonMark is allowed."
+ },
+ "servers": {
+ "type": "array",
+ "description": "The references of the servers on which this channel is available. If absent or empty then this channel must be available on all servers.",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ "uniqueItems": true
+ },
+ "tags": {
+ "type": "array",
+ "description": "A list of tags for logical grouping of channels.",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/tag.json"
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "externalDocs": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ },
+ "bindings": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/channelBindingsObject.json"
+ }
+ ]
+ }
+ },
+ "examples": [
+ {
+ "address": "users.{userId}",
+ "title": "Users channel",
+ "description": "This channel is used to exchange messages about user events.",
+ "messages": {
+ "userSignedUp": {
+ "$ref": "#/components/messages/userSignedUp"
+ },
+ "userCompletedOrder": {
+ "$ref": "#/components/messages/userCompletedOrder"
+ }
+ },
+ "parameters": {
+ "userId": {
+ "$ref": "#/components/parameters/userId"
+ }
+ },
+ "servers": [
+ {
+ "$ref": "#/servers/rabbitmqInProd"
+ },
+ {
+ "$ref": "#/servers/rabbitmqInStaging"
+ }
+ ],
+ "bindings": {
+ "amqp": {
+ "is": "queue",
+ "queue": {
+ "exclusive": true
+ }
+ }
+ },
+ "tags": [
+ {
+ "name": "user",
+ "description": "User-related messages"
+ }
+ ],
+ "externalDocs": {
+ "description": "Find more info here",
+ "url": "https://example.com"
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/channelMessages.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/channelMessages.json",
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/messageObject.json"
+ }
+ ]
+ },
+ "description": "A map of the messages that will be sent to this channel by any application at any time. **Every message sent to this channel MUST be valid against one, and only one, of the message objects defined in this map.**"
+ },
+ "http://asyncapi.com/definitions/3.0.0/messageObject.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/messageObject.json",
+ "type": "object",
+ "description": "Describes a message received on a given channel and operation.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "contentType": {
+ "type": "string",
+ "description": "The content type to use when encoding/decoding a message's payload. The value MUST be a specific media type (e.g. application/json). When omitted, the value MUST be the one specified on the defaultContentType field."
+ },
+ "headers": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/anySchema.json"
+ },
+ "payload": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/anySchema.json"
+ },
+ "correlationId": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/correlationId.json"
+ }
+ ]
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/tag.json"
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the message."
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the message."
+ },
+ "title": {
+ "type": "string",
+ "description": "A human-friendly title for the message."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the message. CommonMark is allowed."
+ },
+ "externalDocs": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "examples": {
+ "type": "array",
+ "description": "List of examples.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [
+ {
+ "required": [
+ "payload"
+ ]
+ },
+ {
+ "required": [
+ "headers"
+ ]
+ }
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Machine readable name of the message example."
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the message example."
+ },
+ "headers": {
+ "type": "object",
+ "description": "Example of the application headers. It can be of any type."
+ },
+ "payload": {
+ "description": "Example of the message payload. It can be of any type."
+ }
+ }
+ }
+ },
+ "bindings": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/messageBindingsObject.json"
+ }
+ ]
+ },
+ "traits": {
+ "type": "array",
+ "description": "A list of traits to apply to the message object. Traits MUST be merged using traits merge mechanism. The resulting object MUST be a valid Message Object.",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/messageTrait.json"
+ },
+ {
+ "type": "array",
+ "items": [
+ {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/messageTrait.json"
+ }
+ ]
+ },
+ {
+ "type": "object",
+ "additionalItems": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "examples": [
+ {
+ "messageId": "userSignup",
+ "name": "UserSignup",
+ "title": "User signup",
+ "summary": "Action to sign a user up.",
+ "description": "A longer description",
+ "contentType": "application/json",
+ "tags": [
+ {
+ "name": "user"
+ },
+ {
+ "name": "signup"
+ },
+ {
+ "name": "register"
+ }
+ ],
+ "headers": {
+ "type": "object",
+ "properties": {
+ "correlationId": {
+ "description": "Correlation ID set by application",
+ "type": "string"
+ },
+ "applicationInstanceId": {
+ "description": "Unique identifier for a given instance of the publishing application",
+ "type": "string"
+ }
+ }
+ },
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/userCreate"
+ },
+ "signup": {
+ "$ref": "#/components/schemas/signup"
+ }
+ }
+ },
+ "correlationId": {
+ "description": "Default Correlation ID",
+ "location": "$message.header#/correlationId"
+ },
+ "traits": [
+ {
+ "$ref": "#/components/messageTraits/commonHeaders"
+ }
+ ],
+ "examples": [
+ {
+ "name": "SimpleSignup",
+ "summary": "A simple UserSignup example message",
+ "headers": {
+ "correlationId": "my-correlation-id",
+ "applicationInstanceId": "myInstanceId"
+ },
+ "payload": {
+ "user": {
+ "someUserKey": "someUserValue"
+ },
+ "signup": {
+ "someSignupKey": "someSignupValue"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/anySchema.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/anySchema.json",
+ "if": {
+ "required": [
+ "schema"
+ ]
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/multiFormatSchema.json"
+ },
+ "else": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ "description": "An object representing either a schema or a multiFormatSchema based on the existence of the 'schema' property. If the property 'schema' is present, use the multi-format schema. Use the default AsyncAPI Schema otherwise."
+ },
+ "http://asyncapi.com/definitions/3.0.0/multiFormatSchema.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/multiFormatSchema.json",
+ "description": "The Multi Format Schema Object represents a schema definition. It differs from the Schema Object in that it supports multiple schema formats or languages (e.g., JSON Schema, Avro, etc.).",
+ "if": {
+ "not": {
+ "type": "object"
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ "else": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "schemaFormat": {
+ "description": "A string containing the name of the schema format that is used to define the information. If schemaFormat is missing, it MUST default to application/vnd.aai.asyncapi+json;version={{asyncapi}} where {{asyncapi}} matches the AsyncAPI Version String. In such a case, this would make the Multi Format Schema Object equivalent to the Schema Object. When using Reference Object within the schema, the schemaFormat of the resource being referenced MUST match the schemaFormat of the schema that contains the initial reference. For example, if you reference Avro schema, then schemaFormat of referencing resource and the resource being reference MUST match.",
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "description": "All the schema formats tooling MUST support",
+ "enum": [
+ "application/schema+json;version=draft-07",
+ "application/schema+yaml;version=draft-07",
+ "application/vnd.aai.asyncapi;version=3.0.0",
+ "application/vnd.aai.asyncapi+json;version=3.0.0",
+ "application/vnd.aai.asyncapi+yaml;version=3.0.0"
+ ]
+ },
+ {
+ "description": "All the schema formats tools are RECOMMENDED to support",
+ "enum": [
+ "application/vnd.oai.openapi;version=3.0.0",
+ "application/vnd.oai.openapi+json;version=3.0.0",
+ "application/vnd.oai.openapi+yaml;version=3.0.0",
+ "application/vnd.apache.avro;version=1.9.0",
+ "application/vnd.apache.avro+json;version=1.9.0",
+ "application/vnd.apache.avro+yaml;version=1.9.0",
+ "application/raml+yaml;version=1.0"
+ ]
+ }
+ ]
+ },
+ "schema": {
+ "description": "Definition of the message payload. It can be of any type but defaults to Schema Object. It MUST match the schema format defined in schemaFormat, including the encoding type. E.g., Avro should be inlined as either a YAML or JSON object instead of as a string to be parsed as YAML or JSON. Non-JSON-based schemas (e.g., Protobuf or XSD) MUST be inlined as a string."
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "not": {
+ "description": "If no schemaFormat has been defined, default to schema or reference",
+ "required": [
+ "schemaFormat"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "description": "If schemaFormat has been defined check if it's one of the AsyncAPI Schema Object formats",
+ "required": [
+ "schemaFormat"
+ ],
+ "properties": {
+ "schemaFormat": {
+ "enum": [
+ "application/vnd.aai.asyncapi;version=2.0.0",
+ "application/vnd.aai.asyncapi+json;version=2.0.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.0.0",
+ "application/vnd.aai.asyncapi;version=2.1.0",
+ "application/vnd.aai.asyncapi+json;version=2.1.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.1.0",
+ "application/vnd.aai.asyncapi;version=2.2.0",
+ "application/vnd.aai.asyncapi+json;version=2.2.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.2.0",
+ "application/vnd.aai.asyncapi;version=2.3.0",
+ "application/vnd.aai.asyncapi+json;version=2.3.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.3.0",
+ "application/vnd.aai.asyncapi;version=2.4.0",
+ "application/vnd.aai.asyncapi+json;version=2.4.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.4.0",
+ "application/vnd.aai.asyncapi;version=2.5.0",
+ "application/vnd.aai.asyncapi+json;version=2.5.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.5.0",
+ "application/vnd.aai.asyncapi;version=2.6.0",
+ "application/vnd.aai.asyncapi+json;version=2.6.0",
+ "application/vnd.aai.asyncapi+yaml;version=2.6.0",
+ "application/vnd.aai.asyncapi;version=3.0.0",
+ "application/vnd.aai.asyncapi+json;version=3.0.0",
+ "application/vnd.aai.asyncapi+yaml;version=3.0.0"
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "schemaFormat"
+ ],
+ "properties": {
+ "schemaFormat": {
+ "enum": [
+ "application/schema+json;version=draft-07",
+ "application/schema+yaml;version=draft-07"
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://json-schema.org/draft-07/schema"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "schemaFormat"
+ ],
+ "properties": {
+ "schemaFormat": {
+ "enum": [
+ "application/vnd.oai.openapi;version=3.0.0",
+ "application/vnd.oai.openapi+json;version=3.0.0",
+ "application/vnd.oai.openapi+yaml;version=3.0.0"
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/openapiSchema_3_0.json"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "schemaFormat"
+ ],
+ "properties": {
+ "schemaFormat": {
+ "enum": [
+ "application/vnd.apache.avro;version=1.9.0",
+ "application/vnd.apache.avro+json;version=1.9.0",
+ "application/vnd.apache.avro+yaml;version=1.9.0"
+ ]
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/avroSchema_v1.json"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ "http://asyncapi.com/definitions/3.0.0/openapiSchema_3_0.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/openapiSchema_3_0.json",
+ "type": "object",
+ "definitions": {
+ "ExternalDocumentation": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri-reference"
+ }
+ },
+ "patternProperties": {
+ "^x-": {}
+ },
+ "additionalProperties": false
+ },
+ "Discriminator": {
+ "type": "object",
+ "required": [
+ "propertyName"
+ ],
+ "properties": {
+ "propertyName": {
+ "type": "string"
+ },
+ "mapping": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "Reference": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ],
+ "patternProperties": {
+ "^\\$ref$": {
+ "type": "string",
+ "format": "uri-reference"
+ }
+ }
+ },
+ "XML": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "namespace": {
+ "type": "string",
+ "format": "uri"
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "attribute": {
+ "type": "boolean",
+ "default": false
+ },
+ "wrapped": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "patternProperties": {
+ "^x-": {}
+ },
+ "additionalProperties": false
+ }
+ },
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "multipleOf": {
+ "type": "number",
+ "exclusiveMinimum": 0
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "exclusiveMaximum": {
+ "type": "boolean",
+ "default": false
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "exclusiveMinimum": {
+ "type": "boolean",
+ "default": false
+ },
+ "maxLength": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minLength": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "maxItems": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minItems": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "uniqueItems": {
+ "type": "boolean",
+ "default": false
+ },
+ "maxProperties": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minProperties": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "required": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "enum": {
+ "type": "array",
+ "items": true,
+ "minItems": 1,
+ "uniqueItems": false
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string"
+ ]
+ },
+ "not": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "allOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "oneOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "anyOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "properties": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "type": "boolean"
+ }
+ ],
+ "default": true
+ },
+ "description": {
+ "type": "string"
+ },
+ "format": {
+ "type": "string"
+ },
+ "default": true,
+ "nullable": {
+ "type": "boolean",
+ "default": false
+ },
+ "discriminator": {
+ "$ref": "#/definitions/Discriminator"
+ },
+ "readOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "writeOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "example": true,
+ "externalDocs": {
+ "$ref": "#/definitions/ExternalDocumentation"
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "xml": {
+ "$ref": "#/definitions/XML"
+ }
+ },
+ "patternProperties": {
+ "^x-": true
+ },
+ "additionalProperties": false
+ },
+ "http://asyncapi.com/definitions/3.0.0/avroSchema_v1.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/avroSchema_v1.json",
+ "definitions": {
+ "avroSchema": {
+ "title": "Avro Schema",
+ "description": "Root Schema",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/types"
+ }
+ ]
+ },
+ "types": {
+ "title": "Avro Types",
+ "description": "Allowed Avro types",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/primitiveType"
+ },
+ {
+ "$ref": "#/definitions/primitiveTypeWithMetadata"
+ },
+ {
+ "$ref": "#/definitions/customTypeReference"
+ },
+ {
+ "$ref": "#/definitions/avroRecord"
+ },
+ {
+ "$ref": "#/definitions/avroEnum"
+ },
+ {
+ "$ref": "#/definitions/avroArray"
+ },
+ {
+ "$ref": "#/definitions/avroMap"
+ },
+ {
+ "$ref": "#/definitions/avroFixed"
+ },
+ {
+ "$ref": "#/definitions/avroUnion"
+ }
+ ]
+ },
+ "primitiveType": {
+ "title": "Primitive Type",
+ "description": "Basic type primitives.",
+ "type": "string",
+ "enum": [
+ "null",
+ "boolean",
+ "int",
+ "long",
+ "float",
+ "double",
+ "bytes",
+ "string"
+ ]
+ },
+ "primitiveTypeWithMetadata": {
+ "title": "Primitive Type With Metadata",
+ "description": "A primitive type with metadata attached.",
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/definitions/primitiveType"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "customTypeReference": {
+ "title": "Custom Type",
+ "description": "Reference to a ComplexType",
+ "not": {
+ "$ref": "#/definitions/primitiveType"
+ },
+ "type": "string",
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*$"
+ },
+ "avroUnion": {
+ "title": "Union",
+ "description": "A Union of types",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/avroSchema"
+ },
+ "minItems": 1
+ },
+ "avroField": {
+ "title": "Field",
+ "description": "A field within a Record",
+ "type": "object",
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "type": {
+ "$ref": "#/definitions/types"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "default": true,
+ "order": {
+ "enum": [
+ "ascending",
+ "descending",
+ "ignore"
+ ]
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ }
+ },
+ "required": [
+ "name",
+ "type"
+ ]
+ },
+ "avroRecord": {
+ "title": "Record",
+ "description": "A Record",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "record"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "fields": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/avroField"
+ }
+ }
+ },
+ "required": [
+ "type",
+ "name",
+ "fields"
+ ]
+ },
+ "avroEnum": {
+ "title": "Enum",
+ "description": "An enumeration",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "enum"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "symbols": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ }
+ },
+ "required": [
+ "type",
+ "name",
+ "symbols"
+ ]
+ },
+ "avroArray": {
+ "title": "Array",
+ "description": "An array",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "array"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "items": {
+ "$ref": "#/definitions/types"
+ }
+ },
+ "required": [
+ "type",
+ "items"
+ ]
+ },
+ "avroMap": {
+ "title": "Map",
+ "description": "A map of values",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "map"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "values": {
+ "$ref": "#/definitions/types"
+ }
+ },
+ "required": [
+ "type",
+ "values"
+ ]
+ },
+ "avroFixed": {
+ "title": "Fixed",
+ "description": "A fixed sized array of bytes",
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "fixed"
+ },
+ "name": {
+ "$ref": "#/definitions/name"
+ },
+ "namespace": {
+ "$ref": "#/definitions/namespace"
+ },
+ "doc": {
+ "type": "string"
+ },
+ "aliases": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/name"
+ }
+ },
+ "size": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "type",
+ "name",
+ "size"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
+ },
+ "namespace": {
+ "type": "string",
+ "pattern": "^([A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)*)*$"
+ }
+ },
+ "description": "Json-Schema definition for Avro AVSC files.",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/avroSchema"
+ }
+ ],
+ "title": "Avro Schema Definition"
+ },
+ "http://asyncapi.com/definitions/3.0.0/correlationId.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/correlationId.json",
+ "type": "object",
+ "description": "An object that specifies an identifier at design time that can used for message tracing and correlation.",
+ "required": [
+ "location"
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "description": {
+ "type": "string",
+ "description": "A optional description of the correlation ID. GitHub Flavored Markdown is allowed."
+ },
+ "location": {
+ "type": "string",
+ "description": "A runtime expression that specifies the location of the correlation ID",
+ "pattern": "^\\$message\\.(header|payload)#(\\/(([^\\/~])|(~[01]))*)*"
+ }
+ },
+ "examples": [
+ {
+ "description": "Default Correlation ID",
+ "location": "$message.header#/correlationId"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/messageBindingsObject.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/messageBindingsObject.json",
+ "type": "object",
+ "description": "Map describing protocol-specific definitions for a message.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "http": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0",
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/http/0.2.0/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/http/0.2.0/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/http/0.3.0/message.json"
+ }
+ }
+ ]
+ },
+ "ws": {},
+ "amqp": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/amqp/0.3.0/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/amqp/0.3.0/message.json"
+ }
+ }
+ ]
+ },
+ "amqp1": {},
+ "mqtt": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/mqtt/0.2.0/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/mqtt/0.2.0/message.json"
+ }
+ }
+ ]
+ },
+ "kafka": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.4.0",
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.4.0/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.4.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.4.0/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.3.0/message.json"
+ }
+ }
+ ]
+ },
+ "anypointmq": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.0.1"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/anypointmq/0.0.1/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.0.1"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/anypointmq/0.0.1/message.json"
+ }
+ }
+ ]
+ },
+ "nats": {},
+ "jms": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.0.1"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/jms/0.0.1/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.0.1"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/jms/0.0.1/message.json"
+ }
+ }
+ ]
+ },
+ "sns": {},
+ "sqs": {},
+ "stomp": {},
+ "redis": {},
+ "ibmmq": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/ibmmq/0.1.0/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/ibmmq/0.1.0/message.json"
+ }
+ }
+ ]
+ },
+ "solace": {},
+ "googlepubsub": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/googlepubsub/0.2.0/message.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/googlepubsub/0.2.0/message.json"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "http://asyncapi.com/bindings/http/0.2.0/message.json": {
+ "$id": "http://asyncapi.com/bindings/http/0.2.0/message.json",
+ "title": "HTTP message bindings object",
+ "description": "This object contains information about the message representation in HTTP.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "headers": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "\tA Schema object containing the definitions for HTTP-specific headers. This schema MUST be of type 'object' and have a 'properties' key."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding. If omitted, \"latest\" MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "headers": {
+ "type": "object",
+ "properties": {
+ "Content-Type": {
+ "type": "string",
+ "enum": [
+ "application/json"
+ ]
+ }
+ }
+ },
+ "bindingVersion": "0.2.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/http/0.3.0/message.json": {
+ "$id": "http://asyncapi.com/bindings/http/0.3.0/message.json",
+ "title": "HTTP message bindings object",
+ "description": "This object contains information about the message representation in HTTP.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "headers": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "\tA Schema object containing the definitions for HTTP-specific headers. This schema MUST be of type 'object' and have a 'properties' key."
+ },
+ "statusCode": {
+ "type": "number",
+ "description": "The HTTP response status code according to [RFC 9110](https://httpwg.org/specs/rfc9110.html#overview.of.status.codes). `statusCode` is only relevant for messages referenced by the [Operation Reply Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0#operationReplyObject), as it defines the status code for the response. In all other cases, this value can be safely ignored."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, \"latest\" MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "headers": {
+ "type": "object",
+ "properties": {
+ "Content-Type": {
+ "type": "string",
+ "enum": [
+ "application/json"
+ ]
+ }
+ }
+ },
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/amqp/0.3.0/message.json": {
+ "$id": "http://asyncapi.com/bindings/amqp/0.3.0/message.json",
+ "title": "AMQP message bindings object",
+ "description": "This object contains information about the message representation in AMQP.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "contentEncoding": {
+ "type": "string",
+ "description": "A MIME encoding for the message content."
+ },
+ "messageType": {
+ "type": "string",
+ "description": "Application-specific message type."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, \"latest\" MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "contentEncoding": "gzip",
+ "messageType": "user.signup",
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/mqtt/0.2.0/message.json": {
+ "$id": "http://asyncapi.com/bindings/mqtt/0.2.0/message.json",
+ "title": "MQTT message bindings object",
+ "description": "This object contains information about the message representation in MQTT.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "payloadFormatIndicator": {
+ "type": "integer",
+ "enum": [
+ 0,
+ 1
+ ],
+ "description": "1 indicates that the payload is UTF-8 encoded character data. 0 indicates that the payload format is unspecified.",
+ "default": 0
+ },
+ "correlationData": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ ],
+ "description": "Correlation Data is used by the sender of the request message to identify which request the response message is for when it is received."
+ },
+ "contentType": {
+ "type": "string",
+ "description": "String describing the content type of the message payload. This should not conflict with the contentType field of the associated AsyncAPI Message object."
+ },
+ "responseTopic": {
+ "oneOf": [
+ {
+ "type": "string",
+ "format": "uri-template",
+ "minLength": 1
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ ],
+ "description": "The topic (channel URI) to be used for a response message."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "bindingVersion": "0.2.0"
+ },
+ {
+ "contentType": "application/json",
+ "correlationData": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "responseTopic": "application/responses",
+ "bindingVersion": "0.2.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/kafka/0.4.0/message.json": {
+ "$id": "http://asyncapi.com/bindings/kafka/0.4.0/message.json",
+ "title": "Message Schema",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "key": {
+ "anyOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/avroSchema_v1.json"
+ }
+ ],
+ "description": "The message key."
+ },
+ "schemaIdLocation": {
+ "type": "string",
+ "description": "If a Schema Registry is used when performing this operation, tells where the id of schema is stored.",
+ "enum": [
+ "header",
+ "payload"
+ ]
+ },
+ "schemaIdPayloadEncoding": {
+ "type": "string",
+ "description": "Number of bytes or vendor specific values when schema id is encoded in payload."
+ },
+ "schemaLookupStrategy": {
+ "type": "string",
+ "description": "Freeform string for any naming strategy class to use. Clients should default to the vendor default if not supplied."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.4.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "key": {
+ "type": "string",
+ "enum": [
+ "myKey"
+ ]
+ },
+ "schemaIdLocation": "payload",
+ "schemaIdPayloadEncoding": "apicurio-new",
+ "schemaLookupStrategy": "TopicIdStrategy",
+ "bindingVersion": "0.4.0"
+ },
+ {
+ "key": {
+ "$ref": "path/to/user-create.avsc#/UserCreate"
+ },
+ "schemaIdLocation": "payload",
+ "schemaIdPayloadEncoding": "4",
+ "bindingVersion": "0.4.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/kafka/0.3.0/message.json": {
+ "$id": "http://asyncapi.com/bindings/kafka/0.3.0/message.json",
+ "title": "Message Schema",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "key": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "The message key."
+ },
+ "schemaIdLocation": {
+ "type": "string",
+ "description": "If a Schema Registry is used when performing this operation, tells where the id of schema is stored.",
+ "enum": [
+ "header",
+ "payload"
+ ]
+ },
+ "schemaIdPayloadEncoding": {
+ "type": "string",
+ "description": "Number of bytes or vendor specific values when schema id is encoded in payload."
+ },
+ "schemaLookupStrategy": {
+ "type": "string",
+ "description": "Freeform string for any naming strategy class to use. Clients should default to the vendor default if not supplied."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "key": {
+ "type": "string",
+ "enum": [
+ "myKey"
+ ]
+ },
+ "schemaIdLocation": "payload",
+ "schemaIdPayloadEncoding": "apicurio-new",
+ "schemaLookupStrategy": "TopicIdStrategy",
+ "bindingVersion": "0.3.0"
+ },
+ {
+ "key": {
+ "$ref": "path/to/user-create.avsc#/UserCreate"
+ },
+ "schemaIdLocation": "payload",
+ "schemaIdPayloadEncoding": "4",
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/anypointmq/0.0.1/message.json": {
+ "$id": "http://asyncapi.com/bindings/anypointmq/0.0.1/message.json",
+ "title": "Anypoint MQ message bindings object",
+ "description": "This object contains configuration for describing an Anypoint MQ message as an AsyncAPI message. This objects only contains configuration that can not be provided in the AsyncAPI standard message object.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "headers": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ ],
+ "description": "A Schema object containing the definitions for Anypoint MQ-specific headers (protocol headers). This schema MUST be of type 'object' and have a 'properties' key. Examples of Anypoint MQ protocol headers are 'messageId' and 'messageGroupId'."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.0.1"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "headers": {
+ "type": "object",
+ "properties": {
+ "messageId": {
+ "type": "string"
+ }
+ }
+ },
+ "bindingVersion": "0.0.1"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/jms/0.0.1/message.json": {
+ "$id": "http://asyncapi.com/bindings/jms/0.0.1/message.json",
+ "title": "Message Schema",
+ "description": "This object contains configuration for describing a JMS message as an AsyncAPI message. This objects only contains configuration that can not be provided in the AsyncAPI standard message object.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "headers": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "A Schema object containing the definitions for JMS headers (protocol headers). This schema MUST be of type 'object' and have a 'properties' key. Examples of JMS protocol headers are 'JMSMessageID', 'JMSTimestamp', and 'JMSCorrelationID'."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.0.1"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "headers": {
+ "type": "object",
+ "required": [
+ "JMSMessageID"
+ ],
+ "properties": {
+ "JMSMessageID": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "A unique message identifier. This may be set by your JMS Provider on your behalf."
+ },
+ "JMSTimestamp": {
+ "type": "integer",
+ "description": "The time the message was sent. This may be set by your JMS Provider on your behalf. The time the message was sent. The value of the timestamp is the amount of time, measured in milliseconds, that has elapsed since midnight, January 1, 1970, UTC."
+ },
+ "JMSDeliveryMode": {
+ "type": "string",
+ "enum": [
+ "PERSISTENT",
+ "NON_PERSISTENT"
+ ],
+ "default": "PERSISTENT",
+ "description": "Denotes the delivery mode for the message. This may be set by your JMS Provider on your behalf."
+ },
+ "JMSPriority": {
+ "type": "integer",
+ "default": 4,
+ "description": "The priority of the message. This may be set by your JMS Provider on your behalf."
+ },
+ "JMSExpires": {
+ "type": "integer",
+ "description": "The time at which the message expires. This may be set by your JMS Provider on your behalf. A value of zero means that the message does not expire. Any non-zero value is the amount of time, measured in milliseconds, that has elapsed since midnight, January 1, 1970, UTC, at which the message will expire."
+ },
+ "JMSType": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The type of message. Some JMS providers use a message repository that contains the definitions of messages sent by applications. The 'JMSType' header field may reference a message's definition in the provider's repository. The JMS API does not define a standard message definition repository, nor does it define a naming policy for the definitions it contains. Some messaging systems require that a message type definition for each application message be created and that each message specify its type. In order to work with such JMS providers, JMS clients should assign a value to 'JMSType', whether the application makes use of it or not. This ensures that the field is properly set for those providers that require it."
+ },
+ "JMSCorrelationID": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "The correlation identifier of the message. A client can use the 'JMSCorrelationID' header field to link one message with another. A typical use is to link a response message with its request message. Since each message sent by a JMS provider is assigned a message ID value, it is convenient to link messages via message ID, such message ID values must start with the 'ID:' prefix. Conversely, application-specified values must not start with the 'ID:' prefix; this is reserved for provider-generated message ID values."
+ },
+ "JMSReplyTo": {
+ "type": "string",
+ "description": "The queue or topic that the message sender expects replies to."
+ }
+ }
+ },
+ "bindingVersion": "0.0.1"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/ibmmq/0.1.0/message.json": {
+ "$id": "http://asyncapi.com/bindings/ibmmq/0.1.0/message.json",
+ "title": "IBM MQ message bindings object",
+ "description": "This object contains information about the message representation in IBM MQ.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "string",
+ "jms",
+ "binary"
+ ],
+ "default": "string",
+ "description": "The type of the message."
+ },
+ "headers": {
+ "type": "string",
+ "description": "Defines the IBM MQ message headers to include with this message. More than one header can be specified as a comma separated list. Supporting information on IBM MQ message formats can be found on this [page](https://www.ibm.com/docs/en/ibm-mq/9.2?topic=mqmd-format-mqchar8) in the IBM MQ Knowledge Center."
+ },
+ "description": {
+ "type": "string",
+ "description": "Provides additional information for application developers: describes the message type or format."
+ },
+ "expiry": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0,
+ "description": "The recommended setting the client should use for the TTL (Time-To-Live) of the message. This is a period of time expressed in milliseconds and set by the application that puts the message. 'expiry' values are API dependant e.g., MQI and JMS use different units of time and default values for 'unlimited'. General information on IBM MQ message expiry can be found on this [page](https://www.ibm.com/docs/en/ibm-mq/9.2?topic=mqmd-expiry-mqlong) in the IBM MQ Knowledge Center."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0"
+ ],
+ "description": "The version of this binding."
+ }
+ },
+ "oneOf": [
+ {
+ "properties": {
+ "type": {
+ "const": "binary"
+ }
+ }
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "jms"
+ }
+ },
+ "not": {
+ "required": [
+ "headers"
+ ]
+ }
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "string"
+ }
+ },
+ "not": {
+ "required": [
+ "headers"
+ ]
+ }
+ }
+ ],
+ "examples": [
+ {
+ "type": "string",
+ "bindingVersion": "0.1.0"
+ },
+ {
+ "type": "jms",
+ "description": "JMS stream message",
+ "bindingVersion": "0.1.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/googlepubsub/0.2.0/message.json": {
+ "$id": "http://asyncapi.com/bindings/googlepubsub/0.2.0/message.json",
+ "title": "Cloud Pub/Sub Channel Schema",
+ "description": "This object contains information about the message representation for Google Cloud Pub/Sub.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding."
+ },
+ "attributes": {
+ "type": "object"
+ },
+ "orderingKey": {
+ "type": "string"
+ },
+ "schema": {
+ "type": "object",
+ "additionalItems": false,
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "name"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "schema": {
+ "name": "projects/your-project-id/schemas/your-avro-schema-id"
+ }
+ },
+ {
+ "schema": {
+ "name": "projects/your-project-id/schemas/your-protobuf-schema-id"
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/messageTrait.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/messageTrait.json",
+ "type": "object",
+ "description": "Describes a trait that MAY be applied to a Message Object. This object MAY contain any property from the Message Object, except payload and traits.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "contentType": {
+ "type": "string",
+ "description": "The content type to use when encoding/decoding a message's payload. The value MUST be a specific media type (e.g. application/json). When omitted, the value MUST be the one specified on the defaultContentType field."
+ },
+ "headers": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/anySchema.json"
+ },
+ "correlationId": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/correlationId.json"
+ }
+ ]
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/tag.json"
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the message."
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the message."
+ },
+ "title": {
+ "type": "string",
+ "description": "A human-friendly title for the message."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the message. CommonMark is allowed."
+ },
+ "externalDocs": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "examples": {
+ "type": "array",
+ "description": "List of examples.",
+ "items": {
+ "type": "object"
+ }
+ },
+ "bindings": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/messageBindingsObject.json"
+ }
+ ]
+ }
+ },
+ "examples": [
+ {
+ "contentType": "application/json"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/parameters.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/parameters.json",
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/parameter.json"
+ }
+ ]
+ },
+ "description": "JSON objects describing re-usable channel parameters.",
+ "examples": [
+ {
+ "address": "user/{userId}/signedup",
+ "parameters": {
+ "userId": {
+ "description": "Id of the user."
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/parameter.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/parameter.json",
+ "description": "Describes a parameter included in a channel address.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "description": {
+ "type": "string",
+ "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed."
+ },
+ "enum": {
+ "description": "An enumeration of string values to be used if the substitution options are from a limited set.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "default": {
+ "description": "The default value to use for substitution, and to send, if an alternate value is not supplied.",
+ "type": "string"
+ },
+ "examples": {
+ "description": "An array of examples of the parameter value.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "location": {
+ "type": "string",
+ "description": "A runtime expression that specifies the location of the parameter value",
+ "pattern": "^\\$message\\.(header|payload)#(\\/(([^\\/~])|(~[01]))*)*"
+ }
+ },
+ "examples": [
+ {
+ "address": "user/{userId}/signedup",
+ "parameters": {
+ "userId": {
+ "description": "Id of the user.",
+ "location": "$message.payload#/user/id"
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/channelBindingsObject.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/channelBindingsObject.json",
+ "type": "object",
+ "description": "Map describing protocol-specific definitions for a channel.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "http": {},
+ "ws": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/websockets/0.1.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/websockets/0.1.0/channel.json"
+ }
+ }
+ ]
+ },
+ "amqp": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/amqp/0.3.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/amqp/0.3.0/channel.json"
+ }
+ }
+ ]
+ },
+ "amqp1": {},
+ "mqtt": {},
+ "kafka": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.4.0",
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.4.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.4.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.4.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.3.0/channel.json"
+ }
+ }
+ ]
+ },
+ "anypointmq": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.0.1"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/anypointmq/0.0.1/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.0.1"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/anypointmq/0.0.1/channel.json"
+ }
+ }
+ ]
+ },
+ "nats": {},
+ "jms": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.0.1"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/jms/0.0.1/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.0.1"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/jms/0.0.1/channel.json"
+ }
+ }
+ ]
+ },
+ "sns": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/channel.json"
+ }
+ }
+ ]
+ },
+ "sqs": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json"
+ }
+ }
+ ]
+ },
+ "stomp": {},
+ "redis": {},
+ "ibmmq": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/ibmmq/0.1.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/ibmmq/0.1.0/channel.json"
+ }
+ }
+ ]
+ },
+ "solace": {},
+ "googlepubsub": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/googlepubsub/0.2.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/googlepubsub/0.2.0/channel.json"
+ }
+ }
+ ]
+ },
+ "pulsar": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/pulsar/0.1.0/channel.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/pulsar/0.1.0/channel.json"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "http://asyncapi.com/bindings/websockets/0.1.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/websockets/0.1.0/channel.json",
+ "title": "WebSockets channel bindings object",
+ "description": "When using WebSockets, the channel represents the connection. Unlike other protocols that support multiple virtual channels (topics, routing keys, etc.) per connection, WebSockets doesn't support virtual channels or, put it another way, there's only one channel and its characteristics are strongly related to the protocol used for the handshake, i.e., HTTP.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "method": {
+ "type": "string",
+ "enum": [
+ "GET",
+ "POST"
+ ],
+ "description": "The HTTP method to use when establishing the connection. Its value MUST be either 'GET' or 'POST'."
+ },
+ "query": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ ],
+ "description": "A Schema object containing the definitions for each query parameter. This schema MUST be of type 'object' and have a 'properties' key."
+ },
+ "headers": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ ],
+ "description": "A Schema object containing the definitions of the HTTP headers to use when establishing the connection. This schema MUST be of type 'object' and have a 'properties' key."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "method": "POST",
+ "bindingVersion": "0.1.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/amqp/0.3.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/amqp/0.3.0/channel.json",
+ "title": "AMQP channel bindings object",
+ "description": "This object contains information about the channel representation in AMQP.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "is": {
+ "type": "string",
+ "enum": [
+ "queue",
+ "routingKey"
+ ],
+ "description": "Defines what type of channel is it. Can be either 'queue' or 'routingKey' (default)."
+ },
+ "exchange": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the exchange. It MUST NOT exceed 255 characters long."
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "topic",
+ "direct",
+ "fanout",
+ "default",
+ "headers"
+ ],
+ "description": "The type of the exchange. Can be either 'topic', 'direct', 'fanout', 'default' or 'headers'."
+ },
+ "durable": {
+ "type": "boolean",
+ "description": "Whether the exchange should survive broker restarts or not."
+ },
+ "autoDelete": {
+ "type": "boolean",
+ "description": "Whether the exchange should be deleted when the last queue is unbound from it."
+ },
+ "vhost": {
+ "type": "string",
+ "default": "/",
+ "description": "The virtual host of the exchange. Defaults to '/'."
+ }
+ },
+ "description": "When is=routingKey, this object defines the exchange properties."
+ },
+ "queue": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the queue. It MUST NOT exceed 255 characters long."
+ },
+ "durable": {
+ "type": "boolean",
+ "description": "Whether the queue should survive broker restarts or not."
+ },
+ "exclusive": {
+ "type": "boolean",
+ "description": "Whether the queue should be used only by one connection or not."
+ },
+ "autoDelete": {
+ "type": "boolean",
+ "description": "Whether the queue should be deleted when the last consumer unsubscribes."
+ },
+ "vhost": {
+ "type": "string",
+ "default": "/",
+ "description": "The virtual host of the queue. Defaults to '/'."
+ }
+ },
+ "description": "When is=queue, this object defines the queue properties."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "oneOf": [
+ {
+ "properties": {
+ "is": {
+ "const": "routingKey"
+ }
+ },
+ "required": [
+ "exchange"
+ ],
+ "not": {
+ "required": [
+ "queue"
+ ]
+ }
+ },
+ {
+ "properties": {
+ "is": {
+ "const": "queue"
+ }
+ },
+ "required": [
+ "queue"
+ ],
+ "not": {
+ "required": [
+ "exchange"
+ ]
+ }
+ }
+ ],
+ "examples": [
+ {
+ "is": "routingKey",
+ "exchange": {
+ "name": "myExchange",
+ "type": "topic",
+ "durable": true,
+ "autoDelete": false,
+ "vhost": "/"
+ },
+ "bindingVersion": "0.3.0"
+ },
+ {
+ "is": "queue",
+ "queue": {
+ "name": "my-queue-name",
+ "durable": true,
+ "exclusive": true,
+ "autoDelete": false,
+ "vhost": "/"
+ },
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/kafka/0.4.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/kafka/0.4.0/channel.json",
+ "title": "Channel Schema",
+ "description": "This object contains information about the channel representation in Kafka.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "topic": {
+ "type": "string",
+ "description": "Kafka topic name if different from channel name."
+ },
+ "partitions": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Number of partitions configured on this topic."
+ },
+ "replicas": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Number of replicas configured on this topic."
+ },
+ "topicConfiguration": {
+ "description": "Topic configuration properties that are relevant for the API.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "cleanup.policy": {
+ "description": "The [`cleanup.policy`](https://kafka.apache.org/documentation/#topicconfigs_cleanup.policy) configuration option.",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "compact",
+ "delete"
+ ]
+ }
+ },
+ "retention.ms": {
+ "description": "The [`retention.ms`](https://kafka.apache.org/documentation/#topicconfigs_retention.ms) configuration option.",
+ "type": "integer",
+ "minimum": -1
+ },
+ "retention.bytes": {
+ "description": "The [`retention.bytes`](https://kafka.apache.org/documentation/#topicconfigs_retention.bytes) configuration option.",
+ "type": "integer",
+ "minimum": -1
+ },
+ "delete.retention.ms": {
+ "description": "The [`delete.retention.ms`](https://kafka.apache.org/documentation/#topicconfigs_delete.retention.ms) configuration option.",
+ "type": "integer",
+ "minimum": 0
+ },
+ "max.message.bytes": {
+ "description": "The [`max.message.bytes`](https://kafka.apache.org/documentation/#topicconfigs_max.message.bytes) configuration option.",
+ "type": "integer",
+ "minimum": 0
+ }
+ }
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.4.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "topic": "my-specific-topic",
+ "partitions": 20,
+ "replicas": 3,
+ "bindingVersion": "0.4.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/kafka/0.3.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/kafka/0.3.0/channel.json",
+ "title": "Channel Schema",
+ "description": "This object contains information about the channel representation in Kafka.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "topic": {
+ "type": "string",
+ "description": "Kafka topic name if different from channel name."
+ },
+ "partitions": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Number of partitions configured on this topic."
+ },
+ "replicas": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Number of replicas configured on this topic."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "topic": "my-specific-topic",
+ "partitions": 20,
+ "replicas": 3,
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/anypointmq/0.0.1/channel.json": {
+ "$id": "http://asyncapi.com/bindings/anypointmq/0.0.1/channel.json",
+ "title": "Anypoint MQ channel bindings object",
+ "description": "This object contains configuration for describing an Anypoint MQ exchange, queue, or FIFO queue as an AsyncAPI channel. This objects only contains configuration that can not be provided in the AsyncAPI standard channel object.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "destination": {
+ "type": "string",
+ "description": "The destination (queue or exchange) name for this channel. SHOULD only be specified if the channel name differs from the actual destination name, such as when the channel name is not a valid destination name in Anypoint MQ. Defaults to the channel name."
+ },
+ "destinationType": {
+ "type": "string",
+ "enum": [
+ "exchange",
+ "queue",
+ "fifo-queue"
+ ],
+ "default": "queue",
+ "description": "The type of destination. SHOULD be specified to document the messaging model (publish/subscribe, point-to-point, strict message ordering) supported by this channel."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.0.1"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "destination": "user-signup-exchg",
+ "destinationType": "exchange",
+ "bindingVersion": "0.0.1"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/jms/0.0.1/channel.json": {
+ "$id": "http://asyncapi.com/bindings/jms/0.0.1/channel.json",
+ "title": "Channel Schema",
+ "description": "This object contains configuration for describing a JMS queue, or FIFO queue as an AsyncAPI channel. This objects only contains configuration that can not be provided in the AsyncAPI standard channel object.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "destination": {
+ "type": "string",
+ "description": "The destination (queue) name for this channel. SHOULD only be specified if the channel name differs from the actual destination name, such as when the channel name is not a valid destination name according to the JMS Provider. Defaults to the channel name."
+ },
+ "destinationType": {
+ "type": "string",
+ "enum": [
+ "queue",
+ "fifo-queue"
+ ],
+ "default": "queue",
+ "description": "The type of destination. SHOULD be specified to document the messaging model (point-to-point, or strict message ordering) supported by this channel."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.0.1"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "destination": "user-signed-up",
+ "destinationType": "fifo-queue",
+ "bindingVersion": "0.0.1"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/sns/0.1.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/sns/0.1.0/channel.json",
+ "title": "Channel Schema",
+ "description": "This object contains information about the channel representation in SNS.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the topic. Can be different from the channel name to allow flexibility around AWS resource naming limitations."
+ },
+ "ordering": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/channel.json#/definitions/ordering"
+ },
+ "policy": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/channel.json#/definitions/policy"
+ },
+ "tags": {
+ "type": "object",
+ "description": "Key-value pairs that represent AWS tags on the topic."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "description": "The version of this binding.",
+ "default": "latest"
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "definitions": {
+ "ordering": {
+ "type": "object",
+ "description": "By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic.",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Defines the type of SNS Topic.",
+ "enum": [
+ "standard",
+ "FIFO"
+ ]
+ },
+ "contentBasedDeduplication": {
+ "type": "boolean",
+ "description": "True to turn on de-duplication of messages for a channel."
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "policy": {
+ "type": "object",
+ "description": "The security policy for the SNS Topic.",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "statements": {
+ "type": "array",
+ "description": "An array of statement objects, each of which controls a permission for this topic",
+ "items": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/channel.json#/definitions/statement"
+ }
+ }
+ },
+ "required": [
+ "statements"
+ ]
+ },
+ "statement": {
+ "type": "object",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "effect": {
+ "type": "string",
+ "enum": [
+ "Allow",
+ "Deny"
+ ]
+ },
+ "principal": {
+ "description": "The AWS account or resource ARN that this statement applies to.",
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "action": {
+ "description": "The SNS permission being allowed or denied e.g. sns:Publish",
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ }
+ },
+ "required": [
+ "effect",
+ "principal",
+ "action"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "name": "my-sns-topic",
+ "policy": {
+ "statements": [
+ {
+ "effect": "Allow",
+ "principal": "*",
+ "action": "SNS:Publish"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/sqs/0.2.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json",
+ "title": "Channel Schema",
+ "description": "This object contains information about the channel representation in SQS.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "queue": {
+ "description": "A definition of the queue that will be used as the channel.",
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json#/definitions/queue"
+ },
+ "deadLetterQueue": {
+ "description": "A definition of the queue that will be used for un-processable messages.",
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json#/definitions/queue"
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0",
+ "0.2.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed.",
+ "default": "latest"
+ }
+ },
+ "required": [
+ "queue"
+ ],
+ "definitions": {
+ "queue": {
+ "type": "object",
+ "description": "A definition of a queue.",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the queue. When an SNS Operation Binding Object references an SQS queue by name, the identifier should be the one in this field."
+ },
+ "fifoQueue": {
+ "type": "boolean",
+ "description": "Is this a FIFO queue?",
+ "default": false
+ },
+ "deduplicationScope": {
+ "type": "string",
+ "enum": [
+ "queue",
+ "messageGroup"
+ ],
+ "description": "Specifies whether message deduplication occurs at the message group or queue level. Valid values are messageGroup and queue (default).",
+ "default": "queue"
+ },
+ "fifoThroughputLimit": {
+ "type": "string",
+ "enum": [
+ "perQueue",
+ "perMessageGroupId"
+ ],
+ "description": "Specifies whether the FIFO queue throughput quota applies to the entire queue or per message group. Valid values are perQueue (default) and perMessageGroupId.",
+ "default": "perQueue"
+ },
+ "deliveryDelay": {
+ "type": "integer",
+ "description": "The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue.",
+ "minimum": 0,
+ "maximum": 15,
+ "default": 0
+ },
+ "visibilityTimeout": {
+ "type": "integer",
+ "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again.",
+ "minimum": 0,
+ "maximum": 43200,
+ "default": 30
+ },
+ "receiveMessageWaitTime": {
+ "type": "integer",
+ "description": "Determines if the queue uses short polling or long polling. Set to zero the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning.",
+ "default": 0
+ },
+ "messageRetentionPeriod": {
+ "type": "integer",
+ "description": "How long to retain a message on the queue in seconds, unless deleted.",
+ "minimum": 60,
+ "maximum": 1209600,
+ "default": 345600
+ },
+ "redrivePolicy": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json#/definitions/redrivePolicy"
+ },
+ "policy": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json#/definitions/policy"
+ },
+ "tags": {
+ "type": "object",
+ "description": "Key-value pairs that represent AWS tags on the queue."
+ }
+ },
+ "required": [
+ "name",
+ "fifoQueue"
+ ]
+ },
+ "redrivePolicy": {
+ "type": "object",
+ "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "deadLetterQueue": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json#/definitions/identifier"
+ },
+ "maxReceiveCount": {
+ "type": "integer",
+ "description": "The number of times a message is delivered to the source queue before being moved to the dead-letter queue.",
+ "default": 10
+ }
+ },
+ "required": [
+ "deadLetterQueue"
+ ]
+ },
+ "identifier": {
+ "type": "object",
+ "description": "The SQS queue to use as a dead letter queue (DLQ).",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "arn": {
+ "type": "string",
+ "description": "The target is an ARN. For example, for SQS, the identifier may be an ARN, which will be of the form: arn:aws:sqs:{region}:{account-id}:{queueName}"
+ },
+ "name": {
+ "type": "string",
+ "description": "The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a binding for that protocol on this publish Operation Object. For example, if the protocol is 'sqs' then the name refers to the name field sqs binding."
+ }
+ }
+ },
+ "policy": {
+ "type": "object",
+ "description": "The security policy for the SQS Queue",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "statements": {
+ "type": "array",
+ "description": "An array of statement objects, each of which controls a permission for this queue.",
+ "items": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/channel.json#/definitions/statement"
+ }
+ }
+ },
+ "required": [
+ "statements"
+ ]
+ },
+ "statement": {
+ "type": "object",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "effect": {
+ "type": "string",
+ "enum": [
+ "Allow",
+ "Deny"
+ ]
+ },
+ "principal": {
+ "description": "The AWS account or resource ARN that this statement applies to.",
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "action": {
+ "description": "The SQS permission being allowed or denied e.g. sqs:ReceiveMessage",
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ }
+ },
+ "required": [
+ "effect",
+ "principal",
+ "action"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "queue": {
+ "name": "myQueue",
+ "fifoQueue": true,
+ "deduplicationScope": "messageGroup",
+ "fifoThroughputLimit": "perMessageGroupId",
+ "deliveryDelay": 15,
+ "visibilityTimeout": 60,
+ "receiveMessageWaitTime": 0,
+ "messageRetentionPeriod": 86400,
+ "redrivePolicy": {
+ "deadLetterQueue": {
+ "arn": "arn:aws:SQS:eu-west-1:0000000:123456789"
+ },
+ "maxReceiveCount": 15
+ },
+ "policy": {
+ "statements": [
+ {
+ "effect": "Deny",
+ "principal": "arn:aws:iam::123456789012:user/dec.kolakowski",
+ "action": [
+ "sqs:SendMessage",
+ "sqs:ReceiveMessage"
+ ]
+ }
+ ]
+ },
+ "tags": {
+ "owner": "AsyncAPI.NET",
+ "platform": "AsyncAPIOrg"
+ }
+ },
+ "deadLetterQueue": {
+ "name": "myQueue_error",
+ "deliveryDelay": 0,
+ "visibilityTimeout": 0,
+ "receiveMessageWaitTime": 0,
+ "messageRetentionPeriod": 604800
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/ibmmq/0.1.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/ibmmq/0.1.0/channel.json",
+ "title": "IBM MQ channel bindings object",
+ "description": "This object contains information about the channel representation in IBM MQ. Each channel corresponds to a Queue or Topic within IBM MQ.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "destinationType": {
+ "type": "string",
+ "enum": [
+ "topic",
+ "queue"
+ ],
+ "default": "topic",
+ "description": "Defines the type of AsyncAPI channel."
+ },
+ "queue": {
+ "type": "object",
+ "description": "Defines the properties of a queue.",
+ "properties": {
+ "objectName": {
+ "type": "string",
+ "maxLength": 48,
+ "description": "Defines the name of the IBM MQ queue associated with the channel."
+ },
+ "isPartitioned": {
+ "type": "boolean",
+ "default": false,
+ "description": "Defines if the queue is a cluster queue and therefore partitioned. If 'true', a binding option MAY be specified when accessing the queue. More information on binding options can be found on this page in the IBM MQ Knowledge Center."
+ },
+ "exclusive": {
+ "type": "boolean",
+ "default": false,
+ "description": "Specifies if it is recommended to open the queue exclusively."
+ }
+ },
+ "required": [
+ "objectName"
+ ]
+ },
+ "topic": {
+ "type": "object",
+ "description": "Defines the properties of a topic.",
+ "properties": {
+ "string": {
+ "type": "string",
+ "maxLength": 10240,
+ "description": "The value of the IBM MQ topic string to be used."
+ },
+ "objectName": {
+ "type": "string",
+ "maxLength": 48,
+ "description": "The name of the IBM MQ topic object."
+ },
+ "durablePermitted": {
+ "type": "boolean",
+ "default": true,
+ "description": "Defines if the subscription may be durable."
+ },
+ "lastMsgRetained": {
+ "type": "boolean",
+ "default": false,
+ "description": "Defines if the last message published will be made available to new subscriptions."
+ }
+ }
+ },
+ "maxMsgLength": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 104857600,
+ "description": "The maximum length of the physical message (in bytes) accepted by the Topic or Queue. Messages produced that are greater in size than this value may fail to be delivered. More information on the maximum message length can be found on this [page](https://www.ibm.com/support/knowledgecenter/SSFKSJ_latest/com.ibm.mq.ref.dev.doc/q097520_.html) in the IBM MQ Knowledge Center."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0"
+ ],
+ "description": "The version of this binding."
+ }
+ },
+ "oneOf": [
+ {
+ "properties": {
+ "destinationType": {
+ "const": "topic"
+ }
+ },
+ "not": {
+ "required": [
+ "queue"
+ ]
+ }
+ },
+ {
+ "properties": {
+ "destinationType": {
+ "const": "queue"
+ }
+ },
+ "required": [
+ "queue"
+ ],
+ "not": {
+ "required": [
+ "topic"
+ ]
+ }
+ }
+ ],
+ "examples": [
+ {
+ "destinationType": "topic",
+ "topic": {
+ "objectName": "myTopicName"
+ },
+ "bindingVersion": "0.1.0"
+ },
+ {
+ "destinationType": "queue",
+ "queue": {
+ "objectName": "myQueueName",
+ "exclusive": true
+ },
+ "bindingVersion": "0.1.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/googlepubsub/0.2.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/googlepubsub/0.2.0/channel.json",
+ "title": "Cloud Pub/Sub Channel Schema",
+ "description": "This object contains information about the channel representation for Google Cloud Pub/Sub.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding."
+ },
+ "labels": {
+ "type": "object"
+ },
+ "messageRetentionDuration": {
+ "type": "string"
+ },
+ "messageStoragePolicy": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "allowedPersistenceRegions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "schemaSettings": {
+ "type": "object",
+ "additionalItems": false,
+ "properties": {
+ "encoding": {
+ "type": "string"
+ },
+ "firstRevisionId": {
+ "type": "string"
+ },
+ "lastRevisionId": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "encoding",
+ "name"
+ ]
+ }
+ },
+ "required": [
+ "schemaSettings"
+ ],
+ "examples": [
+ {
+ "labels": {
+ "label1": "value1",
+ "label2": "value2"
+ },
+ "messageRetentionDuration": "86400s",
+ "messageStoragePolicy": {
+ "allowedPersistenceRegions": [
+ "us-central1",
+ "us-east1"
+ ]
+ },
+ "schemaSettings": {
+ "encoding": "json",
+ "name": "projects/your-project-id/schemas/your-schema"
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/pulsar/0.1.0/channel.json": {
+ "$id": "http://asyncapi.com/bindings/pulsar/0.1.0/channel.json",
+ "title": "Channel Schema",
+ "description": "This object contains information about the channel representation in Pulsar, which covers namespace and topic level admin configuration. This object contains additional information not possible to represent within the core AsyncAPI specification.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "required": [
+ "namespace",
+ "persistence"
+ ],
+ "properties": {
+ "namespace": {
+ "type": "string",
+ "description": "The namespace, the channel is associated with."
+ },
+ "persistence": {
+ "type": "string",
+ "enum": [
+ "persistent",
+ "non-persistent"
+ ],
+ "description": "persistence of the topic in Pulsar."
+ },
+ "compaction": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Topic compaction threshold given in MB"
+ },
+ "geo-replication": {
+ "type": "array",
+ "description": "A list of clusters the topic is replicated to.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "retention": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "time": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Time given in Minutes. `0` = Disable message retention."
+ },
+ "size": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Size given in MegaBytes. `0` = Disable message retention."
+ }
+ }
+ },
+ "ttl": {
+ "type": "integer",
+ "description": "TTL in seconds for the specified topic"
+ },
+ "deduplication": {
+ "type": "boolean",
+ "description": "Whether deduplication of events is enabled or not."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "namespace": "ns1",
+ "persistence": "persistent",
+ "compaction": 1000,
+ "retention": {
+ "time": 15,
+ "size": 1000
+ },
+ "ttl": 360,
+ "geo-replication": [
+ "us-west",
+ "us-east"
+ ],
+ "deduplication": true,
+ "bindingVersion": "0.1.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/operations.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/operations.json",
+ "type": "object",
+ "description": "Holds a dictionary with all the operations this application MUST implement.",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operation.json"
+ }
+ ]
+ },
+ "examples": [
+ {
+ "onUserSignUp": {
+ "title": "User sign up",
+ "summary": "Action to sign a user up.",
+ "description": "A longer description",
+ "channel": {
+ "$ref": "#/channels/userSignup"
+ },
+ "action": "send",
+ "tags": [
+ {
+ "name": "user"
+ },
+ {
+ "name": "signup"
+ },
+ {
+ "name": "register"
+ }
+ ],
+ "bindings": {
+ "amqp": {
+ "ack": false
+ }
+ },
+ "traits": [
+ {
+ "$ref": "#/components/operationTraits/kafka"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/operation.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/operation.json",
+ "type": "object",
+ "description": "Describes a specific operation.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "required": [
+ "action",
+ "channel"
+ ],
+ "properties": {
+ "action": {
+ "type": "string",
+ "description": "Allowed values are send and receive. Use send when it's expected that the application will send a message to the given channel, and receive when the application should expect receiving messages from the given channel.",
+ "enum": [
+ "send",
+ "receive"
+ ]
+ },
+ "channel": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ "messages": {
+ "type": "array",
+ "description": "A list of $ref pointers pointing to the supported Message Objects that can be processed by this operation. It MUST contain a subset of the messages defined in the channel referenced in this operation. Every message processed by this operation MUST be valid against one, and only one, of the message objects referenced in this list. Please note the messages property value MUST be a list of Reference Objects and, therefore, MUST NOT contain Message Objects. However, it is RECOMMENDED that parsers (or other software) dereference this property for a better development experience.",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ },
+ "reply": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationReply.json"
+ }
+ ]
+ },
+ "traits": {
+ "type": "array",
+ "description": "A list of traits to apply to the operation object. Traits MUST be merged using traits merge mechanism. The resulting object MUST be a valid Operation Object.",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationTrait.json"
+ }
+ ]
+ }
+ },
+ "title": {
+ "type": "string",
+ "description": "A human-friendly title for the operation."
+ },
+ "summary": {
+ "type": "string",
+ "description": "A brief summary of the operation."
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of the operation. CommonMark is allowed."
+ },
+ "security": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/securityRequirements.json"
+ },
+ "tags": {
+ "type": "array",
+ "description": "A list of tags for logical grouping and categorization of operations.",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/tag.json"
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "externalDocs": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ },
+ "bindings": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationBindingsObject.json"
+ }
+ ]
+ }
+ },
+ "examples": [
+ {
+ "title": "User sign up",
+ "summary": "Action to sign a user up.",
+ "description": "A longer description",
+ "channel": {
+ "$ref": "#/channels/userSignup"
+ },
+ "action": "send",
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ],
+ "tags": [
+ {
+ "name": "user"
+ },
+ {
+ "name": "signup"
+ },
+ {
+ "name": "register"
+ }
+ ],
+ "bindings": {
+ "amqp": {
+ "ack": false
+ }
+ },
+ "traits": [
+ {
+ "$ref": "#/components/operationTraits/kafka"
+ }
+ ],
+ "messages": [
+ {
+ "$ref": "/components/messages/userSignedUp"
+ }
+ ],
+ "reply": {
+ "address": {
+ "location": "$message.header#/replyTo"
+ },
+ "channel": {
+ "$ref": "#/channels/userSignupReply"
+ },
+ "messages": [
+ {
+ "$ref": "/components/messages/userSignedUpReply"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/operationReply.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/operationReply.json",
+ "type": "object",
+ "description": "Describes the reply part that MAY be applied to an Operation Object. If an operation implements the request/reply pattern, the reply object represents the response message.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "address": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationReplyAddress.json"
+ }
+ ]
+ },
+ "channel": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ "messages": {
+ "type": "array",
+ "description": "A list of $ref pointers pointing to the supported Message Objects that can be processed by this operation as reply. It MUST contain a subset of the messages defined in the channel referenced in this operation reply. Every message processed by this operation MUST be valid against one, and only one, of the message objects referenced in this list. Please note the messages property value MUST be a list of Reference Objects and, therefore, MUST NOT contain Message Objects. However, it is RECOMMENDED that parsers (or other software) dereference this property for a better development experience.",
+ "items": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ }
+ }
+ },
+ "http://asyncapi.com/definitions/3.0.0/operationReplyAddress.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/operationReplyAddress.json",
+ "type": "object",
+ "description": "An object that specifies where an operation has to send the reply",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "required": [
+ "location"
+ ],
+ "properties": {
+ "location": {
+ "type": "string",
+ "description": "A runtime expression that specifies the location of the reply address.",
+ "pattern": "^\\$message\\.(header|payload)#(\\/(([^\\/~])|(~[01]))*)*"
+ },
+ "description": {
+ "type": "string",
+ "description": "An optional description of the address. CommonMark is allowed."
+ }
+ },
+ "examples": [
+ {
+ "description": "Consumer inbox",
+ "location": "$message.header#/replyTo"
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/operationTrait.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/operationTrait.json",
+ "type": "object",
+ "description": "Describes a trait that MAY be applied to an Operation Object. This object MAY contain any property from the Operation Object, except the action, channel and traits ones.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "title": {
+ "description": "A human-friendly title for the operation.",
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operation.json#/properties/title"
+ },
+ "summary": {
+ "description": "A short summary of what the operation is about.",
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operation.json#/properties/summary"
+ },
+ "description": {
+ "description": "A verbose explanation of the operation. CommonMark syntax can be used for rich text representation.",
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operation.json#/properties/description"
+ },
+ "security": {
+ "description": "A declaration of which security schemes are associated with this operation. Only one of the security scheme objects MUST be satisfied to authorize an operation. In cases where Server Security also applies, it MUST also be satisfied.",
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operation.json#/properties/security"
+ },
+ "tags": {
+ "description": "A list of tags for logical grouping and categorization of operations.",
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operation.json#/properties/tags"
+ },
+ "externalDocs": {
+ "description": "Additional external documentation for this operation.",
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operation.json#/properties/externalDocs"
+ },
+ "bindings": {
+ "description": "A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the operation.",
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationBindingsObject.json"
+ }
+ ]
+ }
+ },
+ "examples": [
+ {
+ "bindings": {
+ "amqp": {
+ "ack": false
+ }
+ }
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/operationBindingsObject.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/operationBindingsObject.json",
+ "type": "object",
+ "description": "Map describing protocol-specific definitions for an operation.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "http": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0",
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/http/0.2.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/http/0.2.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/http/0.3.0/operation.json"
+ }
+ }
+ ]
+ },
+ "ws": {},
+ "amqp": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/amqp/0.3.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/amqp/0.3.0/operation.json"
+ }
+ }
+ ]
+ },
+ "amqp1": {},
+ "mqtt": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/mqtt/0.2.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/mqtt/0.2.0/operation.json"
+ }
+ }
+ ]
+ },
+ "kafka": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.4.0",
+ "0.3.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.4.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.4.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.4.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/kafka/0.3.0/operation.json"
+ }
+ }
+ ]
+ },
+ "anypointmq": {},
+ "nats": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/nats/0.1.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/nats/0.1.0/operation.json"
+ }
+ }
+ ]
+ },
+ "jms": {},
+ "sns": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.1.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.1.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json"
+ }
+ }
+ ]
+ },
+ "sqs": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/operation.json"
+ }
+ }
+ ]
+ },
+ "stomp": {},
+ "redis": {},
+ "ibmmq": {},
+ "solace": {
+ "properties": {
+ "bindingVersion": {
+ "enum": [
+ "0.4.0",
+ "0.3.0",
+ "0.2.0"
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "description": "If no bindingVersion specified, use the latest binding",
+ "if": {
+ "not": {
+ "required": [
+ "bindingVersion"
+ ]
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/solace/0.4.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.4.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/solace/0.4.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.3.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/solace/0.3.0/operation.json"
+ }
+ },
+ {
+ "if": {
+ "required": [
+ "bindingVersion"
+ ],
+ "properties": {
+ "bindingVersion": {
+ "const": "0.2.0"
+ }
+ }
+ },
+ "then": {
+ "$ref": "http://asyncapi.com/bindings/solace/0.2.0/operation.json"
+ }
+ }
+ ]
+ },
+ "googlepubsub": {}
+ }
+ },
+ "http://asyncapi.com/bindings/http/0.2.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/http/0.2.0/operation.json",
+ "title": "HTTP operation bindings object",
+ "description": "This object contains information about the operation representation in HTTP.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "method": {
+ "type": "string",
+ "enum": [
+ "GET",
+ "PUT",
+ "POST",
+ "PATCH",
+ "DELETE",
+ "HEAD",
+ "OPTIONS",
+ "CONNECT",
+ "TRACE"
+ ],
+ "description": "When 'type' is 'request', this is the HTTP method, otherwise it MUST be ignored. Its value MUST be one of 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'CONNECT', and 'TRACE'."
+ },
+ "query": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "A Schema object containing the definitions for each query parameter. This schema MUST be of type 'object' and have a properties key."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "query": {
+ "type": "object",
+ "required": [
+ "companyId"
+ ],
+ "properties": {
+ "companyId": {
+ "type": "number",
+ "minimum": 1,
+ "description": "The Id of the company."
+ }
+ },
+ "additionalProperties": false
+ },
+ "bindingVersion": "0.2.0"
+ },
+ {
+ "method": "GET",
+ "query": {
+ "type": "object",
+ "required": [
+ "companyId"
+ ],
+ "properties": {
+ "companyId": {
+ "type": "number",
+ "minimum": 1,
+ "description": "The Id of the company."
+ }
+ },
+ "additionalProperties": false
+ },
+ "bindingVersion": "0.2.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/http/0.3.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/http/0.3.0/operation.json",
+ "title": "HTTP operation bindings object",
+ "description": "This object contains information about the operation representation in HTTP.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "method": {
+ "type": "string",
+ "enum": [
+ "GET",
+ "PUT",
+ "POST",
+ "PATCH",
+ "DELETE",
+ "HEAD",
+ "OPTIONS",
+ "CONNECT",
+ "TRACE"
+ ],
+ "description": "When 'type' is 'request', this is the HTTP method, otherwise it MUST be ignored. Its value MUST be one of 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'CONNECT', and 'TRACE'."
+ },
+ "query": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "A Schema object containing the definitions for each query parameter. This schema MUST be of type 'object' and have a properties key."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "query": {
+ "type": "object",
+ "required": [
+ "companyId"
+ ],
+ "properties": {
+ "companyId": {
+ "type": "number",
+ "minimum": 1,
+ "description": "The Id of the company."
+ }
+ },
+ "additionalProperties": false
+ },
+ "bindingVersion": "0.3.0"
+ },
+ {
+ "method": "GET",
+ "query": {
+ "type": "object",
+ "required": [
+ "companyId"
+ ],
+ "properties": {
+ "companyId": {
+ "type": "number",
+ "minimum": 1,
+ "description": "The Id of the company."
+ }
+ },
+ "additionalProperties": false
+ },
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/amqp/0.3.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/amqp/0.3.0/operation.json",
+ "title": "AMQP operation bindings object",
+ "description": "This object contains information about the operation representation in AMQP.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "expiration": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "TTL (Time-To-Live) for the message. It MUST be greater than or equal to zero."
+ },
+ "userId": {
+ "type": "string",
+ "description": "Identifies the user who has sent the message."
+ },
+ "cc": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "The routing keys the message should be routed to at the time of publishing."
+ },
+ "priority": {
+ "type": "integer",
+ "description": "A priority for the message."
+ },
+ "deliveryMode": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2
+ ],
+ "description": "Delivery mode of the message. Its value MUST be either 1 (transient) or 2 (persistent)."
+ },
+ "mandatory": {
+ "type": "boolean",
+ "description": "Whether the message is mandatory or not."
+ },
+ "bcc": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "Like cc but consumers will not receive this information."
+ },
+ "timestamp": {
+ "type": "boolean",
+ "description": "Whether the message should include a timestamp or not."
+ },
+ "ack": {
+ "type": "boolean",
+ "description": "Whether the consumer should ack the message or not."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, \"latest\" MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "expiration": 100000,
+ "userId": "guest",
+ "cc": [
+ "user.logs"
+ ],
+ "priority": 10,
+ "deliveryMode": 2,
+ "mandatory": false,
+ "bcc": [
+ "external.audit"
+ ],
+ "timestamp": true,
+ "ack": false,
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/mqtt/0.2.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/mqtt/0.2.0/operation.json",
+ "title": "MQTT operation bindings object",
+ "description": "This object contains information about the operation representation in MQTT.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "qos": {
+ "type": "integer",
+ "enum": [
+ 0,
+ 1,
+ 2
+ ],
+ "description": "Defines the Quality of Service (QoS) levels for the message flow between client and server. Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery)."
+ },
+ "retain": {
+ "type": "boolean",
+ "description": "Whether the broker should retain the message or not."
+ },
+ "messageExpiryInterval": {
+ "oneOf": [
+ {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 4294967295
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ }
+ ],
+ "description": "Lifetime of the message in seconds"
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "qos": 2,
+ "retain": true,
+ "messageExpiryInterval": 60,
+ "bindingVersion": "0.2.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/kafka/0.4.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/kafka/0.4.0/operation.json",
+ "title": "Operation Schema",
+ "description": "This object contains information about the operation representation in Kafka.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "groupId": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "Id of the consumer group."
+ },
+ "clientId": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "Id of the consumer inside a consumer group."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.4.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "groupId": {
+ "type": "string",
+ "enum": [
+ "myGroupId"
+ ]
+ },
+ "clientId": {
+ "type": "string",
+ "enum": [
+ "myClientId"
+ ]
+ },
+ "bindingVersion": "0.4.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/kafka/0.3.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/kafka/0.3.0/operation.json",
+ "title": "Operation Schema",
+ "description": "This object contains information about the operation representation in Kafka.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "groupId": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "Id of the consumer group."
+ },
+ "clientId": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/schema.json",
+ "description": "Id of the consumer inside a consumer group."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "groupId": {
+ "type": "string",
+ "enum": [
+ "myGroupId"
+ ]
+ },
+ "clientId": {
+ "type": "string",
+ "enum": [
+ "myClientId"
+ ]
+ },
+ "bindingVersion": "0.3.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/nats/0.1.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/nats/0.1.0/operation.json",
+ "title": "NATS operation bindings object",
+ "description": "This object contains information about the operation representation in NATS.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "queue": {
+ "type": "string",
+ "description": "Defines the name of the queue to use. It MUST NOT exceed 255 characters.",
+ "maxLength": 255
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "queue": "MyCustomQueue",
+ "bindingVersion": "0.1.0"
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/sns/0.1.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/sns/0.1.0/operation.json",
+ "title": "Operation Schema",
+ "description": "This object contains information about the operation representation in SNS.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "topic": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json#/definitions/identifier",
+ "description": "Often we can assume that the SNS Topic is the channel name-we provide this field in case the you need to supply the ARN, or the Topic name is not the channel name in the AsyncAPI document."
+ },
+ "consumers": {
+ "type": "array",
+ "description": "The protocols that listen to this topic and their endpoints.",
+ "items": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json#/definitions/consumer"
+ },
+ "minItems": 1
+ },
+ "deliveryPolicy": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json#/definitions/deliveryPolicy",
+ "description": "Policy for retries to HTTP. The field is the default for HTTP receivers of the SNS Topic which may be overridden by a specific consumer."
+ },
+ "bindingVersion": {
+ "type": "string",
+ "description": "The version of this binding.",
+ "default": "latest"
+ }
+ },
+ "required": [
+ "consumers"
+ ],
+ "definitions": {
+ "identifier": {
+ "type": "object",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "url": {
+ "type": "string",
+ "description": "The endpoint is a URL."
+ },
+ "email": {
+ "type": "string",
+ "description": "The endpoint is an email address."
+ },
+ "phone": {
+ "type": "string",
+ "description": "The endpoint is a phone number."
+ },
+ "arn": {
+ "type": "string",
+ "description": "The target is an ARN. For example, for SQS, the identifier may be an ARN, which will be of the form: arn:aws:sqs:{region}:{account-id}:{queueName}"
+ },
+ "name": {
+ "type": "string",
+ "description": "The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a binding for that protocol on this publish Operation Object. For example, if the protocol is 'sqs' then the name refers to the name field sqs binding. We don't use $ref because we are referring, not including."
+ }
+ }
+ },
+ "consumer": {
+ "type": "object",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "protocol": {
+ "description": "The protocol that this endpoint receives messages by.",
+ "type": "string",
+ "enum": [
+ "http",
+ "https",
+ "email",
+ "email-json",
+ "sms",
+ "sqs",
+ "application",
+ "lambda",
+ "firehose"
+ ]
+ },
+ "endpoint": {
+ "description": "The endpoint messages are delivered to.",
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json#/definitions/identifier"
+ },
+ "filterPolicy": {
+ "type": "object",
+ "description": "Only receive a subset of messages from the channel, determined by this policy. Depending on the FilterPolicyScope, a map of either a message attribute or message body to an array of possible matches. The match may be a simple string for an exact match, but it may also be an object that represents a constraint and values for that constraint.",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "object"
+ }
+ ]
+ }
+ },
+ "filterPolicyScope": {
+ "type": "string",
+ "description": "Determines whether the FilterPolicy applies to MessageAttributes or MessageBody.",
+ "enum": [
+ "MessageAttributes",
+ "MessageBody"
+ ],
+ "default": "MessageAttributes"
+ },
+ "rawMessageDelivery": {
+ "type": "boolean",
+ "description": "If true AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If false the SNS attributes are included in the body."
+ },
+ "redrivePolicy": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json#/definitions/redrivePolicy"
+ },
+ "deliveryPolicy": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json#/definitions/deliveryPolicy",
+ "description": "Policy for retries to HTTP. The parameter is for that SNS Subscription and overrides any policy on the SNS Topic."
+ },
+ "displayName": {
+ "type": "string",
+ "description": "The display name to use with an SNS subscription"
+ }
+ },
+ "required": [
+ "protocol",
+ "endpoint",
+ "rawMessageDelivery"
+ ]
+ },
+ "deliveryPolicy": {
+ "type": "object",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "minDelayTarget": {
+ "type": "integer",
+ "description": "The minimum delay for a retry in seconds."
+ },
+ "maxDelayTarget": {
+ "type": "integer",
+ "description": "The maximum delay for a retry in seconds."
+ },
+ "numRetries": {
+ "type": "integer",
+ "description": "The total number of retries, including immediate, pre-backoff, backoff, and post-backoff retries."
+ },
+ "numNoDelayRetries": {
+ "type": "integer",
+ "description": "The number of immediate retries (with no delay)."
+ },
+ "numMinDelayRetries": {
+ "type": "integer",
+ "description": "The number of immediate retries (with delay)."
+ },
+ "numMaxDelayRetries": {
+ "type": "integer",
+ "description": "The number of post-backoff phase retries, with the maximum delay between retries."
+ },
+ "backoffFunction": {
+ "type": "string",
+ "description": "The algorithm for backoff between retries.",
+ "enum": [
+ "arithmetic",
+ "exponential",
+ "geometric",
+ "linear"
+ ]
+ },
+ "maxReceivesPerSecond": {
+ "type": "integer",
+ "description": "The maximum number of deliveries per second, per subscription."
+ }
+ }
+ },
+ "redrivePolicy": {
+ "type": "object",
+ "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "deadLetterQueue": {
+ "$ref": "http://asyncapi.com/bindings/sns/0.1.0/operation.json#/definitions/identifier",
+ "description": "The SQS queue to use as a dead letter queue (DLQ)."
+ },
+ "maxReceiveCount": {
+ "type": "integer",
+ "description": "The number of times a message is delivered to the source queue before being moved to the dead-letter queue.",
+ "default": 10
+ }
+ },
+ "required": [
+ "deadLetterQueue"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "topic": {
+ "name": "someTopic"
+ },
+ "consumers": [
+ {
+ "protocol": "sqs",
+ "endpoint": {
+ "name": "someQueue"
+ },
+ "filterPolicy": {
+ "store": [
+ "asyncapi_corp"
+ ],
+ "event": [
+ {
+ "anything-but": "order_cancelled"
+ }
+ ],
+ "customer_interests": [
+ "rugby",
+ "football",
+ "baseball"
+ ]
+ },
+ "filterPolicyScope": "MessageAttributes",
+ "rawMessageDelivery": false,
+ "redrivePolicy": {
+ "deadLetterQueue": {
+ "arn": "arn:aws:SQS:eu-west-1:0000000:123456789"
+ },
+ "maxReceiveCount": 25
+ },
+ "deliveryPolicy": {
+ "minDelayTarget": 10,
+ "maxDelayTarget": 100,
+ "numRetries": 5,
+ "numNoDelayRetries": 2,
+ "numMinDelayRetries": 3,
+ "numMaxDelayRetries": 5,
+ "backoffFunction": "linear",
+ "maxReceivesPerSecond": 2
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/sqs/0.2.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/sqs/0.2.0/operation.json",
+ "title": "Operation Schema",
+ "description": "This object contains information about the operation representation in SQS.",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "queues": {
+ "type": "array",
+ "description": "Queue objects that are either the endpoint for an SNS Operation Binding Object, or the deadLetterQueue of the SQS Operation Binding Object.",
+ "items": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/operation.json#/definitions/queue"
+ }
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.1.0",
+ "0.2.0"
+ ],
+ "description": "The version of this binding. If omitted, 'latest' MUST be assumed.",
+ "default": "latest"
+ }
+ },
+ "required": [
+ "queues"
+ ],
+ "definitions": {
+ "queue": {
+ "type": "object",
+ "description": "A definition of a queue.",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "$ref": {
+ "type": "string",
+ "description": "Allows for an external definition of a queue. The referenced structure MUST be in the format of a Queue. If there are conflicts between the referenced definition and this Queue's definition, the behavior is undefined."
+ },
+ "name": {
+ "type": "string",
+ "description": "The name of the queue. When an SNS Operation Binding Object references an SQS queue by name, the identifier should be the one in this field."
+ },
+ "fifoQueue": {
+ "type": "boolean",
+ "description": "Is this a FIFO queue?",
+ "default": false
+ },
+ "deduplicationScope": {
+ "type": "string",
+ "enum": [
+ "queue",
+ "messageGroup"
+ ],
+ "description": "Specifies whether message deduplication occurs at the message group or queue level. Valid values are messageGroup and queue (default).",
+ "default": "queue"
+ },
+ "fifoThroughputLimit": {
+ "type": "string",
+ "enum": [
+ "perQueue",
+ "perMessageGroupId"
+ ],
+ "description": "Specifies whether the FIFO queue throughput quota applies to the entire queue or per message group. Valid values are perQueue (default) and perMessageGroupId.",
+ "default": "perQueue"
+ },
+ "deliveryDelay": {
+ "type": "integer",
+ "description": "The number of seconds to delay before a message sent to the queue can be received. Used to create a delay queue.",
+ "minimum": 0,
+ "maximum": 15,
+ "default": 0
+ },
+ "visibilityTimeout": {
+ "type": "integer",
+ "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again.",
+ "minimum": 0,
+ "maximum": 43200,
+ "default": 30
+ },
+ "receiveMessageWaitTime": {
+ "type": "integer",
+ "description": "Determines if the queue uses short polling or long polling. Set to zero the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning.",
+ "default": 0
+ },
+ "messageRetentionPeriod": {
+ "type": "integer",
+ "description": "How long to retain a message on the queue in seconds, unless deleted.",
+ "minimum": 60,
+ "maximum": 1209600,
+ "default": 345600
+ },
+ "redrivePolicy": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/operation.json#/definitions/redrivePolicy"
+ },
+ "policy": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/operation.json#/definitions/policy"
+ },
+ "tags": {
+ "type": "object",
+ "description": "Key-value pairs that represent AWS tags on the queue."
+ }
+ },
+ "required": [
+ "name"
+ ]
+ },
+ "redrivePolicy": {
+ "type": "object",
+ "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "deadLetterQueue": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/operation.json#/definitions/identifier"
+ },
+ "maxReceiveCount": {
+ "type": "integer",
+ "description": "The number of times a message is delivered to the source queue before being moved to the dead-letter queue.",
+ "default": 10
+ }
+ },
+ "required": [
+ "deadLetterQueue"
+ ]
+ },
+ "identifier": {
+ "type": "object",
+ "description": "The SQS queue to use as a dead letter queue (DLQ).",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "arn": {
+ "type": "string",
+ "description": "The target is an ARN. For example, for SQS, the identifier may be an ARN, which will be of the form: arn:aws:sqs:{region}:{account-id}:{queueName}"
+ },
+ "name": {
+ "type": "string",
+ "description": "The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a binding for that protocol on this publish Operation Object. For example, if the protocol is 'sqs' then the name refers to the name field sqs binding."
+ }
+ }
+ },
+ "policy": {
+ "type": "object",
+ "description": "The security policy for the SQS Queue",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "statements": {
+ "type": "array",
+ "description": "An array of statement objects, each of which controls a permission for this queue.",
+ "items": {
+ "$ref": "http://asyncapi.com/bindings/sqs/0.2.0/operation.json#/definitions/statement"
+ }
+ }
+ },
+ "required": [
+ "statements"
+ ]
+ },
+ "statement": {
+ "type": "object",
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "effect": {
+ "type": "string",
+ "enum": [
+ "Allow",
+ "Deny"
+ ]
+ },
+ "principal": {
+ "description": "The AWS account or resource ARN that this statement applies to.",
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "action": {
+ "description": "The SQS permission being allowed or denied e.g. sqs:ReceiveMessage",
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ }
+ },
+ "required": [
+ "effect",
+ "principal",
+ "action"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "queues": [
+ {
+ "name": "myQueue",
+ "fifoQueue": true,
+ "deduplicationScope": "messageGroup",
+ "fifoThroughputLimit": "perMessageGroupId",
+ "deliveryDelay": 10,
+ "redrivePolicy": {
+ "deadLetterQueue": {
+ "name": "myQueue_error"
+ },
+ "maxReceiveCount": 15
+ },
+ "policy": {
+ "statements": [
+ {
+ "effect": "Deny",
+ "principal": "arn:aws:iam::123456789012:user/dec.kolakowski",
+ "action": [
+ "sqs:SendMessage",
+ "sqs:ReceiveMessage"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "name": "myQueue_error",
+ "deliveryDelay": 10
+ }
+ ]
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/solace/0.4.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/solace/0.4.0/operation.json",
+ "title": "Solace operation bindings object",
+ "description": "This object contains information about the operation representation in Solace.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.4.0"
+ ],
+ "description": "The version of this binding. If omitted, \"latest\" MUST be assumed."
+ },
+ "destinations": {
+ "description": "The list of Solace destinations referenced in the operation.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "deliveryMode": {
+ "type": "string",
+ "enum": [
+ "direct",
+ "persistent"
+ ]
+ }
+ },
+ "oneOf": [
+ {
+ "properties": {
+ "destinationType": {
+ "type": "string",
+ "const": "queue",
+ "description": "If the type is queue, then the subscriber can bind to the queue. The queue subscribes to the given topicSubscriptions. If no topicSubscriptions are provied, the queue will subscribe to the topic as represented by the channel name."
+ },
+ "queue": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the queue"
+ },
+ "topicSubscriptions": {
+ "type": "array",
+ "description": "The list of topics that the queue subscribes to.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "accessType": {
+ "type": "string",
+ "enum": [
+ "exclusive",
+ "nonexclusive"
+ ]
+ },
+ "maxTtl": {
+ "type": "string",
+ "description": "The maximum TTL to apply to messages to be spooled."
+ },
+ "maxMsgSpoolUsage": {
+ "type": "string",
+ "description": "The maximum amount of message spool that the given queue may use"
+ }
+ }
+ }
+ }
+ },
+ {
+ "properties": {
+ "destinationType": {
+ "type": "string",
+ "const": "topic",
+ "description": "If the type is topic, then the subscriber subscribes to the given topicSubscriptions. If no topicSubscriptions are provided, the client will subscribe to the topic as represented by the channel name."
+ },
+ "topicSubscriptions": {
+ "type": "array",
+ "description": "The list of topics that the client subscribes to.",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ "timeToLive": {
+ "type": "integer",
+ "description": "Interval in milliseconds or a Schema Object containing the definition of the lifetime of the message."
+ },
+ "priority": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 255,
+ "description": "The valid priority value range is 0-255 with 0 as the lowest priority and 255 as the highest or a Schema Object containing the definition of the priority."
+ },
+ "dmqEligible": {
+ "type": "boolean",
+ "description": "Set the message to be eligible to be moved to a Dead Message Queue. The default value is false."
+ }
+ },
+ "examples": [
+ {
+ "bindingVersion": "0.4.0",
+ "destinations": [
+ {
+ "destinationType": "queue",
+ "queue": {
+ "name": "sampleQueue",
+ "topicSubscriptions": [
+ "samples/*"
+ ],
+ "accessType": "nonexclusive"
+ }
+ },
+ {
+ "destinationType": "topic",
+ "topicSubscriptions": [
+ "samples/*"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/solace/0.3.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/solace/0.3.0/operation.json",
+ "title": "Solace operation bindings object",
+ "description": "This object contains information about the operation representation in Solace.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "destinations": {
+ "description": "The list of Solace destinations referenced in the operation.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "deliveryMode": {
+ "type": "string",
+ "enum": [
+ "direct",
+ "persistent"
+ ]
+ }
+ },
+ "oneOf": [
+ {
+ "properties": {
+ "destinationType": {
+ "type": "string",
+ "const": "queue",
+ "description": "If the type is queue, then the subscriber can bind to the queue. The queue subscribes to the given topicSubscriptions. If no topicSubscriptions are provied, the queue will subscribe to the topic as represented by the channel name."
+ },
+ "queue": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the queue"
+ },
+ "topicSubscriptions": {
+ "type": "array",
+ "description": "The list of topics that the queue subscribes to.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "accessType": {
+ "type": "string",
+ "enum": [
+ "exclusive",
+ "nonexclusive"
+ ]
+ },
+ "maxTtl": {
+ "type": "string",
+ "description": "The maximum TTL to apply to messages to be spooled."
+ },
+ "maxMsgSpoolUsage": {
+ "type": "string",
+ "description": "The maximum amount of message spool that the given queue may use"
+ }
+ }
+ }
+ }
+ },
+ {
+ "properties": {
+ "destinationType": {
+ "type": "string",
+ "const": "topic",
+ "description": "If the type is topic, then the subscriber subscribes to the given topicSubscriptions. If no topicSubscriptions are provided, the client will subscribe to the topic as represented by the channel name."
+ },
+ "topicSubscriptions": {
+ "type": "array",
+ "description": "The list of topics that the client subscribes to.",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.3.0"
+ ],
+ "description": "The version of this binding. If omitted, \"latest\" MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "bindingVersion": "0.3.0",
+ "destinations": [
+ {
+ "destinationType": "queue",
+ "queue": {
+ "name": "sampleQueue",
+ "topicSubscriptions": [
+ "samples/*"
+ ],
+ "accessType": "nonexclusive"
+ }
+ },
+ {
+ "destinationType": "topic",
+ "topicSubscriptions": [
+ "samples/*"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "http://asyncapi.com/bindings/solace/0.2.0/operation.json": {
+ "$id": "http://asyncapi.com/bindings/solace/0.2.0/operation.json",
+ "title": "Solace operation bindings object",
+ "description": "This object contains information about the operation representation in Solace.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "destinations": {
+ "description": "The list of Solace destinations referenced in the operation.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "deliveryMode": {
+ "type": "string",
+ "enum": [
+ "direct",
+ "persistent"
+ ]
+ }
+ },
+ "oneOf": [
+ {
+ "properties": {
+ "destinationType": {
+ "type": "string",
+ "const": "queue",
+ "description": "If the type is queue, then the subscriber can bind to the queue. The queue subscribes to the given topicSubscriptions. If no topicSubscriptions are provied, the queue will subscribe to the topic as represented by the channel name."
+ },
+ "queue": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the queue"
+ },
+ "topicSubscriptions": {
+ "type": "array",
+ "description": "The list of topics that the queue subscribes to.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "accessType": {
+ "type": "string",
+ "enum": [
+ "exclusive",
+ "nonexclusive"
+ ]
+ }
+ }
+ }
+ }
+ },
+ {
+ "properties": {
+ "destinationType": {
+ "type": "string",
+ "const": "topic",
+ "description": "If the type is topic, then the subscriber subscribes to the given topicSubscriptions. If no topicSubscriptions are provided, the client will subscribe to the topic as represented by the channel name."
+ },
+ "topicSubscriptions": {
+ "type": "array",
+ "description": "The list of topics that the client subscribes to.",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ "bindingVersion": {
+ "type": "string",
+ "enum": [
+ "0.2.0"
+ ],
+ "description": "The version of this binding. If omitted, \"latest\" MUST be assumed."
+ }
+ },
+ "examples": [
+ {
+ "bindingVersion": "0.2.0",
+ "destinations": [
+ {
+ "destinationType": "queue",
+ "queue": {
+ "name": "sampleQueue",
+ "topicSubscriptions": [
+ "samples/*"
+ ],
+ "accessType": "nonexclusive"
+ }
+ },
+ {
+ "destinationType": "topic",
+ "topicSubscriptions": [
+ "samples/*"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "http://asyncapi.com/definitions/3.0.0/components.json": {
+ "$id": "http://asyncapi.com/definitions/3.0.0/components.json",
+ "type": "object",
+ "description": "An object to hold a set of reusable objects for different aspects of the AsyncAPI specification. All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object.",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^x-[\\w\\d\\.\\x2d_]+$": {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/specificationExtension.json"
+ }
+ },
+ "properties": {
+ "schemas": {
+ "type": "object",
+ "description": "An object to hold reusable Schema Object. If this is a Schema Object, then the schemaFormat will be assumed to be 'application/vnd.aai.asyncapi+json;version=asyncapi' where the version is equal to the AsyncAPI Version String.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/anySchema.json"
+ }
+ ]
+ }
+ }
+ },
+ "servers": {
+ "type": "object",
+ "description": "An object to hold reusable Server Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/server.json"
+ }
+ ]
+ }
+ }
+ },
+ "channels": {
+ "type": "object",
+ "description": "An object to hold reusable Channel Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/channel.json"
+ }
+ ]
+ }
+ }
+ },
+ "serverVariables": {
+ "type": "object",
+ "description": "An object to hold reusable Server Variable Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/serverVariable.json"
+ }
+ ]
+ }
+ }
+ },
+ "operations": {
+ "type": "object",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operation.json"
+ }
+ ]
+ }
+ }
+ },
+ "messages": {
+ "type": "object",
+ "description": "An object to hold reusable Message Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/messageObject.json"
+ }
+ ]
+ }
+ }
+ },
+ "securitySchemes": {
+ "type": "object",
+ "description": "An object to hold reusable Security Scheme Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/SecurityScheme.json"
+ }
+ ]
+ }
+ }
+ },
+ "parameters": {
+ "type": "object",
+ "description": "An object to hold reusable Parameter Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/parameter.json"
+ }
+ ]
+ }
+ }
+ },
+ "correlationIds": {
+ "type": "object",
+ "description": "An object to hold reusable Correlation ID Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/correlationId.json"
+ }
+ ]
+ }
+ }
+ },
+ "operationTraits": {
+ "type": "object",
+ "description": "An object to hold reusable Operation Trait Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationTrait.json"
+ }
+ ]
+ }
+ }
+ },
+ "messageTraits": {
+ "type": "object",
+ "description": "An object to hold reusable Message Trait Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/messageTrait.json"
+ }
+ ]
+ }
+ }
+ },
+ "replies": {
+ "type": "object",
+ "description": "An object to hold reusable Operation Reply Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationReply.json"
+ }
+ ]
+ }
+ }
+ },
+ "replyAddresses": {
+ "type": "object",
+ "description": "An object to hold reusable Operation Reply Address Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationReplyAddress.json"
+ }
+ ]
+ }
+ }
+ },
+ "serverBindings": {
+ "type": "object",
+ "description": "An object to hold reusable Server Bindings Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/serverBindingsObject.json"
+ }
+ ]
+ }
+ }
+ },
+ "channelBindings": {
+ "type": "object",
+ "description": "An object to hold reusable Channel Bindings Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/channelBindingsObject.json"
+ }
+ ]
+ }
+ }
+ },
+ "operationBindings": {
+ "type": "object",
+ "description": "An object to hold reusable Operation Bindings Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/operationBindingsObject.json"
+ }
+ ]
+ }
+ }
+ },
+ "messageBindings": {
+ "type": "object",
+ "description": "An object to hold reusable Message Bindings Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/messageBindingsObject.json"
+ }
+ ]
+ }
+ }
+ },
+ "tags": {
+ "type": "object",
+ "description": "An object to hold reusable Tag Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/tag.json"
+ }
+ ]
+ }
+ }
+ },
+ "externalDocs": {
+ "type": "object",
+ "description": "An object to hold reusable External Documentation Objects.",
+ "patternProperties": {
+ "^[\\w\\d\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/Reference.json"
+ },
+ {
+ "$ref": "http://asyncapi.com/definitions/3.0.0/externalDocs.json"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "components": {
+ "schemas": {
+ "Category": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ },
+ "Tag": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ },
+ "AvroExample": {
+ "schemaFormat": "application/vnd.apache.avro+json;version=1.9.0",
+ "schema": {
+ "$ref": "path/to/user-create.avsc#/UserCreate"
+ }
+ }
+ },
+ "servers": {
+ "development": {
+ "host": "{stage}.in.mycompany.com:{port}",
+ "description": "RabbitMQ broker",
+ "protocol": "amqp",
+ "protocolVersion": "0-9-1",
+ "variables": {
+ "stage": {
+ "$ref": "#/components/serverVariables/stage"
+ },
+ "port": {
+ "$ref": "#/components/serverVariables/port"
+ }
+ }
+ }
+ },
+ "serverVariables": {
+ "stage": {
+ "default": "demo",
+ "description": "This value is assigned by the service provider, in this example `mycompany.com`"
+ },
+ "port": {
+ "enum": [
+ "5671",
+ "5672"
+ ],
+ "default": "5672"
+ }
+ },
+ "channels": {
+ "user/signedup": {
+ "subscribe": {
+ "message": {
+ "$ref": "#/components/messages/userSignUp"
+ }
+ }
+ }
+ },
+ "messages": {
+ "userSignUp": {
+ "summary": "Action to sign a user up.",
+ "description": "Multiline description of what this action does.\nHere you have another line.\n",
+ "tags": [
+ {
+ "name": "user"
+ },
+ {
+ "name": "signup"
+ }
+ ],
+ "headers": {
+ "type": "object",
+ "properties": {
+ "applicationInstanceId": {
+ "description": "Unique identifier for a given instance of the publishing application",
+ "type": "string"
+ }
+ }
+ },
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/userCreate"
+ },
+ "signup": {
+ "$ref": "#/components/schemas/signup"
+ }
+ }
+ }
+ }
+ },
+ "parameters": {
+ "userId": {
+ "description": "Id of the user."
+ }
+ },
+ "correlationIds": {
+ "default": {
+ "description": "Default Correlation ID",
+ "location": "$message.header#/correlationId"
+ }
+ },
+ "messageTraits": {
+ "commonHeaders": {
+ "headers": {
+ "type": "object",
+ "properties": {
+ "my-app-header": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ "description": "!!Auto generated!! \n Do not manually edit. "
+}
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.schema.patch.json b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.schema.patch.json
new file mode 100644
index 0000000000..23e293bfd9
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.schema.patch.json
@@ -0,0 +1,259 @@
+[
+ {
+ "op": "add",
+ "path": "/$defs/binding/properties/type/enum/-",
+ "value": "asyncapi"
+ },
+ {
+ "op": "add",
+ "path": "/$defs/binding/allOf/-",
+ "value":
+ {
+ "if":
+ {
+ "properties":
+ {
+ "type":
+ {
+ "const": "asyncapi"
+ }
+ }
+ },
+ "then":
+ {
+ "properties":
+ {
+ "type":
+ {
+ "const": "asyncapi"
+ },
+ "kind":
+ {
+ "enum": [ "server", "client", "proxy" ]
+ },
+ "options":
+ {
+ "properties":
+ {
+ "specs":
+ {
+ "title": "Specifications",
+ "type": "object",
+ "apiId":
+ {
+ "type": "object",
+ "patternProperties":
+ {
+ "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$":
+ {
+ "type": "string"
+ }
+ },
+ "maxProperties": 1
+ }
+ },
+ "tcp": "#/$defs/binding/tcp/options",
+ "tls": "#/$defs/binding/tls/options",
+ "http":
+ {
+ "title": "Http",
+ "type": "object",
+ "properties":
+ {
+ "authorization": "$defs/options/binding/http/authorization"
+ },
+ "additionalProperties": false
+ },
+ "kafka":
+ {
+ "title": "Kafka",
+ "type": "object",
+ "properties":
+ {
+ "sasl": "$defs/options/binding/kafka/sasl"
+ },
+ "additionalProperties": false
+ },
+ "mqtt_kafka":
+ {
+ "title": "MQTT-Kafka",
+ "type": "object",
+ "properties":
+ {
+ "channels":
+ {
+ "title": "Channels",
+ "type": "object",
+ "properties":
+ {
+ "sessions":
+ {
+ "title": "Kafka Sessions Channel",
+ "type": "string"
+ },
+ "messages":
+ {
+ "title": "Kafka Messages Channel",
+ "type": "string"
+ },
+ "retained":
+ {
+ "title": "Kafka Retained Channel",
+ "type": "string"
+ },
+ "additionalProperties": false
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "routes":
+ {
+ "items":
+ {
+ "properties":
+ {
+ "when":
+ {
+ "items":
+ {
+ "additionalProperties": false,
+ "properties":
+ {
+ "api-id":
+ {
+ "title": "MQTT API Id",
+ "type": "string"
+ },
+ "operation-id":
+ {
+ "title": "MQTT Operation Id",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "with":
+ {
+ "properties":
+ {
+ "api-id":
+ {
+ "title": "Kafka API Id",
+ "type": "string"
+ },
+ "operation-id":
+ {
+ "title": "Kafka Operation Id",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "required":
+ [
+ "with"
+ ]
+ }
+ }
+ },
+ "oneOf":
+ [
+ {
+ "properties":
+ {
+ "kind":
+ {
+ "const": "server"
+ }
+ },
+ "anyOf":
+ [
+ {
+ "required":
+ [
+ "exit"
+ ]
+ },
+ {
+ "properties":
+ {
+ "routes":
+ {
+ "required":
+ [
+ "exit"
+ ]
+ }
+ },
+ "required":
+ [
+ "routes"
+ ]
+ }
+ ]
+ },
+ {
+ "properties":
+ {
+ "kind":
+ {
+ "const": "proxy"
+ }
+ },
+ "anyOf":
+ [
+ {
+ "required":
+ [
+ "exit"
+ ]
+ },
+ {
+ "properties":
+ {
+ "routes":
+ {
+ "required":
+ [
+ "exit"
+ ]
+ }
+ },
+ "required":
+ [
+ "routes"
+ ]
+ }
+ ]
+ },
+ {
+ "properties":
+ {
+ "kind":
+ {
+ "const": "client"
+ },
+ "routes":
+ {
+ "items":
+ {
+ "properties":
+ {
+ "exit": false
+ }
+ }
+ },
+ "exit": false
+ }
+ }
+ ]
+ }
+ }
+ }
+]
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/client.rpt
new file mode 100644
index 0000000000..6e0038ff3d
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/client.rpt
@@ -0,0 +1,51 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(759838734)
+ .operationId("createPet")
+ .extension(http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "POST")
+ .header(":scheme", "http")
+ .header(":path", "/pets")
+ .header(":authority", "localhost:8080")
+ .header("content-type", "application/json")
+ .header("content-length", "8")
+ .build())
+ .build()}
+connected
+
+write "{\"test\"}"
+write close
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .operationId("createPet")
+ .extension(http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "200")
+ .header("content-type", "application/json")
+ .header("content-length", "21")
+ .build())
+ .build()}
+
+read "{\"message\": \"string\"}"
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/server.rpt
new file mode 100644
index 0000000000..92f26191d2
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/server.rpt
@@ -0,0 +1,54 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+accept "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(759838734)
+ .operationId("createPet")
+ .extension(http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "POST")
+ .header(":scheme", "http")
+ .header(":path", "/pets")
+ .header(":authority", "localhost:8080")
+ .header("content-type", "application/json")
+ .header("content-length", "8")
+ .build())
+ .build()}
+connected
+
+read "{\"test\"}"
+read closed
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .operationId("createPet")
+ .extension(http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "200")
+ .header("content-type", "application/json")
+ .header("content-length", "21")
+ .build())
+ .build()}
+
+write "{\"message\": \"string\"}"
+write flush
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/kafka/produce.message/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/kafka/produce.message/client.rpt
new file mode 100644
index 0000000000..dbd8c02087
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/kafka/produce.message/client.rpt
@@ -0,0 +1,47 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+property deltaMillis 0L
+property newTimestamp ${kafka:timestamp() + deltaMillis}
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(kafka:beginEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .capabilities("PRODUCE_ONLY")
+ .topic("test")
+ .ackMode("LEADER_ONLY")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+write zilla:data.ext ${kafka:dataEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .produce()
+ .timestamp(newTimestamp)
+ .partition(0, 1)
+ .build()
+ .build()}
+write "Hello, world"
+write flush
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/kafka/produce.message/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/kafka/produce.message/server.rpt
new file mode 100644
index 0000000000..e725f5ad6e
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/kafka/produce.message/server.rpt
@@ -0,0 +1,44 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+accept "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(kafka:beginEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .capabilities("PRODUCE_ONLY")
+ .topic("test")
+ .ackMode("LEADER_ONLY")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+read zilla:data.ext ${kafka:matchDataEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .produce()
+ .partition(0, 1)
+ .build()
+ .build()}
+read "Hello, world"
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/client.rpt
new file mode 100644
index 0000000000..9c04a2d76f
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/client.rpt
@@ -0,0 +1,95 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(3724230511)
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build())
+ .build()}
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+read zilla:data.empty
+
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(3724230511)
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .clientId("client")
+ .topic("sensor/one")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+write zilla:data.ext ${mqtt:dataEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .qos("AT_MOST_ONCE")
+ .expiryInterval(15)
+ .contentType("asyncapiMessage")
+ .format("TEXT")
+ .responseTopic("sensor/one")
+ .correlation("info")
+ .build()
+ .build()}
+write "asyncapiMessage"
+write flush
+
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(3724230511)
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .subscribe()
+ .clientId("client")
+ .filter("sensor/two", 1, "AT_MOST_ONCE", "SEND_RETAINED")
+ .build()
+ .build())
+ .build()}
+connected
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/server.rpt
new file mode 100644
index 0000000000..a30cd06c20
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/server.rpt
@@ -0,0 +1,94 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+accept "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(3724230511)
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build())
+ .build()}
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+write zilla:data.empty
+write flush
+
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(3724230511)
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .clientId("client")
+ .topic("sensor/one")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+read zilla:data.ext ${mqtt:dataEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .qos("AT_MOST_ONCE")
+ .expiryInterval(15)
+ .contentType("asyncapiMessage")
+ .format("TEXT")
+ .responseTopic("sensor/one")
+ .correlation("info")
+ .build()
+ .build()}
+read "asyncapiMessage"
+
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(3724230511)
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .subscribe()
+ .clientId("client")
+ .filter("sensor/two", 1, "AT_MOST_ONCE", "SEND_RETAINED")
+ .build()
+ .build())
+ .build()}
+
+connected
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/produce.message/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/produce.message/client.rpt
new file mode 100644
index 0000000000..dbd8c02087
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/produce.message/client.rpt
@@ -0,0 +1,47 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+property deltaMillis 0L
+property newTimestamp ${kafka:timestamp() + deltaMillis}
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(kafka:beginEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .capabilities("PRODUCE_ONLY")
+ .topic("test")
+ .ackMode("LEADER_ONLY")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+write zilla:data.ext ${kafka:dataEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .produce()
+ .timestamp(newTimestamp)
+ .partition(0, 1)
+ .build()
+ .build()}
+write "Hello, world"
+write flush
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/produce.message/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/produce.message/server.rpt
new file mode 100644
index 0000000000..e725f5ad6e
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/produce.message/server.rpt
@@ -0,0 +1,44 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+accept "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(kafka:beginEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .capabilities("PRODUCE_ONLY")
+ .topic("test")
+ .ackMode("LEADER_ONLY")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+read zilla:data.ext ${kafka:matchDataEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .produce()
+ .partition(0, 1)
+ .build()
+ .build()}
+read "Hello, world"
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.kafka.publish/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.kafka.publish/client.rpt
new file mode 100644
index 0000000000..4c4c5da8b1
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.kafka.publish/client.rpt
@@ -0,0 +1,62 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+property deltaMillis 0L
+property newTimestamp ${kafka:timestamp() + deltaMillis}
+
+connect "zilla://streams/asyncapi_kafka0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(810158698)
+ .extension(kafka:beginEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .capabilities("PRODUCE_ONLY")
+ .topic("sensors")
+ .partition(-1, -2)
+ .ackMode("NONE")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+write zilla:data.ext ${kafka:dataEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .produce()
+ .deferred(0)
+ .partition(-1, -1)
+ .key("sensors/one")
+ .header("zilla:filter", "sensors")
+ .header("zilla:filter", "one")
+ .header("zilla:local", "client")
+ .headerInt("zilla:expiry", 15)
+ .header("zilla:content-type", "message")
+ .header("zilla:format", "TEXT")
+ .header("zilla:reply-to", "sensors")
+ .header("zilla:reply-key", "sensors/one")
+ .header("zilla:reply-filter", "sensors")
+ .header("zilla:reply-filter", "one")
+ .header("zilla:correlation-id", "info")
+ .header("zilla:qos", "0")
+ .build()
+ .build()}
+write "message"
+write flush
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.kafka.publish/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.kafka.publish/server.rpt
new file mode 100644
index 0000000000..d8954e59c0
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.kafka.publish/server.rpt
@@ -0,0 +1,60 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+accept "zilla://streams/asyncapi_kafka0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(810158698)
+ .extension(kafka:beginEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .capabilities("PRODUCE_ONLY")
+ .topic("sensors")
+ .partition(-1, -2)
+ .ackMode("NONE")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+read zilla:data.ext ${kafka:matchDataEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .produce()
+ .deferred(0)
+ .partition(-1, -1)
+ .key("sensors/one")
+ .header("zilla:filter", "sensors")
+ .header("zilla:filter", "one")
+ .header("zilla:local", "client")
+ .headerInt("zilla:expiry", 15)
+ .header("zilla:content-type", "message")
+ .header("zilla:format", "TEXT")
+ .header("zilla:reply-to", "sensors")
+ .header("zilla:reply-key", "sensors/one")
+ .header("zilla:reply-filter", "sensors")
+ .header("zilla:reply-filter", "one")
+ .header("zilla:correlation-id", "info")
+ .header("zilla:qos", "0")
+ .build()
+ .build()}
+read "message"
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.mqtt.publish/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.mqtt.publish/client.rpt
new file mode 100644
index 0000000000..a617fcde59
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.mqtt.publish/client.rpt
@@ -0,0 +1,47 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+connect "zilla://streams/asyncapi_proxy0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(3724230511)
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .clientId("client")
+ .topic("sensors/one")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+write zilla:data.ext ${mqtt:dataEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .qos("AT_MOST_ONCE")
+ .expiryInterval(15)
+ .contentType("message")
+ .format("TEXT")
+ .responseTopic("sensors/one")
+ .correlation("info")
+ .build()
+ .build()}
+write "message"
+write flush
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.mqtt.publish/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.mqtt.publish/server.rpt
new file mode 100644
index 0000000000..0b74c3634e
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/proxy.mqtt.publish/server.rpt
@@ -0,0 +1,48 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+accept "zilla://streams/asyncapi_proxy0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .apiId(3724230511)
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .clientId("client")
+ .topic("sensors/one")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+read zilla:data.ext ${mqtt:dataEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .qos("AT_MOST_ONCE")
+ .expiryInterval(15)
+ .contentType("message")
+ .format("TEXT")
+ .responseTopic("sensors/one")
+ .correlation("info")
+ .build()
+ .build()}
+read "message"
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/publish.and.subscribe/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/publish.and.subscribe/client.rpt
new file mode 100644
index 0000000000..7e16896b71
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/publish.and.subscribe/client.rpt
@@ -0,0 +1,92 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build())
+ .build()}
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+read zilla:data.empty
+
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .clientId("client")
+ .topic("sensor/one")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+write zilla:data.ext ${mqtt:dataEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .qos("AT_MOST_ONCE")
+ .expiryInterval(15)
+ .contentType("asyncapiMessage")
+ .format("TEXT")
+ .responseTopic("sensor/one")
+ .correlation("info")
+ .build()
+ .build()}
+write "asyncapiMessage"
+write flush
+
+
+connect "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .subscribe()
+ .clientId("client")
+ .filter("sensor/two", 1, "AT_MOST_ONCE", "SEND_RETAINED")
+ .build()
+ .build())
+ .build()}
+connected
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/publish.and.subscribe/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/publish.and.subscribe/server.rpt
new file mode 100644
index 0000000000..6155cf6cb4
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/publish.and.subscribe/server.rpt
@@ -0,0 +1,91 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+accept "zilla://streams/asyncapi0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build())
+ .build()}
+
+write zilla:begin.ext ${asyncapi:beginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+write zilla:data.empty
+write flush
+
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .clientId("client")
+ .topic("sensor/one")
+ .build()
+ .build())
+ .build()}
+
+connected
+
+read zilla:data.ext ${mqtt:dataEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .qos("AT_MOST_ONCE")
+ .expiryInterval(15)
+ .contentType("asyncapiMessage")
+ .format("TEXT")
+ .responseTopic("sensor/one")
+ .correlation("info")
+ .build()
+ .build()}
+read "asyncapiMessage"
+
+
+accepted
+
+read zilla:begin.ext ${asyncapi:matchBeginEx()
+ .typeId(zilla:id("asyncapi"))
+ .extension(mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .subscribe()
+ .clientId("client")
+ .filter("sensor/two", 1, "AT_MOST_ONCE", "SEND_RETAINED")
+ .build()
+ .build())
+ .build()}
+
+connected
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/client.rpt
new file mode 100644
index 0000000000..519bc10f7d
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/client.rpt
@@ -0,0 +1,43 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+connect "zilla://streams/composite0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+ option zilla:ephemeral "test:composite0/http"
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "POST")
+ .header(":scheme", "http")
+ .header(":path", "/pets")
+ .header(":authority", "localhost:8080")
+ .header("content-type", "application/json")
+ .header("content-length", "8")
+ .build()}
+connected
+
+write "{\"test\"}"
+write close
+
+read zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "200")
+ .header("content-type", "application/json")
+ .header("content-length", "21")
+ .build()}
+
+read "{\"message\": \"string\"}"
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/server.rpt
new file mode 100644
index 0000000000..3f504e0c61
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/server.rpt
@@ -0,0 +1,47 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+property serverAddress "zilla://streams/composite0"
+
+accept ${serverAddress}
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+accepted
+
+read zilla:begin.ext ${http:matchBeginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "POST")
+ .header(":scheme", "http")
+ .header(":path", "/pets")
+ .header(":authority", "localhost:8080")
+ .header("content-type", "application/json")
+ .header("content-length", "8")
+ .build()}
+connected
+
+read "{\"test\"}"
+read closed
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "200")
+ .header("content-type", "application/json")
+ .header("content-length", "21")
+ .build()}
+
+write "{\"message\": \"string\"}"
+write flush
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/client.rpt
new file mode 100644
index 0000000000..1e13239fe6
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/client.rpt
@@ -0,0 +1,45 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+property deltaMillis 0L
+property newTimestamp ${kafka:timestamp() + deltaMillis}
+
+connect "zilla://streams/composite0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+ option zilla:ephemeral "test:composite0/kafka"
+
+write zilla:begin.ext ${kafka:beginEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .capabilities("PRODUCE_ONLY")
+ .topic("test")
+ .ackMode("LEADER_ONLY")
+ .build()
+ .build()}
+
+connected
+
+write zilla:data.ext ${kafka:dataEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .produce()
+ .timestamp(newTimestamp)
+ .partition(0, 1)
+ .build()
+ .build()}
+write "Hello, world"
+write flush
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/server.rpt
new file mode 100644
index 0000000000..ea9e2d6bb9
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/server.rpt
@@ -0,0 +1,43 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+property serverAddress "zilla://streams/composite0"
+
+accept ${serverAddress}
+ option zilla:window 16
+ option zilla:transmission "half-duplex"
+
+accepted
+
+read zilla:begin.ext ${kafka:matchBeginEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .capabilities("PRODUCE_ONLY")
+ .topic("test")
+ .ackMode("LEADER_ONLY")
+ .build()
+ .build()}
+
+connected
+
+read zilla:data.ext ${kafka:matchDataEx()
+ .typeId(zilla:id("kafka"))
+ .merged()
+ .produce()
+ .partition(0, 1)
+ .build()
+ .build()}
+read "Hello, world"
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/client.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/client.rpt
new file mode 100644
index 0000000000..c0de30bc54
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/client.rpt
@@ -0,0 +1,88 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+connect "zilla://streams/composite0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+ option zilla:ephemeral "test:composite0/mqtt"
+
+write zilla:begin.ext ${mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build()}
+
+read zilla:begin.ext ${mqtt:matchBeginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build()}
+
+connected
+
+read zilla:data.empty
+read notify RECEIVED_SESSION_STATE
+
+
+connect await RECEIVED_SESSION_STATE
+ "zilla://streams/composite0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+ option zilla:ephemeral "test:composite0/mqtt"
+
+write zilla:begin.ext ${mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .clientId("client")
+ .topic("sensor/one")
+ .build()
+ .build()}
+
+connected
+
+write zilla:data.ext ${mqtt:dataEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .qos("AT_MOST_ONCE")
+ .expiryInterval(15)
+ .contentType("asyncapiMessage")
+ .format("TEXT")
+ .responseTopic("sensor/one")
+ .correlation("info")
+ .build()
+ .build()}
+
+write "asyncapiMessage"
+write flush
+
+
+connect await RECEIVED_SESSION_STATE
+ "zilla://streams/composite0"
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+ option zilla:ephemeral "test:composite0/mqtt"
+
+write zilla:begin.ext ${mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .subscribe()
+ .clientId("client")
+ .filter("sensor/two", 1, "AT_MOST_ONCE", "SEND_RETAINED")
+ .build()
+ .build()}
+
+connected
diff --git a/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/server.rpt b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/server.rpt
new file mode 100644
index 0000000000..dc22830300
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/server.rpt
@@ -0,0 +1,82 @@
+#
+# Copyright 2021-2023 Aklivity Inc.
+#
+# Aklivity licenses this file to you 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.
+#
+
+property serverAddress "zilla://streams/composite0"
+
+accept ${serverAddress}
+ option zilla:window 8192
+ option zilla:transmission "duplex"
+
+accepted
+
+read zilla:begin.ext ${mqtt:matchBeginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build()}
+
+write zilla:begin.ext ${mqtt:beginEx()
+ .typeId(zilla:id("mqtt"))
+ .session()
+ .clientId("client")
+ .build()
+ .build()}
+
+connected
+
+write zilla:data.empty
+write flush
+
+
+accepted
+
+read zilla:begin.ext ${mqtt:matchBeginEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .clientId("client")
+ .topic("sensor/one")
+ .build()
+ .build()}
+
+connected
+
+read zilla:data.ext ${mqtt:matchDataEx()
+ .typeId(zilla:id("mqtt"))
+ .publish()
+ .qos("AT_MOST_ONCE")
+ .expiryInterval(15)
+ .contentType("asyncapiMessage")
+ .format("TEXT")
+ .responseTopic("sensor/one")
+ .correlation("info")
+ .build()
+ .build()}
+
+read "asyncapiMessage"
+
+
+accepted
+
+read zilla:begin.ext ${mqtt:matchBeginEx()
+ .typeId(zilla:id("mqtt"))
+ .subscribe()
+ .clientId("client")
+ .filter("sensor/two", 1, "AT_MOST_ONCE", "SEND_RETAINED")
+ .build()
+ .build()}
+
+connected
diff --git a/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiFunctionsTest.java b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiFunctionsTest.java
new file mode 100644
index 0000000000..44ab1567fd
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/AsyncapiFunctionsTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.nio.ByteBuffer;
+
+import org.agrona.DirectBuffer;
+import org.agrona.MutableDirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.junit.Test;
+import org.kaazing.k3po.lang.el.BytesMatcher;
+
+import io.aklivity.zilla.specs.binding.asyncapi.internal.types.OctetsFW;
+import io.aklivity.zilla.specs.binding.asyncapi.internal.types.stream.AsyncapiBeginExFW;
+
+public class AsyncapiFunctionsTest
+{
+ @Test
+ public void shouldGetMapper()
+ {
+ AsyncapiFunctions.Mapper mapper = new AsyncapiFunctions.Mapper();
+ assertEquals("asyncapi", mapper.getPrefixName());
+ }
+
+ @Test
+ public void shouldEncodeAsyncapiBeginExt()
+ {
+ final byte[] array = AsyncapiFunctions.beginEx()
+ .typeId(0)
+ .apiId(1)
+ .operationId("operationId")
+ .extension(new byte[] {1})
+ .build();
+
+ DirectBuffer buffer = new UnsafeBuffer(array);
+ AsyncapiBeginExFW asyncapiBeginEx = new AsyncapiBeginExFW().wrap(buffer, 0, buffer.capacity());
+ MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[1]);
+
+ assertEquals(1, asyncapiBeginEx.apiId());
+ assertEquals("operationId", asyncapiBeginEx.operationId().asString());
+ assertEquals(new OctetsFW.Builder().wrap(writeBuffer, 0, 1).set(new byte[] {1}).build(),
+ asyncapiBeginEx.extension());
+ }
+
+ @Test
+ public void shouldMatchAsyncapiBeginExtensionOnly() throws Exception
+ {
+ BytesMatcher matcher = AsyncapiFunctions.matchBeginEx()
+ .typeId(0x00)
+ .apiId(1L)
+ .extension(new byte[] {1})
+ .build();
+
+ ByteBuffer byteBuf = ByteBuffer.allocate(15);
+ MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[1]);
+
+ new AsyncapiBeginExFW.Builder().wrap(new UnsafeBuffer(byteBuf), 0, byteBuf.capacity())
+ .typeId(0x00)
+ .apiId(1L)
+ .extension(new OctetsFW.Builder().wrap(writeBuffer, 0, 1).set(new byte[] {1}).build())
+ .build();
+
+ assertNotNull(matcher.match(byteBuf));
+ }
+
+ @Test
+ public void shouldMatchAsyncapiBeginExtension() throws Exception
+ {
+ BytesMatcher matcher = AsyncapiFunctions.matchBeginEx()
+ .typeId(0x00)
+ .apiId(1L)
+ .operationId("operationId")
+ .extension(new byte[] {1})
+ .build();
+
+ ByteBuffer byteBuf = ByteBuffer.allocate(26);
+ MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[1]);
+
+ new AsyncapiBeginExFW.Builder().wrap(new UnsafeBuffer(byteBuf), 0, byteBuf.capacity())
+ .typeId(0x00)
+ .apiId(1)
+ .operationId("operationId")
+ .extension(new OctetsFW.Builder().wrap(writeBuffer, 0, 1).set(new byte[] {1}).build())
+ .build();
+
+ assertNotNull(matcher.match(byteBuf));
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/config/SchemaTest.java b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/config/SchemaTest.java
new file mode 100644
index 0000000000..b7b6a8bf6d
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/config/SchemaTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi.config;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+
+import jakarta.json.JsonObject;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import io.aklivity.zilla.specs.engine.config.ConfigSchemaRule;
+
+public class SchemaTest
+{
+ @Rule
+ public final ConfigSchemaRule schema = new ConfigSchemaRule()
+ .schemaPatch("io/aklivity/zilla/specs/binding/asyncapi/schema/asyncapi.schema.patch.json")
+ .schemaPatch("io/aklivity/zilla/specs/engine/schema/vault/test.schema.patch.json")
+ .configurationRoot("io/aklivity/zilla/specs/binding/asyncapi/config");
+
+ @Test
+ public void shouldValidateMqttClient()
+ {
+ JsonObject config = schema.validate("client.mqtt.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateMqttSecureClient()
+ {
+ JsonObject config = schema.validate("client.mqtt.secure.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateMqttServer()
+ {
+ JsonObject config = schema.validate("server.mqtt.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateMqttSecureServer()
+ {
+ JsonObject config = schema.validate("server.mqtt.secure.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateHttpClient()
+ {
+ JsonObject config = schema.validate("client.http.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateHttpSecureClient()
+ {
+ JsonObject config = schema.validate("client.http.secure.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateHttpServer()
+ {
+ JsonObject config = schema.validate("server.http.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateHttpSecureServer()
+ {
+ JsonObject config = schema.validate("server.http.secure.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateKafkaClient()
+ {
+ JsonObject config = schema.validate("client.kafka.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateKafkaClientSasl()
+ {
+ JsonObject config = schema.validate("client.kafka.sasl.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+
+ @Test
+ public void shouldValidateAsyncapiProxy()
+ {
+ JsonObject config = schema.validate("proxy.mqtt.kafka.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/HttpIT.java b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/HttpIT.java
new file mode 100644
index 0000000000..a12163b237
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/HttpIT.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi.streams;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.rules.RuleChain.outerRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+import org.kaazing.k3po.junit.annotation.Specification;
+import org.kaazing.k3po.junit.rules.K3poRule;
+
+public class HttpIT
+{
+ private final K3poRule k3po = new K3poRule()
+ .addScriptRoot("http", "io/aklivity/zilla/specs/binding/asyncapi/streams/http");
+
+ private final TestRule timeout = new DisableOnDebug(new Timeout(5, SECONDS));
+
+ @Rule
+ public final TestRule chain = outerRule(k3po).around(timeout);
+
+
+ @Test
+ @Specification({
+ "${http}/create.pet/client",
+ "${http}/create.pet/server"
+ })
+ public void shouldCreatePet() throws Exception
+ {
+ k3po.finish();
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/KafkaIT.java b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/KafkaIT.java
new file mode 100644
index 0000000000..9e43d077af
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/KafkaIT.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi.streams;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.rules.RuleChain.outerRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+import org.kaazing.k3po.junit.annotation.Specification;
+import org.kaazing.k3po.junit.rules.K3poRule;
+
+public class KafkaIT
+{
+ private final K3poRule k3po = new K3poRule()
+ .addScriptRoot("kafka", "io/aklivity/zilla/specs/binding/asyncapi/streams/kafka");
+
+ private final TestRule timeout = new DisableOnDebug(new Timeout(5, SECONDS));
+
+ @Rule
+ public final TestRule chain = outerRule(k3po).around(timeout);
+
+
+ @Test
+ @Specification({
+ "${kafka}/produce.message/client",
+ "${kafka}/produce.message/server"
+ })
+ public void shouldProduceMessage() throws Exception
+ {
+ k3po.finish();
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/MqttIT.java b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/MqttIT.java
new file mode 100644
index 0000000000..51ac9a8bec
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/MqttIT.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi.streams;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.rules.RuleChain.outerRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+import org.kaazing.k3po.junit.annotation.Specification;
+import org.kaazing.k3po.junit.rules.K3poRule;
+
+public class MqttIT
+{
+ private final K3poRule k3po = new K3poRule()
+ .addScriptRoot("mqtt", "io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt");
+
+ private final TestRule timeout = new DisableOnDebug(new Timeout(5, SECONDS));
+
+ @Rule
+ public final TestRule chain = outerRule(k3po).around(timeout);
+
+
+ @Test
+ @Specification({
+ "${mqtt}/publish.and.subscribe/client",
+ "${mqtt}/publish.and.subscribe/server"
+ })
+ public void shouldPublishAndSubscribe() throws Exception
+ {
+ k3po.finish();
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/AsyncapiIT.java b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/AsyncapiIT.java
new file mode 100644
index 0000000000..77b4cbaf38
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/AsyncapiIT.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi.streams.asyncapi;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.rules.RuleChain.outerRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+import org.kaazing.k3po.junit.annotation.Specification;
+import org.kaazing.k3po.junit.rules.K3poRule;
+
+public class AsyncapiIT
+{
+ private final K3poRule k3po = new K3poRule()
+ .addScriptRoot("asyncapi", "io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi");
+
+ private final TestRule timeout = new DisableOnDebug(new Timeout(5, SECONDS));
+
+ @Rule
+ public final TestRule chain = outerRule(k3po).around(timeout);
+
+ @Test
+ @Specification({
+ "${asyncapi}/mqtt/publish.and.subscribe/client",
+ "${asyncapi}/mqtt/publish.and.subscribe/server"
+ })
+ public void shouldPublishAndSubscribe() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${asyncapi}/http/create.pet/client",
+ "${asyncapi}/http/create.pet/server"
+ })
+ public void shouldCreatePet() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${asyncapi}/kafka/produce.message/client",
+ "${asyncapi}/kafka/produce.message/server"
+ })
+ public void shouldProduceMessage() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${asyncapi}/proxy.kafka.publish/client",
+ "${asyncapi}/proxy.kafka.publish/server"
+ })
+ public void shouldProxyPublishMessageKafka() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${asyncapi}/proxy.mqtt.publish/client",
+ "${asyncapi}/proxy.mqtt.publish/server"
+ })
+ public void shouldProxyPublishMessageMqtt() throws Exception
+ {
+ k3po.finish();
+ }
+}
diff --git a/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/http/HttpIT.java b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/http/HttpIT.java
new file mode 100644
index 0000000000..ccddb26bbd
--- /dev/null
+++ b/incubator/binding-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/asyncapi/streams/http/HttpIT.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc.
+ *
+ * Aklivity licenses this file to you 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.
+ */
+package io.aklivity.zilla.specs.binding.asyncapi.streams.http;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.rules.RuleChain.outerRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+import org.kaazing.k3po.junit.annotation.Specification;
+import org.kaazing.k3po.junit.rules.K3poRule;
+
+public class HttpIT
+{
+ private final K3poRule k3po = new K3poRule()
+ .addScriptRoot("http", "io/aklivity/zilla/specs/binding/asyncapi/streams/http");
+
+ private final TestRule timeout = new DisableOnDebug(new Timeout(5, SECONDS));
+
+ @Rule
+ public final TestRule chain = outerRule(k3po).around(timeout);
+
+
+ @Test
+ @Specification({
+ "${http}/create.pet/client",
+ "${http}/create.pet/server"
+ })
+ public void shouldCreatePet() throws Exception
+ {
+ k3po.finish();
+ }
+}
diff --git a/incubator/binding-asyncapi/COPYRIGHT b/incubator/binding-asyncapi/COPYRIGHT
new file mode 100644
index 0000000000..0cb10b6f62
--- /dev/null
+++ b/incubator/binding-asyncapi/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyright ${copyrightYears} Aklivity Inc
+
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
diff --git a/incubator/binding-asyncapi/LICENSE b/incubator/binding-asyncapi/LICENSE
new file mode 100644
index 0000000000..f6abb6327b
--- /dev/null
+++ b/incubator/binding-asyncapi/LICENSE
@@ -0,0 +1,114 @@
+ Aklivity Community License Agreement
+ Version 1.0
+
+This Aklivity Community License Agreement Version 1.0 (the “Agreement”) sets
+forth the terms on which Aklivity, Inc. (“Aklivity”) makes available certain
+software made available by Aklivity under this Agreement (the “Software”). BY
+INSTALLING, DOWNLOADING, ACCESSING, USING OR DISTRIBUTING ANY OF THE SOFTWARE,
+YOU AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE TO
+SUCH TERMS AND CONDITIONS, YOU MUST NOT USE THE SOFTWARE. IF YOU ARE RECEIVING
+THE SOFTWARE ON BEHALF OF A LEGAL ENTITY, YOU REPRESENT AND WARRANT THAT YOU
+HAVE THE ACTUAL AUTHORITY TO AGREE TO THE TERMS AND CONDITIONS OF THIS
+AGREEMENT ON BEHALF OF SUCH ENTITY. “Licensee” means you, an individual, or
+the entity on whose behalf you are receiving the Software.
+
+ 1. LICENSE GRANT AND CONDITIONS.
+
+ 1.1 License. Subject to the terms and conditions of this Agreement,
+ Aklivity hereby grants to Licensee a non-exclusive, royalty-free,
+ worldwide, non-transferable, non-sublicenseable license during the term
+ of this Agreement to: (a) use the Software; (b) prepare modifications and
+ derivative works of the Software; (c) distribute the Software (including
+ without limitation in source code or object code form); and (d) reproduce
+ copies of the Software (the “License”). Licensee is not granted the
+ right to, and Licensee shall not, exercise the License for an Excluded
+ Purpose. For purposes of this Agreement, “Excluded Purpose” means making
+ available any software-as-a-service, platform-as-a-service,
+ infrastructure-as-a-service or other similar online service that competes
+ with Aklivity products or services that provide the Software.
+
+ 1.2 Conditions. In consideration of the License, Licensee’s distribution
+ of the Software is subject to the following conditions:
+
+ (a) Licensee must cause any Software modified by Licensee to carry
+ prominent notices stating that Licensee modified the Software.
+
+ (b) On each Software copy, Licensee shall reproduce and not remove or
+ alter all Aklivity or third party copyright or other proprietary
+ notices contained in the Software, and Licensee must provide the
+ notice below with each copy.
+
+ “This software is made available by Aklivity, Inc., under the
+ terms of the Aklivity Community License Agreement, Version 1.0
+ located at http://www.Aklivity.io/Aklivity-community-license. BY
+ INSTALLING, DOWNLOADING, ACCESSING, USING OR DISTRIBUTING ANY OF
+ THE SOFTWARE, YOU AGREE TO THE TERMS OF SUCH LICENSE AGREEMENT.”
+
+ 1.3 Licensee Modifications. Licensee may add its own copyright notices
+ to modifications made by Licensee and may provide additional or different
+ license terms and conditions for use, reproduction, or distribution of
+ Licensee’s modifications. While redistributing the Software or
+ modifications thereof, Licensee may choose to offer, for a fee or free of
+ charge, support, warranty, indemnity, or other obligations. Licensee, and
+ not Aklivity, will be responsible for any such obligations.
+
+ 1.4 No Sublicensing. The License does not include the right to
+ sublicense the Software, however, each recipient to which Licensee
+ provides the Software may exercise the Licenses so long as such recipient
+ agrees to the terms and conditions of this Agreement.
+
+ 2. TERM AND TERMINATION. This Agreement will continue unless and until
+ earlier terminated as set forth herein. If Licensee breaches any of its
+ conditions or obligations under this Agreement, this Agreement will
+ terminate automatically and the License will terminate automatically and
+ permanently.
+
+ 3. INTELLECTUAL PROPERTY. As between the parties, Aklivity will retain all
+ right, title, and interest in the Software, and all intellectual property
+ rights therein. Aklivity hereby reserves all rights not expressly granted
+ to Licensee in this Agreement. Aklivity hereby reserves all rights in its
+ trademarks and service marks, and no licenses therein are granted in this
+ Agreement.
+
+ 4. DISCLAIMER. Aklivity HEREBY DISCLAIMS ANY AND ALL WARRANTIES AND
+ CONDITIONS, EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, AND SPECIFICALLY
+ DISCLAIMS ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+ PURPOSE, WITH RESPECT TO THE SOFTWARE.
+
+ 5. LIMITATION OF LIABILITY. Aklivity WILL NOT BE LIABLE FOR ANY DAMAGES OF
+ ANY KIND, INCLUDING BUT NOT LIMITED TO, LOST PROFITS OR ANY CONSEQUENTIAL,
+ SPECIAL, INCIDENTAL, INDIRECT, OR DIRECT DAMAGES, HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, ARISING OUT OF THIS AGREEMENT. THE FOREGOING SHALL
+ APPLY TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+
+ 6.GENERAL.
+
+ 6.1 Governing Law. This Agreement will be governed by and interpreted in
+ accordance with the laws of the state of California, without reference to
+ its conflict of laws principles. If Licensee is located within the
+ United States, all disputes arising out of this Agreement are subject to
+ the exclusive jurisdiction of courts located in Santa Clara County,
+ California. USA. If Licensee is located outside of the United States,
+ any dispute, controversy or claim arising out of or relating to this
+ Agreement will be referred to and finally determined by arbitration in
+ accordance with the JAMS International Arbitration Rules. The tribunal
+ will consist of one arbitrator. The place of arbitration will be Palo
+ Alto, California. The language to be used in the arbitral proceedings
+ will be English. Judgment upon the award rendered by the arbitrator may
+ be entered in any court having jurisdiction thereof.
+
+ 6.2 Assignment. Licensee is not authorized to assign its rights under
+ this Agreement to any third party. Aklivity may freely assign its rights
+ under this Agreement to any third party.
+
+ 6.3 Other. This Agreement is the entire agreement between the parties
+ regarding the subject matter hereof. No amendment or modification of
+ this Agreement will be valid or binding upon the parties unless made in
+ writing and signed by the duly authorized representatives of both
+ parties. In the event that any provision, including without limitation
+ any condition, of this Agreement is held to be unenforceable, this
+ Agreement and all licenses and rights granted hereunder will immediately
+ terminate. Waiver by Aklivity of a breach of any provision of this
+ Agreement or the failure by Aklivity to exercise any right hereunder
+ will not be construed as a waiver of any subsequent breach of that right
+ or as a waiver of any other right.
\ No newline at end of file
diff --git a/incubator/binding-asyncapi/NOTICE b/incubator/binding-asyncapi/NOTICE
new file mode 100644
index 0000000000..17478992e3
--- /dev/null
+++ b/incubator/binding-asyncapi/NOTICE
@@ -0,0 +1,18 @@
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+
+This project includes:
+ Jackson-annotations under The Apache Software License, Version 2.0
+ Jackson-core under The Apache Software License, Version 2.0
+ jackson-databind under The Apache Software License, Version 2.0
+ Jackson-dataformat-YAML under The Apache Software License, Version 2.0
+ SnakeYAML under Apache License, Version 2.0
+
diff --git a/incubator/binding-asyncapi/NOTICE.template b/incubator/binding-asyncapi/NOTICE.template
new file mode 100644
index 0000000000..209ca12f74
--- /dev/null
+++ b/incubator/binding-asyncapi/NOTICE.template
@@ -0,0 +1,13 @@
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+
+This project includes:
+#GENERATED_NOTICES#
diff --git a/incubator/binding-asyncapi/mvnw b/incubator/binding-asyncapi/mvnw
new file mode 100755
index 0000000000..d2f0ea3808
--- /dev/null
+++ b/incubator/binding-asyncapi/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/incubator/binding-asyncapi/mvnw.cmd b/incubator/binding-asyncapi/mvnw.cmd
new file mode 100644
index 0000000000..b26ab24f03
--- /dev/null
+++ b/incubator/binding-asyncapi/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/incubator/binding-asyncapi/pom.xml b/incubator/binding-asyncapi/pom.xml
new file mode 100644
index 0000000000..b7b34f4780
--- /dev/null
+++ b/incubator/binding-asyncapi/pom.xml
@@ -0,0 +1,342 @@
+
+
+
+ 4.0.0
+
+ io.aklivity.zilla
+ incubator
+ 0.9.69
+ ../pom.xml
+
+
+ binding-asyncapi
+ zilla::incubator::binding-asyncapi
+
+
+
+ Aklivity Community License Agreement
+ https://www.aklivity.io/aklivity-community-license/
+ repo
+
+
+
+
+ 11
+ 11
+ 0.60
+ 4
+
+
+
+
+ ${project.groupId}
+ binding-asyncapi.spec
+ ${project.version}
+ provided
+
+
+ ${project.groupId}
+ engine.spec
+ ${project.version}
+ provided
+
+
+ ${project.groupId}
+ engine
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ binding-mqtt
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ binding-http
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ binding-kafka
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ binding-tcp
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ binding-mqtt-kafka
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ binding-tls
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ catalog-inline
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ model-core
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ model-json
+ ${project.version}
+ provided
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+ 2.16.1
+
+
+ ${project.groupId}
+ engine
+ test-jar
+ ${project.version}
+ test
+
+
+ junit
+ junit
+ test
+
+
+ org.hamcrest
+ hamcrest
+ test
+
+
+ com.vtence.hamcrest
+ hamcrest-jpa
+ test
+
+
+ com.github.npathai
+ hamcrest-optional
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.kaazing
+ k3po.junit
+ test
+
+
+ org.kaazing
+ k3po.lang
+ test
+
+
+ io.aklivity.zilla
+ binding-mqtt-kafka
+ test-jar
+ ${project.version}
+ test
+
+
+ org.openjdk.jmh
+ jmh-core
+ test
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ test
+
+
+
+
+
+
+ ${project.groupId}
+ flyweight-maven-plugin
+ ${project.version}
+
+ core mqtt http kafka asyncapi
+ io.aklivity.zilla.runtime.binding.asyncapi.internal.types
+
+
+
+
+ generate
+
+
+
+
+
+ maven-dependency-plugin
+
+
+ process-resources
+
+ unpack
+
+
+
+
+ ${project.groupId}
+ binding-asyncapi.spec
+
+
+ ^\Qio/aklivity/zilla/specs/binding/asyncapi/\E
+ io/aklivity/zilla/runtime/binding/asyncapi/internal/
+
+
+
+
+ io/aklivity/zilla/specs/binding/asyncapi/schema/*.json
+ ${project.build.directory}/classes
+
+
+
+ extract-files
+ process-resources
+
+ unpack
+
+
+
+
+ ${project.groupId}
+ binding-asyncapi.spec
+ ${project.version}
+ ${basedir}/target/test-classes
+ **\/*.yaml
+
+
+
+
+
+
+
+ org.jasig.maven
+ maven-notice-plugin
+
+
+ com.mycila
+ license-maven-plugin
+
+
+ src/test/resources/io/aklivity/zilla/runtime/binding/asyncapi/internal/**/*
+
+
+
+
+ maven-checkstyle-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.moditect
+ moditect-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ test-jar
+
+
+
+
+
+ org.kaazing
+ k3po-maven-plugin
+
+
+ ${project.groupId}
+ engine
+ ${project.version}
+ test-jar
+
+
+ ${project.groupId}
+ engine
+ ${project.version}
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+ io/aklivity/zilla/runtime/binding/asyncapi/internal/types/**/*.class
+ io/aklivity/zilla/runtime/binding/asyncapi/internal/model/*.class
+ io/aklivity/zilla/runtime/binding/asyncapi/internal/model2/*.class
+
+
+
+ BUNDLE
+
+
+ INSTRUCTION
+ COVEREDRATIO
+ ${jacoco.coverage.ratio}
+
+
+ CLASS
+ MISSEDCOUNT
+ ${jacoco.missed.count}
+
+
+
+
+
+
+
+ io.gatling
+ maven-shade-plugin
+
+
+
+ org.agrona:agrona
+ io.aklivity.zilla:engine
+ org.openjdk.jmh:jmh-core
+ net.sf.jopt-simple:jopt-simple
+ org.apache.commons:commons-math3
+ commons-cli:commons-cli
+ com.github.biboudis:jmh-profilers
+
+
+
+
+
+
+
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiChannelsConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiChannelsConfig.java
new file mode 100644
index 0000000000..4b80d6f882
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiChannelsConfig.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.config;
+
+import java.util.function.Function;
+
+public class AsyncapiChannelsConfig
+{
+ public final String sessions;
+ public final String messages;
+ public final String retained;
+
+ public static AsyncapiChannelsConfigBuilder builder()
+ {
+ return new AsyncapiChannelsConfigBuilder<>(AsyncapiChannelsConfig.class::cast);
+ }
+
+ public static AsyncapiChannelsConfigBuilder builder(
+ Function mapper)
+ {
+ return new AsyncapiChannelsConfigBuilder<>(mapper);
+ }
+
+ public AsyncapiChannelsConfig(
+ String sessions,
+ String messages,
+ String retained)
+ {
+ this.sessions = sessions;
+ this.messages = messages;
+ this.retained = retained;
+ }
+}
+
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiChannelsConfigBuilder.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiChannelsConfigBuilder.java
new file mode 100644
index 0000000000..815d38ab62
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiChannelsConfigBuilder.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.config;
+
+import java.util.function.Function;
+
+import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
+public class AsyncapiChannelsConfigBuilder extends ConfigBuilder>
+{
+ private final Function mapper;
+
+ private String sessions;
+ private String messages;
+ private String retained;
+ AsyncapiChannelsConfigBuilder(
+ Function mapper)
+ {
+ this.mapper = mapper;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Class> thisType()
+ {
+ return (Class>) getClass();
+ }
+
+
+ public AsyncapiChannelsConfigBuilder sessions(
+ String sessions)
+ {
+ this.sessions = sessions;
+ return this;
+ }
+
+ public AsyncapiChannelsConfigBuilder messages(
+ String messages)
+ {
+ this.messages = messages;
+ return this;
+ }
+
+ public AsyncapiChannelsConfigBuilder retained(
+ String retained)
+ {
+ this.retained = retained;
+ return this;
+ }
+
+
+ @Override
+ public T build()
+ {
+ return mapper.apply(
+ new AsyncapiChannelsConfig(sessions, messages, retained));
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiConfig.java
new file mode 100644
index 0000000000..628692248a
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiConfig.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.config;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+
+public class AsyncapiConfig
+{
+ public final String apiLabel;
+ public final long apiId;
+ public final String location;
+ public final Asyncapi asyncapi;
+
+ public AsyncapiConfig(
+ String apiLabel,
+ long apiId,
+ String location,
+ Asyncapi asyncapi)
+ {
+ this.apiLabel = apiLabel;
+ this.apiId = apiId;
+ this.location = location;
+ this.asyncapi = asyncapi;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiMqttKafkaConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiMqttKafkaConfig.java
new file mode 100644
index 0000000000..a4e5190e8c
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiMqttKafkaConfig.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.config;
+
+import java.util.function.Function;
+
+public class AsyncapiMqttKafkaConfig
+{
+ public final AsyncapiChannelsConfig channels;
+
+ public static AsyncapiMqttKafkaConfigBuilder builder()
+ {
+ return new AsyncapiMqttKafkaConfigBuilder<>(AsyncapiMqttKafkaConfig.class::cast);
+ }
+
+ public static AsyncapiMqttKafkaConfigBuilder builder(
+ Function mapper)
+ {
+ return new AsyncapiMqttKafkaConfigBuilder<>(mapper);
+ }
+
+ public AsyncapiMqttKafkaConfig(
+ AsyncapiChannelsConfig channels)
+ {
+ this.channels = channels;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiMqttKafkaConfigBuilder.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiMqttKafkaConfigBuilder.java
new file mode 100644
index 0000000000..31c2566380
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiMqttKafkaConfigBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.config;
+
+import java.util.function.Function;
+
+import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
+
+public final class AsyncapiMqttKafkaConfigBuilder extends ConfigBuilder>
+{
+ private final Function mapper;
+ private AsyncapiChannelsConfig channels;
+
+ AsyncapiMqttKafkaConfigBuilder(
+ Function mapper)
+ {
+ this.mapper = mapper;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Class> thisType()
+ {
+ return (Class>) getClass();
+ }
+
+ public AsyncapiMqttKafkaConfigBuilder channels(
+ AsyncapiChannelsConfig channels)
+ {
+ this.channels = channels;
+ return this;
+ }
+
+ @Override
+ public T build()
+ {
+ return mapper.apply(new AsyncapiMqttKafkaConfig(channels));
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiOptionsConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiOptionsConfig.java
new file mode 100644
index 0000000000..105f83e5d5
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiOptionsConfig.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.config;
+
+import java.util.List;
+import java.util.function.Function;
+
+import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfig;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaOptionsConfig;
+import io.aklivity.zilla.runtime.binding.tcp.config.TcpOptionsConfig;
+import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig;
+import io.aklivity.zilla.runtime.engine.config.OptionsConfig;
+
+public final class AsyncapiOptionsConfig extends OptionsConfig
+{
+ public final List specs;
+ public final TcpOptionsConfig tcp;
+ public final TlsOptionsConfig tls;
+ public final HttpOptionsConfig http;
+ public final KafkaOptionsConfig kafka;
+ public final AsyncapiMqttKafkaConfig mqttKafka;
+
+ public static AsyncapiOptionsConfigBuilder builder()
+ {
+ return new AsyncapiOptionsConfigBuilder<>(AsyncapiOptionsConfig.class::cast);
+ }
+
+ public static AsyncapiOptionsConfigBuilder builder(
+ Function mapper)
+ {
+ return new AsyncapiOptionsConfigBuilder<>(mapper);
+ }
+
+ public AsyncapiOptionsConfig(
+ List specs,
+ TcpOptionsConfig tcp,
+ TlsOptionsConfig tls,
+ HttpOptionsConfig http,
+ KafkaOptionsConfig kafka,
+ AsyncapiMqttKafkaConfig mqttKafka)
+ {
+ this.specs = specs;
+ this.http = http;
+ this.tcp = tcp;
+ this.tls = tls;
+ this.kafka = kafka;
+ this.mqttKafka = mqttKafka;
+ }
+
+ public long resolveApiId(
+ String apiLabel)
+ {
+ long apiId = -1;
+ for (AsyncapiConfig c : specs)
+ {
+ if (c.apiLabel.equals(apiLabel))
+ {
+ apiId = c.apiId;
+ break;
+ }
+ }
+ return apiId;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiOptionsConfigBuilder.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiOptionsConfigBuilder.java
new file mode 100644
index 0000000000..06d9a852e0
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiOptionsConfigBuilder.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.config;
+
+import java.util.List;
+import java.util.function.Function;
+
+import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfig;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaOptionsConfig;
+import io.aklivity.zilla.runtime.binding.tcp.config.TcpOptionsConfig;
+import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig;
+import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.OptionsConfig;
+
+public final class AsyncapiOptionsConfigBuilder extends ConfigBuilder>
+{
+ private static final String DEFAULT_SESSIONS_CHANNEL = "mqttSessions";
+ private static final String DEFAULT_RETAINED_CHANNEL = "mqttRetained";
+ private static final String DEFAULT_MESSAGES_CHANNEL = "mqttMessages";
+ private static final AsyncapiMqttKafkaConfig DEFAULT_MQTT_KAFKA =
+ AsyncapiMqttKafkaConfig.builder()
+ .channels(AsyncapiChannelsConfig.builder()
+ .sessions(DEFAULT_SESSIONS_CHANNEL)
+ .messages(DEFAULT_MESSAGES_CHANNEL)
+ .retained(DEFAULT_RETAINED_CHANNEL)
+ .build())
+ .build();
+
+ private final Function mapper;
+
+ public List specs;
+ private TcpOptionsConfig tcp;
+ private TlsOptionsConfig tls;
+ private HttpOptionsConfig http;
+ private KafkaOptionsConfig kafka;
+ private AsyncapiMqttKafkaConfig mqttKafka = DEFAULT_MQTT_KAFKA;
+
+ AsyncapiOptionsConfigBuilder(
+ Function mapper)
+ {
+ this.mapper = mapper;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Class> thisType()
+ {
+ return (Class>) getClass();
+ }
+
+ public AsyncapiOptionsConfigBuilder specs(
+ List specs)
+ {
+ this.specs = specs;
+ return this;
+ }
+
+ public AsyncapiOptionsConfigBuilder tcp(
+ TcpOptionsConfig tcp)
+ {
+ this.tcp = tcp;
+ return this;
+ }
+
+ public AsyncapiOptionsConfigBuilder tls(
+ TlsOptionsConfig tls)
+ {
+ this.tls = tls;
+ return this;
+ }
+
+ public AsyncapiOptionsConfigBuilder http(
+ HttpOptionsConfig http)
+ {
+ this.http = http;
+ return this;
+ }
+
+ public AsyncapiOptionsConfigBuilder kafka(
+ KafkaOptionsConfig kafka)
+ {
+ this.kafka = kafka;
+ return this;
+ }
+
+ public AsyncapiOptionsConfigBuilder mqttKafka(
+ AsyncapiMqttKafkaConfig mqttKafka)
+ {
+ this.mqttKafka = mqttKafka;
+ return this;
+ }
+
+ @Override
+ public T build()
+ {
+ return mapper.apply(new AsyncapiOptionsConfig(specs, tcp, tls, http, kafka, mqttKafka));
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiParser.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiParser.java
new file mode 100644
index 0000000000..403b966819
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/config/AsyncapiParser.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.config;
+
+import static java.util.Collections.unmodifiableMap;
+import static org.agrona.LangUtil.rethrowUnchecked;
+
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonReader;
+import jakarta.json.bind.Jsonb;
+import jakarta.json.bind.JsonbBuilder;
+
+import org.agrona.collections.Object2ObjectHashMap;
+import org.leadpony.justify.api.JsonSchema;
+import org.leadpony.justify.api.JsonValidationService;
+import org.leadpony.justify.api.ProblemHandler;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiBinding;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+import io.aklivity.zilla.runtime.engine.config.ConfigException;
+
+public class AsyncapiParser
+{
+ private final Map schemas;
+
+ public AsyncapiParser()
+ {
+ Map schemas = new Object2ObjectHashMap<>();
+ schemas.put("2.6.0", schema("2.6.0"));
+ schemas.put("3.0.0", schema("3.0.0"));
+ this.schemas = unmodifiableMap(schemas);
+ }
+
+ public Asyncapi parse(
+ String asyncapiText)
+ {
+ Asyncapi asyncapi = null;
+
+ List errors = new LinkedList<>();
+
+ try
+ {
+ String asyncApiVersion = detectAsyncApiVersion(asyncapiText);
+
+ JsonValidationService service = JsonValidationService.newInstance();
+ ProblemHandler handler = service.createProblemPrinter(msg -> errors.add(new ConfigException(msg)));
+ JsonSchema schema = schemas.get(asyncApiVersion);
+
+ service.createReader(new StringReader(asyncapiText), schema, handler).read();
+
+ Jsonb jsonb = JsonbBuilder.create();
+
+ asyncapi = jsonb.fromJson(asyncapiText, Asyncapi.class);
+ }
+ catch (Exception ex)
+ {
+ errors.add(ex);
+ }
+
+ if (!errors.isEmpty())
+ {
+ Exception ex = errors.remove(0);
+ errors.forEach(ex::addSuppressed);
+ rethrowUnchecked(ex);
+ }
+
+ return asyncapi;
+ }
+
+ private JsonSchema schema(
+ String version)
+ {
+ InputStream schemaInput = null;
+
+ if (version.startsWith("2.6"))
+ {
+ schemaInput = AsyncapiBinding.class.getResourceAsStream("schema/asyncapi.2.6.schema.json");
+ }
+ else if (version.startsWith("3.0"))
+ {
+ schemaInput = AsyncapiBinding.class.getResourceAsStream("schema/asyncapi.3.0.schema.json");
+ }
+
+ JsonValidationService service = JsonValidationService.newInstance();
+
+ return service.createSchemaReaderFactoryBuilder()
+ .withSpecVersionDetection(true)
+ .build()
+ .createSchemaReader(schemaInput)
+ .read();
+ }
+
+ private String detectAsyncApiVersion(
+ String openapiText)
+ {
+ try (JsonReader reader = Json.createReader(new StringReader(openapiText)))
+ {
+ JsonObject json = reader.readObject();
+ if (json.containsKey("asyncapi"))
+ {
+ return json.getString("asyncapi");
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unable to determine AsyncApi version.");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Error reading AsyncApi document.", e);
+ }
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBinding.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBinding.java
new file mode 100644
index 0000000000..45ed67c811
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBinding.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import java.net.URL;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.binding.Binding;
+import io.aklivity.zilla.runtime.engine.config.KindConfig;
+
+public final class AsyncapiBinding implements Binding
+{
+ public static final String NAME = "asyncapi";
+
+ private final AsyncapiConfiguration config;
+
+ AsyncapiBinding(
+ AsyncapiConfiguration config)
+ {
+ this.config = config;
+ }
+
+ @Override
+ public String name()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public URL type()
+ {
+ return getClass().getResource("schema/asyncapi.schema.patch.json");
+ }
+
+ @Override
+ public String originType(
+ KindConfig kind)
+ {
+ return kind == KindConfig.CLIENT ? NAME : null;
+ }
+
+ @Override
+ public String routedType(
+ KindConfig kind)
+ {
+ return kind == KindConfig.SERVER ? NAME : null;
+ }
+
+ @Override
+ public AsyncapiBindingContext supply(
+ EngineContext context)
+ {
+ return new AsyncapiBindingContext(config, context);
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingAdapter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingAdapter.java
new file mode 100644
index 0000000000..8f4af3e8fa
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingAdapter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.CLIENT;
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.PROXY;
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.SERVER;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.function.UnaryOperator;
+
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+import io.aklivity.zilla.runtime.engine.config.CompositeBindingAdapterSpi;
+import io.aklivity.zilla.runtime.engine.config.KindConfig;
+
+public class AsyncapiBindingAdapter implements CompositeBindingAdapterSpi
+{
+ private final Map> composites;
+
+ public AsyncapiBindingAdapter()
+ {
+ Map> composites = new EnumMap<>(KindConfig.class);
+ composites.put(SERVER, new AsyncapiServerCompositeBindingAdapter()::adapt);
+ composites.put(CLIENT, new AsyncapiClientCompositeBindingAdapter()::adapt);
+ composites.put(PROXY, new AsyncapiProxyCompositeBindingAdapter()::adapt);
+ this.composites = composites;
+ }
+
+ @Override
+ public String type()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public BindingConfig adapt(
+ BindingConfig binding)
+ {
+ return composites.get(binding.kind).apply(binding);
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingContext.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingContext.java
new file mode 100644
index 0000000000..d97c23edb7
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingContext.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.CLIENT;
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.PROXY;
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.SERVER;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.stream.AsyncapiClientFactory;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.stream.AsyncapiProxyFactory;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.stream.AsyncapiServerFactory;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.stream.AsyncapiStreamFactory;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.binding.BindingContext;
+import io.aklivity.zilla.runtime.engine.binding.BindingHandler;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+import io.aklivity.zilla.runtime.engine.config.KindConfig;
+
+final class AsyncapiBindingContext implements BindingContext
+{
+ private final Map factories;
+
+ AsyncapiBindingContext(
+ AsyncapiConfiguration config,
+ EngineContext context)
+ {
+ Map factories = new EnumMap<>(KindConfig.class);
+ factories.put(SERVER, new AsyncapiServerFactory(config, context));
+ factories.put(CLIENT, new AsyncapiClientFactory(config, context));
+ factories.put(PROXY, new AsyncapiProxyFactory(config, context));
+ this.factories = factories;
+ }
+
+ @Override
+ public BindingHandler attach(
+ BindingConfig binding)
+ {
+ AsyncapiStreamFactory factory = factories.get(binding.kind);
+
+ if (factory != null)
+ {
+ factory.attach(binding);
+ }
+
+ return factory;
+ }
+
+ @Override
+ public void detach(
+ BindingConfig binding)
+ {
+ AsyncapiStreamFactory factory = factories.get(binding.kind);
+
+ if (factory != null)
+ {
+ factory.detach(binding.id);
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s %s", getClass().getSimpleName(), factories);
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingFactorySpi.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingFactorySpi.java
new file mode 100644
index 0000000000..e55fb89fd0
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiBindingFactorySpi.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import io.aklivity.zilla.runtime.common.feature.Incubating;
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.binding.BindingFactorySpi;
+
+@Incubating
+public final class AsyncapiBindingFactorySpi implements BindingFactorySpi
+{
+ @Override
+ public String type()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public AsyncapiBinding create(
+ Configuration config)
+ {
+ return new AsyncapiBinding(new AsyncapiConfiguration(config));
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiClientCompositeBindingAdapter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiClientCompositeBindingAdapter.java
new file mode 100644
index 0000000000..2beccbbd22
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiClientCompositeBindingAdapter.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.CLIENT;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+import io.aklivity.zilla.runtime.engine.config.CompositeBindingAdapterSpi;
+import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder;
+
+public class AsyncapiClientCompositeBindingAdapter extends AsyncapiCompositeBindingAdapter implements CompositeBindingAdapterSpi
+{
+ @Override
+ public String type()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public BindingConfig adapt(
+ BindingConfig binding)
+ {
+ AsyncapiOptionsConfig options = (AsyncapiOptionsConfig) binding.options;
+ AsyncapiConfig asyncapiConfig = options.specs.get(0);
+ this.asyncapi = asyncapiConfig.asyncapi;
+
+ //TODO: add composite for all servers
+ AsyncapiServerView firstServer = AsyncapiServerView.of(asyncapi.servers.entrySet().iterator().next().getValue());
+ this.qname = binding.qname;
+ this.qvault = binding.qvault;
+ this.protocol = resolveProtocol(firstServer.protocol(), options);
+ this.isTlsEnabled = protocol.isSecure();
+
+ return BindingConfig.builder(binding)
+ .composite()
+ .name(String.format("%s.%s", qname, "$composite"))
+ .inject(n -> this.injectCatalog(n, asyncapi))
+ .inject(protocol::injectProtocolClientCache)
+ .binding()
+ .name(String.format("%s_client0", protocol.scheme))
+ .type(protocol.scheme)
+ .kind(CLIENT)
+ .inject(protocol::injectProtocolClientOptions)
+ .exit(isTlsEnabled ? "tls_client0" : "tcp_client0")
+ .build()
+ .inject(n -> injectTlsClient(n, options))
+ .binding()
+ .name("tcp_client0")
+ .type("tcp")
+ .kind(CLIENT)
+ .options(options.tcp)
+ .build()
+ .build()
+ .build();
+ }
+
+ private NamespaceConfigBuilder injectTlsClient(
+ NamespaceConfigBuilder namespace,
+ AsyncapiOptionsConfig options)
+ {
+ if (isTlsEnabled)
+ {
+ namespace
+ .binding()
+ .name("tls_client0")
+ .type("tls")
+ .kind(CLIENT)
+ .options(options.tls)
+ .vault(qvault)
+ .exit("tcp_client0")
+ .build();
+ }
+ return namespace;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiCompositeBindingAdapter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiCompositeBindingAdapter.java
new file mode 100644
index 0000000000..127a2afbba
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiCompositeBindingAdapter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.MINIMIZE_QUOTES;
+import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.WRITE_DOC_START_MARKER;
+import static org.agrona.LangUtil.rethrowUnchecked;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jakarta.json.bind.Jsonb;
+import jakarta.json.bind.JsonbBuilder;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiSchema;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiSchemaView;
+import io.aklivity.zilla.runtime.catalog.inline.config.InlineOptionsConfig;
+import io.aklivity.zilla.runtime.catalog.inline.config.InlineSchemaConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder;
+
+public class AsyncapiCompositeBindingAdapter
+{
+ protected static final String INLINE_CATALOG_NAME = "catalog0";
+ protected static final String INLINE_CATALOG_TYPE = "inline";
+ protected static final String VERSION_LATEST = "latest";
+ protected static final String APPLICATION_JSON = "application/json";
+
+ protected Asyncapi asyncapi;
+ protected Map asyncApis;
+ protected boolean isTlsEnabled;
+ protected AsyncapiProtocol protocol;
+ protected String qname;
+ protected String qvault;
+
+
+ protected AsyncapiProtocol resolveProtocol(
+ String protocolName,
+ AsyncapiOptionsConfig options)
+ {
+ Pattern pattern = Pattern.compile("(http|mqtt|kafka)");
+ Matcher matcher = pattern.matcher(protocolName);
+ AsyncapiProtocol protocol = null;
+ if (matcher.find())
+ {
+ switch (matcher.group())
+ {
+ case "http":
+ protocol = new AsyncapiHttpProtocol(qname, asyncapi, options);
+ break;
+ case "mqtt":
+ protocol = new AyncapiMqttProtocol(qname, asyncapi);
+ break;
+ case "kafka":
+ case "kafka-secure":
+ protocol = new AyncapiKafkaProtocol(qname, asyncapi, options, protocolName);
+ break;
+ }
+ }
+ else
+ {
+ // TODO: should we do something?
+ }
+ return protocol;
+ }
+
+ protected NamespaceConfigBuilder injectCatalog(
+ NamespaceConfigBuilder namespace,
+ Asyncapi asyncapi)
+ {
+ if (asyncapi.components != null && asyncapi.components.schemas != null && !asyncapi.components.schemas.isEmpty())
+ {
+ namespace
+ .catalog()
+ .name(INLINE_CATALOG_NAME)
+ .type(INLINE_CATALOG_TYPE)
+ .options(InlineOptionsConfig::builder)
+ .subjects()
+ .inject(this::injectSubjects)
+ .build()
+ .build()
+ .build();
+
+ }
+ return namespace;
+ }
+
+ protected InlineSchemaConfigBuilder injectSubjects(
+ InlineSchemaConfigBuilder subjects)
+ {
+ try (Jsonb jsonb = JsonbBuilder.create())
+ {
+ YAMLMapper yaml = YAMLMapper.builder()
+ .disable(WRITE_DOC_START_MARKER)
+ .enable(MINIMIZE_QUOTES)
+ .build();
+ for (Map.Entry entry : asyncapi.components.schemas.entrySet())
+ {
+ AsyncapiSchemaView schema = AsyncapiSchemaView.of(asyncapi.components.schemas, entry.getValue());
+ subjects
+ .subject(entry.getKey())
+ .version(VERSION_LATEST)
+ .schema(writeSchemaYaml(jsonb, yaml, schema))
+ .build();
+ }
+ }
+ catch (Exception ex)
+ {
+ rethrowUnchecked(ex);
+ }
+ return subjects;
+ }
+
+ protected static String writeSchemaYaml(
+ Jsonb jsonb,
+ YAMLMapper yaml,
+ Object schema)
+ {
+ String result = null;
+ try
+ {
+ String schemaJson = jsonb.toJson(schema);
+ JsonNode json = new ObjectMapper().readTree(schemaJson);
+ result = yaml.writeValueAsString(json);
+ }
+ catch (JsonProcessingException ex)
+ {
+ rethrowUnchecked(ex);
+ }
+ return result;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiConfiguration.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiConfiguration.java
new file mode 100644
index 0000000000..bf602321da
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+
+public class AsyncapiConfiguration extends Configuration
+{
+ public static final LongPropertyDef ASYNCAPI_TARGET_ROUTE_ID;
+ private static final ConfigurationDef ASYNCAPI_CONFIG;
+
+ static
+ {
+ final ConfigurationDef config = new ConfigurationDef("zilla.binding.asyncapi");
+ ASYNCAPI_TARGET_ROUTE_ID = config.property("target.route.id", -1L);
+ ASYNCAPI_CONFIG = config;
+ }
+
+ public AsyncapiConfiguration(
+ Configuration config)
+ {
+ super(ASYNCAPI_CONFIG, config);
+ }
+
+ public long targetRouteId()
+ {
+ return ASYNCAPI_TARGET_ROUTE_ID.getAsLong(this);
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiHttpProtocol.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiHttpProtocol.java
new file mode 100644
index 0000000000..bbcc1757ec
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiHttpProtocol.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static io.aklivity.zilla.runtime.binding.http.config.HttpPolicyConfig.CROSS_ORIGIN;
+import static java.util.Objects.requireNonNull;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiItem;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiMessage;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiOperation;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiParameter;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiServer;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiChannelView;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiMessageView;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView;
+import io.aklivity.zilla.runtime.binding.http.config.HttpAuthorizationConfig;
+import io.aklivity.zilla.runtime.binding.http.config.HttpConditionConfig;
+import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfig;
+import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfigBuilder;
+import io.aklivity.zilla.runtime.binding.http.config.HttpRequestConfig.Method;
+import io.aklivity.zilla.runtime.binding.http.config.HttpRequestConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.GuardedConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.config.RouteConfigBuilder;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class AsyncapiHttpProtocol extends AsyncapiProtocol
+{
+ private static final Map MODELS = Map.of(
+ "string", StringModelConfig.builder().build(),
+ "integer", IntegerModelConfig.builder().build()
+ );
+ private static final String SCHEME = "http";
+ private static final String SECURE_SCHEME = "https";
+ private final Map securitySchemes;
+ private final String authorizationHeader;
+ private final boolean isJwtEnabled;
+ private final String guardName;
+ private final HttpAuthorizationConfig authorization;
+
+ protected AsyncapiHttpProtocol(
+ String qname,
+ Asyncapi asyncApi,
+ AsyncapiOptionsConfig options)
+ {
+ super(qname, asyncApi, SCHEME, SECURE_SCHEME);
+ this.securitySchemes = resolveSecuritySchemes();
+ this.authorizationHeader = resolveAuthorizationHeader();
+ this.isJwtEnabled = !securitySchemes.isEmpty();
+ final HttpOptionsConfig httpOptions = options.http;
+ this.guardName = httpOptions != null ? httpOptions.authorization.name : null;
+ this.authorization = httpOptions != null ? httpOptions.authorization : null;
+ }
+
+
+ @Override
+ public BindingConfigBuilder injectProtocolServerOptions(
+ BindingConfigBuilder binding)
+ {
+ return binding
+ .options(HttpOptionsConfig::builder)
+ .access()
+ .policy(CROSS_ORIGIN)
+ .build()
+ .inject(this::injectHttpServerOptions)
+ .inject(this::injectHttpServerRequests)
+ .build();
+ }
+
+ @Override
+ public BindingConfigBuilder injectProtocolServerRoutes(
+ BindingConfigBuilder binding)
+ {
+ for (Map.Entry entry : asyncApi.servers.entrySet())
+ {
+ AsyncapiServerView server = AsyncapiServerView.of(entry.getValue());
+ for (String name : asyncApi.operations.keySet())
+ {
+ AsyncapiOperation operation = asyncApi.operations.get(name);
+ AsyncapiChannelView channel = AsyncapiChannelView.of(asyncApi.channels, operation.channel);
+ String path = channel.address().replaceAll("\\{[^}]+\\}", "*");
+ String method = operation.bindings.get("http").method;
+ binding
+ .route()
+ .exit(qname)
+ .when(HttpConditionConfig::builder)
+ .header(":scheme", server.scheme())
+ .header(":authority", server.authority())
+ .header(":path", path)
+ .header(":method", method)
+ .build()
+ .inject(route -> injectHttpServerRouteGuarded(route, server))
+ .build();
+ }
+ }
+ return binding;
+ }
+
+ @Override
+ protected boolean isSecure()
+ {
+ return findFirstServerUrlWithScheme(SECURE_SCHEME) != null;
+ }
+
+ private HttpOptionsConfigBuilder injectHttpServerOptions(
+ HttpOptionsConfigBuilder options)
+ {
+ if (isJwtEnabled)
+ {
+ options.authorization(authorization).build();
+ }
+ return options;
+ }
+
+ private HttpOptionsConfigBuilder injectHttpServerRequests(
+ HttpOptionsConfigBuilder options)
+ {
+ for (String name : asyncApi.operations.keySet())
+ {
+ AsyncapiOperation operation = asyncApi.operations.get(name);
+ AsyncapiChannelView channel = AsyncapiChannelView.of(asyncApi.channels, operation.channel);
+ String path = channel.address();
+ Method method = Method.valueOf(operation.bindings.get("http").method);
+ if (channel.messages() != null && !channel.messages().isEmpty() ||
+ channel.parameters() != null && !channel.parameters().isEmpty())
+ {
+ options
+ .request()
+ .path(path)
+ .method(method)
+ .inject(request -> injectContent(request, channel.messages()))
+ .inject(request -> injectPathParams(request, channel.parameters()))
+ .build();
+ }
+ }
+ return options;
+ }
+
+ private HttpRequestConfigBuilder injectContent(
+ HttpRequestConfigBuilder request,
+ Map messages)
+ {
+ if (messages != null)
+ {
+ if (hasJsonContentType())
+ {
+ request.
+ content(JsonModelConfig::builder)
+ .catalog()
+ .name(INLINE_CATALOG_NAME)
+ .inject(catalog -> injectSchemas(catalog, messages))
+ .build()
+ .build();
+ }
+ }
+ return request;
+ }
+
+ private CatalogedConfigBuilder injectSchemas(
+ CatalogedConfigBuilder catalog,
+ Map messages)
+ {
+ for (String name : messages.keySet())
+ {
+ AsyncapiMessageView message = AsyncapiMessageView.of(asyncApi.components.messages, messages.get(name));
+ String subject = message.refKey() != null ? message.refKey() : name;
+ catalog
+ .schema()
+ .subject(subject)
+ .build()
+ .build();
+ }
+ return catalog;
+ }
+
+ private HttpRequestConfigBuilder injectPathParams(
+ HttpRequestConfigBuilder request,
+ Map parameters)
+ {
+ if (parameters != null)
+ {
+ for (String name : parameters.keySet())
+ {
+ AsyncapiParameter parameter = parameters.get(name);
+ if (parameter.schema != null && parameter.schema.type != null)
+ {
+ ModelConfig model = MODELS.get(parameter.schema.type);
+ if (model != null)
+ {
+ request
+ .pathParam()
+ .name(name)
+ .model(model)
+ .build();
+ }
+ }
+ }
+ }
+ return request;
+ }
+
+ private RouteConfigBuilder injectHttpServerRouteGuarded(
+ RouteConfigBuilder route,
+ AsyncapiServerView server)
+ {
+ if (server.security() != null)
+ {
+ for (Map> securityItem : server.security())
+ {
+ for (String securityItemLabel : securityItem.keySet())
+ {
+ if (isJwtEnabled && "jwt".equals(securitySchemes.get(securityItemLabel)))
+ {
+ route
+ .guarded()
+ .name(guardName)
+ .inject(guarded -> injectGuardedRoles(guarded, securityItem.get(securityItemLabel)))
+ .build();
+ break;
+ }
+ }
+ }
+ }
+ return route;
+ }
+
+ private GuardedConfigBuilder injectGuardedRoles(
+ GuardedConfigBuilder guarded,
+ List roles)
+ {
+ for (String role : roles)
+ {
+ guarded.role(role);
+ }
+ return guarded;
+ }
+
+ private Map resolveSecuritySchemes()
+ {
+ requireNonNull(asyncApi);
+ Map result = new HashMap<>();
+ if (asyncApi.components != null && asyncApi.components.securitySchemes != null)
+ {
+ for (String securitySchemeName : asyncApi.components.securitySchemes.keySet())
+ {
+ String guardType = asyncApi.components.securitySchemes.get(securitySchemeName).bearerFormat;
+ if ("jwt".equals(guardType))
+ {
+ result.put(securitySchemeName, guardType);
+ }
+ }
+ }
+ return result;
+ }
+
+ private String resolveAuthorizationHeader()
+ {
+ requireNonNull(asyncApi);
+ requireNonNull(asyncApi.components);
+ String result = null;
+ if (asyncApi.components.messages != null)
+ {
+ for (Map.Entry entry : asyncApi.components.messages.entrySet())
+ {
+ AsyncapiMessage message = entry.getValue();
+ if (message.headers != null && message.headers.properties != null)
+ {
+ AsyncapiItem authorization = message.headers.properties.get("authorization");
+ if (authorization != null)
+ {
+ result = authorization.description;
+ break;
+ }
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiProtocol.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiProtocol.java
new file mode 100644
index 0000000000..66ab35de82
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiProtocol.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static java.util.Objects.requireNonNull;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiMessage;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiMessageView;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView;
+import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder;
+
+public abstract class AsyncapiProtocol
+{
+ protected static final String INLINE_CATALOG_NAME = "catalog0";
+ protected static final Pattern JSON_CONTENT_TYPE = Pattern.compile("^application/(?:.+\\+)?json$");
+ protected static final String VERSION_LATEST = "latest";
+
+ protected final Matcher jsonContentType = JSON_CONTENT_TYPE.matcher("");
+
+ protected Asyncapi asyncApi;
+ protected String qname;
+ public final String scheme;
+ public final String secureScheme;
+
+ protected AsyncapiProtocol(
+ String qname,
+ Asyncapi asyncApi,
+ String scheme,
+ String secureScheme)
+ {
+ this.qname = qname;
+ this.asyncApi = asyncApi;
+ this.scheme = scheme;
+ this.secureScheme = secureScheme;
+ }
+
+ public abstract BindingConfigBuilder injectProtocolServerOptions(
+ BindingConfigBuilder binding);
+
+ public abstract BindingConfigBuilder injectProtocolServerRoutes(
+ BindingConfigBuilder binding);
+
+ public NamespaceConfigBuilder injectProtocolClientCache(
+ NamespaceConfigBuilder namespace)
+ {
+ return namespace;
+ }
+
+ public BindingConfigBuilder injectProtocolClientOptions(
+ BindingConfigBuilder binding)
+ {
+ return binding;
+ }
+
+ protected CatalogedConfigBuilder injectJsonSchemas(
+ CatalogedConfigBuilder cataloged,
+ Map messages,
+ String contentType)
+ {
+ for (Map.Entry messageEntry : messages.entrySet())
+ {
+ AsyncapiMessageView message =
+ AsyncapiMessageView.of(asyncApi.components.messages, messageEntry.getValue());
+ String schema = messageEntry.getKey();
+ if (message.contentType().equals(contentType))
+ {
+ cataloged
+ .schema()
+ .version(VERSION_LATEST)
+ .subject(schema)
+ .build()
+ .build();
+ }
+ else
+ {
+ throw new RuntimeException("Invalid content type");
+ }
+ }
+ return cataloged;
+ }
+
+ protected boolean hasJsonContentType()
+ {
+ String contentType = null;
+ if (asyncApi.components != null && asyncApi.components.messages != null &&
+ !asyncApi.components.messages.isEmpty())
+ {
+ AsyncapiMessage firstAsyncapiMessage = asyncApi.components.messages.entrySet().stream()
+ .findFirst().get().getValue();
+ contentType = AsyncapiMessageView.of(asyncApi.components.messages, firstAsyncapiMessage).contentType();
+ }
+ return contentType != null && jsonContentType.reset(contentType).matches();
+ }
+
+ protected abstract boolean isSecure();
+
+ protected int[] resolvePorts()
+ {
+ requireNonNull(scheme);
+ int[] ports = null;
+ URI url = findFirstServerUrlWithScheme(scheme);
+ if (url != null)
+ {
+ ports = new int[] {url.getPort()};
+ }
+ return ports;
+ }
+
+ protected URI findFirstServerUrlWithScheme(
+ String scheme)
+ {
+ requireNonNull(scheme);
+ URI result = null;
+ for (String key : asyncApi.servers.keySet())
+ {
+ AsyncapiServerView server = AsyncapiServerView.of(asyncApi.servers.get(key));
+ if (scheme.equals(server.url().getScheme()))
+ {
+ result = server.url();
+ break;
+ }
+ }
+ return result;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiProxyCompositeBindingAdapter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiProxyCompositeBindingAdapter.java
new file mode 100644
index 0000000000..c85e764503
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiProxyCompositeBindingAdapter.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.PROXY;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiConditionConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiRouteConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiOperation;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiChannelView;
+import io.aklivity.zilla.runtime.binding.mqtt.kafka.config.MqttKafkaConditionConfig;
+import io.aklivity.zilla.runtime.binding.mqtt.kafka.config.MqttKafkaConditionKind;
+import io.aklivity.zilla.runtime.binding.mqtt.kafka.config.MqttKafkaOptionsConfig;
+import io.aklivity.zilla.runtime.binding.mqtt.kafka.config.MqttKafkaWithConfig;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.CompositeBindingAdapterSpi;
+import io.aklivity.zilla.runtime.engine.config.RouteConfigBuilder;
+
+public class AsyncapiProxyCompositeBindingAdapter extends AsyncapiCompositeBindingAdapter implements CompositeBindingAdapterSpi
+{
+ private static final String ASYNCAPI_SEND_ACTION_NAME = "send";
+ private static final String ASYNCAPI_RECEIVE_ACTION_NAME = "receive";
+ private static final String ASYNCAPI_KAFKA_PROTOCOL_NAME = "kafka";
+ private static final String ASYNCAPI_MQTT_PROTOCOL_NAME = "mqtt";
+
+ @Override
+ public String type()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public BindingConfig adapt(
+ BindingConfig binding)
+ {
+ AsyncapiOptionsConfig options = (AsyncapiOptionsConfig) binding.options;
+ List routes = binding.routes.stream()
+ .map(r -> new AsyncapiRouteConfig(r, options::resolveApiId))
+ .collect(Collectors.toList());
+ this.asyncApis = options.specs.stream().collect(Collectors.toUnmodifiableMap(a -> a.apiLabel, a -> a.asyncapi));
+ this.qname = binding.qname;
+
+ String sessions = "";
+ String messages = "";
+ String retained = "";
+ for (Asyncapi asyncapi : asyncApis.values())
+ {
+ if (asyncapi.channels.containsKey(options.mqttKafka.channels.sessions))
+ {
+ sessions = asyncapi.channels.get(options.mqttKafka.channels.sessions).address;
+ }
+
+ if (asyncapi.channels.containsKey(options.mqttKafka.channels.messages))
+ {
+ messages = asyncapi.channels.get(options.mqttKafka.channels.messages).address;
+ }
+
+ if (asyncapi.channels.containsKey(options.mqttKafka.channels.retained))
+ {
+ retained = asyncapi.channels.get(options.mqttKafka.channels.retained).address;
+ }
+ }
+
+ return BindingConfig.builder(binding)
+ .composite()
+ .name(String.format("%s/%s", qname, "mqtt-kafka"))
+ .binding()
+ .name("mqtt_kafka_proxy0")
+ .type("mqtt-kafka")
+ .kind(PROXY)
+ .options(MqttKafkaOptionsConfig::builder)
+ .topics()
+ .sessions(sessions)
+ .messages(messages)
+ .retained(retained)
+ .build()
+ .clients(Collections.emptyList())
+ .build()
+ .inject(b -> this.injectMqttKafkaRoutes(b, routes))
+ .build()
+ .build()
+ .build();
+ }
+
+ public BindingConfigBuilder injectMqttKafkaRoutes(
+ BindingConfigBuilder binding,
+ List routes)
+ {
+ inject:
+ for (AsyncapiRouteConfig route : routes)
+ {
+ final RouteConfigBuilder> routeBuilder = binding.route();
+
+ final Asyncapi kafkaAsyncapi = asyncApis.get(route.with.apiId);
+
+ if (kafkaAsyncapi.servers.values().stream().anyMatch(s -> !s.protocol.startsWith(ASYNCAPI_KAFKA_PROTOCOL_NAME)))
+ {
+ break inject;
+ }
+
+ final AsyncapiOperation withOperation = kafkaAsyncapi.operations.get(route.with.operationId);
+ final String messages = AsyncapiChannelView.of(kafkaAsyncapi.channels, withOperation.channel).address();
+
+ for (AsyncapiConditionConfig condition : route.when)
+ {
+ final Asyncapi mqttAsyncapi = asyncApis.get(condition.apiId);
+ if (mqttAsyncapi.servers.values().stream().anyMatch(s -> !s.protocol.startsWith(ASYNCAPI_MQTT_PROTOCOL_NAME)))
+ {
+ break inject;
+ }
+ final AsyncapiOperation whenOperation = mqttAsyncapi.operations.get(condition.operationId);
+ final AsyncapiChannelView channel = AsyncapiChannelView.of(mqttAsyncapi.channels, whenOperation.channel);
+ final MqttKafkaConditionKind kind = whenOperation.action.equals(ASYNCAPI_SEND_ACTION_NAME) ?
+ MqttKafkaConditionKind.PUBLISH : MqttKafkaConditionKind.SUBSCRIBE;
+ final String topic = channel.address().replaceAll("\\{[^}]+\\}", "+");
+ routeBuilder
+ .when(MqttKafkaConditionConfig::builder)
+ .topic(topic)
+ .kind(kind)
+ .build()
+ .with(MqttKafkaWithConfig::builder)
+ .messages(messages)
+ .build()
+ .exit(qname);
+ }
+ binding = routeBuilder.build();
+ }
+ return binding;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiServerCompositeBindingAdapter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiServerCompositeBindingAdapter.java
new file mode 100644
index 0000000000..56712d6fdd
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AsyncapiServerCompositeBindingAdapter.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.SERVER;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiView;
+import io.aklivity.zilla.runtime.binding.tcp.config.TcpConditionConfig;
+import io.aklivity.zilla.runtime.binding.tcp.config.TcpOptionsConfig;
+import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.CompositeBindingAdapterSpi;
+import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder;
+
+public class AsyncapiServerCompositeBindingAdapter extends AsyncapiCompositeBindingAdapter implements CompositeBindingAdapterSpi
+{
+ private int[] compositePorts;
+
+ @Override
+ public String type()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public BindingConfig adapt(
+ BindingConfig binding)
+ {
+ AsyncapiOptionsConfig options = (AsyncapiOptionsConfig) binding.options;
+ AsyncapiConfig asyncapiConfig = options.specs.get(0);
+ this.asyncapi = asyncapiConfig.asyncapi;
+ AsyncapiView view = AsyncapiView.of(asyncapi);
+
+ //TODO: add composite for all servers
+ AsyncapiServerView firstServer = AsyncapiServerView.of(asyncapi.servers.entrySet().iterator().next().getValue());
+
+ this.qname = binding.qname;
+ this.qvault = binding.qvault;
+ this.protocol = resolveProtocol(firstServer.protocol(), options);
+ int[] allPorts = view.resolveAllPorts();
+ this.compositePorts = protocol.resolvePorts();
+ this.isTlsEnabled = protocol.isSecure();
+
+ return BindingConfig.builder(binding)
+ .composite()
+ .name(String.format("%s/%s", qname, protocol.scheme))
+ .inject(n -> this.injectCatalog(n, asyncapi))
+ .binding()
+ .name("tcp_server0")
+ .type("tcp")
+ .kind(SERVER)
+ .options(TcpOptionsConfig::builder)
+ .host("0.0.0.0")
+ .ports(allPorts)
+ .build()
+ .inject(this::injectPlainTcpRoute)
+ .inject(this::injectTlsTcpRoute)
+ .build()
+ .inject(n -> injectTlsServer(n, options))
+ .binding()
+ .name(String.format("%s_server0", protocol.scheme))
+ .type(protocol.scheme)
+ .kind(SERVER)
+ .inject(protocol::injectProtocolServerOptions)
+ .inject(protocol::injectProtocolServerRoutes)
+ .build()
+ .build()
+ .build();
+ }
+
+ private BindingConfigBuilder injectPlainTcpRoute(
+ BindingConfigBuilder binding)
+ {
+ if (!isTlsEnabled)
+ {
+ binding
+ .route()
+ .when(TcpConditionConfig::builder)
+ .ports(compositePorts)
+ .build()
+ .exit(String.format("%s_server0", protocol.scheme))
+ .build();
+ }
+ return binding;
+ }
+
+ private BindingConfigBuilder injectTlsTcpRoute(
+ BindingConfigBuilder binding)
+ {
+ if (isTlsEnabled)
+ {
+ binding
+ .route()
+ .when(TcpConditionConfig::builder)
+ .ports(compositePorts)
+ .build()
+ .exit("tls_server0")
+ .build();
+ }
+ return binding;
+ }
+
+ private NamespaceConfigBuilder injectTlsServer(
+ NamespaceConfigBuilder namespace,
+ AsyncapiOptionsConfig options)
+ {
+ if (isTlsEnabled)
+ {
+ namespace
+ .binding()
+ .name("tls_server0")
+ .type("tls")
+ .kind(SERVER)
+ .options(TlsOptionsConfig::builder)
+ .keys(options.tls.keys)
+ .sni(options.tls.sni)
+ .alpn(options.tls.alpn)
+ .build()
+ .vault(qvault)
+ .exit(String.format("%s_server0", protocol.scheme))
+ .build();
+ }
+ return namespace;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AyncapiKafkaProtocol.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AyncapiKafkaProtocol.java
new file mode 100644
index 0000000000..ec7e1243b2
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AyncapiKafkaProtocol.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiMessage;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiOperation;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiChannelView;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiMessageView;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiSchemaView;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaOptionsConfig;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaOptionsConfigBuilder;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaSaslConfig;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaServerConfig;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaTopicConfig;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaTopicConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.KindConfig;
+import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class AyncapiKafkaProtocol extends AsyncapiProtocol
+{
+ private static final String SCHEME = "kafka";
+ private static final String SECURE_SCHEME = "";
+ private static final String SECURE_PROTOCOL = "kafka-secure";
+ private static final Pattern PARAMETERIZED_TOPIC_PATTERN = Pattern.compile("\\{.*?\\}");
+
+ private final String protocol;
+ private final KafkaSaslConfig sasl;
+
+ public AyncapiKafkaProtocol(
+ String qname,
+ Asyncapi asyncApi,
+ AsyncapiOptionsConfig options,
+ String protocol)
+ {
+ super(qname, asyncApi, SCHEME, SECURE_SCHEME);
+ this.protocol = protocol;
+ this.sasl = options.kafka != null ? options.kafka.sasl : null;
+ }
+
+ @Override
+ public NamespaceConfigBuilder injectProtocolClientCache(
+ NamespaceConfigBuilder namespace)
+ {
+ return namespace
+ .binding()
+ .name("kafka_cache_client0")
+ .type("kafka")
+ .kind(KindConfig.CACHE_CLIENT)
+ .options(KafkaOptionsConfig::builder)
+ .inject(this::injectKafkaTopicOptions)
+ .build()
+ .exit("kafka_cache_server0")
+ .build()
+ .binding()
+ .name("kafka_cache_server0")
+ .type("kafka")
+ .kind(KindConfig.CACHE_SERVER)
+ .options(KafkaOptionsConfig::builder)
+ .inject(this::injectKafkaBootstrapOptions)
+ .inject(this::injectKafkaTopicOptions)
+ .build()
+ .exit("kafka_client0")
+ .build();
+ }
+
+ @Override
+ public BindingConfigBuilder injectProtocolClientOptions(
+ BindingConfigBuilder binding)
+ {
+ return binding.options(KafkaOptionsConfig::builder)
+ .inject(this::injectKafkaSaslOptions)
+ .inject(this::injectKafkaServerOptions)
+ .build();
+ }
+
+ @Override
+ public BindingConfigBuilder injectProtocolServerOptions(
+ BindingConfigBuilder binding)
+ {
+ return binding;
+ }
+
+ @Override
+ public BindingConfigBuilder injectProtocolServerRoutes(
+ BindingConfigBuilder binding)
+ {
+ return binding;
+ }
+
+ @Override
+ protected boolean isSecure()
+ {
+ return protocol.equals(SECURE_PROTOCOL);
+ }
+
+ private KafkaOptionsConfigBuilder injectKafkaSaslOptions(
+ KafkaOptionsConfigBuilder options)
+ {
+ return sasl != null ? options.sasl(KafkaSaslConfig::builder)
+ .mechanism(sasl.mechanism)
+ .username(sasl.username)
+ .password(sasl.password)
+ .build() : options;
+ }
+
+ private KafkaOptionsConfigBuilder injectKafkaServerOptions(
+ KafkaOptionsConfigBuilder options)
+ {
+ return options.servers(asyncApi.servers.values().stream().map(s ->
+ {
+ String[] hostAndPort = s.host.split(":");
+ return KafkaServerConfig.builder()
+ .host(hostAndPort[0])
+ .port(Integer.parseInt(hostAndPort[1]))
+ .build();
+ }).collect(Collectors.toList()));
+ }
+
+ private KafkaOptionsConfigBuilder injectKafkaTopicOptions(
+ KafkaOptionsConfigBuilder options)
+ {
+ for (String name : asyncApi.operations.keySet())
+ {
+ AsyncapiOperation operation = asyncApi.operations.get(name);
+ AsyncapiChannelView channel = AsyncapiChannelView.of(asyncApi.channels, operation.channel);
+ String topic = channel.address();
+
+ if (channel.messages() != null && !channel.messages().isEmpty() ||
+ channel.parameters() != null && !channel.parameters().isEmpty())
+ {
+ options
+ .topic(KafkaTopicConfig::builder)
+ .name(topic)
+ .inject(topicConfig -> injectValue(topicConfig, channel.messages()))
+ .build()
+ .build();
+ }
+ }
+ return options;
+ }
+
+ private KafkaOptionsConfigBuilder injectKafkaBootstrapOptions(
+ KafkaOptionsConfigBuilder options)
+ {
+ return options.bootstrap(asyncApi.channels.values().stream()
+ .filter(c -> !PARAMETERIZED_TOPIC_PATTERN.matcher(c.address).find())
+ .map(c -> AsyncapiChannelView.of(asyncApi.channels, c).address()).collect(Collectors.toList()));
+ }
+
+ private KafkaTopicConfigBuilder injectValue(
+ KafkaTopicConfigBuilder topic,
+ Map messages)
+ {
+ if (messages != null)
+ {
+ if (hasJsonContentType())
+ {
+ topic
+ .value(JsonModelConfig::builder)
+ .catalog()
+ .name(INLINE_CATALOG_NAME)
+ .inject(catalog -> injectSchemas(catalog, messages))
+ .build()
+ .build();
+ }
+ }
+ return topic;
+ }
+
+ private CatalogedConfigBuilder injectSchemas(
+ CatalogedConfigBuilder catalog,
+ Map messages)
+ {
+ for (String name : messages.keySet())
+ {
+ AsyncapiMessageView message = AsyncapiMessageView.of(asyncApi.components.messages, messages.get(name));
+ AsyncapiSchemaView payload = AsyncapiSchemaView.of(asyncApi.components.schemas, message.payload());
+ String subject = payload.refKey() != null ? payload.refKey() : name;
+ catalog
+ .schema()
+ .subject(subject)
+ .version(VERSION_LATEST)
+ .build()
+ .build();
+ }
+ return catalog;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AyncapiMqttProtocol.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AyncapiMqttProtocol.java
new file mode 100644
index 0000000000..cf315bc69c
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/AyncapiMqttProtocol.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal;
+
+import static io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiCompositeBindingAdapter.APPLICATION_JSON;
+
+import java.util.Map;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiChannel;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiMessage;
+import io.aklivity.zilla.runtime.binding.mqtt.config.MqttConditionConfig;
+import io.aklivity.zilla.runtime.binding.mqtt.config.MqttOptionsConfig;
+import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class AyncapiMqttProtocol extends AsyncapiProtocol
+{
+ private static final String SCHEME = "mqtt";
+ private static final String SECURE_SCHEME = "mqtts";
+
+ public AyncapiMqttProtocol(
+ String qname,
+ Asyncapi asyncApi)
+ {
+ super(qname, asyncApi, SCHEME, SECURE_SCHEME);
+ }
+
+ @Override
+ public BindingConfigBuilder injectProtocolServerOptions(
+ BindingConfigBuilder binding)
+ {
+ for (Map.Entry channelEntry : asyncApi.channels.entrySet())
+ {
+ String topic = channelEntry.getValue().address.replaceAll("\\{[^}]+\\}", "#");
+ Map messages = channelEntry.getValue().messages;
+ if (hasJsonContentType())
+ {
+ binding
+ .options(MqttOptionsConfig::builder)
+ .topic()
+ .name(topic)
+ .content(JsonModelConfig::builder)
+ .catalog()
+ .name(INLINE_CATALOG_NAME)
+ .inject(cataloged -> injectJsonSchemas(cataloged, messages, APPLICATION_JSON))
+ .build()
+ .build()
+ .build()
+ .build()
+ .build();
+ }
+ }
+ return binding;
+ }
+
+ @Override
+ public BindingConfigBuilder injectProtocolServerRoutes(
+ BindingConfigBuilder binding)
+ {
+ for (Map.Entry entry : asyncApi.channels.entrySet())
+ {
+ String topic = entry.getValue().address.replaceAll("\\{[^}]+\\}", "#");
+ binding
+ .route()
+ .when(MqttConditionConfig::builder)
+ .publish()
+ .topic(topic)
+ .build()
+ .build()
+ .when(MqttConditionConfig::builder)
+ .subscribe()
+ .topic(topic)
+ .build()
+ .build()
+ .exit(qname)
+ .build();
+ }
+ return binding;
+ }
+
+ @Override
+ protected boolean isSecure()
+ {
+ return findFirstServerUrlWithScheme(SECURE_SCHEME) != null;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiBindingConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiBindingConfig.java
new file mode 100644
index 0000000000..cf7c05c1d3
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiBindingConfig.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.config;
+
+import static io.aklivity.zilla.runtime.engine.config.KindConfig.CACHE_CLIENT;
+import static java.util.Collections.unmodifiableMap;
+import static java.util.stream.Collector.of;
+import static java.util.stream.Collector.Characteristics.IDENTITY_FINISH;
+import static java.util.stream.Collectors.toList;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.agrona.AsciiSequenceView;
+import org.agrona.DirectBuffer;
+import org.agrona.collections.Int2ObjectHashMap;
+import org.agrona.collections.Long2LongHashMap;
+import org.agrona.collections.Object2ObjectHashMap;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.HttpHeaderFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.String16FW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.String8FW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.HttpBeginExFW;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+import io.aklivity.zilla.runtime.engine.config.KindConfig;
+import io.aklivity.zilla.runtime.engine.namespace.NamespacedId;
+
+public final class AsyncapiBindingConfig
+{
+ public final long id;
+ public final String name;
+ public final KindConfig kind;
+ public final AsyncapiOptionsConfig options;
+ public final List routes;
+ private final Int2ObjectHashMap composites;
+ private final long overrideRouteId;
+ private final Long2LongHashMap compositeResolvedIds;
+ private final HttpHeaderHelper helper;
+ private final Object2ObjectHashMap paths;
+ private final Map operationIds;
+
+ public AsyncapiBindingConfig(
+ BindingConfig binding,
+ long overrideRouteId)
+ {
+ this.id = binding.id;
+ this.name = binding.name;
+ this.kind = binding.kind;
+ this.overrideRouteId = overrideRouteId;
+ this.options = AsyncapiOptionsConfig.class.cast(binding.options);
+ this.routes = binding.routes.stream().map(r -> new AsyncapiRouteConfig(r, options::resolveApiId)).collect(toList());
+ this.compositeResolvedIds = binding.composites.stream()
+ .map(c -> c.bindings)
+ .flatMap(List::stream)
+ .filter(b -> b.type.equals("mqtt") || b.type.equals("http") ||
+ b.type.equals("kafka") && b.kind == CACHE_CLIENT || b.type.equals("mqtt-kafka"))
+ .collect(of(
+ () -> new Long2LongHashMap(-1),
+ (m, r) -> m.put(options.specs.get(0).apiId, r.id),
+ (m, r) -> m,
+ IDENTITY_FINISH
+ ));
+ this.composites = new Int2ObjectHashMap<>();
+ binding.composites.stream()
+ .map(c -> c.bindings)
+ .flatMap(List::stream)
+ .filter(b -> b.type.equals("mqtt") || b.type.equals("http") || b.type.equals("kafka") && b.kind == CACHE_CLIENT ||
+ b.type.equals("mqtt-kafka"))
+ .forEach(b -> this.composites.put(NamespacedId.namespaceId(b.id), b.type));
+
+ this.paths = new Object2ObjectHashMap<>();
+ options.specs.forEach(c -> c.asyncapi.channels.forEach((k, v) ->
+ {
+ String regex = v.address.replaceAll("\\{[^/]+}", "[^/]+");
+ regex = "^" + regex + "$";
+ Pattern pattern = Pattern.compile(regex);
+ paths.put(pattern.matcher(""), k);
+ }));
+
+ this.helper = new HttpHeaderHelper();
+
+ Map resolversByMethod = new TreeMap<>(CharSequence::compare);
+ options.specs.forEach(c -> c.asyncapi.operations.forEach((k, v) ->
+ {
+ String[] refParts = v.channel.ref.split("/");
+ resolversByMethod.put(refParts[refParts.length - 1], k);
+ }));
+ this.operationIds = unmodifiableMap(resolversByMethod);
+ }
+
+ public boolean isCompositeOriginId(
+ long originId)
+ {
+ return composites.containsKey(NamespacedId.namespaceId(originId));
+ }
+
+ public String getCompositeOriginType(
+ long originId)
+ {
+ return composites.get(NamespacedId.namespaceId(originId));
+ }
+
+ public long resolveCompositeResolvedId(
+ long apiId)
+ {
+ return overrideRouteId != -1 ? overrideRouteId : compositeResolvedIds.get(apiId);
+ }
+
+ public String resolveOperationId(
+ HttpBeginExFW httpBeginEx)
+ {
+ helper.visit(httpBeginEx);
+
+ String operationId = null;
+
+ for (Map.Entry item : paths.entrySet())
+ {
+ Matcher matcher = item.getKey();
+ matcher.reset(helper.path);
+ if (matcher.find())
+ {
+ String channelName = item.getValue();
+ operationId = operationIds.get(channelName);
+ break;
+ }
+ }
+
+ return operationId;
+ }
+
+ public AsyncapiRouteConfig resolve(
+ long authorization)
+ {
+ return routes.stream()
+ .filter(r -> r.authorized(authorization))
+ .findFirst()
+ .orElse(null);
+ }
+
+ public AsyncapiRouteConfig resolve(
+ long authorization,
+ long apiId)
+ {
+ return routes.stream()
+ .filter(r -> r.authorized(authorization) && r.matches(apiId))
+ .findFirst()
+ .orElse(null);
+ }
+
+ private static final class HttpHeaderHelper
+ {
+ private static final String8FW HEADER_NAME_METHOD = new String8FW(":method");
+ private static final String8FW HEADER_NAME_PATH = new String8FW(":path");
+ private static final String8FW HEADER_NAME_SCHEME = new String8FW(":scheme");
+ private static final String8FW HEADER_NAME_AUTHORITY = new String8FW(":authority");
+
+ private final Map> visitors;
+ {
+ Map> visitors = new HashMap<>();
+ visitors.put(HEADER_NAME_METHOD, this::visitMethod);
+ visitors.put(HEADER_NAME_PATH, this::visitPath);
+ visitors.put(HEADER_NAME_SCHEME, this::visitScheme);
+ visitors.put(HEADER_NAME_AUTHORITY, this::visitAuthority);
+ this.visitors = visitors;
+ }
+ private final AsciiSequenceView methodRO = new AsciiSequenceView();
+ private final AsciiSequenceView pathRO = new AsciiSequenceView();
+ private final String16FW schemeRO = new String16FW();
+ private final String16FW authorityRO = new String16FW();
+
+ public CharSequence path;
+ public CharSequence method;
+ public String16FW scheme;
+ public String16FW authority;
+
+ private void visit(
+ HttpBeginExFW beginEx)
+ {
+ method = null;
+ path = null;
+ scheme = null;
+ authority = null;
+
+ if (beginEx != null)
+ {
+ beginEx.headers().forEach(this::dispatch);
+ }
+ }
+
+ private boolean dispatch(
+ HttpHeaderFW header)
+ {
+ final String8FW name = header.name();
+ final Consumer visitor = visitors.get(name);
+ if (visitor != null)
+ {
+ visitor.accept(header.value());
+ }
+
+ return method != null &&
+ path != null &&
+ scheme != null &&
+ authority != null;
+ }
+
+ private void visitMethod(
+ String16FW value)
+ {
+ final DirectBuffer buffer = value.buffer();
+ final int offset = value.offset() + value.fieldSizeLength();
+ final int length = value.sizeof() - value.fieldSizeLength();
+ method = methodRO.wrap(buffer, offset, length);
+ }
+
+ private void visitPath(
+ String16FW value)
+ {
+ final DirectBuffer buffer = value.buffer();
+ final int offset = value.offset() + value.fieldSizeLength();
+ final int length = value.sizeof() - value.fieldSizeLength();
+ path = pathRO.wrap(buffer, offset, length);
+ }
+
+ private void visitScheme(
+ String16FW value)
+ {
+ scheme = schemeRO.wrap(value.buffer(), value.offset(), value.limit());
+ }
+
+ private void visitAuthority(
+ String16FW value)
+ {
+ authority = authorityRO.wrap(value.buffer(), value.offset(), value.limit());
+ }
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiConditionConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiConditionConfig.java
new file mode 100644
index 0000000000..b3e3f70c62
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiConditionConfig.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.config;
+
+import java.util.function.Function;
+
+import io.aklivity.zilla.runtime.engine.config.ConditionConfig;
+
+public class AsyncapiConditionConfig extends ConditionConfig
+{
+ public final String apiId;
+ public final String operationId;
+
+ public AsyncapiConditionConfig(
+ String apiId,
+ String operationId)
+ {
+ this.apiId = apiId;
+ this.operationId = operationId;
+ }
+
+ public boolean matches(
+ long apiId,
+ Function supplyApiId)
+ {
+ return matchesApiId(apiId, supplyApiId);
+ }
+
+ private boolean matchesApiId(
+ long apiId,
+ Function supplyApiId)
+ {
+ return supplyApiId.apply(this.apiId) == apiId;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiConditionConfigAdapter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiConditionConfigAdapter.java
new file mode 100644
index 0000000000..8d659d7141
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiConditionConfigAdapter.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.config;
+
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonObjectBuilder;
+import jakarta.json.bind.adapter.JsonbAdapter;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiBinding;
+import io.aklivity.zilla.runtime.engine.config.ConditionConfig;
+import io.aklivity.zilla.runtime.engine.config.ConditionConfigAdapterSpi;
+
+public class AsyncapiConditionConfigAdapter implements ConditionConfigAdapterSpi, JsonbAdapter
+{
+ private static final String API_ID_NAME = "api-id";
+ private static final String OPERATION_ID_NAME = "operation-id";
+
+ @Override
+ public String type()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public JsonObject adaptToJson(
+ ConditionConfig condition)
+ {
+ AsyncapiConditionConfig asyncapiCondition = (AsyncapiConditionConfig) condition;
+ JsonObjectBuilder object = Json.createObjectBuilder();
+
+ object.add(API_ID_NAME, asyncapiCondition.apiId);
+ object.add(OPERATION_ID_NAME, asyncapiCondition.operationId);
+
+ return object.build();
+ }
+
+ @Override
+ public ConditionConfig adaptFromJson(
+ JsonObject object)
+ {
+ String apiId = object.getString(API_ID_NAME);
+ String operationId = object.getString(OPERATION_ID_NAME);
+ return new AsyncapiConditionConfig(apiId, operationId);
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiOptionsConfigAdapter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiOptionsConfigAdapter.java
new file mode 100644
index 0000000000..e7c61ed268
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiOptionsConfigAdapter.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.config;
+
+import static java.util.stream.Collectors.toList;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.zip.CRC32C;
+
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonObjectBuilder;
+import jakarta.json.JsonString;
+import jakarta.json.JsonValue;
+import jakarta.json.bind.adapter.JsonbAdapter;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiChannelsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiChannelsConfigBuilder;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiMqttKafkaConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiMqttKafkaConfigBuilder;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfigBuilder;
+import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiParser;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiBinding;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi;
+import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfig;
+import io.aklivity.zilla.runtime.binding.kafka.config.KafkaOptionsConfig;
+import io.aklivity.zilla.runtime.binding.tcp.config.TcpOptionsConfig;
+import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig;
+import io.aklivity.zilla.runtime.engine.config.ConfigAdapterContext;
+import io.aklivity.zilla.runtime.engine.config.OptionsConfig;
+import io.aklivity.zilla.runtime.engine.config.OptionsConfigAdapter;
+import io.aklivity.zilla.runtime.engine.config.OptionsConfigAdapterSpi;
+
+public final class AsyncapiOptionsConfigAdapter implements OptionsConfigAdapterSpi, JsonbAdapter
+{
+ private static final String SPECS_NAME = "specs";
+ private static final String TCP_NAME = "tcp";
+ private static final String TLS_NAME = "tls";
+ private static final String HTTP_NAME = "http";
+ private static final String KAFKA_NAME = "kafka";
+ private static final String MQTT_KAFKA_NAME = "mqtt_kafka";
+ private static final String CHANNELS_NAME = "channels";
+ private static final String SESSIONS_NAME = "sessions";
+ private static final String MESSAGES_NAME = "messages";
+ private static final String RETAINED_NAME = "retained";
+
+ private final AsyncapiParser parser;
+ private final CRC32C crc;
+
+ private OptionsConfigAdapter tcpOptions;
+ private OptionsConfigAdapter tlsOptions;
+ private OptionsConfigAdapter httpOptions;
+ private OptionsConfigAdapter kafkaOptions;
+ private Function readURL;
+
+ public AsyncapiOptionsConfigAdapter()
+ {
+ this.parser = new AsyncapiParser();
+ this.crc = new CRC32C();
+ }
+
+ public Kind kind()
+ {
+ return Kind.BINDING;
+ }
+
+ @Override
+ public String type()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public JsonObject adaptToJson(
+ OptionsConfig options)
+ {
+ AsyncapiOptionsConfig asyncapiOptions = (AsyncapiOptionsConfig) options;
+
+ JsonObjectBuilder object = Json.createObjectBuilder();
+
+ if (asyncapiOptions.specs != null)
+ {
+ JsonObjectBuilder specs = Json.createObjectBuilder();
+ asyncapiOptions.specs.forEach(p -> specs.add(p.apiLabel, p.location));
+ object.add(SPECS_NAME, specs);
+ }
+
+ if (asyncapiOptions.tcp != null)
+ {
+ final TcpOptionsConfig tcp = asyncapiOptions.tcp;
+ object.add(TCP_NAME, tcpOptions.adaptToJson(tcp));
+ }
+
+ if (asyncapiOptions.tls != null)
+ {
+ final TlsOptionsConfig tls = asyncapiOptions.tls;
+ object.add(TLS_NAME, tlsOptions.adaptToJson(tls));
+ }
+
+ if (asyncapiOptions.http != null)
+ {
+ final HttpOptionsConfig http = asyncapiOptions.http;
+ object.add(HTTP_NAME, httpOptions.adaptToJson(http));
+ }
+
+ if (asyncapiOptions.kafka != null)
+ {
+ final KafkaOptionsConfig kafka = asyncapiOptions.kafka;
+ object.add(KAFKA_NAME, kafkaOptions.adaptToJson(kafka));
+ }
+
+ if (asyncapiOptions.mqttKafka != null)
+ {
+ AsyncapiMqttKafkaConfig mqttKafka = asyncapiOptions.mqttKafka;
+ JsonObjectBuilder newMqttKafka = Json.createObjectBuilder();
+ AsyncapiChannelsConfig channels = mqttKafka.channels;
+ if (channels != null)
+ {
+ JsonObjectBuilder newChannels = Json.createObjectBuilder();
+ String sessions = channels.sessions;
+ if (sessions != null)
+ {
+ newChannels.add(SESSIONS_NAME, sessions);
+ }
+
+ String messages = channels.messages;
+ if (messages != null)
+ {
+ newChannels.add(MESSAGES_NAME, messages);
+ }
+
+ String retained = channels.retained;
+ if (retained != null)
+ {
+ newChannels.add(RETAINED_NAME, retained);
+ }
+ newMqttKafka.add(CHANNELS_NAME, newChannels);
+
+ object.add(MQTT_KAFKA_NAME, newMqttKafka);
+ }
+ }
+
+ return object.build();
+ }
+
+ @Override
+ public OptionsConfig adaptFromJson(
+ JsonObject object)
+ {
+ final AsyncapiOptionsConfigBuilder asyncapiOptions = AsyncapiOptionsConfig.builder();
+
+ List specs = object.containsKey(SPECS_NAME)
+ ? asListAsyncapis(object.getJsonObject(SPECS_NAME))
+ : null;
+ asyncapiOptions.specs(specs);
+
+ if (object.containsKey(TCP_NAME))
+ {
+ final JsonObject tcp = object.getJsonObject(TCP_NAME);
+ final TcpOptionsConfig tcpOptions = (TcpOptionsConfig) this.tcpOptions.adaptFromJson(tcp);
+ asyncapiOptions.tcp(tcpOptions);
+ }
+
+ if (object.containsKey(TLS_NAME))
+ {
+ final JsonObject tls = object.getJsonObject(TLS_NAME);
+ final TlsOptionsConfig tlsOptions = (TlsOptionsConfig) this.tlsOptions.adaptFromJson(tls);
+ asyncapiOptions.tls(tlsOptions);
+ }
+
+ if (object.containsKey(HTTP_NAME))
+ {
+ final JsonObject http = object.getJsonObject(HTTP_NAME);
+ final HttpOptionsConfig httpOptions = (HttpOptionsConfig) this.httpOptions.adaptFromJson(http);
+ asyncapiOptions.http(httpOptions);
+ }
+
+ if (object.containsKey(KAFKA_NAME))
+ {
+ final JsonObject kafka = object.getJsonObject(KAFKA_NAME);
+ final KafkaOptionsConfig kafkaOptions = (KafkaOptionsConfig) this.kafkaOptions.adaptFromJson(kafka);
+ asyncapiOptions.kafka(kafkaOptions);
+ }
+
+ if (object.containsKey(MQTT_KAFKA_NAME))
+ {
+ AsyncapiMqttKafkaConfigBuilder mqttKafkaBuilder = AsyncapiMqttKafkaConfig.builder();
+ final JsonObject mqttKafka = object.getJsonObject(MQTT_KAFKA_NAME);
+ if (mqttKafka.containsKey(CHANNELS_NAME))
+ {
+ AsyncapiChannelsConfigBuilder channelsBuilder = AsyncapiChannelsConfig.builder();
+ JsonObject channels = mqttKafka.getJsonObject(CHANNELS_NAME);
+
+ if (channels.containsKey(SESSIONS_NAME))
+ {
+ channelsBuilder.sessions(channels.getString(SESSIONS_NAME));
+ }
+ if (channels.containsKey(MESSAGES_NAME))
+ {
+ channelsBuilder.messages(channels.getString(MESSAGES_NAME));
+ }
+ if (channels.containsKey(RETAINED_NAME))
+ {
+ channelsBuilder.retained(channels.getString(RETAINED_NAME));
+ }
+ asyncapiOptions.mqttKafka(mqttKafkaBuilder.channels(channelsBuilder.build()).build());
+ }
+ }
+ return asyncapiOptions.build();
+ }
+
+ @Override
+ public void adaptContext(
+ ConfigAdapterContext context)
+ {
+ this.readURL = context::readURL;
+ this.tcpOptions = new OptionsConfigAdapter(Kind.BINDING, context);
+ this.tcpOptions.adaptType("tcp");
+ this.tlsOptions = new OptionsConfigAdapter(Kind.BINDING, context);
+ this.tlsOptions.adaptType("tls");
+ this.httpOptions = new OptionsConfigAdapter(Kind.BINDING, context);
+ this.httpOptions.adaptType("http");
+ this.kafkaOptions = new OptionsConfigAdapter(Kind.BINDING, context);
+ this.kafkaOptions.adaptType("kafka");
+ }
+
+ private List asListAsyncapis(
+ JsonObject array)
+ {
+ return array.entrySet().stream()
+ .map(this::asAsyncapi)
+ .collect(toList());
+ }
+
+ private AsyncapiConfig asAsyncapi(
+ Map.Entry entry)
+ {
+ final String apiLabel = entry.getKey();
+ final String location = ((JsonString) entry.getValue()).getString();
+ final String specText = readURL.apply(location);
+ crc.reset();
+ crc.update(specText.getBytes(StandardCharsets.UTF_8));
+ final long apiId = crc.getValue();
+ Asyncapi asyncapi = parser.parse(specText);
+
+ return new AsyncapiConfig(apiLabel, apiId, location, asyncapi);
+ }
+
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiRouteConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiRouteConfig.java
new file mode 100644
index 0000000000..00545968fe
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiRouteConfig.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.config;
+
+import static java.util.stream.Collectors.toList;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.LongPredicate;
+
+import io.aklivity.zilla.runtime.engine.config.RouteConfig;
+
+public final class AsyncapiRouteConfig
+{
+ public final long id;
+ public final AsyncapiWithConfig with;
+ public final List when;
+ private final LongPredicate authorized;
+ private final Function supplyApiId;
+
+ public AsyncapiRouteConfig(
+ RouteConfig route,
+ Function supplyApiId)
+ {
+ this.id = route.id;
+ this.authorized = route.authorized;
+ this.when = route.when.stream()
+ .map(AsyncapiConditionConfig.class::cast)
+ .collect(toList());
+ this.with = (AsyncapiWithConfig) route.with;
+ this.supplyApiId = supplyApiId;
+ }
+
+ boolean authorized(
+ long authorization)
+ {
+ return authorized.test(authorization);
+ }
+
+ boolean matches(
+ long apiId)
+ {
+ return when.isEmpty() || when.stream().anyMatch(m -> m.matches(apiId, supplyApiId));
+ }
+}
diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaWithConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiWithConfig.java
similarity index 66%
rename from runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaWithConfig.java
rename to incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiWithConfig.java
index 5d7b0b77d7..285af68e8e 100644
--- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaWithConfig.java
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiWithConfig.java
@@ -12,17 +12,20 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.config;
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.config;
import io.aklivity.zilla.runtime.engine.config.WithConfig;
-public class MqttKafkaWithConfig extends WithConfig
+public class AsyncapiWithConfig extends WithConfig
{
- public final String messages;
+ public final String apiId;
+ public final String operationId;
- public MqttKafkaWithConfig(
- String messages)
+ public AsyncapiWithConfig(
+ String apiId,
+ String operationId)
{
- this.messages = messages;
+ this.apiId = apiId;
+ this.operationId = operationId;
}
}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiWithConfigAdapter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiWithConfigAdapter.java
new file mode 100644
index 0000000000..7fa0347114
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiWithConfigAdapter.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.config;
+
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonObjectBuilder;
+import jakarta.json.bind.adapter.JsonbAdapter;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiBinding;
+import io.aklivity.zilla.runtime.engine.config.WithConfig;
+import io.aklivity.zilla.runtime.engine.config.WithConfigAdapterSpi;
+
+public class AsyncapiWithConfigAdapter implements WithConfigAdapterSpi, JsonbAdapter
+{
+ private static final String API_ID_NAME = "api-id";
+ private static final String OPERATION_ID_NAME = "operation-id";
+
+ @Override
+ public String type()
+ {
+ return AsyncapiBinding.NAME;
+ }
+
+ @Override
+ public JsonObject adaptToJson(
+ WithConfig with)
+ {
+ AsyncapiWithConfig config = (AsyncapiWithConfig) with;
+
+ JsonObjectBuilder object = Json.createObjectBuilder();
+
+ if (config.apiId != null)
+ {
+ object.add(API_ID_NAME, config.apiId);
+ }
+
+ if (config.operationId != null)
+ {
+ object.add(OPERATION_ID_NAME, config.operationId);
+ }
+
+ return object.build();
+ }
+
+ @Override
+ public WithConfig adaptFromJson(
+ JsonObject object)
+ {
+ String apiId = object.containsKey(API_ID_NAME)
+ ? object.getString(API_ID_NAME)
+ : null;
+
+ String operationId = object.containsKey(OPERATION_ID_NAME)
+ ? object.getString(OPERATION_ID_NAME)
+ : null;
+
+ return new AsyncapiWithConfig(apiId, operationId);
+ }
+}
diff --git a/runtime/binding-http-kafka/src/main/java/io/aklivity/zilla/runtime/binding/http/kafka/internal/config/HttpKafkaWithProduceAsyncHeaderConfig.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/Asyncapi.java
similarity index 63%
rename from runtime/binding-http-kafka/src/main/java/io/aklivity/zilla/runtime/binding/http/kafka/internal/config/HttpKafkaWithProduceAsyncHeaderConfig.java
rename to incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/Asyncapi.java
index cb5ee737f1..0894282dac 100644
--- a/runtime/binding-http-kafka/src/main/java/io/aklivity/zilla/runtime/binding/http/kafka/internal/config/HttpKafkaWithProduceAsyncHeaderConfig.java
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/Asyncapi.java
@@ -12,18 +12,14 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.binding.http.kafka.internal.config;
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
-public final class HttpKafkaWithProduceAsyncHeaderConfig
-{
- public final String name;
- public final String value;
+import java.util.Map;
- public HttpKafkaWithProduceAsyncHeaderConfig(
- String name,
- String value)
- {
- this.name = name;
- this.value = value;
- }
+public class Asyncapi
+{
+ public Map servers;
+ public Map channels;
+ public Map operations;
+ public AsyncapiComponents components;
}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiBinding.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiBinding.java
new file mode 100644
index 0000000000..29eb4fe648
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiBinding.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+public class AsyncapiBinding
+{
+ public String method;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiChannel.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiChannel.java
new file mode 100644
index 0000000000..ddfc9021f1
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiChannel.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+import java.util.LinkedHashMap;
+
+import jakarta.json.bind.annotation.JsonbProperty;
+
+public class AsyncapiChannel
+{
+ public String address;
+ public LinkedHashMap messages;
+ public LinkedHashMap parameters;
+
+ @JsonbProperty("$ref")
+ public String ref;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiComponents.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiComponents.java
new file mode 100644
index 0000000000..aeaa0e9c6b
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiComponents.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+import java.util.Map;
+
+public class AsyncapiComponents
+{
+ public Map securitySchemes;
+ public Map messages;
+ public Map schemas;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiItem.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiItem.java
new file mode 100644
index 0000000000..dbdff777ee
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiItem.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+public class AsyncapiItem
+{
+ public String type;
+ public String description;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiMessage.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiMessage.java
new file mode 100644
index 0000000000..70fd6ab122
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiMessage.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+import jakarta.json.bind.annotation.JsonbProperty;
+
+public class AsyncapiMessage
+{
+ public AsyncapiSchema headers;
+ public String contentType;
+ public AsyncapiSchema payload;
+
+ @JsonbProperty("$ref")
+ public String ref;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiOperation.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiOperation.java
new file mode 100644
index 0000000000..1c53959db8
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiOperation.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+import java.util.Map;
+
+public class AsyncapiOperation
+{
+ public Map bindings;
+ public AsyncapiChannel channel;
+ public String action;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiParameter.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiParameter.java
new file mode 100644
index 0000000000..af864bab5b
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiParameter.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+public class AsyncapiParameter
+{
+ public AsyncapiSchema schema;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiSchema.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiSchema.java
new file mode 100644
index 0000000000..6440924e6d
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiSchema.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+import java.util.List;
+import java.util.Map;
+
+import jakarta.json.bind.annotation.JsonbProperty;
+
+public class AsyncapiSchema
+{
+ public String type;
+ public AsyncapiSchema items;
+ public Map properties;
+ public List required;
+
+ @JsonbProperty("$ref")
+ public String ref;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiSecurityScheme.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiSecurityScheme.java
new file mode 100644
index 0000000000..96ba909021
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiSecurityScheme.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+public class AsyncapiSecurityScheme
+{
+ public String bearerFormat;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiServer.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiServer.java
new file mode 100644
index 0000000000..bcf34983e3
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/model/AsyncapiServer.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.model;
+
+import jakarta.json.JsonArray;
+
+public class AsyncapiServer
+{
+ public String host;
+ public String protocol;
+ public JsonArray security;
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiClientFactory.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiClientFactory.java
new file mode 100644
index 0000000000..3a4e590864
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiClientFactory.java
@@ -0,0 +1,1067 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.stream;
+
+import java.util.function.LongSupplier;
+import java.util.function.LongUnaryOperator;
+
+import org.agrona.DirectBuffer;
+import org.agrona.MutableDirectBuffer;
+import org.agrona.collections.Long2ObjectHashMap;
+import org.agrona.concurrent.UnsafeBuffer;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiBinding;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiConfiguration;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiBindingConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.Flyweight;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.OctetsFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.AbortFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.AsyncapiBeginExFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.BeginFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.DataFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.EndFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.FlushFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.ResetFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.WindowFW;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.binding.BindingHandler;
+import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer;
+import io.aklivity.zilla.runtime.engine.buffer.BufferPool;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+
+public final class AsyncapiClientFactory implements AsyncapiStreamFactory
+{
+ private static final String MQTT_TYPE_NAME = "mqtt";
+ private static final OctetsFW EMPTY_OCTETS = new OctetsFW().wrap(new UnsafeBuffer(), 0, 0);
+
+ private final BeginFW beginRO = new BeginFW();
+ private final DataFW dataRO = new DataFW();
+ private final EndFW endRO = new EndFW();
+ private final FlushFW flushRO = new FlushFW();
+ private final AbortFW abortRO = new AbortFW();
+ private final WindowFW windowRO = new WindowFW();
+ private final ResetFW resetRO = new ResetFW();
+
+ private final BeginFW.Builder beginRW = new BeginFW.Builder();
+ private final DataFW.Builder dataRW = new DataFW.Builder();
+ private final EndFW.Builder endRW = new EndFW.Builder();
+ private final AbortFW.Builder abortRW = new AbortFW.Builder();
+ private final WindowFW.Builder windowRW = new WindowFW.Builder();
+ private final ResetFW.Builder resetRW = new ResetFW.Builder();
+ private final FlushFW.Builder flushRW = new FlushFW.Builder();
+
+ private final AsyncapiBeginExFW asyncapiBeginExRO = new AsyncapiBeginExFW();
+
+ private final AsyncapiBeginExFW.Builder asyncapiBeginExRW = new AsyncapiBeginExFW.Builder();
+
+ private final MutableDirectBuffer writeBuffer;
+ private final MutableDirectBuffer extBuffer;
+ private final BufferPool bufferPool;
+ private final BindingHandler streamFactory;
+ private final LongUnaryOperator supplyInitialId;
+ private final LongUnaryOperator supplyReplyId;
+ private final LongSupplier supplyTraceId;
+ private final Long2ObjectHashMap bindings;
+ private final int asyncapiTypeId;
+ private final int mqttTypeId;
+ private final AsyncapiConfiguration config;
+
+
+ public AsyncapiClientFactory(
+ AsyncapiConfiguration config,
+ EngineContext context)
+ {
+ this.config = config;
+ this.writeBuffer = context.writeBuffer();
+ this.extBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]);
+ this.bufferPool = context.bufferPool();
+ this.streamFactory = context.streamFactory();
+ this.supplyInitialId = context::supplyInitialId;
+ this.supplyReplyId = context::supplyReplyId;
+ this.supplyTraceId = context::supplyTraceId;
+ this.bindings = new Long2ObjectHashMap<>();
+ this.asyncapiTypeId = context.supplyTypeId(AsyncapiBinding.NAME);
+ this.mqttTypeId = context.supplyTypeId(MQTT_TYPE_NAME);
+ }
+
+ @Override
+ public int originTypeId()
+ {
+ return mqttTypeId;
+ }
+
+ @Override
+ public int routedTypeId()
+ {
+ return asyncapiTypeId;
+ }
+
+ @Override
+ public void attach(
+ BindingConfig binding)
+ {
+ AsyncapiBindingConfig asyncapiBinding = new AsyncapiBindingConfig(binding, config.targetRouteId());
+ bindings.put(binding.id, asyncapiBinding);
+ }
+
+ @Override
+ public void detach(
+ long bindingId)
+ {
+ bindings.remove(bindingId);
+ }
+
+ @Override
+ public MessageConsumer newStream(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length,
+ MessageConsumer receiver)
+ {
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ final long originId = begin.originId();
+ final long routedId = begin.routedId();
+ final long initialId = begin.streamId();
+ final long affinity = begin.affinity();
+ final long authorization = begin.authorization();
+ final OctetsFW extension = begin.extension();
+ final AsyncapiBeginExFW asyncapiBeginEx = extension.get(asyncapiBeginExRO::tryWrap);
+
+ final AsyncapiBindingConfig binding = bindings.get(routedId);
+
+ MessageConsumer newStream = null;
+
+ if (binding != null)
+ {
+ final long apiId = asyncapiBeginEx.apiId();
+ final String operationId = asyncapiBeginEx.operationId().asString();
+
+ final long resolvedId = binding.resolveCompositeResolvedId(apiId);
+
+ if (resolvedId != -1)
+ {
+ newStream = new AsyncapiStream(
+ receiver,
+ originId,
+ routedId,
+ initialId,
+ affinity,
+ authorization,
+ resolvedId,
+ operationId)::onAsyncapiMessage;
+ }
+
+ }
+
+ return newStream;
+ }
+
+ private final class AsyncapiStream
+ {
+ private final CompositeStream composite;
+ private final MessageConsumer sender;
+ private final String operationId;
+ private final long originId;
+ private final long routedId;
+ private final long initialId;
+ private final long replyId;
+ private final long affinity;
+ private final long authorization;
+
+ private int state;
+
+ private long replyBudgetId;
+
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+ private long replyBud;
+ private int replyCap;
+
+ private AsyncapiStream(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long initialId,
+ long affinity,
+ long authorization,
+ long resolvedId,
+ String operationId)
+ {
+ this.composite = new CompositeStream(this, routedId, resolvedId, authorization);
+ this.sender = sender;
+ this.originId = originId;
+ this.routedId = routedId;
+ this.initialId = initialId;
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.affinity = affinity;
+ this.authorization = authorization;
+ this.operationId = operationId;
+ }
+
+ private void onAsyncapiMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onAsyncapiBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onAsyncapiData(data);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onAsyncapiEnd(end);
+ break;
+ case FlushFW.TYPE_ID:
+ final FlushFW flush = flushRO.wrap(buffer, index, index + length);
+ onAsyncapiFlush(flush);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onAsyncapiAbort(abort);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onAsyncapiWindow(window);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onAsyncapiReset(reset);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onAsyncapiBegin(
+ BeginFW begin)
+ {
+ final long sequence = begin.sequence();
+ final long acknowledge = begin.acknowledge();
+ final long traceId = begin.traceId();
+ final long authorization = begin.authorization();
+ final long affinity = begin.affinity();
+ final OctetsFW extension = begin.extension();
+ final AsyncapiBeginExFW asyncapiBeginEx = extension.get(asyncapiBeginExRO::tryWrap);
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+ assert acknowledge >= initialAck;
+
+ initialSeq = sequence;
+ initialAck = acknowledge;
+ state = AsyncapiState.openingInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ composite.doCompositeBegin(traceId, asyncapiBeginEx.extension());
+ }
+
+ private void onAsyncapiData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final long authorization = data.authorization();
+ final long budgetId = data.budgetId();
+ final int reserved = data.reserved();
+ final int flags = data.flags();
+ final OctetsFW payload = data.payload();
+ final OctetsFW extension = data.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence + reserved;
+
+ assert initialAck <= initialSeq;
+
+ composite.doCompositeData(traceId, authorization, budgetId, reserved, flags, payload, extension);
+ }
+
+ private void onAsyncapiEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+ final long traceId = end.traceId();
+ final OctetsFW extension = end.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+ state = AsyncapiState.closeInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ composite.doCompositeEnd(traceId, extension);
+ }
+
+ private void onAsyncapiFlush(
+ FlushFW flush)
+ {
+ final long sequence = flush.sequence();
+ final long acknowledge = flush.acknowledge();
+ final long traceId = flush.traceId();
+ final int reserved = flush.reserved();
+ final OctetsFW extension = flush.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+
+ assert initialAck <= initialSeq;
+
+ composite.doCompositeFlush(traceId, reserved, extension);
+ }
+
+ private void onAsyncapiAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+ final OctetsFW extension = abort.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+ state = AsyncapiState.closeInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ composite.doCompositeAbort(traceId, extension);
+ }
+
+ private void onAsyncapiReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final int maximum = reset.maximum();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence <= replySeq;
+ assert acknowledge >= replyAck;
+ assert maximum >= replyMax;
+
+ replyAck = acknowledge;
+ replyMax = maximum;
+ state = AsyncapiState.closeReply(state);
+
+ assert replyAck <= replySeq;
+
+ cleanup(traceId);
+ }
+
+ private void onAsyncapiWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final long traceId = window.traceId();
+ final long budgetId = window.budgetId();
+ final int padding = window.padding();
+ final int capabilities = window.capabilities();
+
+ assert acknowledge <= sequence;
+ assert sequence <= replySeq;
+ assert acknowledge >= replyAck;
+ assert maximum >= replyMax;
+
+ replyAck = acknowledge;
+ replyMax = maximum;
+ replyBud = budgetId;
+ replyPad = padding;
+ replyCap = capabilities;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ composite.doCompositeWindow(traceId, acknowledge, budgetId, padding);
+ }
+
+ private void doCompositeBegin(
+ long traceId,
+ OctetsFW extension)
+ {
+ state = AsyncapiState.openingReply(state);
+
+ final AsyncapiBeginExFW asyncapiBeginEx = asyncapiBeginExRW
+ .wrap(extBuffer, 0, extBuffer.capacity())
+ .typeId(asyncapiTypeId)
+ .operationId(operationId)
+ .extension(extension)
+ .build();
+
+ doBegin(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, affinity, asyncapiBeginEx);
+ }
+
+ private void doCompositeReset(
+ long traceId)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ state = AsyncapiState.closeInitial(state);
+
+ doReset(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, EMPTY_OCTETS);
+ }
+ }
+
+ private void doCompositeWindow(
+ long authorization,
+ long traceId,
+ long budgetId,
+ int padding)
+ {
+ initialAck = composite.initialAck;
+ initialMax = composite.initialMax;
+
+ doWindow(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, padding);
+ }
+
+ private void doCompositeData(
+ long traceId,
+ int flag,
+ int reserved,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+
+ doData(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, replyBudgetId, flag, reserved, payload, extension);
+
+ replySeq += reserved;
+ }
+
+ private void doCompositeEnd(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (AsyncapiState.replyOpening(state) && !AsyncapiState.replyClosed(state))
+ {
+ doEnd(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, extension);
+ }
+
+ state = AsyncapiState.closeReply(state);
+ }
+
+ private void doCompositeAbort(
+ long traceId)
+ {
+ if (AsyncapiState.replyOpening(state) && !AsyncapiState.replyClosed(state))
+ {
+ doAbort(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, EMPTY_OCTETS);
+ }
+
+ state = AsyncapiState.closeInitial(state);
+ }
+
+ private void doAsyncapiFlush(
+ long traceId,
+ int reserved,
+ OctetsFW extension)
+ {
+ doFlush(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, replyBudgetId, reserved, extension);
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ doCompositeReset(traceId);
+ doCompositeAbort(traceId);
+
+ composite.cleanup(traceId);
+ }
+ }
+
+ final class CompositeStream
+ {
+ private final AsyncapiStream delegate;
+ private final long originId;
+ private final long routedId;
+ private final long authorization;
+
+ private long initialId;
+ private long replyId;
+ private MessageConsumer receiver;
+
+ private int state;
+
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+ private long initialBud;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+
+ private CompositeStream(
+ AsyncapiStream delegate,
+ long originId,
+ long routedId,
+ long authorization)
+ {
+ this.delegate = delegate;
+ this.originId = originId;
+ this.routedId = routedId;
+ this.receiver = MessageConsumer.NOOP;
+ this.authorization = authorization;
+ }
+
+ private void doCompositeBegin(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialOpening(state))
+ {
+ assert state == 0;
+
+ this.initialId = supplyInitialId.applyAsLong(routedId);
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.receiver = newStream(this::onCompositeMessage,
+ originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, 0L, extension);
+ state = AsyncapiState.openingInitial(state);
+ }
+ }
+
+ private void doCompositeData(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ int flags,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+ doData(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, flags, reserved, payload, extension);
+
+ initialSeq += reserved;
+
+ assert initialSeq <= initialAck + initialMax;
+ }
+
+ private void doCompositeFlush(
+ long traceId,
+ int reserved,
+ OctetsFW extension)
+ {
+ doFlush(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, initialBud, reserved, extension);
+ }
+
+ private void doCompositeEnd(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ doEnd(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, extension);
+
+ state = AsyncapiState.closeInitial(state);
+ }
+ }
+
+ private void doCompositeAbort(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ doAbort(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, extension);
+
+ state = AsyncapiState.closeInitial(state);
+ }
+ }
+
+ private void onCompositeReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= delegate.initialAck;
+
+ delegate.initialAck = acknowledge;
+ state = AsyncapiState.closeInitial(state);
+
+ assert delegate.initialAck <= delegate.initialSeq;
+
+ delegate.doCompositeReset(traceId);
+ }
+
+
+ private void onCompositeWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final long authorization = window.authorization();
+ final long traceId = window.traceId();
+ final long budgetId = window.budgetId();
+ final int padding = window.padding();
+ final int capabilities = window.capabilities();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= delegate.initialAck;
+ assert maximum >= delegate.initialMax;
+
+ initialAck = acknowledge;
+ initialMax = maximum;
+ initialBud = budgetId;
+ state = AsyncapiState.openInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doCompositeWindow(authorization, traceId, budgetId, padding);
+ }
+
+ private void onCompositeMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onCompositeBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onCompositeData(data);
+ break;
+ case FlushFW.TYPE_ID:
+ final FlushFW flush = flushRO.wrap(buffer, index, index + length);
+ onCompositeFlush(flush);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onCompositeEnd(end);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onCompositeAbort(abort);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onCompositeReset(reset);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onCompositeWindow(window);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onCompositeBegin(
+ BeginFW begin)
+ {
+ final long traceId = begin.traceId();
+ final OctetsFW extension = begin.extension();
+
+ state = AsyncapiState.openingReply(state);
+
+ delegate.doCompositeBegin(traceId, extension);
+ }
+
+ private void onCompositeData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final int flags = data.flags();
+ final int reserved = data.reserved();
+ final OctetsFW payload = data.payload();
+ final OctetsFW extension = data.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence + reserved;
+
+ assert replyAck <= replySeq;
+ assert replySeq <= replyAck + replyMax;
+
+ delegate.doCompositeData(traceId, flags, reserved, payload, extension);
+ }
+
+ private void onCompositeFlush(
+ FlushFW flush)
+ {
+ final long sequence = flush.sequence();
+ final long acknowledge = flush.acknowledge();
+ final long traceId = flush.traceId();
+ final int reserved = flush.reserved();
+ final OctetsFW extension = flush.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence + reserved;
+
+ assert replyAck <= replySeq;
+ assert replySeq <= replyAck + replyMax;
+
+ delegate.doAsyncapiFlush(traceId, reserved, extension);
+ }
+
+ private void onCompositeEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+ final long traceId = end.traceId();
+ final OctetsFW extension = end.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doCompositeEnd(traceId, extension);
+ }
+
+ private void onCompositeAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doCompositeAbort(traceId);
+ }
+
+ private void doCompositeReset(
+ long traceId)
+ {
+ if (!AsyncapiState.replyClosed(state))
+ {
+ doReset(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, EMPTY_OCTETS);
+
+ state = AsyncapiState.closeReply(state);
+ }
+ }
+
+ private void doCompositeWindow(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int padding)
+ {
+ replyAck = Math.max(delegate.replyAck - replyPad, 0);
+ replyMax = delegate.replyMax;
+
+ doWindow(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, budgetId, padding + replyPad);
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ doCompositeAbort(traceId, EMPTY_OCTETS);
+ doCompositeReset(traceId);
+ }
+ }
+
+ private MessageConsumer newStream(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long affinity,
+ Flyweight extension)
+ {
+ final BeginFW begin = beginRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .affinity(affinity)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ final MessageConsumer receiver =
+ streamFactory.newStream(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof(), sender);
+
+ receiver.accept(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof());
+
+ return receiver;
+ }
+
+ private void doBegin(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long affinity,
+ Flyweight extension)
+ {
+ final BeginFW begin = beginRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .affinity(affinity)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof());
+ }
+
+ private void doData(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int flags,
+ int reserved,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+ final DataFW frame = dataRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .flags(flags)
+ .budgetId(budgetId)
+ .reserved(reserved)
+ .payload(payload)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(frame.typeId(), frame.buffer(), frame.offset(), frame.sizeof());
+ }
+
+ private void doFlush(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ OctetsFW extension)
+ {
+ final FlushFW flush = flushRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .budgetId(budgetId)
+ .reserved(reserved)
+ .extension(extension)
+ .build();
+
+ receiver.accept(flush.typeId(), flush.buffer(), flush.offset(), flush.sizeof());
+ }
+
+ private void doEnd(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ OctetsFW extension)
+ {
+ final EndFW end = endRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension)
+ .build();
+
+ receiver.accept(end.typeId(), end.buffer(), end.offset(), end.sizeof());
+ }
+
+ private void doAbort(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ OctetsFW extension)
+ {
+ final AbortFW abort = abortRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension)
+ .build();
+
+ receiver.accept(abort.typeId(), abort.buffer(), abort.offset(), abort.sizeof());
+ }
+
+ private void doWindow(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int padding)
+ {
+ final WindowFW window = windowRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .budgetId(budgetId)
+ .padding(padding)
+ .build();
+
+ sender.accept(window.typeId(), window.buffer(), window.offset(), window.sizeof());
+ }
+
+ private void doReset(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ Flyweight extension)
+ {
+ final ResetFW reset = resetRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(reset.typeId(), reset.buffer(), reset.offset(), reset.sizeof());
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiProxyFactory.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiProxyFactory.java
new file mode 100644
index 0000000000..bd90cbe7a3
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiProxyFactory.java
@@ -0,0 +1,1764 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.stream;
+
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.LongSupplier;
+import java.util.function.LongUnaryOperator;
+
+import org.agrona.DirectBuffer;
+import org.agrona.MutableDirectBuffer;
+import org.agrona.collections.Long2LongHashMap;
+import org.agrona.collections.Long2ObjectHashMap;
+import org.agrona.concurrent.UnsafeBuffer;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiBinding;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiConfiguration;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiBindingConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiRouteConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.Flyweight;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.OctetsFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.AbortFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.AsyncapiBeginExFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.BeginFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.DataFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.EndFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.FlushFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.ResetFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.WindowFW;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.binding.BindingHandler;
+import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer;
+import io.aklivity.zilla.runtime.engine.buffer.BufferPool;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+
+public final class AsyncapiProxyFactory implements AsyncapiStreamFactory
+{
+ private static final OctetsFW EMPTY_OCTETS = new OctetsFW().wrap(new UnsafeBuffer(), 0, 0);
+ private final BeginFW beginRO = new BeginFW();
+ private final DataFW dataRO = new DataFW();
+ private final EndFW endRO = new EndFW();
+ private final FlushFW flushRO = new FlushFW();
+ private final AbortFW abortRO = new AbortFW();
+ private final WindowFW windowRO = new WindowFW();
+ private final ResetFW resetRO = new ResetFW();
+
+ private final BeginFW.Builder beginRW = new BeginFW.Builder();
+ private final DataFW.Builder dataRW = new DataFW.Builder();
+ private final EndFW.Builder endRW = new EndFW.Builder();
+ private final AbortFW.Builder abortRW = new AbortFW.Builder();
+ private final WindowFW.Builder windowRW = new WindowFW.Builder();
+ private final ResetFW.Builder resetRW = new ResetFW.Builder();
+ private final FlushFW.Builder flushRW = new FlushFW.Builder();
+
+ private final AsyncapiBeginExFW asyncapiBeginExRO = new AsyncapiBeginExFW();
+
+ private final AsyncapiBeginExFW.Builder asyncapiBeginExRW = new AsyncapiBeginExFW.Builder();
+
+ private final MutableDirectBuffer writeBuffer;
+ private final MutableDirectBuffer extBuffer;
+ private final BufferPool bufferPool;
+ private final BindingHandler streamFactory;
+ private final LongUnaryOperator supplyInitialId;
+ private final LongUnaryOperator supplyReplyId;
+ private final LongSupplier supplyTraceId;
+ private final Function supplyTypeId;
+ private final Long2ObjectHashMap bindings;
+ private final Long2LongHashMap apiIds;
+ private final int asyncapiTypeId;
+
+ private final AsyncapiConfiguration config;
+
+ public AsyncapiProxyFactory(
+ AsyncapiConfiguration config,
+ EngineContext context)
+ {
+ this.config = config;
+ this.writeBuffer = context.writeBuffer();
+ this.extBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]);
+ this.bufferPool = context.bufferPool();
+ this.streamFactory = context.streamFactory();
+ this.supplyInitialId = context::supplyInitialId;
+ this.supplyReplyId = context::supplyReplyId;
+ this.supplyTypeId = context::supplyTypeId;
+ this.supplyTraceId = context::supplyTraceId;
+ this.bindings = new Long2ObjectHashMap<>();
+ this.apiIds = new Long2LongHashMap(-1);
+ this.asyncapiTypeId = context.supplyTypeId(AsyncapiBinding.NAME);
+ }
+
+
+ @Override
+ public int routedTypeId()
+ {
+ return asyncapiTypeId;
+ }
+
+ @Override
+ public void attach(
+ BindingConfig binding)
+ {
+ AsyncapiBindingConfig asyncapiBinding = new AsyncapiBindingConfig(binding, config.targetRouteId());
+ bindings.put(binding.id, asyncapiBinding);
+ }
+
+ @Override
+ public void detach(
+ long bindingId)
+ {
+ bindings.remove(bindingId);
+ }
+
+ @Override
+ public MessageConsumer newStream(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length,
+ MessageConsumer receiver)
+ {
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ final long originId = begin.originId();
+ final long routedId = begin.routedId();
+ final long initialId = begin.streamId();
+ final long affinity = begin.affinity();
+ final long authorization = begin.authorization();
+ final OctetsFW extension = begin.extension();
+
+ final AsyncapiBindingConfig binding = bindings.get(routedId);
+
+ MessageConsumer newStream = null;
+
+ if (binding != null)
+ {
+ if (!binding.isCompositeOriginId(originId))
+ {
+ final AsyncapiBeginExFW asyncapiBeginEx = extension.get(asyncapiBeginExRO::tryWrap);
+ final long apiId = asyncapiBeginEx.apiId();
+ final String operationId = asyncapiBeginEx.operationId().asString();
+
+ final long compositeResolvedId = binding.resolveCompositeResolvedId(apiId);
+ apiIds.put(apiId, apiId);
+
+ if (compositeResolvedId != -1)
+ {
+ newStream = new AsyncapiServerStream(
+ receiver,
+ originId,
+ routedId,
+ initialId,
+ apiId,
+ authorization,
+ compositeResolvedId,
+ operationId)::onAsyncapiServerMessage;
+ }
+ }
+ else
+ {
+ final long apiId = apiIds.get(affinity);
+ final AsyncapiRouteConfig route = binding.resolve(authorization, apiId);
+
+ if (route != null)
+ {
+ final long clientApiId = binding.options.resolveApiId(route.with.apiId);
+ newStream = new CompositeClientStream(
+ receiver,
+ originId,
+ routedId,
+ initialId,
+ authorization,
+ route.id,
+ affinity,
+ clientApiId)::onCompositeClientMessage;
+ }
+ else
+ {
+ // Needed by the willStream which comes directly from the composite without Asyncapi begin pair
+ Optional asyncapiRoute = binding.routes.stream().findFirst();
+ final long routeId = asyncapiRoute.map(r -> r.id).orElse(0L);
+ final long clientApiId = asyncapiRoute.map(asyncapiRouteConfig ->
+ binding.options.resolveApiId(asyncapiRouteConfig.with.apiId)).orElse(0L);
+
+ newStream = new CompositeClientStream(
+ receiver,
+ originId,
+ routedId,
+ initialId,
+ authorization,
+ routeId,
+ affinity,
+ clientApiId)::onCompositeClientMessage;
+ }
+ }
+ }
+
+ return newStream;
+ }
+
+ private final class AsyncapiServerStream
+ {
+ private final CompositeServerStream delegate;
+ private final MessageConsumer sender;
+ private final long originId;
+ private final long routedId;
+ private final long initialId;
+ private final long replyId;
+ private final long affinity;
+ private final long authorization;
+
+ private int state;
+
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+ private long replyBud;
+ private int replyCap;
+
+ private AsyncapiServerStream(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long initialId,
+ long affinity,
+ long authorization,
+ long compositeResolvedId,
+ String operationId)
+ {
+ this.delegate =
+ new CompositeServerStream(this, compositeResolvedId, compositeResolvedId, authorization, operationId);
+ this.sender = sender;
+ this.originId = originId;
+ this.routedId = routedId;
+ this.initialId = initialId;
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.affinity = affinity;
+ this.authorization = authorization;
+ }
+
+ private void onAsyncapiServerMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onAsyncapiServerBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onAsyncapiServerData(data);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onAsyncapiServerEnd(end);
+ break;
+ case FlushFW.TYPE_ID:
+ final FlushFW flush = flushRO.wrap(buffer, index, index + length);
+ onAsyncapiServerFlush(flush);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onAsyncapiServerAbort(abort);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onAsyncapiServerWindow(window);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onAsyncapiServerReset(reset);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onAsyncapiServerBegin(
+ BeginFW begin)
+ {
+ final long sequence = begin.sequence();
+ final long acknowledge = begin.acknowledge();
+ final long traceId = begin.traceId();
+ final OctetsFW extension = begin.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+ assert acknowledge >= initialAck;
+
+ initialSeq = sequence;
+ initialAck = acknowledge;
+ state = AsyncapiState.openingInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ final AsyncapiBeginExFW asyncapiBeginEx = extension.get(asyncapiBeginExRO::tryWrap);
+ delegate.doCompositeBegin(traceId, affinity, asyncapiBeginEx.extension());
+ }
+
+ private void onAsyncapiServerData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final long authorization = data.authorization();
+ final long budgetId = data.budgetId();
+ final int reserved = data.reserved();
+ final int flags = data.flags();
+ final OctetsFW payload = data.payload();
+ final OctetsFW extension = data.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence + reserved;
+
+ assert initialAck <= initialSeq;
+
+ delegate.doCompositeData(traceId, authorization, budgetId, reserved, flags, payload, extension);
+ }
+
+ private void onAsyncapiServerEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+ final long traceId = end.traceId();
+ final OctetsFW extension = end.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+ state = AsyncapiState.closeInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doCompositeEnd(traceId, extension);
+ }
+
+ private void onAsyncapiServerFlush(
+ FlushFW flush)
+ {
+ final long sequence = flush.sequence();
+ final long acknowledge = flush.acknowledge();
+ final long traceId = flush.traceId();
+ final int reserved = flush.reserved();
+ final OctetsFW extension = flush.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+
+ assert initialAck <= initialSeq;
+
+ delegate.doCompositeFlush(traceId, reserved, extension);
+ }
+
+ private void onAsyncapiServerAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+ final OctetsFW extension = abort.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+ state = AsyncapiState.closeInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doCompositeAbort(traceId, extension);
+ }
+
+ private void doAsyncapiServerReset(
+ long traceId)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ state = AsyncapiState.closeInitial(state);
+
+ doReset(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, EMPTY_OCTETS);
+ }
+ }
+
+ private void doAsyncapiServerWindow(
+ long authorization,
+ long traceId,
+ long budgetId,
+ int padding)
+ {
+ initialAck = delegate.initialAck;
+ initialMax = delegate.initialMax;
+
+ doWindow(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, padding);
+ }
+
+ private void doAsyncapiServerBegin(
+ long traceId,
+ OctetsFW extension)
+ {
+ state = AsyncapiState.openingReply(state);
+
+ final AsyncapiBeginExFW asyncapiBeginEx = asyncapiBeginExRW
+ .wrap(extBuffer, 0, extBuffer.capacity())
+ .typeId(asyncapiTypeId)
+ .extension(extension)
+ .build();
+
+ doBegin(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, affinity, asyncapiBeginEx);
+ }
+
+ private void doAsyncapiServerData(
+ long traceId,
+ int flag,
+ int reserved,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+
+ doData(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, replyBud, flag, reserved, payload, extension);
+
+ replySeq += reserved;
+ }
+
+ private void doAsyncapiServerFlush(
+ long traceId,
+ int reserved,
+ OctetsFW extension)
+ {
+ doFlush(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, replyBud, reserved, extension);
+ }
+
+ private void doAsyncapiServerEnd(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (AsyncapiState.replyOpening(state) && !AsyncapiState.replyClosed(state))
+ {
+ doEnd(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, extension);
+ }
+
+ state = AsyncapiState.closeReply(state);
+ }
+
+ private void doAsyncapiServerAbort(
+ long traceId)
+ {
+ if (AsyncapiState.replyOpening(state) && !AsyncapiState.replyClosed(state))
+ {
+ doAbort(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, EMPTY_OCTETS);
+ }
+
+ state = AsyncapiState.closeInitial(state);
+ }
+
+ private void onAsyncapiServerReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final int maximum = reset.maximum();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence <= replySeq;
+ assert acknowledge >= replyAck;
+ assert maximum >= replyMax;
+
+ replyAck = acknowledge;
+ replyMax = maximum;
+ state = AsyncapiState.closeReply(state);
+
+ assert replyAck <= replySeq;
+
+ cleanup(traceId);
+ }
+
+ private void onAsyncapiServerWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final long traceId = window.traceId();
+ final long budgetId = window.budgetId();
+ final int padding = window.padding();
+ final int capabilities = window.capabilities();
+
+ assert acknowledge <= sequence;
+ assert sequence <= replySeq;
+ assert acknowledge >= replyAck;
+ assert maximum >= replyMax;
+
+ replyAck = acknowledge;
+ replyMax = maximum;
+ replyBud = budgetId;
+ replyPad = padding;
+ replyCap = capabilities;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doCompositeWindow(traceId, acknowledge, budgetId, padding);
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ doAsyncapiServerReset(traceId);
+ doAsyncapiServerAbort(traceId);
+
+ delegate.cleanup(traceId);
+ }
+ }
+
+ final class CompositeServerStream
+ {
+ private final String operationId;
+ private final long originId;
+ private final long routedId;
+ private final long authorization;
+
+ private AsyncapiServerStream delegate;
+ private long initialId;
+ private long replyId;
+ private MessageConsumer receiver;
+
+ private int state;
+
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+ private long initialBud;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+
+ private CompositeServerStream(
+ AsyncapiServerStream delegate,
+ long routedId,
+ long compositeResolvedId,
+ long authorization,
+ String operationId)
+ {
+ this.delegate = delegate;
+ this.originId = routedId;
+ this.routedId = compositeResolvedId;
+ this.receiver = MessageConsumer.NOOP;
+ this.authorization = authorization;
+ this.operationId = operationId;
+ }
+
+ private void onCompositeServerMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onCompositeBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onCompositeData(data);
+ break;
+ case FlushFW.TYPE_ID:
+ final FlushFW flush = flushRO.wrap(buffer, index, index + length);
+ onCompositeFlush(flush);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onCompositeEnd(end);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onCompositeAbort(abort);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onCompositeReset(reset);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onCompositeWindow(window);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onCompositeBegin(
+ BeginFW begin)
+ {
+ final long traceId = begin.traceId();
+ final OctetsFW extension = begin.extension();
+
+ state = AsyncapiState.openingReply(state);
+
+ delegate.doAsyncapiServerBegin(traceId, extension);
+ }
+
+ private void onCompositeData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final long authorization = data.authorization();
+ final int flags = data.flags();
+ final long budgetId = data.budgetId();
+ final int reserved = data.reserved();
+ final OctetsFW payload = data.payload();
+ final OctetsFW extension = data.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence + reserved;
+
+ assert replyAck <= replySeq;
+ assert replySeq <= replyAck + replyMax;
+
+ delegate.doAsyncapiServerData(traceId, flags, reserved, payload, extension);
+ }
+
+ private void onCompositeFlush(
+ FlushFW flush)
+ {
+ final long sequence = flush.sequence();
+ final long acknowledge = flush.acknowledge();
+ final long traceId = flush.traceId();
+ final int reserved = flush.reserved();
+ final OctetsFW extension = flush.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence + reserved;
+
+ assert replyAck <= replySeq;
+ assert replySeq <= replyAck + replyMax;
+
+ delegate.doAsyncapiServerFlush(traceId, reserved, extension);
+ }
+
+ private void onCompositeEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+ final long traceId = end.traceId();
+ final OctetsFW extension = end.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doAsyncapiServerEnd(traceId, extension);
+ }
+
+ private void onCompositeAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doAsyncapiServerAbort(traceId);
+ }
+
+ private void onCompositeReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= delegate.initialAck;
+
+ delegate.initialAck = acknowledge;
+ state = AsyncapiState.closeInitial(state);
+
+ assert delegate.initialAck <= delegate.initialSeq;
+
+ delegate.doAsyncapiServerReset(traceId);
+ }
+
+ private void onCompositeWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final long authorization = window.authorization();
+ final long traceId = window.traceId();
+ final long budgetId = window.budgetId();
+ final int padding = window.padding();
+ final int capabilities = window.capabilities();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= delegate.initialAck;
+ assert maximum >= delegate.initialMax;
+
+ initialAck = acknowledge;
+ initialMax = maximum;
+ initialBud = budgetId;
+ state = AsyncapiState.openInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiServerWindow(authorization, traceId, budgetId, padding);
+ }
+
+ private void doCompositeReset(
+ long traceId)
+ {
+ if (!AsyncapiState.replyClosed(state))
+ {
+ doReset(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, EMPTY_OCTETS);
+
+ state = AsyncapiState.closeReply(state);
+ }
+ }
+
+ private void doCompositeWindow(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int padding)
+ {
+ replyAck = Math.max(delegate.replyAck - replyPad, 0);
+ replyMax = delegate.replyMax;
+
+ doWindow(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, budgetId, padding + replyPad);
+ }
+
+ private void doCompositeBegin(
+ long traceId,
+ long affinity,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialOpening(state))
+ {
+ assert state == 0;
+
+ this.initialId = supplyInitialId.applyAsLong(routedId);
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.receiver = newStream(this::onCompositeServerMessage,
+ originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, affinity, extension);
+ state = AsyncapiState.openingInitial(state);
+ }
+ }
+
+ private void doCompositeData(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ int flags,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+ doData(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, flags, reserved, payload, extension);
+
+ initialSeq += reserved;
+
+ assert initialSeq <= initialAck + initialMax;
+ }
+
+ private void doCompositeFlush(
+ long traceId,
+ int reserved,
+ OctetsFW extension)
+ {
+ doFlush(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, initialBud, reserved, extension);
+ }
+
+ private void doCompositeEnd(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ doEnd(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, extension);
+
+ state = AsyncapiState.closeInitial(state);
+ }
+ }
+
+ private void doCompositeAbort(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ doAbort(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, extension);
+
+ state = AsyncapiState.closeInitial(state);
+ }
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ doCompositeAbort(traceId, EMPTY_OCTETS);
+ doCompositeReset(traceId);
+ }
+ }
+
+ final class CompositeClientStream
+ {
+ private final long originId;
+ private final long routedId;
+ private final MessageConsumer sender;
+ private final long affinity;
+ private final long authorization;
+ private final AsyncapiClientStream delegate;
+
+ private long initialId;
+ private long replyId;
+
+ private int state;
+
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+ private long initialBud;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+
+ private CompositeClientStream(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long initialId,
+ long authorization,
+ long resolvedId,
+ long affinity,
+ long apiId)
+ {
+ this.sender = sender;
+ this.originId = originId;
+ this.routedId = routedId;
+ this.initialId = initialId;
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.affinity = affinity;
+ this.authorization = authorization;
+ this.delegate = new AsyncapiClientStream(this, originId, resolvedId, authorization, apiId);
+ }
+
+ private void onCompositeClientMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onCompositeBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onCompositeData(data);
+ break;
+ case FlushFW.TYPE_ID:
+ final FlushFW flush = flushRO.wrap(buffer, index, index + length);
+ onCompositeFlush(flush);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onCompositeEnd(end);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onCompositeAbort(abort);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onCompositeReset(reset);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onCompositeWindow(window);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onCompositeBegin(
+ BeginFW begin)
+ {
+ final long sequence = begin.sequence();
+ final long acknowledge = begin.acknowledge();
+ final long traceId = begin.traceId();
+ final OctetsFW extension = begin.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+ assert acknowledge >= initialAck;
+
+ initialSeq = sequence;
+ initialAck = acknowledge;
+
+ state = AsyncapiState.openingInitial(state);
+
+ delegate.doAsyncapiClientBegin(traceId, extension);
+ }
+
+ private void onCompositeData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final long authorization = data.authorization();
+ final int flags = data.flags();
+ final long budgetId = data.budgetId();
+ final int reserved = data.reserved();
+ final OctetsFW payload = data.payload();
+ final OctetsFW extension = data.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence + reserved;
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiClientData(traceId, authorization, budgetId, reserved, flags, payload, extension);
+ }
+
+ private void onCompositeFlush(
+ FlushFW flush)
+ {
+ final long sequence = flush.sequence();
+ final long acknowledge = flush.acknowledge();
+ final long traceId = flush.traceId();
+ final int reserved = flush.reserved();
+ final OctetsFW extension = flush.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence + reserved;
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiClientFlush(traceId, reserved, extension);
+ }
+
+ private void onCompositeEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+ final long traceId = end.traceId();
+ final OctetsFW extension = end.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+ state = AsyncapiState.closeInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiClientEnd(traceId, extension);
+ }
+
+ private void onCompositeAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+ state = AsyncapiState.closeInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiClientAbort(traceId, EMPTY_OCTETS);
+ }
+
+ private void onCompositeReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence <= replySeq;
+ assert acknowledge >= replyAck;
+
+ replyAck = acknowledge;
+
+ state = AsyncapiState.closeReply(state);
+
+ assert delegate.initialAck <= delegate.initialSeq;
+
+ delegate.doAsyncapiClientReset(traceId);
+ }
+
+ private void onCompositeWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final long authorization = window.authorization();
+ final long traceId = window.traceId();
+ final long budgetId = window.budgetId();
+ final int padding = window.padding();
+
+ assert acknowledge <= sequence;
+ assert sequence <= replySeq;
+ assert acknowledge >= replyAck;
+ assert maximum >= replyMax;
+
+ replyAck = acknowledge;
+ replyMax = maximum;
+ replyPad = padding;
+ state = AsyncapiState.openReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doAsyncapiClientWindow(authorization, traceId, budgetId, padding);
+ }
+
+ private void doCompositeReset(
+ long traceId)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ state = AsyncapiState.closeInitial(state);
+
+ doReset(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, EMPTY_OCTETS);
+ }
+ }
+
+ private void doCompositeWindow(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int padding)
+ {
+ initialAck = Math.max(delegate.initialAck, 0);
+ initialMax = delegate.initialMax;
+
+ doWindow(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, padding + replyPad);
+ }
+
+ private void doCompositeBegin(
+ long traceId,
+ OctetsFW extension)
+ {
+ replySeq = delegate.replySeq;
+ replyAck = delegate.replyAck;
+ replyMax = delegate.replyMax;
+ state = AsyncapiState.openingReply(state);
+
+ doBegin(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, affinity, extension);
+ }
+
+ private void doCompositeData(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ int flags,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+ doData(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, budgetId, flags, reserved, payload, extension);
+
+ replySeq += reserved;
+
+ assert replySeq <= replyAck + replyMax;
+ }
+
+ private void doCompositeFlush(
+ long traceId,
+ int reserved,
+ OctetsFW extension)
+ {
+ doFlush(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, initialBud, reserved, extension);
+ }
+
+ private void doCompositeEnd(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.replyClosed(state))
+ {
+ replySeq = delegate.replySeq;
+ state = AsyncapiState.closeReply(state);
+
+ doEnd(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, traceId, authorization, extension);
+ }
+ }
+
+ private void doCompositeAbort(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.replyClosed(state))
+ {
+ replySeq = delegate.replySeq;
+ state = AsyncapiState.closeReply(state);
+
+ doAbort(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, extension);
+ }
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ doCompositeAbort(traceId, EMPTY_OCTETS);
+ doCompositeReset(traceId);
+ }
+ }
+
+ final class AsyncapiClientStream
+ {
+ private final long originId;
+ private final long routedId;
+ private final long authorization;
+ private final CompositeClientStream delegate;
+ private final long apiId;
+
+ private long initialId;
+ private long replyId;
+ private MessageConsumer asyncapi;
+ private int state;
+
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+ private long initialBud;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+
+ private AsyncapiClientStream(
+ CompositeClientStream delegate,
+ long originId,
+ long routedId,
+ long authorization,
+ long apiId)
+ {
+ this.delegate = delegate;
+ this.originId = originId;
+ this.routedId = routedId;
+ this.initialId = supplyInitialId.applyAsLong(routedId);
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.authorization = authorization;
+ this.apiId = apiId;
+ }
+
+ private void onAsyncapiClientMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onAsyncapiClientBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onAsyncapiClientData(data);
+ break;
+ case FlushFW.TYPE_ID:
+ final FlushFW flush = flushRO.wrap(buffer, index, index + length);
+ onAsyncapiClientFlush(flush);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onAsyncapiClientEnd(end);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onAsyncapiClientAbort(abort);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onAsyncapiClientReset(reset);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onAsyncapiClientWindow(window);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onAsyncapiClientBegin(
+ BeginFW begin)
+ {
+ final long traceId = begin.traceId();
+ final OctetsFW extension = begin.extension();
+
+ state = AsyncapiState.openingReply(state);
+
+ final AsyncapiBeginExFW asyncapiBeginEx = extension.get(asyncapiBeginExRO::tryWrap);
+ final OctetsFW asyncapiExtension = asyncapiBeginEx != null ? asyncapiBeginEx.extension() : EMPTY_OCTETS;
+
+ delegate.doCompositeBegin(traceId, asyncapiExtension);
+ }
+
+ private void onAsyncapiClientData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final long authorization = data.authorization();
+ final long budgetId = data.budgetId();
+ final int flags = data.flags();
+ final int reserved = data.reserved();
+ final OctetsFW payload = data.payload();
+ final OctetsFW extension = data.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence + reserved;
+
+ assert replyAck <= replySeq;
+ assert replySeq <= replyAck + replyMax;
+
+ delegate.doCompositeData(traceId, authorization, budgetId, reserved, flags, payload, extension);
+ }
+
+ private void onAsyncapiClientFlush(
+ FlushFW flush)
+ {
+ final long sequence = flush.sequence();
+ final long acknowledge = flush.acknowledge();
+ final long traceId = flush.traceId();
+ final int reserved = flush.reserved();
+ final OctetsFW extension = flush.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence + reserved;
+
+ assert replyAck <= replySeq;
+ assert replySeq <= replyAck + replyMax;
+
+ delegate.doCompositeFlush(traceId, reserved, extension);
+ }
+
+ private void onAsyncapiClientEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+ final long traceId = end.traceId();
+ final OctetsFW extension = end.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doCompositeEnd(traceId, extension);
+ }
+
+ private void onAsyncapiClientAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doCompositeAbort(traceId, EMPTY_OCTETS);
+ }
+
+ private void onAsyncapiClientReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= delegate.initialAck;
+
+ delegate.initialAck = acknowledge;
+ state = AsyncapiState.closeInitial(state);
+
+ assert delegate.initialAck <= delegate.initialSeq;
+
+ delegate.doCompositeReset(traceId);
+ }
+
+
+ private void onAsyncapiClientWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final long authorization = window.authorization();
+ final long traceId = window.traceId();
+ final long budgetId = window.budgetId();
+ final int padding = window.padding();
+ final int capabilities = window.capabilities();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= delegate.initialAck;
+ assert maximum >= delegate.initialMax;
+
+ initialAck = acknowledge;
+ initialMax = maximum;
+ initialBud = budgetId;
+ state = AsyncapiState.openInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doCompositeWindow(authorization, traceId, budgetId, padding);
+ }
+
+ private void doAsyncapiClientReset(
+ long traceId)
+ {
+ if (!AsyncapiState.replyClosed(state))
+ {
+ doReset(asyncapi, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, EMPTY_OCTETS);
+
+ state = AsyncapiState.closeReply(state);
+ }
+ }
+
+ private void doAsyncapiClientWindow(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int padding)
+ {
+ replyAck = Math.max(delegate.replyAck - replyPad, 0);
+ replyMax = delegate.replyMax;
+
+ doWindow(asyncapi, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, budgetId, padding + replyPad);
+ }
+
+ private void doAsyncapiClientBegin(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialOpening(state))
+ {
+ assert state == 0;
+
+ final AsyncapiBeginExFW asyncapiBeginEx = asyncapiBeginExRW
+ .wrap(extBuffer, 0, extBuffer.capacity())
+ .typeId(asyncapiTypeId)
+ .apiId(apiId)
+ .operationId((String) null)
+ .extension(extension)
+ .build();
+
+ this.initialId = supplyInitialId.applyAsLong(routedId);
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.asyncapi = newStream(this::onAsyncapiClientMessage,
+ originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, 0L, asyncapiBeginEx);
+ state = AsyncapiState.openingInitial(state);
+ }
+ }
+
+ private void doAsyncapiClientData(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ int flags,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+ doData(asyncapi, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, flags, reserved, payload, extension);
+
+ initialSeq += reserved;
+
+ assert initialSeq <= initialAck + initialMax;
+ }
+
+ private void doAsyncapiClientFlush(
+ long traceId,
+ int reserved,
+ OctetsFW extension)
+ {
+ doFlush(asyncapi, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, initialBud, reserved, extension);
+ }
+
+ private void doAsyncapiClientEnd(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ doEnd(asyncapi, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, extension);
+
+ state = AsyncapiState.closeInitial(state);
+ }
+ }
+
+ private void doAsyncapiClientAbort(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ doAbort(asyncapi, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, extension);
+
+ state = AsyncapiState.closeInitial(state);
+ }
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ doAsyncapiClientAbort(traceId, EMPTY_OCTETS);
+ delegate.doCompositeReset(traceId);
+ }
+ }
+
+ private MessageConsumer newStream(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long affinity,
+ Flyweight extension)
+ {
+ final BeginFW begin = beginRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .affinity(affinity)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ final MessageConsumer receiver =
+ streamFactory.newStream(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof(), sender);
+
+ receiver.accept(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof());
+
+ return receiver;
+ }
+
+ private void doBegin(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long affinity,
+ Flyweight extension)
+ {
+ final BeginFW begin = beginRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .affinity(affinity)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof());
+ }
+
+ private void doData(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int flags,
+ int reserved,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+ final DataFW frame = dataRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .flags(flags)
+ .budgetId(budgetId)
+ .reserved(reserved)
+ .payload(payload)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(frame.typeId(), frame.buffer(), frame.offset(), frame.sizeof());
+ }
+
+ private void doFlush(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ OctetsFW extension)
+ {
+ final FlushFW flush = flushRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .budgetId(budgetId)
+ .reserved(reserved)
+ .extension(extension)
+ .build();
+
+ receiver.accept(flush.typeId(), flush.buffer(), flush.offset(), flush.sizeof());
+ }
+
+ private void doEnd(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ OctetsFW extension)
+ {
+ final EndFW end = endRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension)
+ .build();
+
+ receiver.accept(end.typeId(), end.buffer(), end.offset(), end.sizeof());
+ }
+
+ private void doAbort(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ OctetsFW extension)
+ {
+ final AbortFW abort = abortRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension)
+ .build();
+
+ receiver.accept(abort.typeId(), abort.buffer(), abort.offset(), abort.sizeof());
+ }
+
+ private void doWindow(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int padding)
+ {
+ final WindowFW window = windowRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .budgetId(budgetId)
+ .padding(padding)
+ .build();
+
+ sender.accept(window.typeId(), window.buffer(), window.offset(), window.sizeof());
+ }
+
+ private void doReset(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ Flyweight extension)
+ {
+ final ResetFW reset = resetRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(reset.typeId(), reset.buffer(), reset.offset(), reset.sizeof());
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiServerFactory.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiServerFactory.java
new file mode 100644
index 0000000000..708507f8f4
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiServerFactory.java
@@ -0,0 +1,1085 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.stream;
+
+import java.util.function.Function;
+import java.util.function.LongSupplier;
+import java.util.function.LongUnaryOperator;
+
+import org.agrona.DirectBuffer;
+import org.agrona.MutableDirectBuffer;
+import org.agrona.collections.Long2ObjectHashMap;
+import org.agrona.concurrent.UnsafeBuffer;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiBinding;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.AsyncapiConfiguration;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiBindingConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiRouteConfig;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.Flyweight;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.OctetsFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.AbortFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.AsyncapiBeginExFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.BeginFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.DataFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.EndFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.FlushFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.HttpBeginExFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.MqttBeginExFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.ResetFW;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.WindowFW;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.binding.BindingHandler;
+import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer;
+import io.aklivity.zilla.runtime.engine.buffer.BufferPool;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+
+public final class AsyncapiServerFactory implements AsyncapiStreamFactory
+{
+ private static final String MQTT_TYPE_NAME = "mqtt";
+ private static final String HTTP_TYPE_NAME = "http";
+ private static final OctetsFW EMPTY_OCTETS = new OctetsFW().wrap(new UnsafeBuffer(), 0, 0);
+ private final BeginFW beginRO = new BeginFW();
+ private final BeginFW compositeBeginRO = new BeginFW();
+ private final HttpBeginExFW httpBeginRO = new HttpBeginExFW();
+ private final DataFW dataRO = new DataFW();
+ private final EndFW endRO = new EndFW();
+ private final FlushFW flushRO = new FlushFW();
+ private final AbortFW abortRO = new AbortFW();
+ private final WindowFW windowRO = new WindowFW();
+ private final ResetFW resetRO = new ResetFW();
+
+ private final BeginFW.Builder beginRW = new BeginFW.Builder();
+ private final DataFW.Builder dataRW = new DataFW.Builder();
+ private final EndFW.Builder endRW = new EndFW.Builder();
+ private final AbortFW.Builder abortRW = new AbortFW.Builder();
+ private final WindowFW.Builder windowRW = new WindowFW.Builder();
+ private final ResetFW.Builder resetRW = new ResetFW.Builder();
+ private final FlushFW.Builder flushRW = new FlushFW.Builder();
+
+ private final AsyncapiBeginExFW asyncapiBeginExRO = new AsyncapiBeginExFW();
+ private final MqttBeginExFW mqttBeginExRO = new MqttBeginExFW();
+ private final HttpBeginExFW httpBeginExRO = new HttpBeginExFW();
+
+ private final AsyncapiBeginExFW.Builder asyncapiBeginExRW = new AsyncapiBeginExFW.Builder();
+
+ private final MutableDirectBuffer writeBuffer;
+ private final MutableDirectBuffer extBuffer;
+ private final BufferPool bufferPool;
+ private final BindingHandler streamFactory;
+ private final LongUnaryOperator supplyInitialId;
+ private final LongUnaryOperator supplyReplyId;
+ private final LongSupplier supplyTraceId;
+ private final Function supplyTypeId;
+ private final Long2ObjectHashMap bindings;
+ private final int asyncapiTypeId;
+ private final int mqttTypeId;
+ private final int httpTypeId;
+ private final AsyncapiConfiguration config;
+
+ public AsyncapiServerFactory(
+ AsyncapiConfiguration config,
+ EngineContext context)
+ {
+ this.config = config;
+ this.writeBuffer = context.writeBuffer();
+ this.extBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]);
+ this.bufferPool = context.bufferPool();
+ this.streamFactory = context.streamFactory();
+ this.supplyInitialId = context::supplyInitialId;
+ this.supplyReplyId = context::supplyReplyId;
+ this.supplyTypeId = context::supplyTypeId;
+ this.supplyTraceId = context::supplyTraceId;
+ this.bindings = new Long2ObjectHashMap<>();
+ this.asyncapiTypeId = context.supplyTypeId(AsyncapiBinding.NAME);
+ this.mqttTypeId = context.supplyTypeId(MQTT_TYPE_NAME);
+ this.httpTypeId = context.supplyTypeId(HTTP_TYPE_NAME);
+ }
+
+ @Override
+ public int originTypeId()
+ {
+ return mqttTypeId;
+ }
+
+ @Override
+ public int routedTypeId()
+ {
+ return asyncapiTypeId;
+ }
+
+ @Override
+ public void attach(
+ BindingConfig binding)
+ {
+ AsyncapiBindingConfig asyncapiBinding = new AsyncapiBindingConfig(binding, config.targetRouteId());
+ bindings.put(binding.id, asyncapiBinding);
+ }
+
+ @Override
+ public void detach(
+ long bindingId)
+ {
+ bindings.remove(bindingId);
+ }
+
+ @Override
+ public MessageConsumer newStream(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length,
+ MessageConsumer receiver)
+ {
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ final long originId = begin.originId();
+ final long routedId = begin.routedId();
+ final long initialId = begin.streamId();
+ final long affinity = begin.affinity();
+ final long authorization = begin.authorization();
+ final OctetsFW extension = begin.extension();
+
+ final AsyncapiBindingConfig binding = bindings.get(routedId);
+
+ MessageConsumer newStream = null;
+
+ if (binding != null && binding.isCompositeOriginId(originId))
+ {
+ final AsyncapiRouteConfig route = binding.resolve(authorization);
+
+ if (route != null)
+ {
+ final int compositeTypeId = supplyTypeId.apply(binding.getCompositeOriginType(originId));
+
+ final String operationId = compositeTypeId == httpTypeId ?
+ binding.resolveOperationId(extension.get(httpBeginRO::tryWrap)) : null;
+ final long apiId = binding.options.specs.get(0).apiId;
+ newStream = new CompositeStream(
+ receiver,
+ originId,
+ routedId,
+ initialId,
+ affinity,
+ authorization,
+ route.id,
+ apiId,
+ operationId)::onCompositeMessage;
+ }
+ }
+
+ return newStream;
+ }
+
+ private final class CompositeStream
+ {
+ private final AsyncapiStream delegate;
+ private final MessageConsumer sender;
+ private final long originId;
+ private final long routedId;
+ private final long initialId;
+ private final long replyId;
+ private final long affinity;
+ private final long authorization;
+
+ private int state;
+
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+ private long replyBud;
+ private int replyCap;
+
+ private CompositeStream(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long initialId,
+ long affinity,
+ long authorization,
+ long resolvedId,
+ long apiId,
+ String operationId)
+ {
+ this.delegate = new AsyncapiStream(this, routedId, resolvedId, authorization, apiId, operationId);
+ this.sender = sender;
+ this.originId = originId;
+ this.routedId = routedId;
+ this.initialId = initialId;
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.affinity = affinity;
+ this.authorization = authorization;
+ }
+
+ private void onCompositeMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onCompositeBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onCompositeData(data);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onCompositeEnd(end);
+ break;
+ case FlushFW.TYPE_ID:
+ final FlushFW flush = flushRO.wrap(buffer, index, index + length);
+ onCompositeFlush(flush);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onCompositeAbort(abort);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onCompositeWindow(window);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onCompositeReset(reset);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onCompositeBegin(
+ BeginFW begin)
+ {
+ final long sequence = begin.sequence();
+ final long acknowledge = begin.acknowledge();
+ final long traceId = begin.traceId();
+ final long authorization = begin.authorization();
+ final long affinity = begin.affinity();
+ final OctetsFW extension = begin.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+ assert acknowledge >= initialAck;
+
+ initialSeq = sequence;
+ initialAck = acknowledge;
+ state = AsyncapiState.openingInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiBegin(traceId, extension);
+ }
+
+ private void onCompositeData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final long authorization = data.authorization();
+ final long budgetId = data.budgetId();
+ final int reserved = data.reserved();
+ final int flags = data.flags();
+ final OctetsFW payload = data.payload();
+ final OctetsFW extension = data.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence + reserved;
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiData(traceId, authorization, budgetId, reserved, flags, payload, extension);
+ }
+
+ private void onCompositeEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+ final long traceId = end.traceId();
+ final OctetsFW extension = end.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+ state = AsyncapiState.closeInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiEnd(traceId, extension);
+ }
+
+ private void onCompositeFlush(
+ FlushFW flush)
+ {
+ final long sequence = flush.sequence();
+ final long acknowledge = flush.acknowledge();
+ final long traceId = flush.traceId();
+ final int reserved = flush.reserved();
+ final OctetsFW extension = flush.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiFlush(traceId, reserved, extension);
+ }
+
+ private void onCompositeAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+ final OctetsFW extension = abort.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+ state = AsyncapiState.closeInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doAsyncapiAbort(traceId, extension);
+ }
+
+ private void doCompositeReset(
+ long traceId)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ state = AsyncapiState.closeInitial(state);
+
+ doReset(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, EMPTY_OCTETS);
+ }
+ }
+
+ private void doCompositeWindow(
+ long authorization,
+ long traceId,
+ long budgetId,
+ int padding)
+ {
+ initialAck = delegate.initialAck;
+ initialMax = delegate.initialMax;
+
+ doWindow(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, padding);
+ }
+
+ private void doCompositeBegin(
+ long traceId,
+ OctetsFW extension)
+ {
+ state = AsyncapiState.openingReply(state);
+
+ doBegin(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, affinity, extension);
+ }
+
+ private void doCompositeData(
+ long traceId,
+ int flag,
+ int reserved,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+
+ doData(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, replyBud, flag, reserved, payload, extension);
+
+ replySeq += reserved;
+ }
+
+ private void doCompositeFlush(
+ long traceId,
+ int reserved,
+ OctetsFW extension)
+ {
+ doFlush(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, replyBud, reserved, extension);
+ }
+
+ private void doCompositeEnd(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (AsyncapiState.replyOpening(state) && !AsyncapiState.replyClosed(state))
+ {
+ doEnd(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, extension);
+ }
+
+ state = AsyncapiState.closeReply(state);
+ }
+
+ private void doCompositeAbort(
+ long traceId)
+ {
+ if (AsyncapiState.replyOpening(state) && !AsyncapiState.replyClosed(state))
+ {
+ doAbort(sender, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, EMPTY_OCTETS);
+ }
+
+ state = AsyncapiState.closeInitial(state);
+ }
+
+ private void onCompositeReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final int maximum = reset.maximum();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence <= replySeq;
+ assert acknowledge >= replyAck;
+ assert maximum >= replyMax;
+
+ replyAck = acknowledge;
+ replyMax = maximum;
+ state = AsyncapiState.closeReply(state);
+
+ assert replyAck <= replySeq;
+
+ cleanup(traceId);
+ }
+
+ private void onCompositeWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final long traceId = window.traceId();
+ final long budgetId = window.budgetId();
+ final int padding = window.padding();
+ final int capabilities = window.capabilities();
+
+ assert acknowledge <= sequence;
+ assert sequence <= replySeq;
+ assert acknowledge >= replyAck;
+ assert maximum >= replyMax;
+
+ replyAck = acknowledge;
+ replyMax = maximum;
+ replyBud = budgetId;
+ replyPad = padding;
+ replyCap = capabilities;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doAsyncapiWindow(traceId, acknowledge, budgetId, padding);
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ doCompositeReset(traceId);
+ doCompositeAbort(traceId);
+
+ delegate.cleanup(traceId);
+ }
+ }
+
+ final class AsyncapiStream
+ {
+ private final CompositeStream delegate;
+ private final String operationId;
+ private final long apiId;
+ private final long originId;
+ private final long routedId;
+ private final long authorization;
+
+ private long initialId;
+ private long replyId;
+ private MessageConsumer receiver;
+
+ private int state;
+
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+ private long initialBud;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+
+ private AsyncapiStream(
+ CompositeStream delegate,
+ long originId,
+ long routedId,
+ long authorization,
+ long apiId,
+ String operationId)
+ {
+ this.delegate = delegate;
+ this.originId = originId;
+ this.routedId = routedId;
+ this.receiver = MessageConsumer.NOOP;
+ this.authorization = authorization;
+ this.apiId = apiId;
+ this.operationId = operationId;
+ }
+
+ private void onAsyncapiMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onAsyncapiBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onAsyncapiData(data);
+ break;
+ case FlushFW.TYPE_ID:
+ final FlushFW flush = flushRO.wrap(buffer, index, index + length);
+ onAsyncapiFlush(flush);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onAsyncapiEnd(end);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onAsyncapiAbort(abort);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onAsyncapiReset(reset);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onAsyncapiWindow(window);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onAsyncapiBegin(
+ BeginFW begin)
+ {
+ final long traceId = begin.traceId();
+ final OctetsFW extension = begin.extension();
+
+ state = AsyncapiState.openingReply(state);
+
+ final AsyncapiBeginExFW asyncapiBeginEx = extension.get(asyncapiBeginExRO::tryWrap);
+ final OctetsFW asyncapiExtension = asyncapiBeginEx != null ? asyncapiBeginEx.extension() : EMPTY_OCTETS;
+
+ delegate.doCompositeBegin(traceId, asyncapiExtension);
+ }
+
+ private void onAsyncapiData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final int flags = data.flags();
+ final int reserved = data.reserved();
+ final OctetsFW payload = data.payload();
+ final OctetsFW extension = data.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence + reserved;
+
+ assert replyAck <= replySeq;
+ assert replySeq <= replyAck + replyMax;
+
+ delegate.doCompositeData(traceId, flags, reserved, payload, extension);
+ }
+
+ private void onAsyncapiFlush(
+ FlushFW flush)
+ {
+ final long sequence = flush.sequence();
+ final long acknowledge = flush.acknowledge();
+ final long traceId = flush.traceId();
+ final int reserved = flush.reserved();
+ final OctetsFW extension = flush.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence + reserved;
+
+ assert replyAck <= replySeq;
+ assert replySeq <= replyAck + replyMax;
+
+ delegate.doCompositeFlush(traceId, reserved, extension);
+ }
+
+ private void onAsyncapiEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+ final long traceId = end.traceId();
+ final OctetsFW extension = end.extension();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doCompositeEnd(traceId, extension);
+ }
+
+ private void onAsyncapiAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ replySeq = sequence;
+ state = AsyncapiState.closingReply(state);
+
+ assert replyAck <= replySeq;
+
+ delegate.doCompositeAbort(traceId);
+ }
+
+ private void onAsyncapiReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= delegate.initialAck;
+
+ delegate.initialAck = acknowledge;
+ state = AsyncapiState.closeInitial(state);
+
+ assert delegate.initialAck <= delegate.initialSeq;
+
+ delegate.doCompositeReset(traceId);
+ }
+
+
+ private void onAsyncapiWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final long authorization = window.authorization();
+ final long traceId = window.traceId();
+ final long budgetId = window.budgetId();
+ final int padding = window.padding();
+ final int capabilities = window.capabilities();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= delegate.initialAck;
+ assert maximum >= delegate.initialMax;
+
+ initialAck = acknowledge;
+ initialMax = maximum;
+ initialBud = budgetId;
+ state = AsyncapiState.openInitial(state);
+
+ assert initialAck <= initialSeq;
+
+ delegate.doCompositeWindow(authorization, traceId, budgetId, padding);
+ }
+
+ private void doAsyncapiReset(
+ long traceId)
+ {
+ if (!AsyncapiState.replyClosed(state))
+ {
+ doReset(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, EMPTY_OCTETS);
+
+ state = AsyncapiState.closeReply(state);
+ }
+ }
+
+ private void doAsyncapiWindow(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int padding)
+ {
+ replyAck = Math.max(delegate.replyAck - replyPad, 0);
+ replyMax = delegate.replyMax;
+
+ doWindow(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax,
+ traceId, authorization, budgetId, padding + replyPad);
+ }
+
+ private void doAsyncapiBegin(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialOpening(state))
+ {
+ assert state == 0;
+
+ final AsyncapiBeginExFW asyncapiBeginEx = asyncapiBeginExRW
+ .wrap(extBuffer, 0, extBuffer.capacity())
+ .typeId(asyncapiTypeId)
+ .apiId(apiId)
+ .operationId(operationId)
+ .extension(extension)
+ .build();
+
+ this.initialId = supplyInitialId.applyAsLong(routedId);
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.receiver = newStream(this::onAsyncapiMessage,
+ originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, 0L, asyncapiBeginEx);
+ state = AsyncapiState.openingInitial(state);
+ }
+ }
+
+ private void doAsyncapiData(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ int flags,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+ doData(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, flags, reserved, payload, extension);
+
+ initialSeq += reserved;
+
+ assert initialSeq <= initialAck + initialMax;
+ }
+
+ private void doAsyncapiFlush(
+ long traceId,
+ int reserved,
+ OctetsFW extension)
+ {
+ doFlush(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, initialBud, reserved, extension);
+ }
+
+ private void doAsyncapiEnd(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ doEnd(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, extension);
+
+ state = AsyncapiState.closeInitial(state);
+ }
+ }
+
+ private void doAsyncapiAbort(
+ long traceId,
+ OctetsFW extension)
+ {
+ if (!AsyncapiState.initialClosed(state))
+ {
+ doAbort(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, extension);
+
+ state = AsyncapiState.closeInitial(state);
+ }
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ doAsyncapiAbort(traceId, EMPTY_OCTETS);
+ doAsyncapiReset(traceId);
+ }
+ }
+
+ private MessageConsumer newStream(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long affinity,
+ Flyweight extension)
+ {
+ final BeginFW begin = beginRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .affinity(affinity)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ final MessageConsumer receiver =
+ streamFactory.newStream(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof(), sender);
+
+ receiver.accept(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof());
+
+ return receiver;
+ }
+
+ private void doBegin(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long affinity,
+ Flyweight extension)
+ {
+ final BeginFW begin = beginRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .affinity(affinity)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof());
+ }
+
+ private void doData(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int flags,
+ int reserved,
+ OctetsFW payload,
+ Flyweight extension)
+ {
+ final DataFW frame = dataRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .flags(flags)
+ .budgetId(budgetId)
+ .reserved(reserved)
+ .payload(payload)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(frame.typeId(), frame.buffer(), frame.offset(), frame.sizeof());
+ }
+
+ private void doFlush(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ OctetsFW extension)
+ {
+ final FlushFW flush = flushRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .budgetId(budgetId)
+ .reserved(reserved)
+ .extension(extension)
+ .build();
+
+ receiver.accept(flush.typeId(), flush.buffer(), flush.offset(), flush.sizeof());
+ }
+
+ private void doEnd(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ OctetsFW extension)
+ {
+ final EndFW end = endRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension)
+ .build();
+
+ receiver.accept(end.typeId(), end.buffer(), end.offset(), end.sizeof());
+ }
+
+ private void doAbort(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ OctetsFW extension)
+ {
+ final AbortFW abort = abortRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension)
+ .build();
+
+ receiver.accept(abort.typeId(), abort.buffer(), abort.offset(), abort.sizeof());
+ }
+
+ private void doWindow(
+ MessageConsumer sender,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ long budgetId,
+ int padding)
+ {
+ final WindowFW window = windowRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .budgetId(budgetId)
+ .padding(padding)
+ .build();
+
+ sender.accept(window.typeId(), window.buffer(), window.offset(), window.sizeof());
+ }
+
+ private void doReset(
+ MessageConsumer receiver,
+ long originId,
+ long routedId,
+ long streamId,
+ long sequence,
+ long acknowledge,
+ int maximum,
+ long traceId,
+ long authorization,
+ Flyweight extension)
+ {
+ final ResetFW reset = resetRW.wrap(writeBuffer, 0, writeBuffer.capacity())
+ .originId(originId)
+ .routedId(routedId)
+ .streamId(streamId)
+ .sequence(sequence)
+ .acknowledge(acknowledge)
+ .maximum(maximum)
+ .traceId(traceId)
+ .authorization(authorization)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
+ .build();
+
+ receiver.accept(reset.typeId(), reset.buffer(), reset.offset(), reset.sizeof());
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiState.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiState.java
new file mode 100644
index 0000000000..8a8724fd20
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiState.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.stream;
+
+public final class AsyncapiState
+{
+ private static final int INITIAL_OPENING = 0x10;
+ private static final int INITIAL_OPENED = 0x20;
+ private static final int INITIAL_CLOSING = 0x40;
+ private static final int INITIAL_CLOSED = 0x80;
+ private static final int REPLY_OPENED = 0x01;
+ private static final int REPLY_OPENING = 0x02;
+ private static final int REPLY_CLOSING = 0x04;
+ private static final int REPLY_CLOSED = 0x08;
+
+ static int openingInitial(
+ int state)
+ {
+ return state | INITIAL_OPENING;
+ }
+
+ static int openInitial(
+ int state)
+ {
+ return openingInitial(state) | INITIAL_OPENED;
+ }
+
+ static boolean initialOpening(
+ int state)
+ {
+ return (state & INITIAL_OPENING) != 0;
+ }
+
+ static boolean initialOpened(
+ int state)
+ {
+ return (state & INITIAL_OPENED) != 0;
+ }
+
+ static int closingInitial(
+ int state)
+ {
+ return state | INITIAL_CLOSING;
+ }
+
+ static int closeInitial(
+ int state)
+ {
+ return closingInitial(state) | INITIAL_CLOSED;
+ }
+
+ static boolean initialClosing(
+ int state)
+ {
+ return (state & INITIAL_CLOSING) != 0;
+ }
+
+ static boolean initialClosed(
+ int state)
+ {
+ return (state & INITIAL_CLOSED) != 0;
+ }
+
+ static int openingReply(
+ int state)
+ {
+ return state | REPLY_OPENING;
+ }
+
+ static int openReply(
+ int state)
+ {
+ return openingReply(state) | REPLY_OPENED;
+ }
+
+ static boolean replyOpening(
+ int state)
+ {
+ return (state & REPLY_OPENING) != 0;
+ }
+
+ static boolean replyOpened(
+ int state)
+ {
+ return (state & REPLY_OPENED) != 0;
+ }
+
+ static int closingReply(
+ int state)
+ {
+ return state | REPLY_CLOSING;
+ }
+
+ static int closeReply(
+ int state)
+ {
+ return closingReply(state) | REPLY_CLOSED;
+ }
+
+ static boolean replyClosing(
+ int state)
+ {
+ return (state & REPLY_CLOSING) != 0;
+ }
+
+ static boolean replyClosed(
+ int state)
+ {
+ return (state & REPLY_CLOSED) != 0;
+ }
+
+ static boolean closed(
+ int state)
+ {
+ return initialClosed(state) && replyClosed(state);
+ }
+
+ private AsyncapiState()
+ {
+ // utility
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiStreamFactory.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiStreamFactory.java
new file mode 100644
index 0000000000..7a8c299e21
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/AsyncapiStreamFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.stream;
+
+import io.aklivity.zilla.runtime.engine.binding.BindingHandler;
+import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+
+public interface AsyncapiStreamFactory extends BindingHandler
+{
+ void attach(
+ BindingConfig binding);
+
+ void detach(
+ long bindingId);
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiChannelView.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiChannelView.java
new file mode 100644
index 0000000000..7b087a05ad
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiChannelView.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.view;
+
+import java.util.Map;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiChannel;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiMessage;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiParameter;
+
+public final class AsyncapiChannelView extends AsyncapiResolvable
+{
+ private final AsyncapiChannel channel;
+
+ public String address()
+ {
+ return channel.address;
+ }
+
+ public Map messages()
+ {
+ return channel.messages;
+ }
+
+ public Map parameters()
+ {
+ return channel.parameters;
+ }
+
+ public static AsyncapiChannelView of(
+ Map channels,
+ AsyncapiChannel asyncapiChannel)
+ {
+ return new AsyncapiChannelView(channels, asyncapiChannel);
+ }
+
+ private AsyncapiChannelView(
+ Map channels,
+ AsyncapiChannel channel)
+ {
+ super(channels, "#/channels/(\\w+)");
+ this.channel = channel.ref == null ? channel : resolveRef(channel.ref);
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiMessageView.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiMessageView.java
new file mode 100644
index 0000000000..a1087313ad
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiMessageView.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.view;
+
+import java.util.Map;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiMessage;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiSchema;
+
+public final class AsyncapiMessageView extends AsyncapiResolvable
+{
+ private final AsyncapiMessage message;
+
+ public String refKey()
+ {
+ return key;
+ }
+
+ public AsyncapiSchema headers()
+ {
+ return message.headers;
+ }
+
+ public String contentType()
+ {
+ return message.contentType;
+ }
+
+ public AsyncapiSchema payload()
+ {
+ return message.payload;
+ }
+
+ public static AsyncapiMessageView of(
+ Map messages,
+ AsyncapiMessage asyncapiMessage)
+ {
+ return new AsyncapiMessageView(messages, asyncapiMessage);
+ }
+
+ private AsyncapiMessageView(
+ Map messages,
+ AsyncapiMessage message)
+ {
+ super(messages, "#/components/messages/(\\w+)");
+ this.message = message.ref == null ? message : resolveRef(message.ref);
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiResolvable.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiResolvable.java
new file mode 100644
index 0000000000..2334037c55
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiResolvable.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.view;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class AsyncapiResolvable
+{
+ private final Map map;
+ private final Matcher matcher;
+
+ protected String key;
+
+ public AsyncapiResolvable(
+ Map map,
+ String regex)
+ {
+ this.map = map;
+ this.matcher = Pattern.compile(regex).matcher("");
+ }
+
+ protected T resolveRef(
+ String ref)
+ {
+ T result = null;
+ if (matcher.reset(ref).matches())
+ {
+ key = matcher.group(1);
+ result = map.get(key);
+ }
+ return result;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiSchemaView.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiSchemaView.java
new file mode 100644
index 0000000000..8755f88bb2
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiSchemaView.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.view;
+
+import java.util.List;
+import java.util.Map;
+
+import jakarta.json.bind.annotation.JsonbPropertyOrder;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiItem;
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiSchema;
+
+@JsonbPropertyOrder({
+ "type",
+ "items",
+ "properties",
+ "required"
+})
+public final class AsyncapiSchemaView extends AsyncapiResolvable
+{
+ private static final String ARRAY_TYPE = "array";
+
+ private final AsyncapiSchema schema;
+ private final Map schemas;
+
+ public String getType()
+ {
+ return schema.type;
+ }
+
+ public String refKey()
+ {
+ return key;
+ }
+
+ public AsyncapiSchemaView getItems()
+ {
+ return schema.items == null ? null : AsyncapiSchemaView.of(schemas, schema.items);
+ }
+
+ public Map getProperties()
+ {
+ return schema.properties;
+ }
+
+ public List getRequired()
+ {
+ return schema.required;
+ }
+
+ public static AsyncapiSchemaView of(
+ Map schemas,
+ AsyncapiSchema asyncapiSchema)
+ {
+ return new AsyncapiSchemaView(schemas, asyncapiSchema);
+ }
+
+ private AsyncapiSchemaView(
+ Map schemas,
+ AsyncapiSchema schema)
+ {
+ super(schemas, "#/components/schemas/(\\w+)");
+ if (schema.ref != null)
+ {
+ schema = resolveRef(schema.ref);
+ }
+ else if (ARRAY_TYPE.equals(schema.type) && schema.items != null && schema.items.ref != null)
+ {
+ schema.items = resolveRef(schema.items.ref);
+ }
+ this.schemas = schemas;
+ this.schema = schema;
+ }
+}
diff --git a/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiServerView.java b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiServerView.java
new file mode 100644
index 0000000000..e1df7b7158
--- /dev/null
+++ b/incubator/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/view/AsyncapiServerView.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.asyncapi.internal.view;
+
+import static org.agrona.LangUtil.rethrowUnchecked;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiServer;
+
+public final class AsyncapiServerView
+{
+ private final AsyncapiServer server;
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ public URI url()
+ {
+ return URI.create(server.host);
+ }
+
+ public List