@shortlink-org/portolan 0.2.4 → 0.3.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.
- package/README.md +23 -0
- package/catalog/enum_test.go +46 -0
- package/catalog/evidence_test.go +35 -0
- package/catalog/model.go +1066 -0
- package/catalog/roundtrip_test.go +203 -0
- package/catalog/via_test.go +38 -0
- package/cli/init.test.mjs +6 -1
- package/cli/portolan.mjs +8 -0
- package/cli/portolan.test.mjs +49 -0
- package/go.mod +14 -0
- package/go.sum +20 -0
- package/internal/gocall/README.md +19 -0
- package/internal/gocall/analyze.go +189 -0
- package/internal/gocall/analyze_test.go +107 -0
- package/internal/gohttp/analyze.go +2562 -0
- package/internal/gohttp/destination.go +373 -0
- package/internal/gohttp/endpoints.go +1067 -0
- package/internal/gohttp/roots.go +320 -0
- package/internal/gohttp/typed.go +96 -0
- package/internal/goscan/constants.go +85 -0
- package/internal/goscan/goscan_test.go +227 -0
- package/internal/goscan/index.go +629 -0
- package/internal/goscan/index_test.go +66 -0
- package/internal/goscan/names.go +52 -0
- package/internal/goscan/parse_test.go +11 -0
- package/internal/goscan/source.go +37 -0
- package/internal/goscan/tree.go +284 -0
- package/internal/goscan/types.go +99 -0
- package/internal/wsdl/ids.go +127 -0
- package/internal/wsdl/ids_test.go +21 -0
- package/internal/wsdl/model.go +70 -0
- package/internal/wsdl/parse.go +949 -0
- package/internal/wsdl/parse_test.go +170 -0
- package/package.json +22 -10
- package/plugin/describe.go +118 -0
- package/plugin/describe_test.go +114 -0
- package/plugin/protocol.go +141 -0
- package/plugin/schematest/schematest.go +126 -0
- package/plugins/README.md +109 -46
- package/plugins/cmd/portolan-http-clients/main.go +19 -0
- package/plugins/extract-celery/extract.py +0 -2
- package/plugins/extract-celery/extract_test.py +1 -1
- package/plugins/extract-django/README.md +39 -17
- package/plugins/extract-django/domain.py +28 -17
- package/plugins/extract-django/extract.py +21 -7
- package/plugins/extract-django/extract_test.py +55 -2
- package/plugins/extract-django/lifecycle.py +2 -0
- package/plugins/extract-django/operations.py +1 -1
- package/plugins/extract-django/routing_test.py +109 -1
- package/plugins/extract-django/store.py +1 -1
- package/plugins/extract-django/transport.py +101 -55
- package/plugins/extract-django/verbs.py +241 -0
- package/plugins/extract-go/README.md +47 -0
- package/plugins/extract-http-clients/describe.go +19 -0
- package/plugins/extract-http-clients/describe_test.go +11 -0
- package/plugins/extract-http-clients/extract.go +740 -0
- package/plugins/extract-http-clients/extract_test.go +1561 -0
- package/plugins/extract-http-clients/main.go +41 -0
- package/plugins/extract-java/build/org/portolan/extract/Extract.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Builder.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Input.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Options.class +0 -0
- package/plugins/extract-python-kafka/extract.py +0 -2
- package/plugins/extract-python-kafka/extract_test.py +1 -1
- package/plugins/extract-ts/extract.test.ts +2 -2
- package/plugins/extract-ts/extract.ts +4 -5
- package/plugins/extract-ts/graphql.test.ts +1 -1
- package/plugins/openapi/ids.go +261 -0
- package/plugins/openapi/ids_test.go +98 -0
- package/plugins/portolan-go.wasm +0 -0
- package/plugins/pyplugin/protocol.py +1 -5
- package/portolan.json +3 -2
- package/schema/portolan.schema.json +34 -0
- package/scripts/README.md +18 -12
- package/scripts/catalog-sources.mjs +6 -0
- package/scripts/delivery-presets.mjs +21 -11
- package/scripts/diff.mjs +5 -1
- package/scripts/django-aggregates.test.mjs +58 -0
- package/scripts/gen-likec4.mjs +1 -1
- package/scripts/gen.mjs +118 -115
- package/scripts/go-discovery.test.mjs +30 -0
- package/scripts/history.mjs +186 -3
- package/scripts/history.test.mjs +1 -1
- package/scripts/host-plugins/fetch-git.mjs +77 -21
- package/scripts/host-plugins/fetch-git.test.mjs +62 -8
- package/scripts/local-api.mjs +71 -4
- package/scripts/local-api.test.mjs +63 -4
- package/scripts/local-discovery.mjs +82 -9
- package/scripts/manifest.mjs +5 -3
- package/scripts/manifest.test.mjs +24 -0
- package/scripts/output-diff.mjs +94 -0
- package/scripts/output-diff.test.mjs +36 -0
- package/scripts/package-smoke.mjs +62 -4
- package/scripts/plugin-host.mjs +22 -2
- package/scripts/plugin-host.test.mjs +9 -0
- package/scripts/plugin-wasm-worker.mjs +4 -1
- package/scripts/provenance.mjs +72 -0
- package/scripts/provenance.test.mjs +149 -0
- package/scripts/run-builtin.mjs +39 -5
- package/scripts/schema.mjs +29 -0
- package/scripts/warning-policy.mjs +161 -0
- package/scripts/warning-policy.test.mjs +56 -0
- package/src/app/Sidebar.tsx +3 -3
- package/src/catalog-docs.test.ts +64 -0
- package/src/catalog-docs.ts +35 -0
- package/src/catalog-error.test.ts +15 -0
- package/src/catalog-model.ts +48 -5
- package/src/catalog-validation.ts +9 -0
- package/src/chat/Starter.tsx +5 -11
- package/src/chat/tools.test.ts +27 -0
- package/src/chat/tools.ts +5 -9
- package/src/components/CatalogStamp.tsx +10 -8
- package/src/components/HTTPDestinationEvidence.test.tsx +23 -0
- package/src/components/HTTPDestinationEvidence.tsx +31 -0
- package/src/components/Integrations.tsx +1 -1
- package/src/components/MachineDocs.tsx +6 -5
- package/src/components/MethodRows.tsx +9 -2
- package/src/components/RelationEvidence.test.tsx +14 -0
- package/src/components/RelationEvidence.tsx +53 -0
- package/src/data.ts +25 -7
- package/src/enrich.test.ts +332 -1
- package/src/enrich.ts +206 -3
- package/src/flow/StepDetail.tsx +6 -0
- package/src/flow/evidence.test.ts +16 -0
- package/src/flow/evidence.ts +34 -0
- package/src/index.css +44 -0
- package/src/landing/DraggableReveal.tsx +3 -2
- package/src/landing/EvidencePipeline.tsx +105 -0
- package/src/landing/LandingPage.tsx +2 -59
- package/src/lib/catalog-diff.ts +1 -1
- package/src/lib/django-aggregates.d.mts +9 -0
- package/src/lib/django-aggregates.mjs +36 -0
- package/src/lib/django-aggregates.test.ts +29 -0
- package/src/lib/django-aggregates.ts +5 -0
- package/src/lib/local-api.ts +20 -2
- package/src/lib/setup-info.test.ts +17 -0
- package/src/lib/setup-info.ts +58 -0
- package/src/lib/warnings.test.ts +54 -0
- package/src/lib/warnings.ts +260 -0
- package/src/map/ContextMapGraph.tsx +76 -32
- package/src/merge.ts +16 -9
- package/src/pages/AggregatePage.tsx +8 -7
- package/src/pages/ContextPage.tsx +6 -5
- package/src/pages/ServicePage.tsx +4 -3
- package/src/pages/Settings.tsx +189 -41
- package/src/pages/settings/DjangoAggregateChoices.tsx +79 -0
- package/src/selection/DetailPanel.tsx +15 -0
- package/src/virtual-provenance.d.ts +11 -0
- package/vite.config.ts +5 -0
- package/scripts/vendor-lock.mjs +0 -58
- package/scripts/vendor-lock.test.mjs +0 -69
package/catalog/model.go
ADDED
|
@@ -0,0 +1,1066 @@
|
|
|
1
|
+
// Package catalog is the Go side of the contract in src/catalog.ts.
|
|
2
|
+
//
|
|
3
|
+
// It is a MIRROR, not a second definition (portolan.0003). The TypeScript file is where the
|
|
4
|
+
// shape is decided and where the prose explaining each decision lives; this
|
|
5
|
+
// package exists so a plugin written in Go can read a catalog without
|
|
6
|
+
// reinventing it, and it is held to the original by a round-trip test rather
|
|
7
|
+
// than by anyone remembering to update both.
|
|
8
|
+
//
|
|
9
|
+
// Nothing here validates. A plugin receives a catalog that the host has
|
|
10
|
+
// already validated, and a second opinion in a second language is how the two
|
|
11
|
+
// drift apart.
|
|
12
|
+
package catalog
|
|
13
|
+
|
|
14
|
+
import (
|
|
15
|
+
"encoding/json"
|
|
16
|
+
"fmt"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
type Status string
|
|
20
|
+
|
|
21
|
+
const (
|
|
22
|
+
StatusVerified Status = "verified"
|
|
23
|
+
StatusDeclared Status = "declared"
|
|
24
|
+
StatusUnresolved Status = "unresolved"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
// Catalog is one source of facts. The estate a reader sees is the merge of
|
|
28
|
+
// several of these, so nothing in a plugin may assume it holds all of them.
|
|
29
|
+
type Catalog struct {
|
|
30
|
+
// The stamp the HOST writes, from the last commit that touched the input
|
|
31
|
+
// this source was read from - never a plugin, which would have to read a
|
|
32
|
+
// clock and produce a different fragment on every run. Both are omitted
|
|
33
|
+
// when empty, because a source nobody generates carries no stamp at all
|
|
34
|
+
// and a mirror that wrote `"generatedAt": ""` would be inventing an answer
|
|
35
|
+
// to a question the file does not answer. The merge dates the estate from
|
|
36
|
+
// the sources that do carry one.
|
|
37
|
+
GeneratedAt string `json:"generatedAt,omitempty"`
|
|
38
|
+
Commit string `json:"commit,omitempty"`
|
|
39
|
+
Contexts []BoundedContext `json:"contexts"`
|
|
40
|
+
Defs map[string]TypeDef `json:"defs"`
|
|
41
|
+
Flows []Flow `json:"flows"`
|
|
42
|
+
Adrs []Adr `json:"adrs"`
|
|
43
|
+
Stores []Store `json:"stores,omitempty"`
|
|
44
|
+
Modules []ProtoModule `json:"modules,omitempty"`
|
|
45
|
+
Terms []Term `json:"terms,omitempty"`
|
|
46
|
+
Repos []RepoPin `json:"repos,omitempty"`
|
|
47
|
+
Externals []External `json:"externals,omitempty"`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// External is a system outside the estate with a contract: what it answers on,
|
|
51
|
+
// read from the copy of its document vendored beside the adapter that calls it,
|
|
52
|
+
// and nothing else. It sits at the root beside the contexts, so its id is its
|
|
53
|
+
// slug and carries no dot.
|
|
54
|
+
type External struct {
|
|
55
|
+
ID string `json:"id"`
|
|
56
|
+
Slug string `json:"slug"`
|
|
57
|
+
Name string `json:"name"`
|
|
58
|
+
Summary string `json:"summary"`
|
|
59
|
+
URL string `json:"url,omitempty"`
|
|
60
|
+
Provides []RpcService `json:"provides"`
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// RepoPin is a repository the estate was read at, and the commit it was read
|
|
64
|
+
// at, so a source path in another repository can still be a link.
|
|
65
|
+
//
|
|
66
|
+
// A list on the catalog rather than a field on Service: the pin is a fact
|
|
67
|
+
// about the estate, and a repository holding three services is fetched once.
|
|
68
|
+
type RepoPin struct {
|
|
69
|
+
// Repo is spelled the way Service.Repo spells it: "github.com/acme/shop".
|
|
70
|
+
Repo string `json:"repo"`
|
|
71
|
+
|
|
72
|
+
// Commit is the full sha. Nothing resolves it locally, so there is
|
|
73
|
+
// nothing a short one could be expanded against.
|
|
74
|
+
Commit string `json:"commit"`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
type Classification string
|
|
78
|
+
|
|
79
|
+
const (
|
|
80
|
+
ClassificationCore Classification = "core"
|
|
81
|
+
ClassificationSupporting Classification = "supporting"
|
|
82
|
+
ClassificationGeneric Classification = "generic"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
// How a context is read. The keys stay `contexts` and `services` (portolan.0004).
|
|
86
|
+
type GroupKind string
|
|
87
|
+
|
|
88
|
+
const (
|
|
89
|
+
GroupKindBoundedContext GroupKind = "bounded-context"
|
|
90
|
+
GroupKindSystem GroupKind = "system"
|
|
91
|
+
GroupKindProduct GroupKind = "product"
|
|
92
|
+
GroupKindTeam GroupKind = "team"
|
|
93
|
+
GroupKindNamespace GroupKind = "namespace"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
type BoundedContext struct {
|
|
97
|
+
ID string `json:"id"`
|
|
98
|
+
Slug string `json:"slug"`
|
|
99
|
+
Name string `json:"name"`
|
|
100
|
+
Summary string `json:"summary"`
|
|
101
|
+
Kind GroupKind `json:"kind,omitempty"`
|
|
102
|
+
Classification Classification `json:"classification,omitempty"`
|
|
103
|
+
ViewID string `json:"viewId,omitempty"`
|
|
104
|
+
Services []Service `json:"services"`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type ComponentKind string
|
|
108
|
+
|
|
109
|
+
const (
|
|
110
|
+
ComponentKindService ComponentKind = "service"
|
|
111
|
+
ComponentKindApplication ComponentKind = "application"
|
|
112
|
+
ComponentKindWebapp ComponentKind = "webapp"
|
|
113
|
+
ComponentKindWorker ComponentKind = "worker"
|
|
114
|
+
ComponentKindJob ComponentKind = "job"
|
|
115
|
+
ComponentKindFunction ComponentKind = "function"
|
|
116
|
+
ComponentKindCLI ComponentKind = "cli"
|
|
117
|
+
ComponentKindLibrary ComponentKind = "library"
|
|
118
|
+
ComponentKindDataPipeline ComponentKind = "data-pipeline"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
type Service struct {
|
|
122
|
+
ID string `json:"id"`
|
|
123
|
+
Slug string `json:"slug"`
|
|
124
|
+
Name string `json:"name"`
|
|
125
|
+
Repo string `json:"repo"`
|
|
126
|
+
Path string `json:"path"`
|
|
127
|
+
Readme string `json:"readme"`
|
|
128
|
+
Kind ComponentKind `json:"kind,omitempty"`
|
|
129
|
+
Technologies []string `json:"technologies,omitempty"`
|
|
130
|
+
Provides []RpcService `json:"provides"`
|
|
131
|
+
Consumes []RpcCall `json:"consumes"`
|
|
132
|
+
// Copies are interfaces read from vendored proto modules. They are kept
|
|
133
|
+
// apart from Provides because this service calls rather than implements
|
|
134
|
+
// them, but retain the shapes needed to compare the copy with its publisher.
|
|
135
|
+
Copies []RpcService `json:"copies,omitempty"`
|
|
136
|
+
Aggregates []Aggregate `json:"aggregates"`
|
|
137
|
+
// Stores this service touches, by id. Ownership is not stated here - a
|
|
138
|
+
// store names its own owner, so an id in this list that the store does not
|
|
139
|
+
// call its owner is a read.
|
|
140
|
+
Stores []string `json:"stores,omitempty"`
|
|
141
|
+
|
|
142
|
+
// Modules this service publishes or vendors, by id. Same rule as Stores: a
|
|
143
|
+
// module names its own owner, so an id here that does not call this service
|
|
144
|
+
// its owner is one the service reads.
|
|
145
|
+
Modules []string `json:"modules,omitempty"`
|
|
146
|
+
|
|
147
|
+
// Channels this service declares it publishes on or listens to, read out of
|
|
148
|
+
// an AsyncAPI document. Absent for a service that has no such document,
|
|
149
|
+
// which is not the same as a service that speaks to nobody.
|
|
150
|
+
Channels []Channel `json:"channels,omitempty"`
|
|
151
|
+
|
|
152
|
+
// Owners is who to ask about it, as CODEOWNERS spells them. Handles and
|
|
153
|
+
// nothing more: resolving one to people is a call to a forge, and the
|
|
154
|
+
// handle is what a reviewer types anyway.
|
|
155
|
+
Owners []string `json:"owners,omitempty"`
|
|
156
|
+
|
|
157
|
+
// Commands are what a developer types against the checkout - the make
|
|
158
|
+
// targets, npm scripts, just recipes and task-runner tasks the repository
|
|
159
|
+
// declares. Read from the runner files, never from the README, so the
|
|
160
|
+
// list is the one the runner would accept. Absent when nothing declares
|
|
161
|
+
// any, which is not the same as a service that cannot be built.
|
|
162
|
+
Commands []Command `json:"commands,omitempty"`
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Command is one entry of a task runner's file: a make target, an npm script,
|
|
166
|
+
// a just recipe, a Taskfile task, a poe or pdm task.
|
|
167
|
+
//
|
|
168
|
+
// Run is the whole point - the line a reader copies - and it is spelled here
|
|
169
|
+
// rather than rebuilt from Runner and Name, because `npm test` and
|
|
170
|
+
// `npm run typecheck` are two spellings of one runner and the page should not
|
|
171
|
+
// have to know which scripts npm treats specially.
|
|
172
|
+
type Command struct {
|
|
173
|
+
// Runner is the tool the line is typed at: make, npm, pnpm, yarn, bun,
|
|
174
|
+
// just, task, poe, pdm.
|
|
175
|
+
Runner string `json:"runner"`
|
|
176
|
+
// Name is the target, script, recipe or task as its file spells it.
|
|
177
|
+
Name string `json:"name"`
|
|
178
|
+
// Run is the line to type at a shell in the service's directory.
|
|
179
|
+
Run string `json:"run"`
|
|
180
|
+
// Doc is what the file says the command is for, when it says anything: a
|
|
181
|
+
// `## comment` on a make target, a `#` line over a just recipe, a task's
|
|
182
|
+
// `desc`, a poe task's `help`. Most files say nothing.
|
|
183
|
+
Doc string `json:"doc,omitempty"`
|
|
184
|
+
// Body is what the runner executes for it: the recipe, the script line,
|
|
185
|
+
// the cmds. Carried so a name that says nothing can still be read, and
|
|
186
|
+
// shown folded, because a build script is not a sentence.
|
|
187
|
+
Body string `json:"body,omitempty"`
|
|
188
|
+
// Source is the file and line the entry was read at.
|
|
189
|
+
Source string `json:"source,omitempty"`
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
type RpcService struct {
|
|
193
|
+
ID string `json:"id"`
|
|
194
|
+
Methods []RpcMethod `json:"methods"`
|
|
195
|
+
Source string `json:"source"`
|
|
196
|
+
Messages []RpcMessage `json:"messages,omitempty"`
|
|
197
|
+
// Enums are the closed sets the messages' fields take values from, reached
|
|
198
|
+
// the way Messages are: from the methods, through the fields, as far as
|
|
199
|
+
// the protos read here declare them.
|
|
200
|
+
Enums []RpcEnum `json:"enums,omitempty"`
|
|
201
|
+
|
|
202
|
+
// Module is the schema module declaring this interface, by ProtoModule.ID.
|
|
203
|
+
Module string `json:"module,omitempty"`
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// RpcEnum is an enum a message field names, as the interface's document
|
|
207
|
+
// declares it. Values carry their wire number because a proto consumer sees
|
|
208
|
+
// the number, not the name, in a binary message.
|
|
209
|
+
type RpcEnum struct {
|
|
210
|
+
Name string `json:"name"`
|
|
211
|
+
Doc string `json:"doc,omitempty"`
|
|
212
|
+
Values []RpcEnumValue `json:"values"`
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
type RpcEnumValue struct {
|
|
216
|
+
Name string `json:"name"`
|
|
217
|
+
Number int `json:"number"`
|
|
218
|
+
Doc string `json:"doc,omitempty"`
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// RpcMethod is one method of one interface.
|
|
222
|
+
//
|
|
223
|
+
// A string would have done for the name, and did until protos were read. What
|
|
224
|
+
// a string could not carry is the shapes on either side: an endpoint whose
|
|
225
|
+
// request and response are named is one a reader can follow without opening
|
|
226
|
+
// the source, and a streaming method drawn as a unary call is a lie about how
|
|
227
|
+
// the two ends are coupled.
|
|
228
|
+
//
|
|
229
|
+
// Only Name is required. An interface read from an OpenAPI document supplies
|
|
230
|
+
// nothing else, and must keep reading the way it always did.
|
|
231
|
+
type RpcMethod struct {
|
|
232
|
+
// Name is what the interface declares - a proto method, an OpenAPI
|
|
233
|
+
// operationId. This is what Operation.ExposedBy names.
|
|
234
|
+
Name string `json:"name"`
|
|
235
|
+
Doc string `json:"doc,omitempty"`
|
|
236
|
+
|
|
237
|
+
// Request and Response name messages in RpcService.Messages; the Ref forms
|
|
238
|
+
// key Catalog.Defs when the shape is shared. The same pairing, for the same
|
|
239
|
+
// reason, as Field.Type and Field.Ref.
|
|
240
|
+
Request string `json:"request,omitempty"`
|
|
241
|
+
RequestRef string `json:"requestRef,omitempty"`
|
|
242
|
+
Response string `json:"response,omitempty"`
|
|
243
|
+
ResponseRef string `json:"responseRef,omitempty"`
|
|
244
|
+
|
|
245
|
+
// Streaming is empty for a unary method, which is most of them.
|
|
246
|
+
Streaming Streaming `json:"streaming,omitempty"`
|
|
247
|
+
Deprecated bool `json:"deprecated,omitempty"`
|
|
248
|
+
|
|
249
|
+
// HTTP is the route, for a method read from an OpenAPI document. It is
|
|
250
|
+
// what lets a request seen on the wire be read back to the operation.
|
|
251
|
+
HTTP *HttpRoute `json:"http,omitempty"`
|
|
252
|
+
|
|
253
|
+
// SOAP is the concrete binding of a WSDL operation. Unlike Doc, these
|
|
254
|
+
// fields participate in comparison and let renderers present the contract
|
|
255
|
+
// without reparsing the source document.
|
|
256
|
+
SOAP *SoapRoute `json:"soap,omitempty"`
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
type HttpRoute struct {
|
|
260
|
+
// Method is upper case: POST. It is empty when a framework extractor
|
|
261
|
+
// proved the mount but no declaration proved the verb (extract-django's
|
|
262
|
+
// `Planet.fetch`); such a route is never matched against an outbound
|
|
263
|
+
// call, and a renderer shows the path alone.
|
|
264
|
+
Method string `json:"method"`
|
|
265
|
+
// Path is the template as the document writes it: /v1/users/{id}.
|
|
266
|
+
Path string `json:"path"`
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// SoapRoute is the wire-level part of one WSDL operation. Request, response
|
|
270
|
+
// and fault shapes remain on RpcMethod/RpcService, beside their proto and
|
|
271
|
+
// OpenAPI equivalents.
|
|
272
|
+
type SoapRoute struct {
|
|
273
|
+
Action string `json:"action,omitempty"`
|
|
274
|
+
Version string `json:"version,omitempty"`
|
|
275
|
+
Style string `json:"style,omitempty"`
|
|
276
|
+
Endpoint string `json:"endpoint,omitempty"`
|
|
277
|
+
Binding string `json:"binding,omitempty"`
|
|
278
|
+
Faults []string `json:"faults,omitempty"`
|
|
279
|
+
Headers []string `json:"headers,omitempty"`
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
type Streaming string
|
|
283
|
+
|
|
284
|
+
const (
|
|
285
|
+
StreamingClient Streaming = "client"
|
|
286
|
+
StreamingServer Streaming = "server"
|
|
287
|
+
StreamingBidi Streaming = "bidi"
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
type RpcMessage struct {
|
|
291
|
+
Name string `json:"name"`
|
|
292
|
+
Fields []Field `json:"fields"`
|
|
293
|
+
Discriminator *RpcDiscriminator `json:"discriminator,omitempty"`
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// RpcDiscriminator explains how a polymorphic OpenAPI message selects its
|
|
297
|
+
// concrete shape on the wire.
|
|
298
|
+
type RpcDiscriminator struct {
|
|
299
|
+
Property string `json:"property"`
|
|
300
|
+
Variants []RpcVariant `json:"variants"`
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
type RpcVariant struct {
|
|
304
|
+
Value string `json:"value"`
|
|
305
|
+
Message string `json:"message"`
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
type HTTPDestination struct {
|
|
309
|
+
Transforms []HTTPDestinationJoin `json:"transforms,omitempty"`
|
|
310
|
+
CallSite string `json:"callSite"`
|
|
311
|
+
EndpointExpression string `json:"endpointExpression"`
|
|
312
|
+
Method string `json:"method"`
|
|
313
|
+
LocalPath string `json:"localPath,omitempty"`
|
|
314
|
+
BaseURL *HTTPBaseURL `json:"baseURL,omitempty"`
|
|
315
|
+
ServiceDiscoveryAlias string `json:"serviceDiscoveryAlias,omitempty"`
|
|
316
|
+
FullPath string `json:"fullPath,omitempty"`
|
|
317
|
+
Join *HTTPDestinationJoin `json:"join,omitempty"`
|
|
318
|
+
Resolution *HTTPDestinationResolution `json:"resolution,omitempty"`
|
|
319
|
+
}
|
|
320
|
+
type HTTPBaseURL struct {
|
|
321
|
+
Expression string `json:"expression"`
|
|
322
|
+
ConfigField string `json:"configField,omitempty"`
|
|
323
|
+
EnvironmentVariable string `json:"environmentVariable,omitempty"`
|
|
324
|
+
Value string `json:"value,omitempty"`
|
|
325
|
+
Kind string `json:"kind"`
|
|
326
|
+
Source string `json:"source"`
|
|
327
|
+
OptionSource string `json:"optionSource,omitempty"`
|
|
328
|
+
}
|
|
329
|
+
type HTTPDestinationJoin struct {
|
|
330
|
+
Expression string `json:"expression"`
|
|
331
|
+
Source string `json:"source"`
|
|
332
|
+
}
|
|
333
|
+
type HTTPDestinationResolution struct {
|
|
334
|
+
Basis string `json:"basis"`
|
|
335
|
+
Provider string `json:"provider"`
|
|
336
|
+
Route string `json:"route"`
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
type RpcCall struct {
|
|
340
|
+
Evidence []RelationEvidence `json:"evidence,omitempty"`
|
|
341
|
+
Destination *HTTPDestination `json:"destination,omitempty"`
|
|
342
|
+
ID string `json:"id"`
|
|
343
|
+
Peer string `json:"peer"`
|
|
344
|
+
Status Status `json:"status"`
|
|
345
|
+
Source string `json:"source"`
|
|
346
|
+
Note string `json:"note,omitempty"`
|
|
347
|
+
|
|
348
|
+
// Module is the module the vendored copy this call was read from belongs to.
|
|
349
|
+
Module string `json:"module,omitempty"`
|
|
350
|
+
|
|
351
|
+
// Via is set when the call was derived from a flow step rather than declared.
|
|
352
|
+
Via *EdgeVia `json:"via,omitempty"`
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// EdgeVia names the flow step a derived consumer or call was read from. A
|
|
356
|
+
// plugin never writes one: the host derives edges from flows after the merge,
|
|
357
|
+
// and this is how the generated output can say where an arrow came from.
|
|
358
|
+
type EdgeVia struct {
|
|
359
|
+
Flow string `json:"flow"`
|
|
360
|
+
Step string `json:"step"`
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ProtoModule is a schema module: a set of .proto files with a name, a version
|
|
364
|
+
// and a publisher - "buf.build/acme/shop".
|
|
365
|
+
//
|
|
366
|
+
// It sits at the top level rather than inside the service that publishes it,
|
|
367
|
+
// because the interesting fact about a module is usually who ELSE reads it.
|
|
368
|
+
//
|
|
369
|
+
// Its ID is the module's own registry-global name and NOT "<owner>.<slug>" the
|
|
370
|
+
// way a Store's is. A store is declared by exactly one source. A module is
|
|
371
|
+
// declared by several that do not know each other - the producer, and each
|
|
372
|
+
// consumer reading a vendored copy in another repository - and since the merge
|
|
373
|
+
// unions top-level entities BY ID, an owner-derived id would grow one module
|
|
374
|
+
// per consumer.
|
|
375
|
+
//
|
|
376
|
+
// What it carries is identity and inventory, not schema: the interfaces are
|
|
377
|
+
// found through RpcService.Module and the shapes live in RpcService.Messages.
|
|
378
|
+
type ProtoModule struct {
|
|
379
|
+
// ID is "buf.build/acme/shop", or "local:proto/shop" for a set never
|
|
380
|
+
// published to a registry.
|
|
381
|
+
ID string `json:"id"`
|
|
382
|
+
|
|
383
|
+
// Slug is unique across the catalog, and what the URL uses: "acme-shop".
|
|
384
|
+
Slug string `json:"slug"`
|
|
385
|
+
Name string `json:"name"`
|
|
386
|
+
|
|
387
|
+
// Registry is "buf.build", empty when the module was never published.
|
|
388
|
+
Registry string `json:"registry,omitempty"`
|
|
389
|
+
|
|
390
|
+
// Owner is the service that publishes it, when the estate knows. Empty is
|
|
391
|
+
// an honest answer rather than a defect: a module published by a team, or
|
|
392
|
+
// by a repository outside the estate, is the ordinary case.
|
|
393
|
+
Owner string `json:"owner,omitempty"`
|
|
394
|
+
|
|
395
|
+
Commit string `json:"commit,omitempty"`
|
|
396
|
+
Digest string `json:"digest,omitempty"`
|
|
397
|
+
|
|
398
|
+
Packages []string `json:"packages"`
|
|
399
|
+
Files []string `json:"files"`
|
|
400
|
+
Deps []string `json:"deps,omitempty"`
|
|
401
|
+
Source string `json:"source"`
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
type Aggregate struct {
|
|
405
|
+
ID string `json:"id"`
|
|
406
|
+
Slug string `json:"slug"`
|
|
407
|
+
Name string `json:"name"`
|
|
408
|
+
Readme string `json:"readme"`
|
|
409
|
+
// Kind is "model-group" for a source grouping without an aggregate boundary.
|
|
410
|
+
Kind string `json:"kind,omitempty"`
|
|
411
|
+
Root string `json:"root"`
|
|
412
|
+
Entities []Block `json:"entities"`
|
|
413
|
+
ValueObjects []Block `json:"valueObjects"`
|
|
414
|
+
Operations []Operation `json:"operations"`
|
|
415
|
+
Events []Event `json:"events"`
|
|
416
|
+
// Enums are the closed sets the aggregate's fields take values from. A
|
|
417
|
+
// list beside Entities and ValueObjects rather than a Block with values:
|
|
418
|
+
// an enum has no fields, and a consumer switches on it rather than reads
|
|
419
|
+
// it. Omitted when the source declares none.
|
|
420
|
+
Enums []Enum `json:"enums,omitempty"`
|
|
421
|
+
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Enum is a closed set of values a field can hold - a reason, a status, a
|
|
425
|
+
// code. What a consumer of an event switches on, and so what it has to be
|
|
426
|
+
// told: free text from a schema row says "reason: Reason", and this is what
|
|
427
|
+
// Reason can be.
|
|
428
|
+
type Enum struct {
|
|
429
|
+
ID string `json:"id"` // "<aggregate id>.<slug>"
|
|
430
|
+
Slug string `json:"slug"`
|
|
431
|
+
Name string `json:"name"`
|
|
432
|
+
Doc string `json:"doc"`
|
|
433
|
+
// Deprecated marks the whole set as on its way out.
|
|
434
|
+
Deprecated bool `json:"deprecated,omitempty"`
|
|
435
|
+
Values []EnumValue `json:"values"`
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// EnumValue is one member of an Enum. Name is what a consumer sees on the
|
|
439
|
+
// wire when the source says so - a Go constant's literal - and the variant's
|
|
440
|
+
// own name otherwise.
|
|
441
|
+
type EnumValue struct {
|
|
442
|
+
Name string `json:"name"`
|
|
443
|
+
Doc string `json:"doc"`
|
|
444
|
+
Deprecated bool `json:"deprecated,omitempty"`
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Lifecycle is the root's state machine as the code writes it down: the
|
|
448
|
+
// states in the order listed, the first being where a new root starts, and
|
|
449
|
+
// every move between them. A state nothing leads out of is terminal.
|
|
450
|
+
type Lifecycle struct {
|
|
451
|
+
States []string `json:"states"`
|
|
452
|
+
Transitions []Transition `json:"transitions"`
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Transition is one move: the method on the root that makes it, and the
|
|
456
|
+
// event it hands back for it when it hands one back.
|
|
457
|
+
type Transition struct {
|
|
458
|
+
From string `json:"from"`
|
|
459
|
+
To string `json:"to"`
|
|
460
|
+
On string `json:"on"`
|
|
461
|
+
Emits string `json:"emits,omitempty"`
|
|
462
|
+
Source string `json:"source,omitempty"`
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
type OperationKind string
|
|
466
|
+
|
|
467
|
+
const (
|
|
468
|
+
OperationCommand OperationKind = "command"
|
|
469
|
+
OperationQuery OperationKind = "query"
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
type Operation struct {
|
|
473
|
+
ID string `json:"id"`
|
|
474
|
+
Kind OperationKind `json:"kind"`
|
|
475
|
+
Doc string `json:"doc,omitempty"`
|
|
476
|
+
// ExposedBy names the interface methods that run this operation, as they
|
|
477
|
+
// appear in RpcService.Methods. Empty means nothing outside the service can
|
|
478
|
+
// reach it, which is a fact worth having rather than a gap.
|
|
479
|
+
ExposedBy []string `json:"exposedBy,omitempty"`
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Block is an entity or a value object. The two are told apart by the list
|
|
483
|
+
// they sit in, not by a field, which is why one struct serves both.
|
|
484
|
+
type Block struct {
|
|
485
|
+
ID string `json:"id"`
|
|
486
|
+
Slug string `json:"slug"`
|
|
487
|
+
Name string `json:"name"`
|
|
488
|
+
Doc string `json:"doc"`
|
|
489
|
+
// Ref names a shared catalog.defs entry. When it is set the shape is that
|
|
490
|
+
// def's, and Fields is empty; when it is not, Fields carries a shape local
|
|
491
|
+
// to this aggregate.
|
|
492
|
+
Ref string `json:"ref,omitempty"`
|
|
493
|
+
Fields []Field `json:"fields,omitempty"`
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
type Event struct {
|
|
497
|
+
ID string `json:"id"`
|
|
498
|
+
Slug string `json:"slug"`
|
|
499
|
+
Name string `json:"name"`
|
|
500
|
+
Versions []EventVersion `json:"versions"`
|
|
501
|
+
Consumers []EventConsumer `json:"consumers"`
|
|
502
|
+
// Wire is how the event leaves the service; nil when the source does
|
|
503
|
+
// not say.
|
|
504
|
+
Wire *EventWire `json:"wire,omitempty"`
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// EventWire is the event as the bus sees it: its name on the message and the
|
|
508
|
+
// channel it is published on. A trace carries both, as `event.name` and
|
|
509
|
+
// `messaging.destination.name`, and this is where the catalog meets it.
|
|
510
|
+
type EventWire struct {
|
|
511
|
+
// Name is the name on the message: "cart.BasketCreated".
|
|
512
|
+
Name string `json:"name"`
|
|
513
|
+
// Channel is the topic, subject or stream: "cart_basket". Empty when the
|
|
514
|
+
// source names the event but not where it goes.
|
|
515
|
+
Channel string `json:"channel,omitempty"`
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Channel is a topic, subject or stream a service says it uses, and the
|
|
519
|
+
// messages that travel on it. It is what an AsyncAPI document declares, and it
|
|
520
|
+
// is the async half of what an OpenAPI document says about routes.
|
|
521
|
+
//
|
|
522
|
+
// The catalog already knew about channels, but only by inference: an event
|
|
523
|
+
// carries a Wire, and the channel was whatever the events happened to name. A
|
|
524
|
+
// declaration is a different fact. It says what the service means to put on the
|
|
525
|
+
// bus whether or not any event was found saying so, and it says what the
|
|
526
|
+
// service listens for - which nothing in a publisher's source could ever say.
|
|
527
|
+
type Channel struct {
|
|
528
|
+
// Address is the channel as the broker knows it: "shop.cart.basket". It is
|
|
529
|
+
// the same string an event's Wire.Channel carries, and comparing the two is
|
|
530
|
+
// how a document and the code it belongs to are held against each other.
|
|
531
|
+
Address string `json:"address"`
|
|
532
|
+
// Kind distinguishes domain-event channels, work queues, and generic message
|
|
533
|
+
// streams. Only event channels are checked against the domain event model.
|
|
534
|
+
Kind ChannelKind `json:"kind,omitempty"`
|
|
535
|
+
|
|
536
|
+
Title string `json:"title,omitempty"`
|
|
537
|
+
Doc string `json:"doc,omitempty"`
|
|
538
|
+
|
|
539
|
+
Messages []ChannelMessage `json:"messages"`
|
|
540
|
+
|
|
541
|
+
// Source is the document this was read out of.
|
|
542
|
+
Source string `json:"source,omitempty"`
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
type ChannelKind string
|
|
546
|
+
|
|
547
|
+
const (
|
|
548
|
+
ChannelKindEvent ChannelKind = "event"
|
|
549
|
+
ChannelKindJob ChannelKind = "job"
|
|
550
|
+
ChannelKindMessage ChannelKind = "message"
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
// ChannelDirection is which way a message travels, from this service's side.
|
|
554
|
+
//
|
|
555
|
+
// It decides ownership: a service that sends on a channel is publishing on it,
|
|
556
|
+
// and a channel has one publisher. A service that only receives is a
|
|
557
|
+
// subscriber, and any number of those is fine.
|
|
558
|
+
type ChannelDirection string
|
|
559
|
+
|
|
560
|
+
const (
|
|
561
|
+
ChannelSend ChannelDirection = "send"
|
|
562
|
+
ChannelReceive ChannelDirection = "receive"
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
// ChannelMessage is one message on a channel, by the name it goes by on the
|
|
566
|
+
// wire - the same name an event's Wire.Name carries.
|
|
567
|
+
type ChannelMessage struct {
|
|
568
|
+
Name string `json:"name"`
|
|
569
|
+
Title string `json:"title,omitempty"`
|
|
570
|
+
Doc string `json:"doc,omitempty"`
|
|
571
|
+
Direction ChannelDirection `json:"direction"`
|
|
572
|
+
// Encoding is the normalized payload serialization, for example msgpack.
|
|
573
|
+
// It is deliberately open-ended: a catalog must be able to carry a format
|
|
574
|
+
// before Portolan learns special presentation or compatibility rules for it.
|
|
575
|
+
Encoding string `json:"encoding,omitempty"`
|
|
576
|
+
// ContentType keeps the exact media type declared by a contract. Kafka
|
|
577
|
+
// client code commonly proves an encoding without declaring a media type,
|
|
578
|
+
// so the two facts are independent.
|
|
579
|
+
ContentType string `json:"contentType,omitempty"`
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
type EventConsumer struct {
|
|
583
|
+
Service string `json:"service"`
|
|
584
|
+
Status Status `json:"status"`
|
|
585
|
+
Note string `json:"note,omitempty"`
|
|
586
|
+
|
|
587
|
+
// Via is set when the consumer was derived from a flow step rather than declared.
|
|
588
|
+
Via *EdgeVia `json:"via,omitempty"`
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
type EventVersion struct {
|
|
592
|
+
Version string `json:"version"`
|
|
593
|
+
Doc string `json:"doc"`
|
|
594
|
+
Source string `json:"source"`
|
|
595
|
+
Fields []Field `json:"fields"`
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
type Field struct {
|
|
599
|
+
Name string `json:"name"`
|
|
600
|
+
Type string `json:"type"`
|
|
601
|
+
Doc string `json:"doc"`
|
|
602
|
+
Ref string `json:"ref,omitempty"`
|
|
603
|
+
// Number is the protobuf field number when the source carries one. Other
|
|
604
|
+
// schema and domain extractors leave it absent.
|
|
605
|
+
Number int `json:"number,omitempty"`
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
type TypeDef struct {
|
|
609
|
+
Fields []Field `json:"fields"`
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
type StoreKind string
|
|
613
|
+
|
|
614
|
+
const (
|
|
615
|
+
StoreKindPostgres StoreKind = "postgres"
|
|
616
|
+
StoreKindMySQL StoreKind = "mysql"
|
|
617
|
+
StoreKindSQLite StoreKind = "sqlite"
|
|
618
|
+
StoreKindRedis StoreKind = "redis"
|
|
619
|
+
StoreKindMongoDB StoreKind = "mongodb"
|
|
620
|
+
StoreKindClickHouse StoreKind = "clickhouse"
|
|
621
|
+
StoreKindS3 StoreKind = "s3"
|
|
622
|
+
StoreKindOther StoreKind = "other"
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
type Store struct {
|
|
626
|
+
ID string `json:"id"`
|
|
627
|
+
Slug string `json:"slug"`
|
|
628
|
+
Name string `json:"name"`
|
|
629
|
+
Kind StoreKind `json:"kind"`
|
|
630
|
+
Owner string `json:"owner"`
|
|
631
|
+
Tables []Table `json:"tables"`
|
|
632
|
+
Views []View `json:"views,omitempty"`
|
|
633
|
+
Keyspaces []RedisKeyspace `json:"keyspaces,omitempty"`
|
|
634
|
+
Source string `json:"source,omitempty"`
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
type RedisOperation string
|
|
638
|
+
|
|
639
|
+
const (
|
|
640
|
+
RedisOperationRead RedisOperation = "read"
|
|
641
|
+
RedisOperationWrite RedisOperation = "write"
|
|
642
|
+
RedisOperationDelete RedisOperation = "delete"
|
|
643
|
+
RedisOperationExists RedisOperation = "exists"
|
|
644
|
+
RedisOperationExpire RedisOperation = "expire"
|
|
645
|
+
RedisOperationCount RedisOperation = "count"
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
// RedisKeyspace is a family of keys proved by the expressions passed to a
|
|
649
|
+
// Redis client. Pattern keeps literal separators and writes dynamic pieces in
|
|
650
|
+
// braces; square brackets mark a conditional suffix.
|
|
651
|
+
type RedisKeyspace struct {
|
|
652
|
+
Pattern string `json:"pattern"`
|
|
653
|
+
Operations []RedisOperation `json:"operations"`
|
|
654
|
+
TTL string `json:"ttl,omitempty"`
|
|
655
|
+
Value string `json:"value,omitempty"`
|
|
656
|
+
Source string `json:"source,omitempty"`
|
|
657
|
+
// Persists links the value stored under this key family back to the domain
|
|
658
|
+
// model. It is optional because a counter, lock or coordination key may not
|
|
659
|
+
// hold an aggregate at all.
|
|
660
|
+
Persists *Persists `json:"persists,omitempty"`
|
|
661
|
+
Accesses []RedisAccess `json:"accesses,omitempty"`
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// RedisAccess is one proved client call, kept separately even when several
|
|
665
|
+
// calls use the same key family. Operations is the compact schema summary;
|
|
666
|
+
// accesses answers who performs each read or write and where the proof lives.
|
|
667
|
+
type RedisAccess struct {
|
|
668
|
+
Operation RedisOperation `json:"operation"`
|
|
669
|
+
Method string `json:"method,omitempty"`
|
|
670
|
+
TTL string `json:"ttl,omitempty"`
|
|
671
|
+
Value string `json:"value,omitempty"`
|
|
672
|
+
Source string `json:"source,omitempty"`
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
type TableRole string
|
|
676
|
+
|
|
677
|
+
const (
|
|
678
|
+
TableRoleAggregateRoot TableRole = "aggregate-root"
|
|
679
|
+
TableRoleChild TableRole = "child"
|
|
680
|
+
TableRoleOutbox TableRole = "outbox"
|
|
681
|
+
TableRoleProjection TableRole = "projection"
|
|
682
|
+
TableRoleLookup TableRole = "lookup"
|
|
683
|
+
TableRoleOther TableRole = "other"
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
type Table struct {
|
|
687
|
+
Evidence []RelationEvidence `json:"evidence,omitempty"`
|
|
688
|
+
ID string `json:"id"`
|
|
689
|
+
Name string `json:"name"`
|
|
690
|
+
Doc string `json:"doc,omitempty"`
|
|
691
|
+
Columns []Column `json:"columns"`
|
|
692
|
+
Indexes []TableIndex `json:"indexes,omitempty"`
|
|
693
|
+
Persists *Persists `json:"persists,omitempty"`
|
|
694
|
+
Role TableRole `json:"role,omitempty"`
|
|
695
|
+
// Accesses are the source-backed repository methods that touch this table.
|
|
696
|
+
// They answer who reads or writes the rows; the DDL alone cannot.
|
|
697
|
+
Accesses []TableAccess `json:"accesses,omitempty"`
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
type TableOperation string
|
|
701
|
+
|
|
702
|
+
const (
|
|
703
|
+
TableOperationRead TableOperation = "read"
|
|
704
|
+
TableOperationWrite TableOperation = "write"
|
|
705
|
+
TableOperationDelete TableOperation = "delete"
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
// TableAccess is one SQL statement proved inside a repository method.
|
|
709
|
+
type TableAccess struct {
|
|
710
|
+
Operation TableOperation `json:"operation"`
|
|
711
|
+
Method string `json:"method,omitempty"`
|
|
712
|
+
Source string `json:"source,omitempty"`
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Persists is the link back to the model: which domain object these rows hold.
|
|
716
|
+
type Persists struct {
|
|
717
|
+
Evidence []RelationEvidence `json:"evidence,omitempty"`
|
|
718
|
+
Aggregate string `json:"aggregate,omitempty"`
|
|
719
|
+
Block string `json:"block,omitempty"`
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
type TableIndex struct {
|
|
723
|
+
Name string `json:"name"`
|
|
724
|
+
Columns []string `json:"columns"`
|
|
725
|
+
Unique bool `json:"unique"`
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
type Column struct {
|
|
729
|
+
Name string `json:"name"`
|
|
730
|
+
// Type is the db type as declared - uuid, timestamptz, jsonb - never
|
|
731
|
+
// normalised. A reader comparing a column to a migration wants the string
|
|
732
|
+
// the migration used.
|
|
733
|
+
Type string `json:"type"`
|
|
734
|
+
Nullable bool `json:"nullable"`
|
|
735
|
+
PK bool `json:"pk,omitempty"`
|
|
736
|
+
FK *FK `json:"fk,omitempty"`
|
|
737
|
+
// From is lineage: where this value CAME FROM, as "<table or view id>.<column>".
|
|
738
|
+
// A foreign key answers a different question - which row it points at.
|
|
739
|
+
From []string `json:"from,omitempty"`
|
|
740
|
+
Maps string `json:"maps,omitempty"`
|
|
741
|
+
Doc string `json:"doc,omitempty"`
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
type FK struct {
|
|
745
|
+
Table string `json:"table"`
|
|
746
|
+
Column string `json:"column"`
|
|
747
|
+
OnDelete string `json:"onDelete,omitempty"`
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
type View struct {
|
|
751
|
+
ID string `json:"id"`
|
|
752
|
+
Name string `json:"name"`
|
|
753
|
+
Doc string `json:"doc,omitempty"`
|
|
754
|
+
// Materialized: the database keeps the rows rather than recomputing them,
|
|
755
|
+
// which means they can be stale. A reader has to know that before believing
|
|
756
|
+
// one, so it is drawn differently rather than noted in prose.
|
|
757
|
+
Materialized bool `json:"materialized,omitempty"`
|
|
758
|
+
Columns []Column `json:"columns"`
|
|
759
|
+
Reads []string `json:"reads,omitempty"`
|
|
760
|
+
Definition string `json:"definition,omitempty"`
|
|
761
|
+
Persists *Persists `json:"persists,omitempty"`
|
|
762
|
+
Source string `json:"source,omitempty"`
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Flow is a sequence read out of source. Extractors may attach the execution
|
|
766
|
+
// trigger they proved; authored flows omit it when that evidence is not part of
|
|
767
|
+
// the document.
|
|
768
|
+
type Flow struct {
|
|
769
|
+
ID string `json:"id"`
|
|
770
|
+
Slug string `json:"slug"`
|
|
771
|
+
Name string `json:"name"`
|
|
772
|
+
Summary string `json:"summary"`
|
|
773
|
+
Source string `json:"source,omitempty"`
|
|
774
|
+
// Trigger says how execution enters this flow and how strong the static
|
|
775
|
+
// evidence is. Authored flows may omit it; source extractors should not.
|
|
776
|
+
Trigger *FlowTrigger `json:"trigger,omitempty"`
|
|
777
|
+
// EntryPoint is the source function this fragment expands. It is machine
|
|
778
|
+
// evidence for composing a queue handler with the outbound flow extracted
|
|
779
|
+
// independently from the same function; ordinary authored flows omit it.
|
|
780
|
+
EntryPoint string `json:"entrypoint,omitempty"`
|
|
781
|
+
// Includes names source-backed flow fragments composed into this root flow.
|
|
782
|
+
// It makes composition idempotent and leaves visible provenance for readers.
|
|
783
|
+
Includes []string `json:"includes,omitempty"`
|
|
784
|
+
// Owner is the bounded context the flow belongs to. The extractor knows it
|
|
785
|
+
// - it read the service's own tree to find the flow - so it says so rather
|
|
786
|
+
// than leaving a reader to work it back out of a path.
|
|
787
|
+
Owner string `json:"owner"`
|
|
788
|
+
// Participants order is significant: it is the lane order.
|
|
789
|
+
Participants []Participant `json:"participants"`
|
|
790
|
+
Steps FlowNodes `json:"steps"`
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
type FlowTrigger struct {
|
|
794
|
+
Kind string `json:"kind"`
|
|
795
|
+
Label string `json:"label,omitempty"`
|
|
796
|
+
Confidence string `json:"confidence"`
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
type ParticipantKind string
|
|
800
|
+
|
|
801
|
+
const (
|
|
802
|
+
ParticipantActor ParticipantKind = "actor"
|
|
803
|
+
ParticipantService ParticipantKind = "service"
|
|
804
|
+
ParticipantBroker ParticipantKind = "broker"
|
|
805
|
+
ParticipantStore ParticipantKind = "store"
|
|
806
|
+
ParticipantExternal ParticipantKind = "external"
|
|
807
|
+
ParticipantUnknown ParticipantKind = "unknown"
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
type Participant struct {
|
|
811
|
+
ID string `json:"id"`
|
|
812
|
+
Kind ParticipantKind `json:"kind"`
|
|
813
|
+
// Context is null for actors and brokers, which is a fact rather than an
|
|
814
|
+
// absence - hence a pointer that marshals to null, not an empty string.
|
|
815
|
+
Context *string `json:"context"`
|
|
816
|
+
Label string `json:"label,omitempty"`
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// FlowNode is one entry in a flow: a step, or one of the three shapes that
|
|
820
|
+
// hold steps. It is an interface rather than a struct with four optional
|
|
821
|
+
// members so that a renderer has to say which shape it is handling - a flow
|
|
822
|
+
// that quietly treats an alt as a sequence reads as "the order was cancelled
|
|
823
|
+
// and then charged".
|
|
824
|
+
type FlowNode interface {
|
|
825
|
+
NodeType() string
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// FlowNodes is a list of them. The custom unmarshaller is the only place that
|
|
829
|
+
// knows how the union is discriminated on the wire.
|
|
830
|
+
type FlowNodes []FlowNode
|
|
831
|
+
|
|
832
|
+
func (n *FlowNodes) UnmarshalJSON(data []byte) error {
|
|
833
|
+
var raw []json.RawMessage
|
|
834
|
+
if err := json.Unmarshal(data, &raw); err != nil {
|
|
835
|
+
return err
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
out := make(FlowNodes, 0, len(raw))
|
|
839
|
+
for i, item := range raw {
|
|
840
|
+
var probe struct {
|
|
841
|
+
Type string `json:"type"`
|
|
842
|
+
}
|
|
843
|
+
if err := json.Unmarshal(item, &probe); err != nil {
|
|
844
|
+
return fmt.Errorf("node %d: %w", i, err)
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
var node FlowNode
|
|
848
|
+
switch probe.Type {
|
|
849
|
+
case "step":
|
|
850
|
+
node = &Step{}
|
|
851
|
+
case "parallel":
|
|
852
|
+
node = &Parallel{}
|
|
853
|
+
case "alt":
|
|
854
|
+
node = &Alt{}
|
|
855
|
+
case "loop":
|
|
856
|
+
node = &Loop{}
|
|
857
|
+
default:
|
|
858
|
+
return fmt.Errorf("node %d: unknown flow node type %q", i, probe.Type)
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
if err := json.Unmarshal(item, node); err != nil {
|
|
862
|
+
return fmt.Errorf("node %d (%s): %w", i, probe.Type, err)
|
|
863
|
+
}
|
|
864
|
+
out = append(out, node)
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
*n = out
|
|
868
|
+
|
|
869
|
+
return nil
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
type StepKind string
|
|
873
|
+
|
|
874
|
+
const (
|
|
875
|
+
StepRPC StepKind = "rpc"
|
|
876
|
+
StepEvent StepKind = "event"
|
|
877
|
+
StepCall StepKind = "call"
|
|
878
|
+
StepResponse StepKind = "response"
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
// RelationEvidence records why an extractor or catalog resolution produced a
|
|
882
|
+
// relationship. It describes source evidence, never observed execution.
|
|
883
|
+
type RelationEvidence struct {
|
|
884
|
+
Kind string `json:"kind"`
|
|
885
|
+
Rule string `json:"rule"`
|
|
886
|
+
Source string `json:"source,omitempty"`
|
|
887
|
+
Symbol string `json:"symbol,omitempty"`
|
|
888
|
+
Candidates []string `json:"candidates,omitempty"`
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
type Step struct {
|
|
892
|
+
Evidence []RelationEvidence `json:"evidence,omitempty"`
|
|
893
|
+
Destination *HTTPDestination `json:"destination,omitempty"`
|
|
894
|
+
Type string `json:"type"`
|
|
895
|
+
ID string `json:"id"`
|
|
896
|
+
From string `json:"from"`
|
|
897
|
+
// To is a participant id. From == To is a self-message.
|
|
898
|
+
To string `json:"to"`
|
|
899
|
+
Kind StepKind `json:"kind"`
|
|
900
|
+
// Ref is an Event.id, an RpcCall.id or a provided RPC method id. It
|
|
901
|
+
// resolves, or Status says unresolved; there is no third option.
|
|
902
|
+
Ref string `json:"ref,omitempty"`
|
|
903
|
+
Label string `json:"label,omitempty"`
|
|
904
|
+
Status Status `json:"status"`
|
|
905
|
+
Note string `json:"note,omitempty"`
|
|
906
|
+
Line string `json:"line,omitempty"`
|
|
907
|
+
// ReplyTo names the synchronous request step this synthesized response
|
|
908
|
+
// returns from. Extractors record requests; composition adds the response
|
|
909
|
+
// only when it can prove the nested HTTP or unary RPC execution returns.
|
|
910
|
+
ReplyTo string `json:"replyTo,omitempty"`
|
|
911
|
+
// HTTP describes the wire response when source inspection can prove it.
|
|
912
|
+
// BodyRef names the RPC method whose response is serialized, so the merged
|
|
913
|
+
// catalog can resolve the schema without copying it into every flow.
|
|
914
|
+
HTTP *HTTPResponse `json:"http,omitempty"`
|
|
915
|
+
// ContinuesAt names the source function execution enters after this step.
|
|
916
|
+
// The merge uses it only when exactly one flow declares that entry point.
|
|
917
|
+
ContinuesAt string `json:"continuesAt,omitempty"`
|
|
918
|
+
// Reaches names source functions proven to execute on the path represented
|
|
919
|
+
// by this step. The merge may use them to attach independently extracted
|
|
920
|
+
// protocol fragments that expand those exact functions.
|
|
921
|
+
Reaches []string `json:"reaches,omitempty"`
|
|
922
|
+
// Handoff identifies a source-backed send or receive through an asynchronous
|
|
923
|
+
// channel. Matching is exact on kind, channel, and message.
|
|
924
|
+
Handoff *FlowHandoff `json:"handoff,omitempty"`
|
|
925
|
+
// StoreAccess identifies the repository method at extraction time and is
|
|
926
|
+
// enriched with its Redis operation and key family after store fragments
|
|
927
|
+
// have been merged into the catalog.
|
|
928
|
+
StoreAccess *FlowStoreAccess `json:"storeAccess,omitempty"`
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
func (*Step) NodeType() string { return "step" }
|
|
932
|
+
|
|
933
|
+
type HTTPResponse struct {
|
|
934
|
+
Status int `json:"status,omitempty"`
|
|
935
|
+
ContentType string `json:"contentType,omitempty"`
|
|
936
|
+
Body string `json:"body,omitempty"`
|
|
937
|
+
BodyRef string `json:"bodyRef,omitempty"`
|
|
938
|
+
Encoding string `json:"encoding,omitempty"`
|
|
939
|
+
Outcome string `json:"outcome,omitempty"`
|
|
940
|
+
Warning string `json:"warning,omitempty"`
|
|
941
|
+
Source string `json:"source,omitempty"`
|
|
942
|
+
Fields []Field `json:"fields,omitempty"`
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
type FlowHandoff struct {
|
|
946
|
+
Kind string `json:"kind"`
|
|
947
|
+
Transport string `json:"transport"`
|
|
948
|
+
Channel string `json:"channel"`
|
|
949
|
+
Message string `json:"message,omitempty"`
|
|
950
|
+
Direction string `json:"direction"`
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
type FlowStoreAccess struct {
|
|
954
|
+
Store string `json:"store"`
|
|
955
|
+
Method string `json:"method,omitempty"`
|
|
956
|
+
Operation RedisOperation `json:"operation,omitempty"`
|
|
957
|
+
Keyspace string `json:"keyspace,omitempty"`
|
|
958
|
+
Source string `json:"source,omitempty"`
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
type Parallel struct {
|
|
962
|
+
Type string `json:"type"`
|
|
963
|
+
ID string `json:"id"`
|
|
964
|
+
Title string `json:"title,omitempty"`
|
|
965
|
+
Branches []FlowNodes `json:"branches"`
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
func (*Parallel) NodeType() string { return "parallel" }
|
|
969
|
+
|
|
970
|
+
// Alt is a choice: exactly one branch runs. The branches are not a sequence
|
|
971
|
+
// and nothing that reads a flow may render them as one.
|
|
972
|
+
type Alt struct {
|
|
973
|
+
Type string `json:"type"`
|
|
974
|
+
ID string `json:"id"`
|
|
975
|
+
Branches []AltBranch `json:"branches"`
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
func (*Alt) NodeType() string { return "alt" }
|
|
979
|
+
|
|
980
|
+
type AltBranch struct {
|
|
981
|
+
// Title is the condition under which this branch runs, in words.
|
|
982
|
+
Title string `json:"title"`
|
|
983
|
+
Steps FlowNodes `json:"steps"`
|
|
984
|
+
// Terminal marks a branch that ENDS the flow instead of rejoining it.
|
|
985
|
+
// Without it, the steps drawn after the alt read as if they follow this
|
|
986
|
+
// branch too.
|
|
987
|
+
Terminal bool `json:"terminal,omitempty"`
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
type Loop struct {
|
|
991
|
+
Type string `json:"type"`
|
|
992
|
+
ID string `json:"id"`
|
|
993
|
+
Title string `json:"title"`
|
|
994
|
+
Steps FlowNodes `json:"steps"`
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
func (*Loop) NodeType() string { return "loop" }
|
|
998
|
+
|
|
999
|
+
type AdrStatus string
|
|
1000
|
+
|
|
1001
|
+
const (
|
|
1002
|
+
AdrProposed AdrStatus = "proposed"
|
|
1003
|
+
AdrAccepted AdrStatus = "accepted"
|
|
1004
|
+
AdrSuperseded AdrStatus = "superseded"
|
|
1005
|
+
AdrDeprecated AdrStatus = "deprecated"
|
|
1006
|
+
AdrRejected AdrStatus = "rejected"
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
// AdrScope is org-wide, or one context, or one service. The kind says which of
|
|
1010
|
+
// the two ids is set.
|
|
1011
|
+
type AdrScope struct {
|
|
1012
|
+
Kind string `json:"kind"`
|
|
1013
|
+
Context string `json:"context,omitempty"`
|
|
1014
|
+
Service string `json:"service,omitempty"`
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Adr is frozen history. It says what was decided and when, not what the model
|
|
1018
|
+
// looks like now, so nothing on it is ever regenerated from the current
|
|
1019
|
+
// catalog.
|
|
1020
|
+
type Adr struct {
|
|
1021
|
+
ID string `json:"id"`
|
|
1022
|
+
Slug string `json:"slug"`
|
|
1023
|
+
Number int `json:"number"`
|
|
1024
|
+
Title string `json:"title"`
|
|
1025
|
+
Status AdrStatus `json:"status"`
|
|
1026
|
+
Date string `json:"date"`
|
|
1027
|
+
Scope AdrScope `json:"scope"`
|
|
1028
|
+
Body string `json:"body"`
|
|
1029
|
+
Note string `json:"note,omitempty"`
|
|
1030
|
+
SupersededBy string `json:"supersededBy,omitempty"`
|
|
1031
|
+
Supersedes []string `json:"supersedes,omitempty"`
|
|
1032
|
+
Relates AdrRelates `json:"relates"`
|
|
1033
|
+
Source string `json:"source"`
|
|
1034
|
+
|
|
1035
|
+
// Created is the commit that first added the file, and Revised the one
|
|
1036
|
+
// that last touched it, when that is a different commit. Absent when the
|
|
1037
|
+
// tree has no history to read.
|
|
1038
|
+
Created *AdrCommit `json:"created,omitempty"`
|
|
1039
|
+
Revised *AdrCommit `json:"revised,omitempty"`
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// AdrCommit is one commit of a record's file: who made it and when. The
|
|
1043
|
+
// markdown says when a decision was taken; git says when it was written down
|
|
1044
|
+
// and by whom, which is the other half of "who decided this".
|
|
1045
|
+
type AdrCommit struct {
|
|
1046
|
+
Commit string `json:"commit"`
|
|
1047
|
+
Author string `json:"author"`
|
|
1048
|
+
Date string `json:"date"`
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
type AdrRelates struct {
|
|
1052
|
+
Services []string `json:"services,omitempty"`
|
|
1053
|
+
Events []string `json:"events,omitempty"`
|
|
1054
|
+
Flows []string `json:"flows,omitempty"`
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// Term is one entry of a context's glossary: a word, and what it means inside
|
|
1058
|
+
// the boundary that means it.
|
|
1059
|
+
type Term struct {
|
|
1060
|
+
ID string `json:"id"`
|
|
1061
|
+
Slug string `json:"slug"`
|
|
1062
|
+
Context string `json:"context"`
|
|
1063
|
+
Name string `json:"name"`
|
|
1064
|
+
Definition string `json:"definition"`
|
|
1065
|
+
Source string `json:"source"`
|
|
1066
|
+
}
|