@shortlink-org/portolan 0.1.0 → 0.2.1

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 (381) hide show
  1. package/README.md +69 -205
  2. package/cli/init.mjs +285 -0
  3. package/cli/init.test.mjs +158 -0
  4. package/cli/portolan.mjs +37 -73
  5. package/index.html +19 -0
  6. package/package.json +5 -10
  7. package/plugins/README.md +66 -27
  8. package/plugins/portolan-go.wasm +0 -0
  9. package/portolan.json +52 -73
  10. package/public/landing/cats/bug-hunter.webp +0 -0
  11. package/public/landing/cats/compass-nap.webp +0 -0
  12. package/public/landing/cats/diagrammer.webp +0 -0
  13. package/public/landing/cats/docs-reader.webp +0 -0
  14. package/public/landing/cats/laptop.webp +0 -0
  15. package/public/landing/cats/map-inspector.webp +0 -0
  16. package/public/landing/cats/server-break.webp +0 -0
  17. package/public/landing/cats/star-mapper.webp +0 -0
  18. package/public/landing/cats/system-builder.webp +0 -0
  19. package/public/landing/cats/thread-tangle.webp +0 -0
  20. package/public/og.png +0 -0
  21. package/public/readme-header.webp +0 -0
  22. package/schema/portolan.schema.json +180 -0
  23. package/scripts/builtin-plugins.mjs +14 -0
  24. package/scripts/delivery-presets.mjs +353 -0
  25. package/scripts/gen.mjs +37 -4
  26. package/scripts/history.mjs +126 -0
  27. package/scripts/history.test.mjs +110 -0
  28. package/scripts/host-plugins/fetch-bsr.mjs +351 -0
  29. package/{plugins/fetch-bsr/options.schema.json → scripts/host-plugins/fetch-bsr.options.json} +4 -0
  30. package/scripts/host-plugins/fetch-bsr.test.mjs +212 -0
  31. package/scripts/host-plugins/fetch-csr.mjs +386 -0
  32. package/scripts/host-plugins/fetch-csr.test.mjs +178 -0
  33. package/scripts/host-plugins/fetch-git.mjs +379 -0
  34. package/scripts/host-plugins/fetch-git.test.mjs +210 -0
  35. package/scripts/local-api.mjs +27 -10
  36. package/scripts/local-api.test.mjs +85 -2
  37. package/scripts/manifest.mjs +3 -2
  38. package/scripts/package-smoke.mjs +24 -3
  39. package/scripts/plugin-host.mjs +77 -18
  40. package/scripts/plugin-host.test.mjs +50 -1
  41. package/scripts/plugin-wasm-worker.mjs +6 -3
  42. package/scripts/run-builtin.mjs +6 -26
  43. package/scripts/schema.mjs +6 -1
  44. package/src/app/App.tsx +24 -429
  45. package/src/app/Breadcrumbs.test.ts +7 -0
  46. package/src/app/Breadcrumbs.tsx +15 -2
  47. package/src/app/CatalogApp.tsx +436 -0
  48. package/src/app/Sidebar.tsx +0 -1
  49. package/src/chat/ChatPanel.tsx +98 -41
  50. package/src/chat/Composer.tsx +4 -2
  51. package/src/chat/Conversation.tsx +79 -15
  52. package/src/chat/Header.tsx +43 -9
  53. package/src/chat/Starter.tsx +64 -3
  54. package/src/chat/Steps.tsx +1 -1
  55. package/src/chat/flags.test.ts +51 -14
  56. package/src/chat/flags.ts +8 -2
  57. package/src/chat/page-context.test.ts +51 -0
  58. package/src/chat/page-context.ts +128 -0
  59. package/src/chat/prompt.test.ts +49 -1
  60. package/src/chat/prompt.ts +42 -1
  61. package/src/chat/tools.ts +7 -2
  62. package/src/chat/transport.ts +16 -4
  63. package/src/components/ProblemRow.tsx +182 -0
  64. package/src/data.ts +20 -5
  65. package/src/er/ErCanvas.tsx +1 -1
  66. package/src/graph/DependencyGraph.tsx +10 -1
  67. package/src/graph/FocusedEventGraph.tsx +1 -1
  68. package/src/graph/GraphToolbar.tsx +2 -4
  69. package/src/index.css +220 -2
  70. package/src/landing/DraggableReveal.tsx +168 -0
  71. package/src/landing/EstateGraph.tsx +28 -0
  72. package/src/landing/FlowPlayback.tsx +282 -0
  73. package/src/landing/HeroMap.tsx +128 -0
  74. package/src/landing/LandingPage.tsx +757 -0
  75. package/src/landing/ProductFrame.tsx +68 -0
  76. package/src/landing/ProductTour.tsx +371 -0
  77. package/src/landing/catalog.ts +25 -0
  78. package/src/landing/motion.tsx +52 -0
  79. package/src/lib/all-problems.ts +28 -0
  80. package/src/lib/local-api.ts +35 -1
  81. package/src/lib/setup-info.test.ts +8 -0
  82. package/src/lib/setup-info.ts +3 -2
  83. package/src/lib/source-code.ts +2 -1
  84. package/src/likec4/C4View.tsx +5 -0
  85. package/src/likec4/InteractiveView.tsx +5 -1
  86. package/src/map/ContextMapGraph.tsx +47 -20
  87. package/src/pages/ContextMap.tsx +5 -1
  88. package/src/pages/FlowDetail.tsx +24 -7
  89. package/src/pages/Overview.tsx +68 -12
  90. package/src/pages/Problems.tsx +6 -193
  91. package/src/pages/Settings.tsx +133 -108
  92. package/src/pages/settings/DeliverySettings.tsx +229 -0
  93. package/src/pages/settings/PreferencesSettings.tsx +101 -0
  94. package/src/routes.test.ts +20 -0
  95. package/src/routes.ts +13 -1
  96. package/vite.config.ts +17 -9
  97. package/catalog/enum_test.go +0 -46
  98. package/catalog/model.go +0 -932
  99. package/catalog/roundtrip_test.go +0 -185
  100. package/catalog/via_test.go +0 -38
  101. package/go.mod +0 -14
  102. package/go.sum +0 -14
  103. package/internal/commands/cargo.go +0 -154
  104. package/internal/commands/commands.go +0 -143
  105. package/internal/commands/commands_test.go +0 -323
  106. package/internal/commands/gradle.go +0 -77
  107. package/internal/commands/justfile.go +0 -82
  108. package/internal/commands/makefile.go +0 -106
  109. package/internal/commands/maven.go +0 -93
  110. package/internal/commands/packagejson.go +0 -159
  111. package/internal/commands/pyproject.go +0 -169
  112. package/internal/commands/taskfile.go +0 -101
  113. package/internal/commands/testdata/estate/.cargo/config.toml +0 -7
  114. package/internal/commands/testdata/estate/Makefile +0 -33
  115. package/internal/commands/testdata/estate/Taskfile.yml +0 -21
  116. package/internal/commands/testdata/estate/build.gradle.kts +0 -21
  117. package/internal/commands/testdata/estate/justfile +0 -20
  118. package/internal/commands/testdata/estate/package.json +0 -13
  119. package/internal/commands/testdata/estate/pom.xml +0 -29
  120. package/internal/commands/testdata/estate/pyproject.toml +0 -27
  121. package/internal/commands/testdata/estate/xtask/src/main.rs +0 -27
  122. package/internal/commands/testdata/golden/commands.json +0 -305
  123. package/internal/gohttp/analyze.go +0 -2500
  124. package/internal/gohttp/endpoints.go +0 -1067
  125. package/internal/gohttp/roots.go +0 -320
  126. package/internal/gohttp/typed.go +0 -143
  127. package/internal/goscan/constants.go +0 -85
  128. package/internal/goscan/goscan_test.go +0 -227
  129. package/internal/goscan/names.go +0 -52
  130. package/internal/goscan/parse_test.go +0 -11
  131. package/internal/goscan/source.go +0 -36
  132. package/internal/goscan/tree.go +0 -155
  133. package/internal/goscan/types.go +0 -99
  134. package/internal/wsdl/ids.go +0 -127
  135. package/internal/wsdl/ids_test.go +0 -21
  136. package/internal/wsdl/model.go +0 -62
  137. package/internal/wsdl/parse.go +0 -920
  138. package/internal/wsdl/parse_test.go +0 -133
  139. package/plugin/describe.go +0 -107
  140. package/plugin/describe_test.go +0 -114
  141. package/plugin/protocol.go +0 -117
  142. package/plugin/schematest/schematest.go +0 -126
  143. package/plugins/extract-adr/describe.go +0 -19
  144. package/plugins/extract-adr/describe_test.go +0 -11
  145. package/plugins/extract-adr/extract.go +0 -153
  146. package/plugins/extract-adr/extract_test.go +0 -350
  147. package/plugins/extract-adr/history.go +0 -99
  148. package/plugins/extract-adr/main.go +0 -65
  149. package/plugins/extract-adr/parse.go +0 -642
  150. package/plugins/extract-adr/parse_test.go +0 -405
  151. package/plugins/extract-asyncapi/describe.go +0 -19
  152. package/plugins/extract-asyncapi/describe_test.go +0 -11
  153. package/plugins/extract-asyncapi/extract.go +0 -315
  154. package/plugins/extract-asyncapi/extract_test.go +0 -197
  155. package/plugins/extract-asyncapi/main.go +0 -48
  156. package/plugins/extract-asyncapi/spec.go +0 -151
  157. package/plugins/extract-commands/describe.go +0 -19
  158. package/plugins/extract-commands/describe_test.go +0 -11
  159. package/plugins/extract-commands/extract.go +0 -79
  160. package/plugins/extract-commands/extract_test.go +0 -92
  161. package/plugins/extract-commands/main.go +0 -55
  162. package/plugins/extract-csr/avro.go +0 -258
  163. package/plugins/extract-csr/describe.go +0 -19
  164. package/plugins/extract-csr/describe_test.go +0 -11
  165. package/plugins/extract-csr/extract.go +0 -338
  166. package/plugins/extract-csr/extract_test.go +0 -374
  167. package/plugins/extract-csr/jsonschema.go +0 -343
  168. package/plugins/extract-csr/lock.go +0 -25
  169. package/plugins/extract-csr/main.go +0 -84
  170. package/plugins/extract-csr/subject.go +0 -102
  171. package/plugins/extract-flows/describe.go +0 -19
  172. package/plugins/extract-flows/describe_test.go +0 -11
  173. package/plugins/extract-flows/extract.go +0 -91
  174. package/plugins/extract-flows/main.go +0 -45
  175. package/plugins/extract-flows/parse.go +0 -593
  176. package/plugins/extract-flows/parse_test.go +0 -204
  177. package/plugins/extract-glossary/describe.go +0 -19
  178. package/plugins/extract-glossary/describe_test.go +0 -11
  179. package/plugins/extract-glossary/extract.go +0 -115
  180. package/plugins/extract-glossary/extract_test.go +0 -220
  181. package/plugins/extract-glossary/main.go +0 -59
  182. package/plugins/extract-glossary/parse.go +0 -214
  183. package/plugins/extract-glossary/parse_test.go +0 -203
  184. package/plugins/extract-go/aggregate.go +0 -214
  185. package/plugins/extract-go/client.go +0 -409
  186. package/plugins/extract-go/client_test.go +0 -266
  187. package/plugins/extract-go/describe.go +0 -19
  188. package/plugins/extract-go/describe_test.go +0 -11
  189. package/plugins/extract-go/enum.go +0 -195
  190. package/plugins/extract-go/enum_test.go +0 -82
  191. package/plugins/extract-go/event.go +0 -99
  192. package/plugins/extract-go/extract.go +0 -191
  193. package/plugins/extract-go/extract_test.go +0 -261
  194. package/plugins/extract-go/flow.go +0 -1441
  195. package/plugins/extract-go/flow_test.go +0 -609
  196. package/plugins/extract-go/httpclient.go +0 -174
  197. package/plugins/extract-go/httpclient_test.go +0 -296
  198. package/plugins/extract-go/ids.go +0 -92
  199. package/plugins/extract-go/layout.go +0 -225
  200. package/plugins/extract-go/layout_test.go +0 -125
  201. package/plugins/extract-go/lifecycle.go +0 -324
  202. package/plugins/extract-go/lifecycle_test.go +0 -108
  203. package/plugins/extract-go/main.go +0 -79
  204. package/plugins/extract-go/operation.go +0 -157
  205. package/plugins/extract-go/source.go +0 -316
  206. package/plugins/extract-go/transport.go +0 -321
  207. package/plugins/extract-go/transport_test.go +0 -145
  208. package/plugins/extract-go/wiring.go +0 -434
  209. package/plugins/extract-go-nats/describe.go +0 -19
  210. package/plugins/extract-go-nats/describe_test.go +0 -11
  211. package/plugins/extract-go-nats/extract.go +0 -177
  212. package/plugins/extract-go-nats/extract_test.go +0 -389
  213. package/plugins/extract-go-nats/index.go +0 -379
  214. package/plugins/extract-go-nats/main.go +0 -42
  215. package/plugins/extract-go-nats/resolve.go +0 -161
  216. package/plugins/extract-go-nats/sites.go +0 -224
  217. package/plugins/extract-graphql/describe.go +0 -19
  218. package/plugins/extract-graphql/describe_test.go +0 -11
  219. package/plugins/extract-graphql/extract.go +0 -433
  220. package/plugins/extract-graphql/extract_test.go +0 -256
  221. package/plugins/extract-graphql/ids.go +0 -49
  222. package/plugins/extract-graphql/lex.go +0 -237
  223. package/plugins/extract-graphql/main.go +0 -51
  224. package/plugins/extract-graphql/parse.go +0 -621
  225. package/plugins/extract-graphql/parse_test.go +0 -122
  226. package/plugins/extract-http-clients/describe.go +0 -19
  227. package/plugins/extract-http-clients/describe_test.go +0 -11
  228. package/plugins/extract-http-clients/extract.go +0 -705
  229. package/plugins/extract-http-clients/extract_test.go +0 -1263
  230. package/plugins/extract-http-clients/main.go +0 -42
  231. package/plugins/extract-openapi/describe.go +0 -19
  232. package/plugins/extract-openapi/describe_test.go +0 -11
  233. package/plugins/extract-openapi/discover.go +0 -243
  234. package/plugins/extract-openapi/extract.go +0 -526
  235. package/plugins/extract-openapi/extract_test.go +0 -545
  236. package/plugins/extract-openapi/main.go +0 -75
  237. package/plugins/extract-openapi/spec.go +0 -350
  238. package/plugins/extract-project/describe.go +0 -19
  239. package/plugins/extract-project/describe_test.go +0 -11
  240. package/plugins/extract-project/extract.go +0 -221
  241. package/plugins/extract-project/extract_test.go +0 -109
  242. package/plugins/extract-project/main.go +0 -41
  243. package/plugins/extract-proto/ast.go +0 -125
  244. package/plugins/extract-proto/consumes.go +0 -77
  245. package/plugins/extract-proto/describe.go +0 -19
  246. package/plugins/extract-proto/extract.go +0 -293
  247. package/plugins/extract-proto/extract_test.go +0 -459
  248. package/plugins/extract-proto/ids.go +0 -89
  249. package/plugins/extract-proto/ids_test.go +0 -57
  250. package/plugins/extract-proto/lex.go +0 -285
  251. package/plugins/extract-proto/main.go +0 -100
  252. package/plugins/extract-proto/module.go +0 -120
  253. package/plugins/extract-proto/parse.go +0 -720
  254. package/plugins/extract-proto/parse_test.go +0 -307
  255. package/plugins/extract-proto/provides.go +0 -236
  256. package/plugins/extract-proto/resolve.go +0 -222
  257. package/plugins/extract-proto/resolve_test.go +0 -119
  258. package/plugins/extract-redis/describe.go +0 -19
  259. package/plugins/extract-redis/describe_test.go +0 -11
  260. package/plugins/extract-redis/extract.go +0 -183
  261. package/plugins/extract-redis/extract_test.go +0 -168
  262. package/plugins/extract-redis/keyspaces.go +0 -469
  263. package/plugins/extract-redis/main.go +0 -44
  264. package/plugins/extract-river/describe.go +0 -19
  265. package/plugins/extract-river/describe_test.go +0 -11
  266. package/plugins/extract-river/extract.go +0 -507
  267. package/plugins/extract-river/extract_test.go +0 -132
  268. package/plugins/extract-river/main.go +0 -42
  269. package/plugins/extract-sql/ddl.go +0 -893
  270. package/plugins/extract-sql/ddl_test.go +0 -401
  271. package/plugins/extract-sql/describe.go +0 -19
  272. package/plugins/extract-sql/describe_test.go +0 -11
  273. package/plugins/extract-sql/layout.go +0 -221
  274. package/plugins/extract-sql/layout_test.go +0 -55
  275. package/plugins/extract-sql/lineage.go +0 -107
  276. package/plugins/extract-sql/main.go +0 -141
  277. package/plugins/extract-sql/maps.go +0 -564
  278. package/plugins/extract-sql/maps_java.go +0 -117
  279. package/plugins/extract-sql/maps_rust.go +0 -333
  280. package/plugins/extract-sql/maps_rust_test.go +0 -70
  281. package/plugins/extract-sql/maps_test.go +0 -204
  282. package/plugins/extract-sql/maps_ts.go +0 -398
  283. package/plugins/extract-sql/maps_ts_test.go +0 -136
  284. package/plugins/extract-sql/projection.go +0 -70
  285. package/plugins/extract-sql/projection_test.go +0 -50
  286. package/plugins/extract-sql/store.go +0 -420
  287. package/plugins/extract-sql/store_test.go +0 -233
  288. package/plugins/extract-sql/view.go +0 -295
  289. package/plugins/extract-watermill/describe.go +0 -19
  290. package/plugins/extract-watermill/describe_test.go +0 -11
  291. package/plugins/extract-watermill/extract.go +0 -1228
  292. package/plugins/extract-watermill/extract_test.go +0 -234
  293. package/plugins/extract-watermill/main.go +0 -41
  294. package/plugins/extract-wsdl/describe.go +0 -19
  295. package/plugins/extract-wsdl/describe_test.go +0 -11
  296. package/plugins/extract-wsdl/extract.go +0 -148
  297. package/plugins/extract-wsdl/extract_test.go +0 -45
  298. package/plugins/extract-wsdl/main.go +0 -53
  299. package/plugins/fetch-bsr/auth.go +0 -114
  300. package/plugins/fetch-bsr/bsr.go +0 -240
  301. package/plugins/fetch-bsr/cache.go +0 -66
  302. package/plugins/fetch-bsr/describe.go +0 -19
  303. package/plugins/fetch-bsr/fetch.go +0 -192
  304. package/plugins/fetch-bsr/fetch_test.go +0 -465
  305. package/plugins/fetch-bsr/lock.go +0 -71
  306. package/plugins/fetch-bsr/main.go +0 -117
  307. package/plugins/fetch-csr/auth.go +0 -95
  308. package/plugins/fetch-csr/cache.go +0 -69
  309. package/plugins/fetch-csr/describe.go +0 -19
  310. package/plugins/fetch-csr/describe_test.go +0 -11
  311. package/plugins/fetch-csr/fetch.go +0 -254
  312. package/plugins/fetch-csr/fetch_test.go +0 -494
  313. package/plugins/fetch-csr/lock.go +0 -95
  314. package/plugins/fetch-csr/main.go +0 -122
  315. package/plugins/fetch-csr/registry.go +0 -209
  316. package/plugins/fetch-git/cache.go +0 -65
  317. package/plugins/fetch-git/describe.go +0 -19
  318. package/plugins/fetch-git/describe_test.go +0 -11
  319. package/plugins/fetch-git/fetch.go +0 -181
  320. package/plugins/fetch-git/fetch_test.go +0 -332
  321. package/plugins/fetch-git/git.go +0 -169
  322. package/plugins/fetch-git/lock.go +0 -72
  323. package/plugins/fetch-git/main.go +0 -127
  324. package/plugins/fetch-git/offline.go +0 -39
  325. package/plugins/fetch-git/pin.go +0 -90
  326. package/plugins/fetch-git/pin_test.go +0 -74
  327. package/plugins/gen-backstage/describe.go +0 -17
  328. package/plugins/gen-backstage/main.go +0 -22
  329. package/plugins/gen-backstage/plugin.go +0 -473
  330. package/plugins/gen-backstage/plugin_test.go +0 -145
  331. package/plugins/gen-backstage.wasm +0 -0
  332. package/plugins/gen-markdown/adr.go +0 -162
  333. package/plugins/gen-markdown/aggregate.go +0 -362
  334. package/plugins/gen-markdown/canonical.go +0 -93
  335. package/plugins/gen-markdown/context.go +0 -90
  336. package/plugins/gen-markdown/coverage_test.go +0 -89
  337. package/plugins/gen-markdown/describe.go +0 -19
  338. package/plugins/gen-markdown/describe_test.go +0 -11
  339. package/plugins/gen-markdown/external.go +0 -71
  340. package/plugins/gen-markdown/flow.go +0 -277
  341. package/plugins/gen-markdown/glossary.go +0 -76
  342. package/plugins/gen-markdown/glossary_test.go +0 -148
  343. package/plugins/gen-markdown/llms.go +0 -302
  344. package/plugins/gen-markdown/main.go +0 -22
  345. package/plugins/gen-markdown/markdown.go +0 -254
  346. package/plugins/gen-markdown/markdown_test.go +0 -100
  347. package/plugins/gen-markdown/module.go +0 -107
  348. package/plugins/gen-markdown/plugin.go +0 -39
  349. package/plugins/gen-markdown/quality_test.go +0 -176
  350. package/plugins/gen-markdown/redis_test.go +0 -38
  351. package/plugins/gen-markdown/render.go +0 -344
  352. package/plugins/gen-markdown/render_test.go +0 -186
  353. package/plugins/gen-markdown/service.go +0 -456
  354. package/plugins/gen-markdown/source.go +0 -177
  355. package/plugins/gen-markdown/store.go +0 -201
  356. package/plugins/gen-markdown.wasm +0 -0
  357. package/plugins/gen-mermaid/describe.go +0 -17
  358. package/plugins/gen-mermaid/main.go +0 -22
  359. package/plugins/gen-mermaid/plugin.go +0 -104
  360. package/plugins/gen-mermaid/plugin_test.go +0 -33
  361. package/plugins/gen-mermaid.wasm +0 -0
  362. package/plugins/openapi/ids.go +0 -261
  363. package/plugins/openapi/ids_test.go +0 -98
  364. package/plugins/verify-codeowners/describe.go +0 -19
  365. package/plugins/verify-codeowners/describe_test.go +0 -11
  366. package/plugins/verify-codeowners/main.go +0 -75
  367. package/plugins/verify-codeowners/match.go +0 -85
  368. package/plugins/verify-codeowners/match_test.go +0 -47
  369. package/plugins/verify-codeowners/owners.go +0 -164
  370. package/plugins/verify-codeowners/owners_test.go +0 -225
  371. package/plugins/verify-codeowners/parse.go +0 -90
  372. package/plugins/verify-codeowners/parse_test.go +0 -62
  373. package/plugins/verify-otel/describe.go +0 -19
  374. package/plugins/verify-otel/describe_test.go +0 -11
  375. package/plugins/verify-otel/main.go +0 -53
  376. package/plugins/verify-otel/match.go +0 -336
  377. package/plugins/verify-otel/otlp.go +0 -200
  378. package/plugins/verify-otel/verify.go +0 -734
  379. package/plugins/verify-otel/verify_test.go +0 -460
  380. /package/{plugins/fetch-csr/options.schema.json → scripts/host-plugins/fetch-csr.options.json} +0 -0
  381. /package/{plugins/fetch-git/options.schema.json → scripts/host-plugins/fetch-git.options.json} +0 -0
