@shortlink-org/portolan 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (826) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +387 -0
  3. package/catalog/enum_test.go +46 -0
  4. package/catalog/model.go +932 -0
  5. package/catalog/roundtrip_test.go +185 -0
  6. package/catalog/via_test.go +38 -0
  7. package/cli/portolan.mjs +368 -0
  8. package/go.mod +14 -0
  9. package/go.sum +14 -0
  10. package/index.html +13 -0
  11. package/internal/commands/cargo.go +154 -0
  12. package/internal/commands/commands.go +143 -0
  13. package/internal/commands/commands_test.go +323 -0
  14. package/internal/commands/gradle.go +77 -0
  15. package/internal/commands/justfile.go +82 -0
  16. package/internal/commands/makefile.go +106 -0
  17. package/internal/commands/maven.go +93 -0
  18. package/internal/commands/packagejson.go +159 -0
  19. package/internal/commands/pyproject.go +169 -0
  20. package/internal/commands/taskfile.go +101 -0
  21. package/internal/commands/testdata/estate/.cargo/config.toml +7 -0
  22. package/internal/commands/testdata/estate/Makefile +33 -0
  23. package/internal/commands/testdata/estate/Taskfile.yml +21 -0
  24. package/internal/commands/testdata/estate/build.gradle.kts +21 -0
  25. package/internal/commands/testdata/estate/justfile +20 -0
  26. package/internal/commands/testdata/estate/package.json +13 -0
  27. package/internal/commands/testdata/estate/pom.xml +29 -0
  28. package/internal/commands/testdata/estate/pyproject.toml +27 -0
  29. package/internal/commands/testdata/estate/xtask/src/main.rs +27 -0
  30. package/internal/commands/testdata/golden/commands.json +305 -0
  31. package/internal/gohttp/analyze.go +2500 -0
  32. package/internal/gohttp/endpoints.go +1067 -0
  33. package/internal/gohttp/roots.go +320 -0
  34. package/internal/gohttp/typed.go +143 -0
  35. package/internal/goscan/constants.go +85 -0
  36. package/internal/goscan/goscan_test.go +227 -0
  37. package/internal/goscan/names.go +52 -0
  38. package/internal/goscan/parse_test.go +11 -0
  39. package/internal/goscan/source.go +36 -0
  40. package/internal/goscan/tree.go +155 -0
  41. package/internal/goscan/types.go +99 -0
  42. package/internal/wsdl/ids.go +127 -0
  43. package/internal/wsdl/ids_test.go +21 -0
  44. package/internal/wsdl/model.go +62 -0
  45. package/internal/wsdl/parse.go +920 -0
  46. package/internal/wsdl/parse_test.go +133 -0
  47. package/package.json +117 -0
  48. package/plugin/describe.go +107 -0
  49. package/plugin/describe_test.go +114 -0
  50. package/plugin/protocol.go +117 -0
  51. package/plugin/schematest/schematest.go +126 -0
  52. package/plugins/README.md +1160 -0
  53. package/plugins/extract-adr/describe.go +19 -0
  54. package/plugins/extract-adr/describe_test.go +11 -0
  55. package/plugins/extract-adr/extract.go +153 -0
  56. package/plugins/extract-adr/extract_test.go +350 -0
  57. package/plugins/extract-adr/history.go +99 -0
  58. package/plugins/extract-adr/main.go +65 -0
  59. package/plugins/extract-adr/options.schema.json +26 -0
  60. package/plugins/extract-adr/parse.go +642 -0
  61. package/plugins/extract-adr/parse_test.go +405 -0
  62. package/plugins/extract-asyncapi/describe.go +19 -0
  63. package/plugins/extract-asyncapi/describe_test.go +11 -0
  64. package/plugins/extract-asyncapi/extract.go +315 -0
  65. package/plugins/extract-asyncapi/extract_test.go +197 -0
  66. package/plugins/extract-asyncapi/main.go +48 -0
  67. package/plugins/extract-asyncapi/options.schema.json +26 -0
  68. package/plugins/extract-asyncapi/spec.go +151 -0
  69. package/plugins/extract-celery/README.md +169 -0
  70. package/plugins/extract-celery/extract.py +346 -0
  71. package/plugins/extract-celery/extract_test.py +192 -0
  72. package/plugins/extract-celery/main.py +66 -0
  73. package/plugins/extract-celery/options.py +31 -0
  74. package/plugins/extract-celery/options.schema.json +31 -0
  75. package/plugins/extract-celery/producers.py +156 -0
  76. package/plugins/extract-celery/routes_test.py +106 -0
  77. package/plugins/extract-commands/describe.go +19 -0
  78. package/plugins/extract-commands/describe_test.go +11 -0
  79. package/plugins/extract-commands/extract.go +79 -0
  80. package/plugins/extract-commands/extract_test.go +92 -0
  81. package/plugins/extract-commands/main.go +55 -0
  82. package/plugins/extract-commands/options.schema.json +20 -0
  83. package/plugins/extract-csr/avro.go +258 -0
  84. package/plugins/extract-csr/describe.go +19 -0
  85. package/plugins/extract-csr/describe_test.go +11 -0
  86. package/plugins/extract-csr/extract.go +338 -0
  87. package/plugins/extract-csr/extract_test.go +374 -0
  88. package/plugins/extract-csr/jsonschema.go +343 -0
  89. package/plugins/extract-csr/lock.go +25 -0
  90. package/plugins/extract-csr/main.go +84 -0
  91. package/plugins/extract-csr/options.schema.json +43 -0
  92. package/plugins/extract-csr/subject.go +102 -0
  93. package/plugins/extract-django/README.md +386 -0
  94. package/plugins/extract-django/apps.py +100 -0
  95. package/plugins/extract-django/auth.py +302 -0
  96. package/plugins/extract-django/auth_test.py +188 -0
  97. package/plugins/extract-django/clients.py +121 -0
  98. package/plugins/extract-django/contracts.py +458 -0
  99. package/plugins/extract-django/database.py +119 -0
  100. package/plugins/extract-django/domain.py +318 -0
  101. package/plugins/extract-django/events.py +86 -0
  102. package/plugins/extract-django/extract.py +601 -0
  103. package/plugins/extract-django/extract_test.py +397 -0
  104. package/plugins/extract-django/flows.py +1278 -0
  105. package/plugins/extract-django/flows_test.py +338 -0
  106. package/plugins/extract-django/ids.py +42 -0
  107. package/plugins/extract-django/ids_test.py +30 -0
  108. package/plugins/extract-django/lifecycle.py +222 -0
  109. package/plugins/extract-django/lifecycle_test.py +76 -0
  110. package/plugins/extract-django/main.py +66 -0
  111. package/plugins/extract-django/openapi.py +229 -0
  112. package/plugins/extract-django/openapi_test.py +60 -0
  113. package/plugins/extract-django/operations.py +96 -0
  114. package/plugins/extract-django/options.py +61 -0
  115. package/plugins/extract-django/options.schema.json +126 -0
  116. package/plugins/extract-django/routing.py +214 -0
  117. package/plugins/extract-django/routing_test.py +198 -0
  118. package/plugins/extract-django/serializers.py +558 -0
  119. package/plugins/extract-django/store.py +434 -0
  120. package/plugins/extract-django/transport.py +242 -0
  121. package/plugins/extract-flows/describe.go +19 -0
  122. package/plugins/extract-flows/describe_test.go +11 -0
  123. package/plugins/extract-flows/extract.go +91 -0
  124. package/plugins/extract-flows/main.go +45 -0
  125. package/plugins/extract-flows/options.schema.json +16 -0
  126. package/plugins/extract-flows/parse.go +593 -0
  127. package/plugins/extract-flows/parse_test.go +204 -0
  128. package/plugins/extract-glossary/describe.go +19 -0
  129. package/plugins/extract-glossary/describe_test.go +11 -0
  130. package/plugins/extract-glossary/extract.go +115 -0
  131. package/plugins/extract-glossary/extract_test.go +220 -0
  132. package/plugins/extract-glossary/main.go +59 -0
  133. package/plugins/extract-glossary/options.schema.json +21 -0
  134. package/plugins/extract-glossary/parse.go +214 -0
  135. package/plugins/extract-glossary/parse_test.go +203 -0
  136. package/plugins/extract-go/aggregate.go +214 -0
  137. package/plugins/extract-go/client.go +409 -0
  138. package/plugins/extract-go/client_test.go +266 -0
  139. package/plugins/extract-go/describe.go +19 -0
  140. package/plugins/extract-go/describe_test.go +11 -0
  141. package/plugins/extract-go/enum.go +195 -0
  142. package/plugins/extract-go/enum_test.go +82 -0
  143. package/plugins/extract-go/event.go +99 -0
  144. package/plugins/extract-go/extract.go +191 -0
  145. package/plugins/extract-go/extract_test.go +261 -0
  146. package/plugins/extract-go/flow.go +1441 -0
  147. package/plugins/extract-go/flow_test.go +609 -0
  148. package/plugins/extract-go/httpclient.go +174 -0
  149. package/plugins/extract-go/httpclient_test.go +296 -0
  150. package/plugins/extract-go/ids.go +92 -0
  151. package/plugins/extract-go/layout.go +225 -0
  152. package/plugins/extract-go/layout_test.go +125 -0
  153. package/plugins/extract-go/lifecycle.go +324 -0
  154. package/plugins/extract-go/lifecycle_test.go +108 -0
  155. package/plugins/extract-go/main.go +79 -0
  156. package/plugins/extract-go/operation.go +157 -0
  157. package/plugins/extract-go/options.schema.json +66 -0
  158. package/plugins/extract-go/source.go +316 -0
  159. package/plugins/extract-go/transport.go +321 -0
  160. package/plugins/extract-go/transport_test.go +145 -0
  161. package/plugins/extract-go/wiring.go +434 -0
  162. package/plugins/extract-go-nats/describe.go +19 -0
  163. package/plugins/extract-go-nats/describe_test.go +11 -0
  164. package/plugins/extract-go-nats/extract.go +177 -0
  165. package/plugins/extract-go-nats/extract_test.go +389 -0
  166. package/plugins/extract-go-nats/index.go +379 -0
  167. package/plugins/extract-go-nats/main.go +42 -0
  168. package/plugins/extract-go-nats/options.schema.json +21 -0
  169. package/plugins/extract-go-nats/resolve.go +161 -0
  170. package/plugins/extract-go-nats/sites.go +224 -0
  171. package/plugins/extract-graphql/describe.go +19 -0
  172. package/plugins/extract-graphql/describe_test.go +11 -0
  173. package/plugins/extract-graphql/extract.go +433 -0
  174. package/plugins/extract-graphql/extract_test.go +256 -0
  175. package/plugins/extract-graphql/ids.go +49 -0
  176. package/plugins/extract-graphql/lex.go +237 -0
  177. package/plugins/extract-graphql/main.go +51 -0
  178. package/plugins/extract-graphql/options.schema.json +31 -0
  179. package/plugins/extract-graphql/parse.go +621 -0
  180. package/plugins/extract-graphql/parse_test.go +122 -0
  181. package/plugins/extract-http-clients/describe.go +19 -0
  182. package/plugins/extract-http-clients/describe_test.go +11 -0
  183. package/plugins/extract-http-clients/extract.go +705 -0
  184. package/plugins/extract-http-clients/extract_test.go +1263 -0
  185. package/plugins/extract-http-clients/main.go +42 -0
  186. package/plugins/extract-http-clients/options.schema.json +33 -0
  187. package/plugins/extract-java/README.md +190 -0
  188. package/plugins/extract-java/build/org/portolan/extract/Catalog.class +0 -0
  189. package/plugins/extract-java/build/org/portolan/extract/Clients$1.class +0 -0
  190. package/plugins/extract-java/build/org/portolan/extract/Clients$2.class +0 -0
  191. package/plugins/extract-java/build/org/portolan/extract/Clients$Call.class +0 -0
  192. package/plugins/extract-java/build/org/portolan/extract/Clients$Client.class +0 -0
  193. package/plugins/extract-java/build/org/portolan/extract/Clients$Route.class +0 -0
  194. package/plugins/extract-java/build/org/portolan/extract/Clients.class +0 -0
  195. package/plugins/extract-java/build/org/portolan/extract/Domain$Aggregate.class +0 -0
  196. package/plugins/extract-java/build/org/portolan/extract/Domain.class +0 -0
  197. package/plugins/extract-java/build/org/portolan/extract/Events$Found.class +0 -0
  198. package/plugins/extract-java/build/org/portolan/extract/Events.class +0 -0
  199. package/plugins/extract-java/build/org/portolan/extract/Extract.class +0 -0
  200. package/plugins/extract-java/build/org/portolan/extract/Flows$1.class +0 -0
  201. package/plugins/extract-java/build/org/portolan/extract/Flows$Binding.class +0 -0
  202. package/plugins/extract-java/build/org/portolan/extract/Flows$Draft.class +0 -0
  203. package/plugins/extract-java/build/org/portolan/extract/Flows$Frame.class +0 -0
  204. package/plugins/extract-java/build/org/portolan/extract/Flows$Options.class +0 -0
  205. package/plugins/extract-java/build/org/portolan/extract/Flows.class +0 -0
  206. package/plugins/extract-java/build/org/portolan/extract/Ids.class +0 -0
  207. package/plugins/extract-java/build/org/portolan/extract/Json$Reader.class +0 -0
  208. package/plugins/extract-java/build/org/portolan/extract/Json.class +0 -0
  209. package/plugins/extract-java/build/org/portolan/extract/Lifecycle$1.class +0 -0
  210. package/plugins/extract-java/build/org/portolan/extract/Lifecycle$Move.class +0 -0
  211. package/plugins/extract-java/build/org/portolan/extract/Lifecycle.class +0 -0
  212. package/plugins/extract-java/build/org/portolan/extract/Main.class +0 -0
  213. package/plugins/extract-java/build/org/portolan/extract/OpenApi$Operation.class +0 -0
  214. package/plugins/extract-java/build/org/portolan/extract/OpenApi$Spec.class +0 -0
  215. package/plugins/extract-java/build/org/portolan/extract/OpenApi.class +0 -0
  216. package/plugins/extract-java/build/org/portolan/extract/Operations$1.class +0 -0
  217. package/plugins/extract-java/build/org/portolan/extract/Operations$UseCase.class +0 -0
  218. package/plugins/extract-java/build/org/portolan/extract/Operations.class +0 -0
  219. package/plugins/extract-java/build/org/portolan/extract/Proto$Rpc.class +0 -0
  220. package/plugins/extract-java/build/org/portolan/extract/Proto$Service.class +0 -0
  221. package/plugins/extract-java/build/org/portolan/extract/Proto.class +0 -0
  222. package/plugins/extract-java/build/org/portolan/extract/Protocol$Builder.class +0 -0
  223. package/plugins/extract-java/build/org/portolan/extract/Protocol$Input.class +0 -0
  224. package/plugins/extract-java/build/org/portolan/extract/Protocol$Options.class +0 -0
  225. package/plugins/extract-java/build/org/portolan/extract/Protocol.class +0 -0
  226. package/plugins/extract-java/build/org/portolan/extract/Source$Project.class +0 -0
  227. package/plugins/extract-java/build/org/portolan/extract/Source$Unit.class +0 -0
  228. package/plugins/extract-java/build/org/portolan/extract/Source.class +0 -0
  229. package/plugins/extract-java/build/org/portolan/extract/Transport$Endpoint.class +0 -0
  230. package/plugins/extract-java/build/org/portolan/extract/Transport.class +0 -0
  231. package/plugins/extract-java/build/org/portolan/extract/Yaml$Line.class +0 -0
  232. package/plugins/extract-java/build/org/portolan/extract/Yaml$Reader.class +0 -0
  233. package/plugins/extract-java/build/org/portolan/extract/Yaml.class +0 -0
  234. package/plugins/extract-java/options.schema.json +70 -0
  235. package/plugins/extract-openapi/describe.go +19 -0
  236. package/plugins/extract-openapi/describe_test.go +11 -0
  237. package/plugins/extract-openapi/discover.go +243 -0
  238. package/plugins/extract-openapi/extract.go +526 -0
  239. package/plugins/extract-openapi/extract_test.go +545 -0
  240. package/plugins/extract-openapi/main.go +75 -0
  241. package/plugins/extract-openapi/options.schema.json +62 -0
  242. package/plugins/extract-openapi/spec.go +350 -0
  243. package/plugins/extract-project/README.md +22 -0
  244. package/plugins/extract-project/describe.go +19 -0
  245. package/plugins/extract-project/describe_test.go +11 -0
  246. package/plugins/extract-project/extract.go +221 -0
  247. package/plugins/extract-project/extract_test.go +109 -0
  248. package/plugins/extract-project/main.go +41 -0
  249. package/plugins/extract-project/options.schema.json +48 -0
  250. package/plugins/extract-proto/ast.go +125 -0
  251. package/plugins/extract-proto/consumes.go +77 -0
  252. package/plugins/extract-proto/describe.go +19 -0
  253. package/plugins/extract-proto/extract.go +293 -0
  254. package/plugins/extract-proto/extract_test.go +459 -0
  255. package/plugins/extract-proto/ids.go +89 -0
  256. package/plugins/extract-proto/ids_test.go +57 -0
  257. package/plugins/extract-proto/lex.go +285 -0
  258. package/plugins/extract-proto/main.go +100 -0
  259. package/plugins/extract-proto/module.go +120 -0
  260. package/plugins/extract-proto/options.schema.json +51 -0
  261. package/plugins/extract-proto/parse.go +720 -0
  262. package/plugins/extract-proto/parse_test.go +307 -0
  263. package/plugins/extract-proto/provides.go +236 -0
  264. package/plugins/extract-proto/resolve.go +222 -0
  265. package/plugins/extract-proto/resolve_test.go +119 -0
  266. package/plugins/extract-python-kafka/README.md +36 -0
  267. package/plugins/extract-python-kafka/extract.py +211 -0
  268. package/plugins/extract-python-kafka/extract_test.py +68 -0
  269. package/plugins/extract-python-kafka/main.py +59 -0
  270. package/plugins/extract-python-kafka/options.py +29 -0
  271. package/plugins/extract-python-kafka/options.schema.json +31 -0
  272. package/plugins/extract-redis/README.md +11 -0
  273. package/plugins/extract-redis/describe.go +19 -0
  274. package/plugins/extract-redis/describe_test.go +11 -0
  275. package/plugins/extract-redis/extract.go +183 -0
  276. package/plugins/extract-redis/extract_test.go +168 -0
  277. package/plugins/extract-redis/keyspaces.go +469 -0
  278. package/plugins/extract-redis/main.go +44 -0
  279. package/plugins/extract-redis/options.schema.json +30 -0
  280. package/plugins/extract-river/describe.go +19 -0
  281. package/plugins/extract-river/describe_test.go +11 -0
  282. package/plugins/extract-river/extract.go +507 -0
  283. package/plugins/extract-river/extract_test.go +132 -0
  284. package/plugins/extract-river/main.go +42 -0
  285. package/plugins/extract-river/options.schema.json +21 -0
  286. package/plugins/extract-rust/Cargo.lock +133 -0
  287. package/plugins/extract-rust/Cargo.toml +23 -0
  288. package/plugins/extract-rust/README.md +204 -0
  289. package/plugins/extract-rust/options.schema.json +65 -0
  290. package/plugins/extract-rust/rustfmt.toml +1 -0
  291. package/plugins/extract-sql/ddl.go +893 -0
  292. package/plugins/extract-sql/ddl_test.go +401 -0
  293. package/plugins/extract-sql/describe.go +19 -0
  294. package/plugins/extract-sql/describe_test.go +11 -0
  295. package/plugins/extract-sql/layout.go +221 -0
  296. package/plugins/extract-sql/layout_test.go +55 -0
  297. package/plugins/extract-sql/lineage.go +107 -0
  298. package/plugins/extract-sql/main.go +141 -0
  299. package/plugins/extract-sql/maps.go +564 -0
  300. package/plugins/extract-sql/maps_java.go +117 -0
  301. package/plugins/extract-sql/maps_rust.go +333 -0
  302. package/plugins/extract-sql/maps_rust_test.go +70 -0
  303. package/plugins/extract-sql/maps_test.go +204 -0
  304. package/plugins/extract-sql/maps_ts.go +398 -0
  305. package/plugins/extract-sql/maps_ts_test.go +136 -0
  306. package/plugins/extract-sql/options.schema.json +53 -0
  307. package/plugins/extract-sql/projection.go +70 -0
  308. package/plugins/extract-sql/projection_test.go +50 -0
  309. package/plugins/extract-sql/store.go +420 -0
  310. package/plugins/extract-sql/store_test.go +233 -0
  311. package/plugins/extract-sql/view.go +295 -0
  312. package/plugins/extract-ts/README.md +306 -0
  313. package/plugins/extract-ts/ast.test.ts +178 -0
  314. package/plugins/extract-ts/ast.ts +648 -0
  315. package/plugins/extract-ts/clients.ts +185 -0
  316. package/plugins/extract-ts/domain.ts +164 -0
  317. package/plugins/extract-ts/extract.test.ts +208 -0
  318. package/plugins/extract-ts/extract.ts +200 -0
  319. package/plugins/extract-ts/flows.ts +783 -0
  320. package/plugins/extract-ts/graphql.test.ts +73 -0
  321. package/plugins/extract-ts/graphql.ts +181 -0
  322. package/plugins/extract-ts/ids.test.ts +21 -0
  323. package/plugins/extract-ts/ids.ts +52 -0
  324. package/plugins/extract-ts/lifecycle.ts +138 -0
  325. package/plugins/extract-ts/main.ts +48 -0
  326. package/plugins/extract-ts/openapi.test.ts +64 -0
  327. package/plugins/extract-ts/openapi.ts +99 -0
  328. package/plugins/extract-ts/operations.ts +93 -0
  329. package/plugins/extract-ts/options.schema.json +96 -0
  330. package/plugins/extract-ts/source.test.ts +174 -0
  331. package/plugins/extract-ts/source.ts +465 -0
  332. package/plugins/extract-ts/transport.ts +147 -0
  333. package/plugins/extract-ts/tsconfig.json +13 -0
  334. package/plugins/extract-ts/wiring.ts +190 -0
  335. package/plugins/extract-watermill/describe.go +19 -0
  336. package/plugins/extract-watermill/describe_test.go +11 -0
  337. package/plugins/extract-watermill/extract.go +1228 -0
  338. package/plugins/extract-watermill/extract_test.go +234 -0
  339. package/plugins/extract-watermill/main.go +41 -0
  340. package/plugins/extract-watermill/options.schema.json +21 -0
  341. package/plugins/extract-wsdl/describe.go +19 -0
  342. package/plugins/extract-wsdl/describe_test.go +11 -0
  343. package/plugins/extract-wsdl/extract.go +148 -0
  344. package/plugins/extract-wsdl/extract_test.go +45 -0
  345. package/plugins/extract-wsdl/main.go +53 -0
  346. package/plugins/extract-wsdl/options.schema.json +59 -0
  347. package/plugins/fetch-bsr/auth.go +114 -0
  348. package/plugins/fetch-bsr/bsr.go +240 -0
  349. package/plugins/fetch-bsr/cache.go +66 -0
  350. package/plugins/fetch-bsr/describe.go +19 -0
  351. package/plugins/fetch-bsr/fetch.go +192 -0
  352. package/plugins/fetch-bsr/fetch_test.go +465 -0
  353. package/plugins/fetch-bsr/lock.go +71 -0
  354. package/plugins/fetch-bsr/main.go +117 -0
  355. package/plugins/fetch-bsr/options.schema.json +42 -0
  356. package/plugins/fetch-csr/auth.go +95 -0
  357. package/plugins/fetch-csr/cache.go +69 -0
  358. package/plugins/fetch-csr/describe.go +19 -0
  359. package/plugins/fetch-csr/describe_test.go +11 -0
  360. package/plugins/fetch-csr/fetch.go +254 -0
  361. package/plugins/fetch-csr/fetch_test.go +494 -0
  362. package/plugins/fetch-csr/lock.go +95 -0
  363. package/plugins/fetch-csr/main.go +122 -0
  364. package/plugins/fetch-csr/options.schema.json +42 -0
  365. package/plugins/fetch-csr/registry.go +209 -0
  366. package/plugins/fetch-git/cache.go +65 -0
  367. package/plugins/fetch-git/describe.go +19 -0
  368. package/plugins/fetch-git/describe_test.go +11 -0
  369. package/plugins/fetch-git/fetch.go +181 -0
  370. package/plugins/fetch-git/fetch_test.go +332 -0
  371. package/plugins/fetch-git/git.go +169 -0
  372. package/plugins/fetch-git/lock.go +72 -0
  373. package/plugins/fetch-git/main.go +127 -0
  374. package/plugins/fetch-git/offline.go +39 -0
  375. package/plugins/fetch-git/options.schema.json +42 -0
  376. package/plugins/fetch-git/pin.go +90 -0
  377. package/plugins/fetch-git/pin_test.go +74 -0
  378. package/plugins/gen-backstage/describe.go +17 -0
  379. package/plugins/gen-backstage/main.go +22 -0
  380. package/plugins/gen-backstage/options.schema.json +30 -0
  381. package/plugins/gen-backstage/plugin.go +473 -0
  382. package/plugins/gen-backstage/plugin_test.go +145 -0
  383. package/plugins/gen-backstage.wasm +0 -0
  384. package/plugins/gen-markdown/adr.go +162 -0
  385. package/plugins/gen-markdown/aggregate.go +362 -0
  386. package/plugins/gen-markdown/canonical.go +93 -0
  387. package/plugins/gen-markdown/context.go +90 -0
  388. package/plugins/gen-markdown/coverage_test.go +89 -0
  389. package/plugins/gen-markdown/describe.go +19 -0
  390. package/plugins/gen-markdown/describe_test.go +11 -0
  391. package/plugins/gen-markdown/external.go +71 -0
  392. package/plugins/gen-markdown/flow.go +277 -0
  393. package/plugins/gen-markdown/glossary.go +76 -0
  394. package/plugins/gen-markdown/glossary_test.go +148 -0
  395. package/plugins/gen-markdown/llms.go +302 -0
  396. package/plugins/gen-markdown/main.go +22 -0
  397. package/plugins/gen-markdown/markdown.go +254 -0
  398. package/plugins/gen-markdown/markdown_test.go +100 -0
  399. package/plugins/gen-markdown/module.go +107 -0
  400. package/plugins/gen-markdown/options.schema.json +16 -0
  401. package/plugins/gen-markdown/plugin.go +39 -0
  402. package/plugins/gen-markdown/quality_test.go +176 -0
  403. package/plugins/gen-markdown/redis_test.go +38 -0
  404. package/plugins/gen-markdown/render.go +344 -0
  405. package/plugins/gen-markdown/render_test.go +186 -0
  406. package/plugins/gen-markdown/service.go +456 -0
  407. package/plugins/gen-markdown/source.go +177 -0
  408. package/plugins/gen-markdown/store.go +201 -0
  409. package/plugins/gen-markdown.wasm +0 -0
  410. package/plugins/gen-mermaid/describe.go +17 -0
  411. package/plugins/gen-mermaid/main.go +22 -0
  412. package/plugins/gen-mermaid/options.schema.json +10 -0
  413. package/plugins/gen-mermaid/plugin.go +104 -0
  414. package/plugins/gen-mermaid/plugin_test.go +33 -0
  415. package/plugins/gen-mermaid.wasm +0 -0
  416. package/plugins/openapi/ids.go +261 -0
  417. package/plugins/openapi/ids_test.go +98 -0
  418. package/plugins/pyplugin/catalog.py +209 -0
  419. package/plugins/pyplugin/celery_conf.py +436 -0
  420. package/plugins/pyplugin/celery_tasks.py +76 -0
  421. package/plugins/pyplugin/kafka.py +570 -0
  422. package/plugins/pyplugin/names.py +38 -0
  423. package/plugins/pyplugin/protocol.py +79 -0
  424. package/plugins/pyplugin/source.py +285 -0
  425. package/plugins/verify-codeowners/describe.go +19 -0
  426. package/plugins/verify-codeowners/describe_test.go +11 -0
  427. package/plugins/verify-codeowners/main.go +75 -0
  428. package/plugins/verify-codeowners/match.go +85 -0
  429. package/plugins/verify-codeowners/match_test.go +47 -0
  430. package/plugins/verify-codeowners/options.schema.json +15 -0
  431. package/plugins/verify-codeowners/owners.go +164 -0
  432. package/plugins/verify-codeowners/owners_test.go +225 -0
  433. package/plugins/verify-codeowners/parse.go +90 -0
  434. package/plugins/verify-codeowners/parse_test.go +62 -0
  435. package/plugins/verify-otel/describe.go +19 -0
  436. package/plugins/verify-otel/describe_test.go +11 -0
  437. package/plugins/verify-otel/main.go +53 -0
  438. package/plugins/verify-otel/match.go +336 -0
  439. package/plugins/verify-otel/options.schema.json +30 -0
  440. package/plugins/verify-otel/otlp.go +200 -0
  441. package/plugins/verify-otel/verify.go +734 -0
  442. package/plugins/verify-otel/verify_test.go +460 -0
  443. package/portolan.json +1073 -0
  444. package/public/favicon.svg +12 -0
  445. package/schema/portolan.schema.json +2558 -0
  446. package/scripts/README.md +53 -0
  447. package/scripts/build-report.mjs +60 -0
  448. package/scripts/build-report.test.mjs +44 -0
  449. package/scripts/builtin-plugins.mjs +49 -0
  450. package/scripts/catalog-sources.mjs +67 -0
  451. package/scripts/diff.mjs +315 -0
  452. package/scripts/diff.test.mjs +151 -0
  453. package/scripts/forge-comment.mjs +144 -0
  454. package/scripts/forge-comment.test.mjs +151 -0
  455. package/scripts/forge-release.mjs +138 -0
  456. package/scripts/forge-release.test.mjs +106 -0
  457. package/scripts/forge.mjs +61 -0
  458. package/scripts/gen-likec4.mjs +854 -0
  459. package/scripts/gen-likec4.test.mjs +258 -0
  460. package/scripts/gen.mjs +603 -0
  461. package/scripts/generated-docs.test.mjs +66 -0
  462. package/scripts/local-api.mjs +1192 -0
  463. package/scripts/local-api.test.mjs +387 -0
  464. package/scripts/manifest.mjs +214 -0
  465. package/scripts/manifest.test.mjs +148 -0
  466. package/scripts/output-path.mjs +79 -0
  467. package/scripts/output-path.test.mjs +45 -0
  468. package/scripts/package-smoke.mjs +37 -0
  469. package/scripts/plugin-host.mjs +419 -0
  470. package/scripts/plugin-host.test.mjs +109 -0
  471. package/scripts/plugin-wasm-worker.mjs +34 -0
  472. package/scripts/run-builtin.mjs +81 -0
  473. package/scripts/schema.mjs +357 -0
  474. package/scripts/site-docs.mjs +295 -0
  475. package/scripts/site-docs.test.mjs +181 -0
  476. package/scripts/vendor-lock.mjs +58 -0
  477. package/scripts/vendor-lock.test.mjs +69 -0
  478. package/src/README.md +38 -0
  479. package/src/app/App.tsx +448 -0
  480. package/src/app/BranchPicker.test.ts +46 -0
  481. package/src/app/BranchPicker.tsx +153 -0
  482. package/src/app/Breadcrumbs.test.ts +38 -0
  483. package/src/app/Breadcrumbs.tsx +223 -0
  484. package/src/app/BuildStamp.tsx +146 -0
  485. package/src/app/CommandPalette.tsx +292 -0
  486. package/src/app/HashScroll.tsx +45 -0
  487. package/src/app/Sidebar.tsx +1742 -0
  488. package/src/app/TopBar.tsx +393 -0
  489. package/src/app/density.tsx +64 -0
  490. package/src/app/forge-access.test.ts +27 -0
  491. package/src/app/forge-access.tsx +80 -0
  492. package/src/app/panels.tsx +141 -0
  493. package/src/app/pins.tsx +242 -0
  494. package/src/app/query-client.ts +24 -0
  495. package/src/app/responsive.ts +55 -0
  496. package/src/app/shortcuts.test.ts +39 -0
  497. package/src/app/shortcuts.tsx +282 -0
  498. package/src/app/theme.tsx +51 -0
  499. package/src/app/title.test.ts +14 -0
  500. package/src/app/title.ts +30 -0
  501. package/src/app/toast.tsx +59 -0
  502. package/src/app/tree-keys.test.ts +80 -0
  503. package/src/app/tree-keys.ts +87 -0
  504. package/src/app/ui-store.ts +52 -0
  505. package/src/catalog-error.test.ts +105 -0
  506. package/src/catalog-profile.test.ts +59 -0
  507. package/src/catalog-profile.ts +101 -0
  508. package/src/catalog-stores.test.ts +431 -0
  509. package/src/catalog.test.ts +1215 -0
  510. package/src/catalog.ts +3125 -0
  511. package/src/chat/Cards.tsx +408 -0
  512. package/src/chat/ChatPanel.tsx +79 -0
  513. package/src/chat/ChatSettings.tsx +219 -0
  514. package/src/chat/Composer.tsx +99 -0
  515. package/src/chat/Conversation.tsx +281 -0
  516. package/src/chat/Header.tsx +46 -0
  517. package/src/chat/Message.tsx +49 -0
  518. package/src/chat/Notice.tsx +195 -0
  519. package/src/chat/Starter.tsx +67 -0
  520. package/src/chat/Steps.tsx +45 -0
  521. package/src/chat/Waiting.tsx +87 -0
  522. package/src/chat/flags.test.ts +59 -0
  523. package/src/chat/flags.ts +155 -0
  524. package/src/chat/linkify.test.ts +30 -0
  525. package/src/chat/linkify.ts +45 -0
  526. package/src/chat/prefs.ts +56 -0
  527. package/src/chat/prompt.test.ts +43 -0
  528. package/src/chat/prompt.ts +157 -0
  529. package/src/chat/store.ts +35 -0
  530. package/src/chat/tools.ts +58 -0
  531. package/src/chat/transport.ts +70 -0
  532. package/src/components/AdrRow.tsx +29 -0
  533. package/src/components/AnchorLink.tsx +67 -0
  534. package/src/components/ApiReference.tsx +134 -0
  535. package/src/components/AsyncApiReference.tsx +120 -0
  536. package/src/components/CatalogStamp.tsx +155 -0
  537. package/src/components/ChannelRows.tsx +132 -0
  538. package/src/components/CommandRows.tsx +139 -0
  539. package/src/components/DiagramSkeleton.tsx +71 -0
  540. package/src/components/EditorLink.tsx +85 -0
  541. package/src/components/FieldTree.tsx +305 -0
  542. package/src/components/FlowTrigger.tsx +34 -0
  543. package/src/components/Ident.tsx +89 -0
  544. package/src/components/Integrations.tsx +243 -0
  545. package/src/components/LifecycleDiagram.tsx +110 -0
  546. package/src/components/MachineDocs.tsx +42 -0
  547. package/src/components/Markdown.tsx +173 -0
  548. package/src/components/MarkdownTable.tsx +206 -0
  549. package/src/components/Mermaid.tsx +211 -0
  550. package/src/components/MethodRows.tsx +309 -0
  551. package/src/components/Overlay.tsx +125 -0
  552. package/src/components/PageHeader.tsx +189 -0
  553. package/src/components/RowActions.tsx +97 -0
  554. package/src/components/SchemaDocument.tsx +89 -0
  555. package/src/components/Select.tsx +126 -0
  556. package/src/components/ShapeRows.tsx +118 -0
  557. package/src/components/SourceDoc.tsx +82 -0
  558. package/src/components/SourcePreview.tsx +441 -0
  559. package/src/components/TabRow.tsx +182 -0
  560. package/src/components/TechIcon.tsx +34 -0
  561. package/src/components/Toc.tsx +132 -0
  562. package/src/components/WhatLinksHere.tsx +273 -0
  563. package/src/components/WsdlReference.tsx +84 -0
  564. package/src/components/ddd-icons.tsx +107 -0
  565. package/src/components/kind.tsx +157 -0
  566. package/src/components/logo.tsx +61 -0
  567. package/src/components/primitives.tsx +264 -0
  568. package/src/data.test.ts +18 -0
  569. package/src/data.ts +202 -0
  570. package/src/enrich.test.ts +1150 -0
  571. package/src/enrich.ts +672 -0
  572. package/src/er/ErCanvas.tsx +533 -0
  573. package/src/er/RedisSchema.tsx +74 -0
  574. package/src/er/RelationCard.tsx +267 -0
  575. package/src/er/StoreHeader.tsx +155 -0
  576. package/src/er/TableNode.tsx +84 -0
  577. package/src/er/ViewNode.tsx +83 -0
  578. package/src/er/layout.test.ts +115 -0
  579. package/src/er/layout.ts +77 -0
  580. package/src/er/lineage.test.ts +140 -0
  581. package/src/er/lineage.ts +107 -0
  582. package/src/er/markers.tsx +79 -0
  583. package/src/er/spec.test.ts +344 -0
  584. package/src/er/spec.ts +426 -0
  585. package/src/flow/ChainList.tsx +162 -0
  586. package/src/flow/FlowTable.tsx +123 -0
  587. package/src/flow/FlowToolbar.tsx +372 -0
  588. package/src/flow/StepDetail.tsx +380 -0
  589. package/src/flow/StepRail.tsx +428 -0
  590. package/src/flow/answers.test.ts +50 -0
  591. package/src/flow/answers.ts +58 -0
  592. package/src/flow/chain.test.ts +383 -0
  593. package/src/flow/chain.ts +353 -0
  594. package/src/flow/chapters.test.ts +185 -0
  595. package/src/flow/chapters.ts +225 -0
  596. package/src/flow/continues.test.ts +102 -0
  597. package/src/flow/continues.ts +65 -0
  598. package/src/flow/cross-context.test.ts +97 -0
  599. package/src/flow/cross-context.ts +35 -0
  600. package/src/flow/mermaid.test.ts +22 -0
  601. package/src/flow/mermaid.ts +141 -0
  602. package/src/flow/outline.test.ts +212 -0
  603. package/src/flow/outline.ts +170 -0
  604. package/src/flow/paths.test.ts +129 -0
  605. package/src/flow/paths.ts +147 -0
  606. package/src/flow/prefs.test.ts +80 -0
  607. package/src/flow/prefs.ts +104 -0
  608. package/src/graph/DependencyGraph.tsx +283 -0
  609. package/src/graph/DependencyNodes.tsx +162 -0
  610. package/src/graph/EdgeLabel.tsx +61 -0
  611. package/src/graph/FocusedEventGraph.tsx +211 -0
  612. package/src/graph/GraphToolbar.tsx +187 -0
  613. package/src/graph/RoutedEdge.tsx +80 -0
  614. package/src/graph/dependency-layout.test.ts +360 -0
  615. package/src/graph/dependency-layout.ts +444 -0
  616. package/src/graph/elk.test.ts +70 -0
  617. package/src/graph/elk.ts +287 -0
  618. package/src/graph/nodes.tsx +97 -0
  619. package/src/graph/theme.ts +81 -0
  620. package/src/graph/useElkFlow.ts +125 -0
  621. package/src/index.css +1547 -0
  622. package/src/language/InLanguage.tsx +40 -0
  623. package/src/language/TermCard.tsx +132 -0
  624. package/src/language/cards.test.ts +114 -0
  625. package/src/language/cards.ts +111 -0
  626. package/src/lib/admonition.test.ts +49 -0
  627. package/src/lib/admonition.ts +48 -0
  628. package/src/lib/adr.test.ts +131 -0
  629. package/src/lib/adr.ts +68 -0
  630. package/src/lib/api.test.ts +122 -0
  631. package/src/lib/api.ts +135 -0
  632. package/src/lib/backlinks.test.ts +330 -0
  633. package/src/lib/backlinks.ts +567 -0
  634. package/src/lib/branch-compare.ts +16 -0
  635. package/src/lib/build-info.test.ts +76 -0
  636. package/src/lib/build-info.ts +80 -0
  637. package/src/lib/catalog-diff.test.ts +275 -0
  638. package/src/lib/catalog-diff.ts +655 -0
  639. package/src/lib/clipboard.ts +43 -0
  640. package/src/lib/comparison-memory.test.ts +40 -0
  641. package/src/lib/comparison-memory.ts +39 -0
  642. package/src/lib/context-color.ts +27 -0
  643. package/src/lib/context-map.test.ts +148 -0
  644. package/src/lib/context-map.ts +399 -0
  645. package/src/lib/data-model.test.ts +245 -0
  646. package/src/lib/data-model.ts +399 -0
  647. package/src/lib/data-problems.test.ts +178 -0
  648. package/src/lib/data-problems.ts +314 -0
  649. package/src/lib/derive.test.ts +251 -0
  650. package/src/lib/derive.ts +515 -0
  651. package/src/lib/editor-link.test.ts +125 -0
  652. package/src/lib/editor-link.ts +96 -0
  653. package/src/lib/editor-prefs.ts +27 -0
  654. package/src/lib/event-graph.test.ts +237 -0
  655. package/src/lib/event-graph.ts +327 -0
  656. package/src/lib/export-canvas.ts +37 -0
  657. package/src/lib/export-file.test.ts +30 -0
  658. package/src/lib/export-file.ts +20 -0
  659. package/src/lib/flow-tree.test.ts +177 -0
  660. package/src/lib/flow-tree.ts +160 -0
  661. package/src/lib/forge-refs.test.ts +50 -0
  662. package/src/lib/forge-refs.ts +60 -0
  663. package/src/lib/format.test.ts +35 -0
  664. package/src/lib/format.ts +64 -0
  665. package/src/lib/github-catalog.test.ts +301 -0
  666. package/src/lib/github-catalog.ts +610 -0
  667. package/src/lib/integrations.test.ts +119 -0
  668. package/src/lib/integrations.ts +133 -0
  669. package/src/lib/kinds.test.ts +91 -0
  670. package/src/lib/kinds.ts +204 -0
  671. package/src/lib/lifecycle.test.ts +93 -0
  672. package/src/lib/lifecycle.ts +165 -0
  673. package/src/lib/local-api.ts +194 -0
  674. package/src/lib/motion-features.ts +11 -0
  675. package/src/lib/motion.test.ts +120 -0
  676. package/src/lib/motion.tsx +269 -0
  677. package/src/lib/palette-recent.test.ts +80 -0
  678. package/src/lib/palette-recent.ts +90 -0
  679. package/src/lib/palette.test.ts +365 -0
  680. package/src/lib/palette.ts +593 -0
  681. package/src/lib/pins.test.ts +139 -0
  682. package/src/lib/pins.ts +130 -0
  683. package/src/lib/problems.test.ts +112 -0
  684. package/src/lib/project-preview.ts +5 -0
  685. package/src/lib/proto-problems.test.ts +121 -0
  686. package/src/lib/proto-problems.ts +65 -0
  687. package/src/lib/queries.test.ts +113 -0
  688. package/src/lib/queries.ts +131 -0
  689. package/src/lib/registry.test.ts +219 -0
  690. package/src/lib/registry.ts +208 -0
  691. package/src/lib/scenarios.ts +547 -0
  692. package/src/lib/setup-info.test.ts +199 -0
  693. package/src/lib/setup-info.ts +415 -0
  694. package/src/lib/shape.test.ts +289 -0
  695. package/src/lib/shape.ts +454 -0
  696. package/src/lib/sidebar-prefs.test.ts +32 -0
  697. package/src/lib/sidebar-prefs.ts +75 -0
  698. package/src/lib/source-code.test.ts +159 -0
  699. package/src/lib/source-code.ts +286 -0
  700. package/src/lib/source-doc.test.ts +131 -0
  701. package/src/lib/source-doc.ts +103 -0
  702. package/src/lib/source-highlight.test.ts +29 -0
  703. package/src/lib/source-highlight.ts +24 -0
  704. package/src/lib/source-link.test.ts +153 -0
  705. package/src/lib/source-link.ts +201 -0
  706. package/src/lib/spec-files.test.ts +24 -0
  707. package/src/lib/spec-files.ts +23 -0
  708. package/src/lib/table-directive.test.ts +139 -0
  709. package/src/lib/table-directive.ts +106 -0
  710. package/src/lib/tech.test.ts +120 -0
  711. package/src/lib/tech.ts +421 -0
  712. package/src/lib/terms.test.ts +67 -0
  713. package/src/lib/terms.ts +179 -0
  714. package/src/lib/wire-problems.test.ts +263 -0
  715. package/src/lib/wire-problems.ts +281 -0
  716. package/src/likec4/C4View.tsx +55 -0
  717. package/src/likec4/CanvasBridge.tsx +187 -0
  718. package/src/likec4/FlowView.tsx +235 -0
  719. package/src/likec4/InteractiveView.tsx +144 -0
  720. package/src/likec4/canvas-viewport.test.ts +149 -0
  721. package/src/likec4/canvas-viewport.ts +135 -0
  722. package/src/likec4/flow-edges.test.ts +51 -0
  723. package/src/likec4/flow-edges.ts +89 -0
  724. package/src/likec4/frame-theme.test.ts +76 -0
  725. package/src/likec4/frame-theme.ts +101 -0
  726. package/src/likec4/highlight-css.test.ts +49 -0
  727. package/src/likec4/highlight-css.ts +52 -0
  728. package/src/likec4/ids.test.ts +151 -0
  729. package/src/likec4/ids.ts +115 -0
  730. package/src/likec4/levels.tsx +70 -0
  731. package/src/likec4/mapping.test.ts +66 -0
  732. package/src/likec4/mapping.ts +54 -0
  733. package/src/likec4/reserved.json +141 -0
  734. package/src/likec4/view-index.ts +78 -0
  735. package/src/main.tsx +13 -0
  736. package/src/map/ContextMapGraph.tsx +274 -0
  737. package/src/map/ContextNode.tsx +70 -0
  738. package/src/map/FloatingEdge.tsx +86 -0
  739. package/src/merge.test.ts +1038 -0
  740. package/src/merge.ts +1004 -0
  741. package/src/pages/AdrDetail.tsx +242 -0
  742. package/src/pages/AdrIndex.tsx +114 -0
  743. package/src/pages/AggregatePage.tsx +727 -0
  744. package/src/pages/BlockPage.tsx +478 -0
  745. package/src/pages/CatalogFailure.tsx +111 -0
  746. package/src/pages/Changes.tsx +313 -0
  747. package/src/pages/ContextMap.tsx +534 -0
  748. package/src/pages/ContextPage.tsx +346 -0
  749. package/src/pages/EnumPage.tsx +282 -0
  750. package/src/pages/EventPage.tsx +686 -0
  751. package/src/pages/ExternalPage.tsx +204 -0
  752. package/src/pages/FlowDetail.tsx +663 -0
  753. package/src/pages/FlowIndex.tsx +303 -0
  754. package/src/pages/GraphPage.tsx +217 -0
  755. package/src/pages/Language.tsx +257 -0
  756. package/src/pages/ModulePage.tsx +366 -0
  757. package/src/pages/NotFound.tsx +54 -0
  758. package/src/pages/Overview.tsx +344 -0
  759. package/src/pages/Problems.tsx +360 -0
  760. package/src/pages/RegistryIndex.tsx +118 -0
  761. package/src/pages/ServicePage.tsx +746 -0
  762. package/src/pages/Settings.tsx +975 -0
  763. package/src/pages/StorePage.tsx +114 -0
  764. package/src/peek/PeekCard.test.ts +35 -0
  765. package/src/peek/PeekCard.tsx +118 -0
  766. package/src/peek/PeekLayer.tsx +147 -0
  767. package/src/peek/model.test.ts +156 -0
  768. package/src/peek/model.ts +253 -0
  769. package/src/routes.test.ts +222 -0
  770. package/src/routes.ts +449 -0
  771. package/src/selection/DetailPanel.tsx +1407 -0
  772. package/src/selection/hash.test.ts +73 -0
  773. package/src/selection/hash.ts +58 -0
  774. package/src/selection/model.test.ts +199 -0
  775. package/src/selection/model.ts +473 -0
  776. package/src/selection/pages.test.ts +115 -0
  777. package/src/selection/pages.ts +268 -0
  778. package/src/selection/store.test.ts +62 -0
  779. package/src/selection/store.ts +46 -0
  780. package/src/selection/sync.tsx +99 -0
  781. package/src/table/ColumnsMenu.tsx +72 -0
  782. package/src/table/DataTable.tsx +780 -0
  783. package/src/table/Facets.tsx +54 -0
  784. package/src/table/GroupMenu.tsx +69 -0
  785. package/src/table/Toolbar.tsx +190 -0
  786. package/src/table/cells.tsx +117 -0
  787. package/src/table/compare.test.ts +117 -0
  788. package/src/table/compare.ts +196 -0
  789. package/src/table/export.test.ts +88 -0
  790. package/src/table/export.ts +66 -0
  791. package/src/table/facet-groups.test.ts +74 -0
  792. package/src/table/facet-groups.ts +56 -0
  793. package/src/table/grouping.test.ts +84 -0
  794. package/src/table/grouping.ts +82 -0
  795. package/src/table/infer.test.ts +57 -0
  796. package/src/table/infer.ts +50 -0
  797. package/src/table/persist.test.ts +76 -0
  798. package/src/table/persist.ts +112 -0
  799. package/src/table/sort-url.test.ts +75 -0
  800. package/src/table/sort-url.ts +52 -0
  801. package/src/table/types.ts +80 -0
  802. package/src/table/useTableState.ts +220 -0
  803. package/src/test-catalog.ts +7 -0
  804. package/src/testing/estate/data__catalog.json +2847 -0
  805. package/src/testing/estate/data__flows.json +1724 -0
  806. package/src/testing/estate/examples__auth__portolan__api.json +212 -0
  807. package/src/testing/estate/examples__auth__portolan__domain.json +1204 -0
  808. package/src/testing/estate/examples__auth__portolan__glossary.json +226 -0
  809. package/src/testing/estate/examples__auth__portolan__observed.json +757 -0
  810. package/src/testing/estate/examples__auth__portolan__stores.json +195 -0
  811. package/src/testing/estate/examples__shop__cart__portolan__api.json +234 -0
  812. package/src/testing/estate/examples__shop__cart__portolan__commands.json +86 -0
  813. package/src/testing/estate/examples__shop__cart__portolan__domain.json +966 -0
  814. package/src/testing/estate/examples__shop__cart__portolan__observed.json +498 -0
  815. package/src/testing/estate/examples__shop__cart__portolan__stores.json +208 -0
  816. package/src/testing/estate/examples__shop__oms__portolan__glossary.json +98 -0
  817. package/src/testing/estate/examples__shop__oms__portolan__proto.json +186 -0
  818. package/src/testing/estate.ts +49 -0
  819. package/src/trail/Trail.tsx +81 -0
  820. package/src/trail/model.test.ts +157 -0
  821. package/src/trail/model.ts +189 -0
  822. package/src/trail/record.tsx +32 -0
  823. package/src/trail/store.test.ts +66 -0
  824. package/src/trail/store.ts +102 -0
  825. package/tsconfig.json +35 -0
  826. package/vite.config.ts +171 -0
