@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.
- package/README.md +69 -205
- package/cli/init.mjs +285 -0
- package/cli/init.test.mjs +158 -0
- package/cli/portolan.mjs +37 -73
- package/index.html +19 -0
- package/package.json +5 -10
- package/plugins/README.md +66 -27
- package/plugins/portolan-go.wasm +0 -0
- package/portolan.json +52 -73
- package/public/landing/cats/bug-hunter.webp +0 -0
- package/public/landing/cats/compass-nap.webp +0 -0
- package/public/landing/cats/diagrammer.webp +0 -0
- package/public/landing/cats/docs-reader.webp +0 -0
- package/public/landing/cats/laptop.webp +0 -0
- package/public/landing/cats/map-inspector.webp +0 -0
- package/public/landing/cats/server-break.webp +0 -0
- package/public/landing/cats/star-mapper.webp +0 -0
- package/public/landing/cats/system-builder.webp +0 -0
- package/public/landing/cats/thread-tangle.webp +0 -0
- package/public/og.png +0 -0
- package/public/readme-header.webp +0 -0
- package/schema/portolan.schema.json +180 -0
- package/scripts/builtin-plugins.mjs +14 -0
- package/scripts/delivery-presets.mjs +353 -0
- package/scripts/gen.mjs +37 -4
- package/scripts/history.mjs +126 -0
- package/scripts/history.test.mjs +110 -0
- package/scripts/host-plugins/fetch-bsr.mjs +351 -0
- package/{plugins/fetch-bsr/options.schema.json → scripts/host-plugins/fetch-bsr.options.json} +4 -0
- package/scripts/host-plugins/fetch-bsr.test.mjs +212 -0
- package/scripts/host-plugins/fetch-csr.mjs +386 -0
- package/scripts/host-plugins/fetch-csr.test.mjs +178 -0
- package/scripts/host-plugins/fetch-git.mjs +379 -0
- package/scripts/host-plugins/fetch-git.test.mjs +210 -0
- package/scripts/local-api.mjs +27 -10
- package/scripts/local-api.test.mjs +85 -2
- package/scripts/manifest.mjs +3 -2
- package/scripts/package-smoke.mjs +24 -3
- package/scripts/plugin-host.mjs +77 -18
- package/scripts/plugin-host.test.mjs +50 -1
- package/scripts/plugin-wasm-worker.mjs +6 -3
- package/scripts/run-builtin.mjs +6 -26
- package/scripts/schema.mjs +6 -1
- package/src/app/App.tsx +24 -429
- package/src/app/Breadcrumbs.test.ts +7 -0
- package/src/app/Breadcrumbs.tsx +15 -2
- package/src/app/CatalogApp.tsx +436 -0
- package/src/app/Sidebar.tsx +0 -1
- package/src/chat/ChatPanel.tsx +98 -41
- package/src/chat/Composer.tsx +4 -2
- package/src/chat/Conversation.tsx +79 -15
- package/src/chat/Header.tsx +43 -9
- package/src/chat/Starter.tsx +64 -3
- package/src/chat/Steps.tsx +1 -1
- package/src/chat/flags.test.ts +51 -14
- package/src/chat/flags.ts +8 -2
- package/src/chat/page-context.test.ts +51 -0
- package/src/chat/page-context.ts +128 -0
- package/src/chat/prompt.test.ts +49 -1
- package/src/chat/prompt.ts +42 -1
- package/src/chat/tools.ts +7 -2
- package/src/chat/transport.ts +16 -4
- package/src/components/ProblemRow.tsx +182 -0
- package/src/data.ts +20 -5
- package/src/er/ErCanvas.tsx +1 -1
- package/src/graph/DependencyGraph.tsx +10 -1
- package/src/graph/FocusedEventGraph.tsx +1 -1
- package/src/graph/GraphToolbar.tsx +2 -4
- package/src/index.css +220 -2
- package/src/landing/DraggableReveal.tsx +168 -0
- package/src/landing/EstateGraph.tsx +28 -0
- package/src/landing/FlowPlayback.tsx +282 -0
- package/src/landing/HeroMap.tsx +128 -0
- package/src/landing/LandingPage.tsx +757 -0
- package/src/landing/ProductFrame.tsx +68 -0
- package/src/landing/ProductTour.tsx +371 -0
- package/src/landing/catalog.ts +25 -0
- package/src/landing/motion.tsx +52 -0
- package/src/lib/all-problems.ts +28 -0
- package/src/lib/local-api.ts +35 -1
- package/src/lib/setup-info.test.ts +8 -0
- package/src/lib/setup-info.ts +3 -2
- package/src/lib/source-code.ts +2 -1
- package/src/likec4/C4View.tsx +5 -0
- package/src/likec4/InteractiveView.tsx +5 -1
- package/src/map/ContextMapGraph.tsx +47 -20
- package/src/pages/ContextMap.tsx +5 -1
- package/src/pages/FlowDetail.tsx +24 -7
- package/src/pages/Overview.tsx +68 -12
- package/src/pages/Problems.tsx +6 -193
- package/src/pages/Settings.tsx +133 -108
- package/src/pages/settings/DeliverySettings.tsx +229 -0
- package/src/pages/settings/PreferencesSettings.tsx +101 -0
- package/src/routes.test.ts +20 -0
- package/src/routes.ts +13 -1
- package/vite.config.ts +17 -9
- package/catalog/enum_test.go +0 -46
- package/catalog/model.go +0 -932
- package/catalog/roundtrip_test.go +0 -185
- package/catalog/via_test.go +0 -38
- package/go.mod +0 -14
- package/go.sum +0 -14
- package/internal/commands/cargo.go +0 -154
- package/internal/commands/commands.go +0 -143
- package/internal/commands/commands_test.go +0 -323
- package/internal/commands/gradle.go +0 -77
- package/internal/commands/justfile.go +0 -82
- package/internal/commands/makefile.go +0 -106
- package/internal/commands/maven.go +0 -93
- package/internal/commands/packagejson.go +0 -159
- package/internal/commands/pyproject.go +0 -169
- package/internal/commands/taskfile.go +0 -101
- package/internal/commands/testdata/estate/.cargo/config.toml +0 -7
- package/internal/commands/testdata/estate/Makefile +0 -33
- package/internal/commands/testdata/estate/Taskfile.yml +0 -21
- package/internal/commands/testdata/estate/build.gradle.kts +0 -21
- package/internal/commands/testdata/estate/justfile +0 -20
- package/internal/commands/testdata/estate/package.json +0 -13
- package/internal/commands/testdata/estate/pom.xml +0 -29
- package/internal/commands/testdata/estate/pyproject.toml +0 -27
- package/internal/commands/testdata/estate/xtask/src/main.rs +0 -27
- package/internal/commands/testdata/golden/commands.json +0 -305
- package/internal/gohttp/analyze.go +0 -2500
- package/internal/gohttp/endpoints.go +0 -1067
- package/internal/gohttp/roots.go +0 -320
- package/internal/gohttp/typed.go +0 -143
- package/internal/goscan/constants.go +0 -85
- package/internal/goscan/goscan_test.go +0 -227
- package/internal/goscan/names.go +0 -52
- package/internal/goscan/parse_test.go +0 -11
- package/internal/goscan/source.go +0 -36
- package/internal/goscan/tree.go +0 -155
- package/internal/goscan/types.go +0 -99
- package/internal/wsdl/ids.go +0 -127
- package/internal/wsdl/ids_test.go +0 -21
- package/internal/wsdl/model.go +0 -62
- package/internal/wsdl/parse.go +0 -920
- package/internal/wsdl/parse_test.go +0 -133
- package/plugin/describe.go +0 -107
- package/plugin/describe_test.go +0 -114
- package/plugin/protocol.go +0 -117
- package/plugin/schematest/schematest.go +0 -126
- package/plugins/extract-adr/describe.go +0 -19
- package/plugins/extract-adr/describe_test.go +0 -11
- package/plugins/extract-adr/extract.go +0 -153
- package/plugins/extract-adr/extract_test.go +0 -350
- package/plugins/extract-adr/history.go +0 -99
- package/plugins/extract-adr/main.go +0 -65
- package/plugins/extract-adr/parse.go +0 -642
- package/plugins/extract-adr/parse_test.go +0 -405
- package/plugins/extract-asyncapi/describe.go +0 -19
- package/plugins/extract-asyncapi/describe_test.go +0 -11
- package/plugins/extract-asyncapi/extract.go +0 -315
- package/plugins/extract-asyncapi/extract_test.go +0 -197
- package/plugins/extract-asyncapi/main.go +0 -48
- package/plugins/extract-asyncapi/spec.go +0 -151
- package/plugins/extract-commands/describe.go +0 -19
- package/plugins/extract-commands/describe_test.go +0 -11
- package/plugins/extract-commands/extract.go +0 -79
- package/plugins/extract-commands/extract_test.go +0 -92
- package/plugins/extract-commands/main.go +0 -55
- package/plugins/extract-csr/avro.go +0 -258
- package/plugins/extract-csr/describe.go +0 -19
- package/plugins/extract-csr/describe_test.go +0 -11
- package/plugins/extract-csr/extract.go +0 -338
- package/plugins/extract-csr/extract_test.go +0 -374
- package/plugins/extract-csr/jsonschema.go +0 -343
- package/plugins/extract-csr/lock.go +0 -25
- package/plugins/extract-csr/main.go +0 -84
- package/plugins/extract-csr/subject.go +0 -102
- package/plugins/extract-flows/describe.go +0 -19
- package/plugins/extract-flows/describe_test.go +0 -11
- package/plugins/extract-flows/extract.go +0 -91
- package/plugins/extract-flows/main.go +0 -45
- package/plugins/extract-flows/parse.go +0 -593
- package/plugins/extract-flows/parse_test.go +0 -204
- package/plugins/extract-glossary/describe.go +0 -19
- package/plugins/extract-glossary/describe_test.go +0 -11
- package/plugins/extract-glossary/extract.go +0 -115
- package/plugins/extract-glossary/extract_test.go +0 -220
- package/plugins/extract-glossary/main.go +0 -59
- package/plugins/extract-glossary/parse.go +0 -214
- package/plugins/extract-glossary/parse_test.go +0 -203
- package/plugins/extract-go/aggregate.go +0 -214
- package/plugins/extract-go/client.go +0 -409
- package/plugins/extract-go/client_test.go +0 -266
- package/plugins/extract-go/describe.go +0 -19
- package/plugins/extract-go/describe_test.go +0 -11
- package/plugins/extract-go/enum.go +0 -195
- package/plugins/extract-go/enum_test.go +0 -82
- package/plugins/extract-go/event.go +0 -99
- package/plugins/extract-go/extract.go +0 -191
- package/plugins/extract-go/extract_test.go +0 -261
- package/plugins/extract-go/flow.go +0 -1441
- package/plugins/extract-go/flow_test.go +0 -609
- package/plugins/extract-go/httpclient.go +0 -174
- package/plugins/extract-go/httpclient_test.go +0 -296
- package/plugins/extract-go/ids.go +0 -92
- package/plugins/extract-go/layout.go +0 -225
- package/plugins/extract-go/layout_test.go +0 -125
- package/plugins/extract-go/lifecycle.go +0 -324
- package/plugins/extract-go/lifecycle_test.go +0 -108
- package/plugins/extract-go/main.go +0 -79
- package/plugins/extract-go/operation.go +0 -157
- package/plugins/extract-go/source.go +0 -316
- package/plugins/extract-go/transport.go +0 -321
- package/plugins/extract-go/transport_test.go +0 -145
- package/plugins/extract-go/wiring.go +0 -434
- package/plugins/extract-go-nats/describe.go +0 -19
- package/plugins/extract-go-nats/describe_test.go +0 -11
- package/plugins/extract-go-nats/extract.go +0 -177
- package/plugins/extract-go-nats/extract_test.go +0 -389
- package/plugins/extract-go-nats/index.go +0 -379
- package/plugins/extract-go-nats/main.go +0 -42
- package/plugins/extract-go-nats/resolve.go +0 -161
- package/plugins/extract-go-nats/sites.go +0 -224
- package/plugins/extract-graphql/describe.go +0 -19
- package/plugins/extract-graphql/describe_test.go +0 -11
- package/plugins/extract-graphql/extract.go +0 -433
- package/plugins/extract-graphql/extract_test.go +0 -256
- package/plugins/extract-graphql/ids.go +0 -49
- package/plugins/extract-graphql/lex.go +0 -237
- package/plugins/extract-graphql/main.go +0 -51
- package/plugins/extract-graphql/parse.go +0 -621
- package/plugins/extract-graphql/parse_test.go +0 -122
- package/plugins/extract-http-clients/describe.go +0 -19
- package/plugins/extract-http-clients/describe_test.go +0 -11
- package/plugins/extract-http-clients/extract.go +0 -705
- package/plugins/extract-http-clients/extract_test.go +0 -1263
- package/plugins/extract-http-clients/main.go +0 -42
- package/plugins/extract-openapi/describe.go +0 -19
- package/plugins/extract-openapi/describe_test.go +0 -11
- package/plugins/extract-openapi/discover.go +0 -243
- package/plugins/extract-openapi/extract.go +0 -526
- package/plugins/extract-openapi/extract_test.go +0 -545
- package/plugins/extract-openapi/main.go +0 -75
- package/plugins/extract-openapi/spec.go +0 -350
- package/plugins/extract-project/describe.go +0 -19
- package/plugins/extract-project/describe_test.go +0 -11
- package/plugins/extract-project/extract.go +0 -221
- package/plugins/extract-project/extract_test.go +0 -109
- package/plugins/extract-project/main.go +0 -41
- package/plugins/extract-proto/ast.go +0 -125
- package/plugins/extract-proto/consumes.go +0 -77
- package/plugins/extract-proto/describe.go +0 -19
- package/plugins/extract-proto/extract.go +0 -293
- package/plugins/extract-proto/extract_test.go +0 -459
- package/plugins/extract-proto/ids.go +0 -89
- package/plugins/extract-proto/ids_test.go +0 -57
- package/plugins/extract-proto/lex.go +0 -285
- package/plugins/extract-proto/main.go +0 -100
- package/plugins/extract-proto/module.go +0 -120
- package/plugins/extract-proto/parse.go +0 -720
- package/plugins/extract-proto/parse_test.go +0 -307
- package/plugins/extract-proto/provides.go +0 -236
- package/plugins/extract-proto/resolve.go +0 -222
- package/plugins/extract-proto/resolve_test.go +0 -119
- package/plugins/extract-redis/describe.go +0 -19
- package/plugins/extract-redis/describe_test.go +0 -11
- package/plugins/extract-redis/extract.go +0 -183
- package/plugins/extract-redis/extract_test.go +0 -168
- package/plugins/extract-redis/keyspaces.go +0 -469
- package/plugins/extract-redis/main.go +0 -44
- package/plugins/extract-river/describe.go +0 -19
- package/plugins/extract-river/describe_test.go +0 -11
- package/plugins/extract-river/extract.go +0 -507
- package/plugins/extract-river/extract_test.go +0 -132
- package/plugins/extract-river/main.go +0 -42
- package/plugins/extract-sql/ddl.go +0 -893
- package/plugins/extract-sql/ddl_test.go +0 -401
- package/plugins/extract-sql/describe.go +0 -19
- package/plugins/extract-sql/describe_test.go +0 -11
- package/plugins/extract-sql/layout.go +0 -221
- package/plugins/extract-sql/layout_test.go +0 -55
- package/plugins/extract-sql/lineage.go +0 -107
- package/plugins/extract-sql/main.go +0 -141
- package/plugins/extract-sql/maps.go +0 -564
- package/plugins/extract-sql/maps_java.go +0 -117
- package/plugins/extract-sql/maps_rust.go +0 -333
- package/plugins/extract-sql/maps_rust_test.go +0 -70
- package/plugins/extract-sql/maps_test.go +0 -204
- package/plugins/extract-sql/maps_ts.go +0 -398
- package/plugins/extract-sql/maps_ts_test.go +0 -136
- package/plugins/extract-sql/projection.go +0 -70
- package/plugins/extract-sql/projection_test.go +0 -50
- package/plugins/extract-sql/store.go +0 -420
- package/plugins/extract-sql/store_test.go +0 -233
- package/plugins/extract-sql/view.go +0 -295
- package/plugins/extract-watermill/describe.go +0 -19
- package/plugins/extract-watermill/describe_test.go +0 -11
- package/plugins/extract-watermill/extract.go +0 -1228
- package/plugins/extract-watermill/extract_test.go +0 -234
- package/plugins/extract-watermill/main.go +0 -41
- package/plugins/extract-wsdl/describe.go +0 -19
- package/plugins/extract-wsdl/describe_test.go +0 -11
- package/plugins/extract-wsdl/extract.go +0 -148
- package/plugins/extract-wsdl/extract_test.go +0 -45
- package/plugins/extract-wsdl/main.go +0 -53
- package/plugins/fetch-bsr/auth.go +0 -114
- package/plugins/fetch-bsr/bsr.go +0 -240
- package/plugins/fetch-bsr/cache.go +0 -66
- package/plugins/fetch-bsr/describe.go +0 -19
- package/plugins/fetch-bsr/fetch.go +0 -192
- package/plugins/fetch-bsr/fetch_test.go +0 -465
- package/plugins/fetch-bsr/lock.go +0 -71
- package/plugins/fetch-bsr/main.go +0 -117
- package/plugins/fetch-csr/auth.go +0 -95
- package/plugins/fetch-csr/cache.go +0 -69
- package/plugins/fetch-csr/describe.go +0 -19
- package/plugins/fetch-csr/describe_test.go +0 -11
- package/plugins/fetch-csr/fetch.go +0 -254
- package/plugins/fetch-csr/fetch_test.go +0 -494
- package/plugins/fetch-csr/lock.go +0 -95
- package/plugins/fetch-csr/main.go +0 -122
- package/plugins/fetch-csr/registry.go +0 -209
- package/plugins/fetch-git/cache.go +0 -65
- package/plugins/fetch-git/describe.go +0 -19
- package/plugins/fetch-git/describe_test.go +0 -11
- package/plugins/fetch-git/fetch.go +0 -181
- package/plugins/fetch-git/fetch_test.go +0 -332
- package/plugins/fetch-git/git.go +0 -169
- package/plugins/fetch-git/lock.go +0 -72
- package/plugins/fetch-git/main.go +0 -127
- package/plugins/fetch-git/offline.go +0 -39
- package/plugins/fetch-git/pin.go +0 -90
- package/plugins/fetch-git/pin_test.go +0 -74
- package/plugins/gen-backstage/describe.go +0 -17
- package/plugins/gen-backstage/main.go +0 -22
- package/plugins/gen-backstage/plugin.go +0 -473
- package/plugins/gen-backstage/plugin_test.go +0 -145
- package/plugins/gen-backstage.wasm +0 -0
- package/plugins/gen-markdown/adr.go +0 -162
- package/plugins/gen-markdown/aggregate.go +0 -362
- package/plugins/gen-markdown/canonical.go +0 -93
- package/plugins/gen-markdown/context.go +0 -90
- package/plugins/gen-markdown/coverage_test.go +0 -89
- package/plugins/gen-markdown/describe.go +0 -19
- package/plugins/gen-markdown/describe_test.go +0 -11
- package/plugins/gen-markdown/external.go +0 -71
- package/plugins/gen-markdown/flow.go +0 -277
- package/plugins/gen-markdown/glossary.go +0 -76
- package/plugins/gen-markdown/glossary_test.go +0 -148
- package/plugins/gen-markdown/llms.go +0 -302
- package/plugins/gen-markdown/main.go +0 -22
- package/plugins/gen-markdown/markdown.go +0 -254
- package/plugins/gen-markdown/markdown_test.go +0 -100
- package/plugins/gen-markdown/module.go +0 -107
- package/plugins/gen-markdown/plugin.go +0 -39
- package/plugins/gen-markdown/quality_test.go +0 -176
- package/plugins/gen-markdown/redis_test.go +0 -38
- package/plugins/gen-markdown/render.go +0 -344
- package/plugins/gen-markdown/render_test.go +0 -186
- package/plugins/gen-markdown/service.go +0 -456
- package/plugins/gen-markdown/source.go +0 -177
- package/plugins/gen-markdown/store.go +0 -201
- package/plugins/gen-markdown.wasm +0 -0
- package/plugins/gen-mermaid/describe.go +0 -17
- package/plugins/gen-mermaid/main.go +0 -22
- package/plugins/gen-mermaid/plugin.go +0 -104
- package/plugins/gen-mermaid/plugin_test.go +0 -33
- package/plugins/gen-mermaid.wasm +0 -0
- package/plugins/openapi/ids.go +0 -261
- package/plugins/openapi/ids_test.go +0 -98
- package/plugins/verify-codeowners/describe.go +0 -19
- package/plugins/verify-codeowners/describe_test.go +0 -11
- package/plugins/verify-codeowners/main.go +0 -75
- package/plugins/verify-codeowners/match.go +0 -85
- package/plugins/verify-codeowners/match_test.go +0 -47
- package/plugins/verify-codeowners/owners.go +0 -164
- package/plugins/verify-codeowners/owners_test.go +0 -225
- package/plugins/verify-codeowners/parse.go +0 -90
- package/plugins/verify-codeowners/parse_test.go +0 -62
- package/plugins/verify-otel/describe.go +0 -19
- package/plugins/verify-otel/describe_test.go +0 -11
- package/plugins/verify-otel/main.go +0 -53
- package/plugins/verify-otel/match.go +0 -336
- package/plugins/verify-otel/otlp.go +0 -200
- package/plugins/verify-otel/verify.go +0 -734
- package/plugins/verify-otel/verify_test.go +0 -460
- /package/{plugins/fetch-csr/options.schema.json → scripts/host-plugins/fetch-csr.options.json} +0 -0
- /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
|
-
}
|