@@ -1,336 +0,0 @@
1
- package main
2
-
3
- import (
4
- "strings"
5
-
6
- "github.com/shortlink-org/portolan/catalog"
7
- )
8
-
9
- // lookup is the catalog, indexed for the questions a span raises: whose span
10
- // is this, which operation answers on this route, which event travels under
11
- // this name, who provides this rpc, where does this service keep its state.
12
- type lookup struct {
13
- opts Options
14
-
15
- contexts map[string]*catalog.BoundedContext
16
- services map[string]*catalog.Service
17
- bySlug map[string]*catalog.Service // unique slugs only
18
- events map[string]*catalog.Event
19
- eventOwner map[string]*catalog.Service
20
- aggregate map[string]*catalog.Aggregate // by event id
21
- byName map[string][]string // event name -> ids
22
- byWire map[string][]string // declared wire name -> ids
23
- providers map[string]*catalog.Service // interface id -> provider
24
- rpcIDs map[string]bool
25
- stores map[string][]*catalog.Store // owner -> stores
26
- openings map[string]*catalog.Flow // opening key -> declared flow
27
- }
28
-
29
- func newLookup(cat *catalog.Catalog, opts Options) *lookup {
30
- l := &lookup{
31
- opts: opts,
32
- contexts: map[string]*catalog.BoundedContext{},
33
- services: map[string]*catalog.Service{},
34
- bySlug: map[string]*catalog.Service{},
35
- events: map[string]*catalog.Event{},
36
- eventOwner: map[string]*catalog.Service{},
37
- aggregate: map[string]*catalog.Aggregate{},
38
- byName: map[string][]string{},
39
- byWire: map[string][]string{},
40
- providers: map[string]*catalog.Service{},
41
- rpcIDs: map[string]bool{},
42
- stores: map[string][]*catalog.Store{},
43
- openings: map[string]*catalog.Flow{},
44
- }
45
-
46
- slugs := map[string]int{}
47
- for i := range cat.Contexts {
48
- ctx := &cat.Contexts[i]
49
- l.contexts[ctx.ID] = ctx
50
- for j := range ctx.Services {
51
- svc := &ctx.Services[j]
52
- l.services[svc.ID] = svc
53
- slugs[svc.Slug]++
54
- l.bySlug[svc.Slug] = svc
55
- for k := range svc.Provides {
56
- provided := &svc.Provides[k]
57
- l.providers[provided.ID] = svc
58
- for _, method := range provided.Methods {
59
- l.rpcIDs[provided.ID+"/"+method.Name] = true
60
- }
61
- }
62
- for _, call := range svc.Consumes {
63
- l.rpcIDs[call.ID] = true
64
- }
65
- for k := range svc.Aggregates {
66
- agg := &svc.Aggregates[k]
67
- for m := range agg.Events {
68
- ev := &agg.Events[m]
69
- l.events[ev.ID] = ev
70
- l.eventOwner[ev.ID] = svc
71
- l.aggregate[ev.ID] = agg
72
- l.byName[ev.Name] = append(l.byName[ev.Name], ev.ID)
73
- if ev.Wire != nil {
74
- l.byWire[ev.Wire.Name] = append(l.byWire[ev.Wire.Name], ev.ID)
75
- }
76
- }
77
- }
78
- }
79
- }
80
- for slug, n := range slugs {
81
- if n > 1 {
82
- delete(l.bySlug, slug)
83
- }
84
- }
85
- for i := range cat.Stores {
86
- store := &cat.Stores[i]
87
- l.stores[store.Owner] = append(l.stores[store.Owner], store)
88
- }
89
- for i := range cat.Flows {
90
- flow := &cat.Flows[i]
91
- if key := declaredOpening(flow); key != "" {
92
- if _, taken := l.openings[key]; !taken {
93
- l.openings[key] = flow
94
- }
95
- }
96
- }
97
-
98
- return l
99
- }
100
-
101
- // service reads a resource's service.name back to the catalog: the manifest's
102
- // word first, then the one service whose slug it is.
103
- func (l *lookup) service(name string) *catalog.Service {
104
- if id, ok := l.opts.Services[name]; ok {
105
- return l.services[id]
106
- }
107
- if svc, ok := l.services[name]; ok {
108
- return svc
109
- }
110
-
111
- return l.bySlug[name]
112
- }
113
-
114
- // operation reads a server span's route back to the operation the service's
115
- // interface declares on it, by the verb and path template the OpenAPI
116
- // extractor recorded.
117
- func (l *lookup) operation(svc *catalog.Service, method, route string) (string, bool) {
118
- for _, provided := range svc.Provides {
119
- for _, m := range provided.Methods {
120
- if m.HTTP != nil && m.HTTP.Method == method && samePath(m.HTTP.Path, route) {
121
- return m.Name, true
122
- }
123
- }
124
- }
125
-
126
- return "", false
127
- }
128
-
129
- func samePath(a, b string) bool {
130
- return shapeOf(a) == shapeOf(b)
131
- }
132
-
133
- // shapeOf replaces every segment that is a parameter - `{userId}` in a
134
- // document - or looks like a value where the document has one - with a
135
- // marker, so a request's concrete path matches its template by position.
136
- // isParam says whether a route segment stands for a value: `{userId}` as an
137
- // OpenAPI document writes it, `:userId` as Fastify and Express report the
138
- // route they matched.
139
- func isParam(seg string) bool {
140
- return (strings.HasPrefix(seg, "{") && strings.HasSuffix(seg, "}")) || (len(seg) > 1 && seg[0] == ':')
141
- }
142
-
143
- func shapeOf(path string) string {
144
- path = strings.TrimSuffix(path, "/")
145
- segments := strings.Split(path, "/")
146
- for i, seg := range segments {
147
- if isParam(seg) {
148
- segments[i] = "*"
149
- }
150
- }
151
-
152
- return strings.Join(segments, "/")
153
- }
154
-
155
- // httpProvider finds the service whose interface answers on a verb and a
156
- // concrete path, matching a template's parameters to the path's segments.
157
- func (l *lookup) httpProvider(method, path string) (*catalog.Service, string, string) {
158
- for _, svc := range l.services {
159
- for _, provided := range svc.Provides {
160
- for _, m := range provided.Methods {
161
- if m.HTTP != nil && m.HTTP.Method == strings.ToUpper(method) && routeMatches(m.HTTP.Path, path) {
162
- return svc, m.Name, provided.ID
163
- }
164
- }
165
- }
166
- }
167
-
168
- return nil, "", ""
169
- }
170
-
171
- // routeMatches says whether a concrete path fits a template, segment by
172
- // segment, a `{param}` standing for any one segment.
173
- func routeMatches(template, path string) bool {
174
- t := strings.Split(strings.TrimSuffix(template, "/"), "/")
175
- p := strings.Split(strings.TrimSuffix(path, "/"), "/")
176
- if len(t) != len(p) {
177
- return false
178
- }
179
- for i := range t {
180
- if isParam(t[i]) {
181
- continue
182
- }
183
- if t[i] != p[i] {
184
- return false
185
- }
186
- }
187
-
188
- return true
189
- }
190
-
191
- // event reads a wire name back to an event id. The manifest's word first;
192
- // then the one event that declares this very name as its wire; then, for a
193
- // producer, the one event of its own with that name as its last segment;
194
- // then, for a consumer of somebody else's event, the one event anywhere with
195
- // that name. Two events sharing a name is an ambiguity the manifest has to
196
- // settle.
197
- func (l *lookup) event(producer *catalog.Service, wire string) (string, bool) {
198
- if id, ok := l.opts.Events[wire]; ok {
199
- _, known := l.events[id]
200
-
201
- return id, known
202
- }
203
- if ids := l.byWire[wire]; len(ids) == 1 {
204
- return ids[0], true
205
- }
206
- name := wire
207
- if i := strings.LastIndex(wire, "."); i >= 0 {
208
- name = wire[i+1:]
209
- }
210
-
211
- candidates := l.byName[name]
212
- if producer != nil {
213
- var own []string
214
- for _, id := range candidates {
215
- if l.eventOwner[id] == producer {
216
- own = append(own, id)
217
- }
218
- }
219
- if len(own) == 1 {
220
- return own[0], true
221
- }
222
- if len(own) > 1 {
223
- return "", false
224
- }
225
- }
226
- if len(candidates) == 1 {
227
- return candidates[0], true
228
- }
229
-
230
- return "", false
231
- }
232
-
233
- // storeLane is where a service's database calls land: its one store, on the
234
- // lane the code extractor names it by, or the service's own lane when it has
235
- // none or several - saying so once beats inventing a database.
236
- func (l *lookup) storeLane(svc *catalog.Service) (catalog.Participant, bool) {
237
- stores := l.stores[svc.ID]
238
- if len(stores) != 1 {
239
- return catalog.Participant{}, false
240
- }
241
- context := contextOf(svc.ID)
242
-
243
- return catalog.Participant{
244
- ID: svc.Slug + "-" + stores[0].Slug,
245
- Kind: catalog.ParticipantStore,
246
- Context: &context,
247
- }, true
248
- }
249
-
250
- func (l *lookup) serviceLane(svc *catalog.Service) catalog.Participant {
251
- context := contextOf(svc.ID)
252
-
253
- return catalog.Participant{ID: svc.ID, Kind: catalog.ParticipantService, Context: &context}
254
- }
255
-
256
- func contextOf(serviceID string) string {
257
- context, _, _ := strings.Cut(serviceID, ".")
258
-
259
- return context
260
- }
261
-
262
- // declaredOpening is the key a flow can be recognised by from its first step:
263
- // the operation somebody calls in on, or the event that arrives. A flow that
264
- // opens any other way - a store call, a self-message - is not one a trace can
265
- // be matched to from its root, and gets no key.
266
- func declaredOpening(flow *catalog.Flow) string {
267
- first := firstStep(flow.Steps)
268
- if first == nil {
269
- return ""
270
- }
271
- brokers := map[string]bool{}
272
- for _, p := range flow.Participants {
273
- if p.Kind == catalog.ParticipantBroker {
274
- brokers[p.ID] = true
275
- }
276
- }
277
- switch {
278
- case first.Kind == catalog.StepRPC && first.Ref == "" && first.From != first.To:
279
- return openingKey(catalog.StepRPC, first.To, first.Label)
280
- case first.Kind == catalog.StepEvent && first.Ref != "" && brokers[first.From]:
281
- return openingKey(catalog.StepEvent, first.To, first.Ref)
282
- }
283
-
284
- return ""
285
- }
286
-
287
- func openingKey(kind catalog.StepKind, service, what string) string {
288
- return string(kind) + "|" + service + "|" + what
289
- }
290
-
291
- func firstStep(nodes catalog.FlowNodes) *catalog.Step {
292
- for _, node := range nodes {
293
- switch x := node.(type) {
294
- case *catalog.Step:
295
- return x
296
- case *catalog.Parallel:
297
- for _, branch := range x.Branches {
298
- if s := firstStep(branch); s != nil {
299
- return s
300
- }
301
- }
302
- case *catalog.Alt:
303
- for _, branch := range x.Branches {
304
- if s := firstStep(branch.Steps); s != nil {
305
- return s
306
- }
307
- }
308
- case *catalog.Loop:
309
- if s := firstStep(x.Steps); s != nil {
310
- return s
311
- }
312
- }
313
- }
314
-
315
- return nil
316
- }
317
-
318
- // walkSteps visits every step, frames included, in flow order.
319
- func walkSteps(nodes catalog.FlowNodes, visit func(*catalog.Step)) {
320
- for _, node := range nodes {
321
- switch x := node.(type) {
322
- case *catalog.Step:
323
- visit(x)
324
- case *catalog.Parallel:
325
- for _, branch := range x.Branches {
326
- walkSteps(branch, visit)
327
- }
328
- case *catalog.Alt:
329
- for _, branch := range x.Branches {
330
- walkSteps(branch.Steps, visit)
331
- }
332
- case *catalog.Loop:
333
- walkSteps(x.Steps, visit)
334
- }
335
- }
336
- }
@@ -1,200 +0,0 @@
1
- package main
2
-
3
- import (
4
- "bytes"
5
- "encoding/json"
6
- "errors"
7
- "fmt"
8
- "io"
9
- "os"
10
- "path/filepath"
11
- "sort"
12
- "strconv"
13
- "strings"
14
- )
15
-
16
- // A span, flattened out of the OTLP shape into the few things a hop is read
17
- // from. Attribute values are kept as strings: everything matched on is a
18
- // name, and a number that mattered would be a number in a string here.
19
- type span struct {
20
- traceID string
21
- spanID string
22
- parentID string
23
- name string
24
- kind int
25
- service string
26
- start uint64
27
- attrs map[string]string
28
- file string
29
- }
30
-
31
- const (
32
- kindInternal = 1
33
- kindServer = 2
34
- kindClient = 3
35
- kindProducer = 4
36
- kindConsumer = 5
37
- )
38
-
39
- // readTraces reads every file the globs name under root, in path order, so
40
- // that the fragment does not depend on the order a directory happens to list.
41
- func readTraces(root string, patterns []string) ([]span, []string, error) {
42
- var files []string
43
- seen := map[string]bool{}
44
- for _, pattern := range patterns {
45
- matches, err := filepath.Glob(filepath.Join(root, pattern))
46
- if err != nil {
47
- return nil, nil, fmt.Errorf("traces %q: %w", pattern, err)
48
- }
49
- for _, match := range matches {
50
- if !seen[match] {
51
- seen[match] = true
52
- files = append(files, match)
53
- }
54
- }
55
- }
56
- sort.Strings(files)
57
-
58
- var spans []span
59
- var names []string
60
- for _, file := range files {
61
- data, err := os.ReadFile(file)
62
- if err != nil {
63
- return nil, nil, err
64
- }
65
- rel, err := filepath.Rel(root, file)
66
- if err != nil {
67
- rel = file
68
- }
69
- rel = filepath.ToSlash(rel)
70
- parsed, err := parseOTLP(data, rel)
71
- if err != nil {
72
- return nil, nil, fmt.Errorf("%s: %w", rel, err)
73
- }
74
- spans = append(spans, parsed...)
75
- names = append(names, rel)
76
- }
77
-
78
- return spans, names, nil
79
- }
80
-
81
- type otlpBatch struct {
82
- ResourceSpans []struct {
83
- Resource struct {
84
- Attributes []otlpAttr `json:"attributes"`
85
- } `json:"resource"`
86
- ScopeSpans []struct {
87
- Spans []otlpSpan `json:"spans"`
88
- } `json:"scopeSpans"`
89
- } `json:"resourceSpans"`
90
- }
91
-
92
- type otlpSpan struct {
93
- TraceID string `json:"traceId"`
94
- SpanID string `json:"spanId"`
95
- ParentSpanID string `json:"parentSpanId"`
96
- Name string `json:"name"`
97
- Kind json.RawMessage `json:"kind"`
98
- StartTimeUnixNano string `json:"startTimeUnixNano"`
99
- Attributes []otlpAttr `json:"attributes"`
100
- }
101
-
102
- type otlpAttr struct {
103
- Key string `json:"key"`
104
- Value map[string]json.RawMessage `json:"value"`
105
- }
106
-
107
- // parseOTLP reads one JSON value, or one per line: a collector's file
108
- // exporter writes the second, an export saved from a viewer the first, and
109
- // the decoder does not care which.
110
- func parseOTLP(data []byte, file string) ([]span, error) {
111
- dec := json.NewDecoder(bytes.NewReader(data))
112
- var out []span
113
- for {
114
- var batch otlpBatch
115
- err := dec.Decode(&batch)
116
- if errors.Is(err, io.EOF) {
117
- break
118
- }
119
- if err != nil {
120
- return nil, err
121
- }
122
- for _, rs := range batch.ResourceSpans {
123
- service := attrs(rs.Resource.Attributes)["service.name"]
124
- for _, ss := range rs.ScopeSpans {
125
- for _, s := range ss.Spans {
126
- start, _ := strconv.ParseUint(s.StartTimeUnixNano, 10, 64)
127
- out = append(out, span{
128
- traceID: s.TraceID,
129
- spanID: s.SpanID,
130
- parentID: s.ParentSpanID,
131
- name: s.Name,
132
- kind: spanKind(s.Kind),
133
- service: service,
134
- start: start,
135
- attrs: attrs(s.Attributes),
136
- file: file,
137
- })
138
- }
139
- }
140
- }
141
- }
142
-
143
- return out, nil
144
- }
145
-
146
- func attrs(list []otlpAttr) map[string]string {
147
- out := map[string]string{}
148
- for _, a := range list {
149
- if v, ok := attrString(a.Value); ok {
150
- out[a.Key] = v
151
- }
152
- }
153
-
154
- return out
155
- }
156
-
157
- // attrString reads the one-of an OTLP value is: a string, or a number or bool
158
- // spelled as one. Arrays and maps are not names and are left out.
159
- func attrString(value map[string]json.RawMessage) (string, bool) {
160
- for _, key := range []string{"stringValue", "intValue", "boolValue", "doubleValue"} {
161
- raw, ok := value[key]
162
- if !ok {
163
- continue
164
- }
165
- var s string
166
- if err := json.Unmarshal(raw, &s); err == nil {
167
- return s, true
168
- }
169
- // A number or a bool, unquoted.
170
- return strings.TrimSpace(string(raw)), true
171
- }
172
-
173
- return "", false
174
- }
175
-
176
- // spanKind reads the enum however it was written: protojson gives the number,
177
- // some exporters the name.
178
- func spanKind(raw json.RawMessage) int {
179
- var n int
180
- if err := json.Unmarshal(raw, &n); err == nil {
181
- return n
182
- }
183
- var s string
184
- if err := json.Unmarshal(raw, &s); err == nil {
185
- switch strings.TrimPrefix(s, "SPAN_KIND_") {
186
- case "INTERNAL":
187
- return kindInternal
188
- case "SERVER":
189
- return kindServer
190
- case "CLIENT":
191
- return kindClient
192
- case "PRODUCER":
193
- return kindProducer
194
- case "CONSUMER":
195
- return kindConsumer
196
- }
197
- }
198
-
199
- return 0
200
- }