@@ -0,0 +1,157 @@
1
+ // What the model is told, and what it may ask for.
2
+ //
3
+ // One file for both halves of the chat: the browser, when the reader brings
4
+ // their own key, and the Cloudflare worker in proxy/, which imports this file
5
+ // as it is. The rules a page path has to satisfy therefore cannot drift
6
+ // between the two, and neither can the instructions.
7
+ //
8
+ // The model never sees the whole catalog. It sees llms.txt - the index, a few
9
+ // hundred lines naming every page - and a tool that opens one page at a time.
10
+ // Four opened pages cost a tenth of the tokens the full file would, which on
11
+ // a free tier is the difference between a demo that answers all day and one
12
+ // that stops before lunch.
13
+
14
+ /** Longest page the tool hands back; the rest is cut with a note. */
15
+ export const PAGE_LIMIT = 60_000;
16
+
17
+ export type ToolName =
18
+ | "read_page"
19
+ | "show_service"
20
+ | "show_flow"
21
+ | "show_between"
22
+ | "show_lifecycle";
23
+
24
+ /** A tool as both halves declare it: a sentence and a flat object schema. */
25
+ export interface ToolSpec {
26
+ description: string;
27
+ input: {
28
+ type: "object";
29
+ properties: Record<string, { type: "string"; description: string }>;
30
+ required: string[];
31
+ };
32
+ }
33
+
34
+ /** Every tool, with the schema both halves declare it with. */
35
+ export const TOOL_SPECS: Record<ToolName, ToolSpec> = {
36
+ read_page: {
37
+ description:
38
+ "Open one page of the catalog by the path the index gives, e.g. docs/auth/README.md. Returns its markdown.",
39
+ input: {
40
+ type: "object",
41
+ properties: {
42
+ path: {
43
+ type: "string",
44
+ description: "A path exactly as the index spells it",
45
+ },
46
+ },
47
+ required: ["path"],
48
+ },
49
+ },
50
+ show_service: {
51
+ description:
52
+ "Show one service as a card: its context, what it provides and consumes, its aggregates and events. Call it last, after the text.",
53
+ input: {
54
+ type: "object",
55
+ properties: {
56
+ id: { type: "string", description: "The service id, e.g. shop.oms" },
57
+ },
58
+ required: ["id"],
59
+ },
60
+ },
61
+ show_flow: {
62
+ description:
63
+ "Draw one flow as a sequence diagram. Call it last, after the text.",
64
+ input: {
65
+ type: "object",
66
+ properties: {
67
+ id: { type: "string", description: "The flow id or slug" },
68
+ },
69
+ required: ["id"],
70
+ },
71
+ },
72
+ show_between: {
73
+ description:
74
+ "Show what runs between two bounded contexts: every call one makes into the other. Call it last, after the text.",
75
+ input: {
76
+ type: "object",
77
+ properties: {
78
+ a: { type: "string", description: "A context id, e.g. shop" },
79
+ b: { type: "string", description: "Another context id, e.g. payments" },
80
+ },
81
+ required: ["a", "b"],
82
+ },
83
+ },
84
+ show_lifecycle: {
85
+ description:
86
+ "Draw an aggregate's state machine. Call it last, after the text.",
87
+ input: {
88
+ type: "object",
89
+ properties: {
90
+ aggregate: {
91
+ type: "string",
92
+ description: "The aggregate id, e.g. auth.auth.user",
93
+ },
94
+ },
95
+ required: ["aggregate"],
96
+ },
97
+ },
98
+ };
99
+
100
+ /** The tools that draw something and end the answer rather than continue it. */
101
+ export const DISPLAY_TOOLS: readonly ToolName[] = [
102
+ "show_service",
103
+ "show_flow",
104
+ "show_between",
105
+ "show_lifecycle",
106
+ ];
107
+
108
+ /** How many model calls one answer may take: reads, then the text, then a card. */
109
+ export const MAX_STEPS = 6;
110
+
111
+ /**
112
+ * A page path the tool may open, or null. The index links pages as
113
+ * `docs/<context>/<page>.md`; the model is allowed to drop the `docs/` and
114
+ * a leading slash, and nothing else - no scheme, no `..`, no other extension.
115
+ */
116
+ export function pagePath(input: unknown): string | null {
117
+ if (typeof input !== "string") return null;
118
+ let path = input.trim().replace(/^\.?\//, "");
119
+ if (!path.startsWith("docs/")) path = `docs/${path}`;
120
+ if (!path.endsWith(".md")) return null;
121
+ const segments = path.split("/");
122
+ if (
123
+ segments.some(
124
+ (segment) =>
125
+ segment === "" ||
126
+ segment === "." ||
127
+ segment === ".." ||
128
+ !/^[A-Za-z0-9._-]+$/.test(segment),
129
+ )
130
+ ) {
131
+ return null;
132
+ }
133
+ return path;
134
+ }
135
+
136
+ /** The page as the model gets it: cut at the limit, and told so. */
137
+ export function clipPage(text: string): string {
138
+ if (text.length <= PAGE_LIMIT) return text;
139
+ return `${text.slice(0, PAGE_LIMIT)}\n\n[cut: the page goes on for ${text.length - PAGE_LIMIT} more characters]`;
140
+ }
141
+
142
+ /** The system prompt, with the index folded in. */
143
+ export function instructions(index: string): string {
144
+ return `You are the guide to an architecture catalog: bounded contexts, services, aggregates, events, flows and decisions (ADRs). The index of its pages is below.
145
+
146
+ How to answer:
147
+ - Answer in the language the question was asked in.
148
+ - Before answering about a particular service, flow, decision, aggregate or context, call read_page on the page that documents it. The index says what each page covers. Open at most four pages per answer.
149
+ - Name things by their catalog ids, spelled exactly as the catalog spells them (shop.oms, auth.auth.user.PasswordChanged, adr slugs), so they can be linked.
150
+ - Be brief: a few sentences or a short list. Markdown is fine. Never draw diagrams yourself.
151
+ - When a picture would help, finish with exactly one show_* call: show_service for one service, show_flow for a flow, show_between for what runs between two contexts, show_lifecycle for an aggregate's state machine. Write the text first; the call is the last thing in the answer.
152
+ - When the catalog does not say, say so rather than guess.
153
+
154
+ # Index
155
+
156
+ ${index}`;
157
+ }
@@ -0,0 +1,35 @@
1
+ // Shell state of the chat: open or not, and what the panel is waiting on.
2
+ //
3
+ // Kept apart from the panel because the top bar opens it and the transport
4
+ // reports into it, and neither should have to import the panel - which is
5
+ // loaded lazily and carries the SDK.
6
+
7
+ import { create } from "zustand";
8
+
9
+ /** What the reader is waiting for, when it is not the model's own words. */
10
+ export type Phase = "index" | null;
11
+
12
+ interface ChatUiState {
13
+ open: boolean;
14
+ setOpen: (open: boolean) => void;
15
+ /** "index" while the browser fetches llms.txt before the first question. */
16
+ phase: Phase;
17
+ setPhase: (phase: Phase) => void;
18
+ /** When the current question was sent, for the "took 31s" line. */
19
+ askedAt: number | null;
20
+ setAskedAt: (at: number | null) => void;
21
+ /** Seconds each answer took, by message id. */
22
+ took: Record<string, number>;
23
+ noteTook: (id: string, seconds: number) => void;
24
+ }
25
+
26
+ export const useChatUi = create<ChatUiState>()((set) => ({
27
+ open: false,
28
+ setOpen: (open) => set({ open }),
29
+ phase: null,
30
+ setPhase: (phase) => set({ phase }),
31
+ askedAt: null,
32
+ setAskedAt: (askedAt) => set({ askedAt }),
33
+ took: {},
34
+ noteTook: (id, seconds) => set((s) => ({ took: { ...s.took, [id]: seconds } })),
35
+ }));
@@ -0,0 +1,58 @@
1
+ // The tools as the browser declares them, for a reader's own model.
2
+ //
3
+ // read_page runs here and fetches the page from the site itself; the show_*
4
+ // tools have no execute on purpose - a call to one ends the answer, and the
5
+ // panel draws the card from the catalog it already has.
6
+
7
+ import { jsonSchema, tool } from "ai";
8
+ import { clipPage, pagePath, TOOL_SPECS } from "./prompt";
9
+
10
+ const base = import.meta.env.BASE_URL;
11
+
12
+ /** One page of the generated docs, as the model gets it. */
13
+ export async function readPage(raw: unknown): Promise<string> {
14
+ const path = pagePath(raw);
15
+ if (!path) return "That is not a page of the catalog. Use a path from the index.";
16
+ const response = await fetch(`${base}${path}`);
17
+ if (!response.ok) return `No page at ${path}. Use a path from the index.`;
18
+ return clipPage(await response.text());
19
+ }
20
+
21
+ /** llms.txt, once per session. */
22
+ let indexPromise: Promise<string> | null = null;
23
+ export function loadIndex(): Promise<string> {
24
+ indexPromise ??= fetch(`${base}llms.txt`).then((response) => {
25
+ if (!response.ok) {
26
+ indexPromise = null;
27
+ throw new Error("the catalog index (llms.txt) could not be read");
28
+ }
29
+ return response.text();
30
+ });
31
+ return indexPromise;
32
+ }
33
+
34
+ export function browserTools() {
35
+ return {
36
+ read_page: tool({
37
+ description: TOOL_SPECS.read_page.description,
38
+ inputSchema: jsonSchema<{ path: string }>(TOOL_SPECS.read_page.input),
39
+ execute: ({ path }) => readPage(path),
40
+ }),
41
+ show_service: tool({
42
+ description: TOOL_SPECS.show_service.description,
43
+ inputSchema: jsonSchema<{ id: string }>(TOOL_SPECS.show_service.input),
44
+ }),
45
+ show_flow: tool({
46
+ description: TOOL_SPECS.show_flow.description,
47
+ inputSchema: jsonSchema<{ id: string }>(TOOL_SPECS.show_flow.input),
48
+ }),
49
+ show_between: tool({
50
+ description: TOOL_SPECS.show_between.description,
51
+ inputSchema: jsonSchema<{ a: string; b: string }>(TOOL_SPECS.show_between.input),
52
+ }),
53
+ show_lifecycle: tool({
54
+ description: TOOL_SPECS.show_lifecycle.description,
55
+ inputSchema: jsonSchema<{ aggregate: string }>(TOOL_SPECS.show_lifecycle.input),
56
+ }),
57
+ };
58
+ }
@@ -0,0 +1,70 @@
1
+ // How a question reaches a model.
2
+ //
3
+ // Through the proxy it is one POST to the worker, which holds the key and the
4
+ // tools. With the reader's own key the whole loop runs in the browser: the
5
+ // agent, the read_page tool and the index it needs - fetched on the first
6
+ // question, not at load, because most readers never open the panel.
7
+
8
+ import {
9
+ DefaultChatTransport,
10
+ DirectChatTransport,
11
+ ToolLoopAgent,
12
+ stepCountIs,
13
+ } from "ai";
14
+ import type { ChatTransport, UIMessage, UIMessageChunk } from "ai";
15
+ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
16
+ import type { ChatRoute, OwnModel } from "./flags";
17
+ import { instructions, MAX_STEPS } from "./prompt";
18
+ import { useChatUi } from "./store";
19
+ import { browserTools, loadIndex } from "./tools";
20
+
21
+ type Answering = Extract<ChatRoute, { kind: "proxy" | "own" }>;
22
+
23
+ class OwnTransport implements ChatTransport<UIMessage> {
24
+ private inner: Promise<ChatTransport<UIMessage>> | null = null;
25
+
26
+ constructor(private readonly own: OwnModel) {}
27
+
28
+ private async build(): Promise<ChatTransport<UIMessage>> {
29
+ const ui = useChatUi.getState();
30
+ ui.setPhase("index");
31
+ let index: string;
32
+ try {
33
+ index = await loadIndex();
34
+ } finally {
35
+ useChatUi.getState().setPhase(null);
36
+ }
37
+ const provider = createOpenAICompatible({
38
+ name: "own",
39
+ baseURL: this.own.baseUrl.trim().replace(/\/+$/, ""),
40
+ ...(this.own.apiKey.trim() ? { apiKey: this.own.apiKey.trim() } : {}),
41
+ });
42
+ const agent = new ToolLoopAgent({
43
+ model: provider.chatModel(this.own.model.trim()),
44
+ instructions: instructions(index),
45
+ tools: browserTools(),
46
+ stopWhen: stepCountIs(MAX_STEPS),
47
+ });
48
+ return new DirectChatTransport({ agent }) as unknown as ChatTransport<UIMessage>;
49
+ }
50
+
51
+ async sendMessages(
52
+ options: Parameters<ChatTransport<UIMessage>["sendMessages"]>[0],
53
+ ): Promise<ReadableStream<UIMessageChunk>> {
54
+ this.inner ??= this.build().catch((error: unknown) => {
55
+ this.inner = null;
56
+ throw error;
57
+ });
58
+ return (await this.inner).sendMessages(options);
59
+ }
60
+
61
+ async reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null> {
62
+ return null;
63
+ }
64
+ }
65
+
66
+ export function transportFor(route: Answering): ChatTransport<UIMessage> {
67
+ return route.kind === "proxy"
68
+ ? new DefaultChatTransport<UIMessage>({ api: route.url })
69
+ : new OwnTransport(route.model);
70
+ }
@@ -0,0 +1,29 @@
1
+ import { Link } from "react-router";
2
+ import type { Adr } from "../catalog";
3
+ import { paths } from "../routes";
4
+ import { AdrNumber, AdrScopePill, AdrStatusChip } from "./primitives";
5
+
6
+ /**
7
+ * The columns a list of these rows declares, so every field starts at the
8
+ * same x down the list: number, title, status, scope, date.
9
+ */
10
+ export const ADR_ROW_COLUMNS = "grid-cols-[auto_minmax(0,1fr)_auto_auto_auto]";
11
+
12
+ /**
13
+ * One decision in a list that is not the decisions index itself. The list
14
+ * is a `.rows` grid with {@link ADR_ROW_COLUMNS}; the row is a subgrid of
15
+ * it, so the title takes what is left and the chips line up.
16
+ */
17
+ export function AdrRow({ adr }: { adr: Adr }) {
18
+ return (
19
+ <Link to={paths.adr(adr.slug)} data-nav-item className="row">
20
+ <AdrNumber adr={adr} />
21
+ <span className="truncate font-semibold" title={adr.title}>
22
+ {adr.title}
23
+ </span>
24
+ <AdrStatusChip status={adr.status} />
25
+ <AdrScopePill scope={adr.scope} link={false} />
26
+ <span className="mono tnum text-muted">{adr.date}</span>
27
+ </Link>
28
+ );
29
+ }
@@ -0,0 +1,67 @@
1
+ // The link back to a heading.
2
+ //
3
+ // Every section in this app already has an id - the counts in a page header
4
+ // link to them, and the TOC walks them - but until now the only way to get one
5
+ // out of the app was to read the TOC's href off the status bar. This is the
6
+ // other half: a real <a> to the fragment, so the browser's own "copy link
7
+ // address" works, and a click that also puts the absolute URL on the clipboard,
8
+ // because that is what the reader wanted from the click.
9
+ //
10
+ // It is hidden until the heading is hovered or something in it takes focus,
11
+ // for the same reason RowActions is: a page with nine sections must not also be
12
+ // a page with nine little chain icons down the left.
13
+
14
+ import { useCallback, useEffect, useRef, useState } from "react";
15
+ import { Check, Link2 } from "lucide-react";
16
+ import { anchorUrl, toClipboard } from "../lib/clipboard";
17
+
18
+ const SHOWN_MS = 1000;
19
+
20
+ export function AnchorLink({
21
+ id,
22
+ label,
23
+ }: {
24
+ /** The id of the element on the page this points at. */
25
+ id: string;
26
+ /** What the link says it points at, for the accessible name. */
27
+ label?: string;
28
+ }) {
29
+ const [copied, setCopied] = useState(false);
30
+ const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
31
+
32
+ useEffect(
33
+ () => () => {
34
+ if (timer.current) clearTimeout(timer.current);
35
+ },
36
+ [],
37
+ );
38
+
39
+ // No preventDefault: the browser still moves to the fragment and puts it in
40
+ // the address bar, which is half of what "link to this" means. The copy is
41
+ // the other half, and it rides along.
42
+ const onClick = useCallback(() => {
43
+ void toClipboard(anchorUrl(id)).then((ok) => {
44
+ setCopied(ok);
45
+ if (timer.current) clearTimeout(timer.current);
46
+ timer.current = setTimeout(() => setCopied(false), SHOWN_MS);
47
+ });
48
+ }, [id]);
49
+
50
+ const what = label ? `link to ${label}` : "link to this section";
51
+
52
+ return (
53
+ <a
54
+ href={`#${id}`}
55
+ onClick={onClick}
56
+ className="anchor-link"
57
+ aria-label={`Copy ${what}`}
58
+ title={copied ? "copied" : `Copy ${what}`}
59
+ >
60
+ {copied ? (
61
+ <Check size={12} aria-hidden />
62
+ ) : (
63
+ <Link2 size={12} aria-hidden />
64
+ )}
65
+ </a>
66
+ );
67
+ }
@@ -0,0 +1,134 @@
1
+ // The OpenAPI document itself, rendered.
2
+ //
3
+ // This is the one place in portolan that draws something the catalog did not
4
+ // give it. Everywhere else the rule holds - the catalog is the input, the site
5
+ // is the output - and it holds here too in the sense that matters: the catalog
6
+ // is what says this service has a document and where it lives. What the
7
+ // catalog cannot carry is the document's own shape, endpoint by endpoint, and
8
+ // re-deriving that into the schema would be rebuilding OpenAPI inside it.
9
+ //
10
+ // So the provides tab keeps the extracted facts - the ones that are searchable,
11
+ // linkable and comparable with a proto service next door - and this tab shows
12
+ // the source document beside them.
13
+
14
+ import { lazy, Suspense, useEffect, useState } from "react";
15
+ import { useTheme } from "../app/theme";
16
+ import { loaderFor as loaderIn } from "../lib/spec-files";
17
+ import { Empty } from "./PageHeader";
18
+
19
+ /**
20
+ * Loaded on demand, so a reader who never opens this tab never waits for it and
21
+ * the reference does not sit in the chunk the app boots from.
22
+ */
23
+ const Reference = lazy(async () => {
24
+ // The stylesheet is a separate export and the bundle does not pull it in, so
25
+ // it is imported here rather than at the top of the file: alongside the
26
+ // component it styles, and only when that component is actually wanted.
27
+ await import("@scalar/api-reference-react/style.css");
28
+ const { ApiReferenceReact } = await import("@scalar/api-reference-react");
29
+
30
+ return { default: ApiReferenceReact };
31
+ });
32
+
33
+ /**
34
+ * The documents in the repository, by path, loaded on demand.
35
+ *
36
+ * A spec that lives in another repository is not here, and that is the normal
37
+ * case for a real estate: the catalog still lists what the service answers,
38
+ * and this tab says plainly that it has nothing to show.
39
+ */
40
+ const SPECS = import.meta.glob<string>(
41
+ [
42
+ "../../**/openapi*.yaml",
43
+ "../../**/openapi*.yml",
44
+ "../../**/openapi*.json",
45
+ "../../**/swagger*.yaml",
46
+ "../../**/swagger*.yml",
47
+ "../../**/swagger*.json",
48
+ "../../examples/**/openapi*.yaml",
49
+ "../../examples/**/openapi*.yml",
50
+ "../../examples/**/openapi*.json",
51
+ "../../examples/**/swagger*.yaml",
52
+ "../../examples/**/swagger*.yml",
53
+ "../../examples/**/swagger*.json",
54
+ "../../vendor/repos/**/openapi*.yaml",
55
+ "../../vendor/repos/**/openapi*.yml",
56
+ "../../vendor/repos/**/openapi*.json",
57
+ "../../vendor/repos/**/swagger*.yaml",
58
+ "../../vendor/repos/**/swagger*.yml",
59
+ "../../vendor/repos/**/swagger*.json",
60
+ // Local onboarding writes generated documents under the project's
61
+ // conventional portolan directory, wherever that project lives.
62
+ "../../**/portolan/openapi*.yaml",
63
+ "../../**/portolan/openapi*.yml",
64
+ "../../**/portolan/openapi*.json",
65
+ "!../../node_modules/**",
66
+ "!../../dist/**",
67
+ "!../../.portolan/**",
68
+ ],
69
+ { query: "?raw", import: "default" },
70
+ );
71
+
72
+ function loaderFor(source: string): (() => Promise<string>) | null {
73
+ return loaderIn(SPECS, source);
74
+ }
75
+
76
+ /** Whether the document a catalog entry points at is one this site can show. */
77
+ export function hasSpec(source: string): boolean {
78
+ return loaderFor(source) !== null;
79
+ }
80
+
81
+ export function ApiReference({ source }: { source: string }) {
82
+ const { theme } = useTheme();
83
+ const [spec, setSpec] = useState<string | null>(null);
84
+ const [missing, setMissing] = useState(false);
85
+
86
+ useEffect(() => {
87
+ const load = loaderFor(source);
88
+ if (!load) {
89
+ setMissing(true);
90
+
91
+ return;
92
+ }
93
+
94
+ let live = true;
95
+ load()
96
+ .then((text) => {
97
+ if (live) setSpec(text);
98
+ })
99
+ .catch(() => {
100
+ if (live) setMissing(true);
101
+ });
102
+
103
+ return () => {
104
+ live = false;
105
+ };
106
+ }, [source]);
107
+
108
+ if (missing) {
109
+ return (
110
+ <Empty>
111
+ this service&apos;s document is not in this repository — only what the
112
+ catalog extracted from it is
113
+ </Empty>
114
+ );
115
+ }
116
+
117
+ if (spec === null) return <Empty>reading the document…</Empty>;
118
+
119
+ return (
120
+ <div className="rounded-card border border-line">
121
+ <Suspense fallback={<Empty>loading the reference…</Empty>}>
122
+ <Reference
123
+ configuration={{
124
+ content: spec,
125
+ // Its sidebar would be a second navigation tree beside the one the
126
+ // app already has, listing the same endpoints.
127
+ showSidebar: false,
128
+ forceDarkModeState: theme,
129
+ }}
130
+ />
131
+ </Suspense>
132
+ </div>
133
+ );
134
+ }
@@ -0,0 +1,120 @@
1
+ // The AsyncAPI document itself, rendered.
2
+ //
3
+ // The same argument the OpenAPI reference makes beside it holds here, and for
4
+ // the same reason: the catalog says the service has a document and where it
5
+ // lives, the bus tab keeps the facts read out of it - the channels, and which
6
+ // way each message travels - and this shows the document those were read from.
7
+ // Re-deriving a document's own shape into the schema would be rebuilding
8
+ // AsyncAPI inside it.
9
+ //
10
+ // What it does NOT do is draw the channels. Those are catalog facts by the time
11
+ // they reach a page: they link to the event that publishes a message and to the
12
+ // service that listens for one, which a rendered document cannot do because it
13
+ // has never heard of the estate around it.
14
+
15
+ import { lazy, Suspense, useEffect, useState } from "react";
16
+ import { loaderFor as loaderIn } from "../lib/spec-files";
17
+ import { Empty } from "./PageHeader";
18
+
19
+ /**
20
+ * Loaded on demand. This one is worth more than the OpenAPI reference is: the
21
+ * component brings the AsyncAPI parser with it, which is most of its weight,
22
+ * and a reader who never opens the tab pays none of it.
23
+ */
24
+ // The parser inside the component is a Node library that reached the browser
25
+ // unchanged - it calls Buffer, util and process while it loads - and the shims
26
+ // it needs are named in vite.config.ts.
27
+ const Reference = lazy(async () => {
28
+ // The stylesheet is a separate file the bundle does not pull in, so it is
29
+ // imported here rather than at the top: alongside the component it styles,
30
+ // and only when that component is wanted. Everything in it is scoped under
31
+ // `.aui-root`, so it meets the app's own styles nowhere.
32
+ await import("@asyncapi/react-component/styles/default.min.css");
33
+ const { default: AsyncApiComponent } = await import(
34
+ "@asyncapi/react-component"
35
+ );
36
+
37
+ return { default: AsyncApiComponent };
38
+ });
39
+
40
+ /**
41
+ * The documents in the repository, by path, loaded on demand. A document that
42
+ * lives in another repository is not here, and that is the normal case: the
43
+ * catalog still lists the channels, and this tab says plainly it has nothing
44
+ * to show.
45
+ */
46
+ const SPECS = import.meta.glob<string>(
47
+ [
48
+ "../../**/asyncapi.yaml",
49
+ "../../**/asyncapi.yml",
50
+ "!../../node_modules/**",
51
+ "!../../dist/**",
52
+ "!../../.portolan/**",
53
+ ],
54
+ { query: "?raw", import: "default" },
55
+ );
56
+
57
+ /** Whether the document a catalog entry points at is one this site can show. */
58
+ export function hasAsyncSpec(source: string): boolean {
59
+ return loaderIn(SPECS, source) !== null;
60
+ }
61
+
62
+ export function AsyncApiReference({ source }: { source: string }) {
63
+ const [spec, setSpec] = useState<string | null>(null);
64
+ const [missing, setMissing] = useState(false);
65
+
66
+ useEffect(() => {
67
+ const load = loaderIn(SPECS, source);
68
+ if (!load) {
69
+ setMissing(true);
70
+
71
+ return;
72
+ }
73
+
74
+ let live = true;
75
+ load()
76
+ .then((text) => {
77
+ if (live) setSpec(text);
78
+ })
79
+ .catch(() => {
80
+ if (live) setMissing(true);
81
+ });
82
+
83
+ return () => {
84
+ live = false;
85
+ };
86
+ }, [source]);
87
+
88
+ if (missing) {
89
+ return (
90
+ <Empty>
91
+ this service&apos;s document is not in this repository — only the
92
+ channels the catalog extracted from it are
93
+ </Empty>
94
+ );
95
+ }
96
+
97
+ if (spec === null) return <Empty>reading the document…</Empty>;
98
+
99
+ return (
100
+ /* A sheet of paper on a dark desk: the document is drawn light whatever the
101
+ app's theme is, because the component's own stylesheet has no dark mode
102
+ to switch. `.spec-sheet` in index.css is where that is arranged, and why
103
+ it takes re-declaring the palette rather than painting a background. */
104
+ <div className="spec-sheet overflow-x-auto rounded-card border border-line p-2">
105
+ <Suspense fallback={<Empty>loading the reference…</Empty>}>
106
+ <Reference
107
+ schema={spec}
108
+ config={{
109
+ show: {
110
+ // Its sidebar would be a second navigation tree beside the one
111
+ // the app already has, over the same channels.
112
+ sidebar: false,
113
+ errors: true,
114
+ },
115
+ }}
116
+ />
117
+ </Suspense>
118
+ </div>
119
+ );
120
+ }