@toa.io/extensions.introspection 1.0.0-alpha.262

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/components/introspection.edges/manifest.toa.yaml +48 -0
  3. package/components/introspection.edges/operations/lib/types.d.ts +28 -0
  4. package/components/introspection.edges/operations/lib/types.js +3 -0
  5. package/components/introspection.edges/operations/lib/types.js.map +1 -0
  6. package/components/introspection.edges/operations/merge.d.ts +9 -0
  7. package/components/introspection.edges/operations/merge.js +25 -0
  8. package/components/introspection.edges/operations/merge.js.map +1 -0
  9. package/components/introspection.edges/source/lib/types.ts +33 -0
  10. package/components/introspection.edges/source/merge.ts +26 -0
  11. package/components/introspection.edges/tsconfig.json +9 -0
  12. package/components/introspection.nodes/manifest.toa.yaml +49 -0
  13. package/components/introspection.nodes/operations/lib/types.d.ts +16 -0
  14. package/components/introspection.nodes/operations/lib/types.js +3 -0
  15. package/components/introspection.nodes/operations/lib/types.js.map +1 -0
  16. package/components/introspection.nodes/operations/merge.d.ts +9 -0
  17. package/components/introspection.nodes/operations/merge.js +21 -0
  18. package/components/introspection.nodes/operations/merge.js.map +1 -0
  19. package/components/introspection.nodes/source/lib/types.ts +18 -0
  20. package/components/introspection.nodes/source/merge.ts +21 -0
  21. package/components/introspection.nodes/tsconfig.json +9 -0
  22. package/cucumber.js +8 -0
  23. package/features/calls.feature +123 -0
  24. package/features/nodes.feature +70 -0
  25. package/features/samples.feature +75 -0
  26. package/features/shutdown.feature +37 -0
  27. package/features/site/_app/immutable/asset.js +1 -0
  28. package/features/site/index.html +6 -0
  29. package/features/steps/Map.ts +151 -0
  30. package/features/steps/UI.ts +88 -0
  31. package/features/steps/components/probe.discreet/manifest.toa.yaml +12 -0
  32. package/features/steps/components/probe.discreet/operations/ping.js +7 -0
  33. package/features/steps/components/probe.quiet/manifest.toa.yaml +11 -0
  34. package/features/steps/components/probe.quiet/operations/ping.js +7 -0
  35. package/features/steps/components/probe.source/manifest.toa.yaml +27 -0
  36. package/features/steps/components/probe.source/operations/crash.js +7 -0
  37. package/features/steps/components/probe.source/operations/fail.js +12 -0
  38. package/features/steps/components/probe.source/operations/relay.js +7 -0
  39. package/features/steps/components/probe.target/manifest.toa.yaml +24 -0
  40. package/features/steps/components/probe.target/operations/compute.js +7 -0
  41. package/features/steps/components/probe.target/operations/count.js +9 -0
  42. package/features/steps/config.ts +20 -0
  43. package/features/steps/tsconfig.json +9 -0
  44. package/features/ui.feature +85 -0
  45. package/package.json +31 -0
  46. package/readme.md +141 -0
  47. package/schemas/annotation.cos.yaml +16 -0
  48. package/schemas/declaration.cos.yaml +2 -0
  49. package/source/Composition.ts +61 -0
  50. package/source/Explorer.ts +16 -0
  51. package/source/Factory.ts +119 -0
  52. package/source/Reporter.ts +210 -0
  53. package/source/Tenant.ts +47 -0
  54. package/source/UI.ts +197 -0
  55. package/source/annotation.ts +83 -0
  56. package/source/const.ts +32 -0
  57. package/source/describe.ts +68 -0
  58. package/source/extension.ts +45 -0
  59. package/source/index.ts +7 -0
  60. package/source/keys.ts +0 -0
  61. package/source/manifest.ts +19 -0
  62. package/source/model.ts +82 -0
  63. package/source/sample.ts +49 -0
  64. package/source/schemas.ts +10 -0
  65. package/transpiled/Composition.d.ts +21 -0
  66. package/transpiled/Composition.js +48 -0
  67. package/transpiled/Composition.js.map +1 -0
  68. package/transpiled/Explorer.d.ts +9 -0
  69. package/transpiled/Explorer.js +19 -0
  70. package/transpiled/Explorer.js.map +1 -0
  71. package/transpiled/Factory.d.ts +22 -0
  72. package/transpiled/Factory.js +93 -0
  73. package/transpiled/Factory.js.map +1 -0
  74. package/transpiled/Reporter.d.ts +44 -0
  75. package/transpiled/Reporter.js +187 -0
  76. package/transpiled/Reporter.js.map +1 -0
  77. package/transpiled/Tenant.d.ts +18 -0
  78. package/transpiled/Tenant.js +40 -0
  79. package/transpiled/Tenant.js.map +1 -0
  80. package/transpiled/UI.d.ts +25 -0
  81. package/transpiled/UI.js +186 -0
  82. package/transpiled/UI.js.map +1 -0
  83. package/transpiled/annotation.d.ts +40 -0
  84. package/transpiled/annotation.js +46 -0
  85. package/transpiled/annotation.js.map +1 -0
  86. package/transpiled/const.d.ts +23 -0
  87. package/transpiled/const.js +27 -0
  88. package/transpiled/const.js.map +1 -0
  89. package/transpiled/contracts.d.ts +51 -0
  90. package/transpiled/contracts.js +53 -0
  91. package/transpiled/contracts.js.map +1 -0
  92. package/transpiled/describe.d.ts +9 -0
  93. package/transpiled/describe.js +64 -0
  94. package/transpiled/describe.js.map +1 -0
  95. package/transpiled/extension.d.ts +11 -0
  96. package/transpiled/extension.js +64 -0
  97. package/transpiled/extension.js.map +1 -0
  98. package/transpiled/index.d.ts +6 -0
  99. package/transpiled/index.js +25 -0
  100. package/transpiled/index.js.map +1 -0
  101. package/transpiled/keys.d.ts +9 -0
  102. package/transpiled/keys.js +0 -0
  103. package/transpiled/keys.js.map +1 -0
  104. package/transpiled/manifest.d.ts +9 -0
  105. package/transpiled/manifest.js +43 -0
  106. package/transpiled/manifest.js.map +1 -0
  107. package/transpiled/model.d.ts +71 -0
  108. package/transpiled/model.js +3 -0
  109. package/transpiled/model.js.map +1 -0
  110. package/transpiled/sample.d.ts +7 -0
  111. package/transpiled/sample.js +44 -0
  112. package/transpiled/sample.js.map +1 -0
  113. package/transpiled/schemas.d.ts +4 -0
  114. package/transpiled/schemas.js +13 -0
  115. package/transpiled/schemas.js.map +1 -0
  116. package/tsconfig.json +12 -0
  117. package/ui/dist/_app/env.js +1 -0
  118. package/ui/dist/_app/immutable/assets/0.fg2cP6bO.css +2 -0
  119. package/ui/dist/_app/immutable/assets/2.BghF56l_.css +1 -0
  120. package/ui/dist/_app/immutable/assets/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2 +0 -0
  121. package/ui/dist/_app/immutable/assets/inter-cyrillic-wght-normal.DqGufNeO.woff2 +0 -0
  122. package/ui/dist/_app/immutable/assets/inter-greek-ext-wght-normal.DlzME5K_.woff2 +0 -0
  123. package/ui/dist/_app/immutable/assets/inter-greek-wght-normal.CkhJZR-_.woff2 +0 -0
  124. package/ui/dist/_app/immutable/assets/inter-latin-ext-wght-normal.DO1Apj_S.woff2 +0 -0
  125. package/ui/dist/_app/immutable/assets/inter-latin-wght-normal.Dx4kXJAl.woff2 +0 -0
  126. package/ui/dist/_app/immutable/assets/inter-vietnamese-wght-normal.CBcvBZtf.woff2 +0 -0
  127. package/ui/dist/_app/immutable/chunks/Bjy-W4x2.js +81 -0
  128. package/ui/dist/_app/immutable/chunks/CIvRtvVA.js +1 -0
  129. package/ui/dist/_app/immutable/chunks/D1jNriZ8.js +1 -0
  130. package/ui/dist/_app/immutable/chunks/DINmginf.js +1 -0
  131. package/ui/dist/_app/immutable/chunks/DKZCAkrF.js +1 -0
  132. package/ui/dist/_app/immutable/chunks/DLG2JvyF.js +6 -0
  133. package/ui/dist/_app/immutable/chunks/DSi-FjwI.js +2 -0
  134. package/ui/dist/_app/immutable/chunks/DdoZuyU1.js +1 -0
  135. package/ui/dist/_app/immutable/chunks/O9IjE_TH.js +1 -0
  136. package/ui/dist/_app/immutable/chunks/PUjOYRcs.js +3 -0
  137. package/ui/dist/_app/immutable/chunks/QKD4Mgck.js +5 -0
  138. package/ui/dist/_app/immutable/chunks/Ux-r8C9U.js +1 -0
  139. package/ui/dist/_app/immutable/chunks/xihTtKlq.js +1 -0
  140. package/ui/dist/_app/immutable/entry/app.CTY34L35.js +2 -0
  141. package/ui/dist/_app/immutable/entry/start.Bq2Gn1Ax.js +1 -0
  142. package/ui/dist/_app/immutable/nodes/0.lOXtBRjQ.js +1 -0
  143. package/ui/dist/_app/immutable/nodes/1.r8ESZdgM.js +1 -0
  144. package/ui/dist/_app/immutable/nodes/2.DuVj0loz.js +8 -0
  145. package/ui/dist/_app/immutable/nodes/3.DhdkQ2Q1.js +1 -0
  146. package/ui/dist/_app/immutable/nodes/4.DUAEZdRr.js +1 -0
  147. package/ui/dist/_app/immutable/nodes/5.CIVn_xgq.js +1 -0
  148. package/ui/dist/_app/version.json +1 -0
  149. package/ui/dist/index.html +48 -0
  150. package/ui/dist/robots.txt +3 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,61 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ # [1.0.0-alpha.262](https://github.com/toa-io/toa/compare/v1.0.0-alpha.261...v1.0.0-alpha.262) (2026-08-28)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **introspection:** keep the collector off the critical path ([965ec77](https://github.com/toa-io/toa/commit/965ec77482d361a5a9a88579152158c7e1c79e66))
12
+ * **introspection:** meet a card across the edge the line touches ([2002de9](https://github.com/toa-io/toa/commit/2002de9bdc12400abc64d5234fa319339db4588f))
13
+ * **introspection:** return the whole map over HTTP ([053c0cd](https://github.com/toa-io/toa/commit/053c0cd5c22b1a80bceb23d2cda68ede33a0d1c0))
14
+ * **introspection:** serve a route that looks like a file ([b43bbb4](https://github.com/toa-io/toa/commit/b43bbb4a290819463c61bcba64357385c2423d25))
15
+ * **introspection:** show the lines an opened neighbour sends ([5fe8aed](https://github.com/toa-io/toa/commit/5fe8aed64c1f1e54f1c10e29b91b50c5cdc296ab))
16
+ * **introspection:** wait for the page before capturing it ([9e63af3](https://github.com/toa-io/toa/commit/9e63af34ee090a4f90dce9658b0d022f4acae50f))
17
+
18
+
19
+ * feat(introspection)!: publish the UI ([81fe2cb](https://github.com/toa-io/toa/commit/81fe2cb4bafe91e74d3af8359327e3102e5b0e8a))
20
+
21
+
22
+ ### Features
23
+
24
+ * **introspection:** act on the only thing the filter left ([1a83709](https://github.com/toa-io/toa/commit/1a8370987b7d60c009f4d58f07005618899cdfd6))
25
+ * **introspection:** add the introspection extension ([a07ed86](https://github.com/toa-io/toa/commit/a07ed8651404258d544f3b6d8236e58cf4da09ac))
26
+ * **introspection:** animate a card opening on the map ([1d2180f](https://github.com/toa-io/toa/commit/1d2180f48fb9dc18d9fa0c2cc4eefa6f46626898))
27
+ * **introspection:** animate every collapsible from one place ([0b6a32b](https://github.com/toa-io/toa/commit/0b6a32b69128f2db2d3e449896614ff478f2775b))
28
+ * **introspection:** ask for the role rather than be refused it ([1ad01a7](https://github.com/toa-io/toa/commit/1ad01a7dd817ae37ed84e3a3b6b20b72049a4216))
29
+ * **introspection:** cache the map API ([f550c27](https://github.com/toa-io/toa/commit/f550c2780a80bbe2fdd131984c33d9848daa8c82))
30
+ * **introspection:** fold away a component's extensions ([de1bea6](https://github.com/toa-io/toa/commit/de1bea6329a1fd920cff6b5ad9a13eedfc527884))
31
+ * **introspection:** give a card's rows their own space ([3253639](https://github.com/toa-io/toa/commit/32536395b9d25e743c25b61deb9dbd5b79d966b6))
32
+ * **introspection:** give the map's two screens their own addresses ([90fd5af](https://github.com/toa-io/toa/commit/90fd5af39b8b6c38e22e05df46c70de533eb15c6))
33
+ * **introspection:** open a component on the map ([6382740](https://github.com/toa-io/toa/commit/63827403407fc5a305d95e9fde72ed5a99a1499a))
34
+ * **introspection:** open an operation onto what it takes ([f16a683](https://github.com/toa-io/toa/commit/f16a683175a89d3660c538768b24cd872b6d0b3d))
35
+ * **introspection:** publish the map as a page ([21b16b2](https://github.com/toa-io/toa/commit/21b16b2220a1b26796bdbedc85a0df2a88df31dd))
36
+ * **introspection:** say a component's shape in counts ([54aa771](https://github.com/toa-io/toa/commit/54aa771a51c257db759107d584d063916f0cd351))
37
+ * **introspection:** say how a silenced card comes back ([6e7674f](https://github.com/toa-io/toa/commit/6e7674f88137cfb780f3a7cac1fc67f191f96984))
38
+ * **introspection:** separate what the runtime provides ([289c7a3](https://github.com/toa-io/toa/commit/289c7a301dd0ab9c063a5b77b24745983ec79e29))
39
+ * **introspection:** show a schema as a shape ([7d9a595](https://github.com/toa-io/toa/commit/7d9a595d86f88846b21bb79aba82bb332b77fbf6))
40
+ * **introspection:** the map is the front page ([dbf1b5f](https://github.com/toa-io/toa/commit/dbf1b5fd6d262aa2aa952bbfe2a6be1e44af6302))
41
+
42
+
43
+ ### Performance Improvements
44
+
45
+ * **introspection:** build a card's details when it shows them ([c10f7c4](https://github.com/toa-io/toa/commit/c10f7c42e51cbef2d3767c36559d846f0e34653a))
46
+
47
+
48
+ ### BREAKING CHANGES
49
+
50
+ * the extension is predefined, so every Context now declares an
51
+ ingress and must say where it lands:
52
+
53
+ ingress:
54
+ hosts: [api.example.com]
55
+
56
+ An application that does not want the page says `introspection: { ui: false }`,
57
+ and one that wants no map at all says `introspection: false`. Failing the export
58
+ is deliberate: the alternative is quietly not publishing a page that was asked
59
+ for.
60
+
61
+ Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@@ -0,0 +1,48 @@
1
+ namespace: introspection
2
+ name: edges
3
+
4
+ # One document per edge of the map: a call one component made to another, with `src`
5
+ # saying what caused it — another operation, an event, or a service. What the
6
+ # application declares is described by `introspection.nodes`; an edge is what
7
+ # actually happened.
8
+ #
9
+ # Every replica of a component derives the same id for the same edge, so `merge` is
10
+ # an upsert and `_updated` shows when the edge was last observed.
11
+
12
+ entity:
13
+ associated: true
14
+ schema:
15
+ src: ~
16
+ dst: ~
17
+ sample: ~
18
+
19
+ operations:
20
+ # a mass transition: the scope is inferred from the algorithm's `objects` parameter
21
+ merge:
22
+ concurrency: retry
23
+ input:
24
+ type: object
25
+ properties:
26
+ edges:
27
+ type: object
28
+ required: [edges]
29
+
30
+ # the map must not describe itself
31
+ introspection: false
32
+
33
+ exposition:
34
+ /:
35
+ auth:role: system:introspection
36
+
37
+ # the map is the whole document, and its shape is what the application happens to declare
38
+ io:output: true
39
+ cache:control: max-age=60, public
40
+ # the map is read whole: a page of ten is of no use to anything that draws it
41
+ GET:
42
+ endpoint: enumerate
43
+ query:
44
+ limit:
45
+ value: 10000
46
+ range: [1, 10000]
47
+ /:id:
48
+ GET: observe
@@ -0,0 +1,28 @@
1
+ export interface Source {
2
+ namespace?: string;
3
+ component?: string;
4
+ operation?: string;
5
+ event?: string;
6
+ service?: string;
7
+ }
8
+ export interface Target {
9
+ namespace: string;
10
+ component: string;
11
+ operation: string;
12
+ }
13
+ export interface Sample {
14
+ at: number;
15
+ input?: unknown;
16
+ outcome: string;
17
+ }
18
+ export interface Observed {
19
+ src: Source;
20
+ dst: Target;
21
+ sample?: Sample;
22
+ }
23
+ export interface Edge extends Observed {
24
+ id: string;
25
+ }
26
+ export interface Input {
27
+ edges: Record<string, Observed>;
28
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../source/lib/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import type { Edge, Input } from './lib/types';
2
+ /**
3
+ * Records the calls observed by a collector since its last flush.
4
+ *
5
+ * The scope is `objects`, so the caller passes every affected id in `query.ids`
6
+ * and the matching edge under `edges[id]`. Unknown edges are initialized by the
7
+ * runtime, since the entity is `associated`.
8
+ */
9
+ export declare function transition(input: Input, objects: Edge[]): Edge[];
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transition = void 0;
4
+ /**
5
+ * Records the calls observed by a collector since its last flush.
6
+ *
7
+ * The scope is `objects`, so the caller passes every affected id in `query.ids`
8
+ * and the matching edge under `edges[id]`. Unknown edges are initialized by the
9
+ * runtime, since the entity is `associated`.
10
+ */
11
+ function transition(input, objects) {
12
+ for (const edge of objects) {
13
+ const observed = input.edges[edge.id];
14
+ if (observed === undefined)
15
+ continue;
16
+ edge.src = observed.src;
17
+ edge.dst = observed.dst;
18
+ // absent when sampling is off, and the last one wins otherwise
19
+ if (observed.sample !== undefined)
20
+ edge.sample = observed.sample;
21
+ }
22
+ return objects;
23
+ }
24
+ exports.transition = transition;
25
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../source/merge.ts"],"names":[],"mappings":";;;AAEA;;;;;;GAMG;AACH,SAAgB,UAAU,CAAE,KAAY,EAAE,OAAe;IACvD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAErC,IAAI,QAAQ,KAAK,SAAS;YACxB,SAAQ;QAEV,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAA;QACvB,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAA;QAEvB,+DAA+D;QAC/D,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS;YAC/B,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAA;IACjC,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAhBD,gCAgBC"}
@@ -0,0 +1,33 @@
1
+ export interface Source {
2
+ namespace?: string
3
+ component?: string
4
+ operation?: string
5
+ event?: string
6
+ service?: string
7
+ }
8
+
9
+ export interface Target {
10
+ namespace: string
11
+ component: string
12
+ operation: string
13
+ }
14
+
15
+ export interface Sample {
16
+ at: number
17
+ input?: unknown
18
+ outcome: string
19
+ }
20
+
21
+ export interface Observed {
22
+ src: Source
23
+ dst: Target
24
+ sample?: Sample
25
+ }
26
+
27
+ export interface Edge extends Observed {
28
+ id: string
29
+ }
30
+
31
+ export interface Input {
32
+ edges: Record<string, Observed>
33
+ }
@@ -0,0 +1,26 @@
1
+ import type { Edge, Input } from './lib/types'
2
+
3
+ /**
4
+ * Records the calls observed by a collector since its last flush.
5
+ *
6
+ * The scope is `objects`, so the caller passes every affected id in `query.ids`
7
+ * and the matching edge under `edges[id]`. Unknown edges are initialized by the
8
+ * runtime, since the entity is `associated`.
9
+ */
10
+ export function transition (input: Input, objects: Edge[]): Edge[] {
11
+ for (const edge of objects) {
12
+ const observed = input.edges[edge.id]
13
+
14
+ if (observed === undefined)
15
+ continue
16
+
17
+ edge.src = observed.src
18
+ edge.dst = observed.dst
19
+
20
+ // absent when sampling is off, and the last one wins otherwise
21
+ if (observed.sample !== undefined)
22
+ edge.sample = observed.sample
23
+ }
24
+
25
+ return objects
26
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./operations"
5
+ },
6
+ "include": [
7
+ "source"
8
+ ]
9
+ }
@@ -0,0 +1,49 @@
1
+ namespace: introspection
2
+ name: nodes
3
+
4
+ # The static description of an application component: entity, operations, events, receivers.
5
+ # Every replica of a component announces the same id, thus `merge` is an upsert
6
+ # (`associated` initializes a missing object) and re-announcing refreshes `_updated`.
7
+
8
+ entity:
9
+ associated: true
10
+ schema:
11
+ namespace*: string
12
+ component*: string
13
+ version: string
14
+ entity: ~
15
+ operations: ~
16
+ events: ~
17
+ receivers: ~
18
+ extensions: ~
19
+
20
+ operations:
21
+ # a mass transition: the scope is inferred from the algorithm's `objects` parameter
22
+ merge:
23
+ concurrency: retry
24
+ input:
25
+ type: object
26
+ properties:
27
+ nodes:
28
+ type: object
29
+ required: [nodes]
30
+
31
+ # the map must not describe itself
32
+ introspection: false
33
+
34
+ exposition:
35
+ /:
36
+ auth:role: system:introspection
37
+
38
+ # the map is the whole document, and its shape is what the application happens to declare
39
+ io:output: true
40
+ cache:control: max-age=60, public
41
+ # the map is read whole: a page of ten is of no use to anything that draws it
42
+ GET:
43
+ endpoint: enumerate
44
+ query:
45
+ limit:
46
+ value: 1000
47
+ range: [1, 1000]
48
+ /:id:
49
+ GET: observe
@@ -0,0 +1,16 @@
1
+ export interface Described {
2
+ namespace: string;
3
+ component: string;
4
+ version?: string;
5
+ entity?: unknown;
6
+ operations?: unknown;
7
+ events?: unknown;
8
+ receivers?: unknown;
9
+ extensions?: unknown;
10
+ }
11
+ export interface Node extends Described {
12
+ id: string;
13
+ }
14
+ export interface Input {
15
+ nodes: Record<string, Described>;
16
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../source/lib/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import type { Input, Node } from './lib/types';
2
+ /**
3
+ * Records the components described by a collector since its last flush.
4
+ *
5
+ * The scope is `objects`, so the caller passes every affected id in `query.ids`
6
+ * and the matching description under `nodes[id]`. Unknown nodes are initialized
7
+ * by the runtime, since the entity is `associated`.
8
+ */
9
+ export declare function transition(input: Input, objects: Node[]): Node[];
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transition = void 0;
4
+ /**
5
+ * Records the components described by a collector since its last flush.
6
+ *
7
+ * The scope is `objects`, so the caller passes every affected id in `query.ids`
8
+ * and the matching description under `nodes[id]`. Unknown nodes are initialized
9
+ * by the runtime, since the entity is `associated`.
10
+ */
11
+ function transition(input, objects) {
12
+ for (const node of objects) {
13
+ const described = input.nodes[node.id];
14
+ if (described === undefined)
15
+ continue;
16
+ Object.assign(node, described);
17
+ }
18
+ return objects;
19
+ }
20
+ exports.transition = transition;
21
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../source/merge.ts"],"names":[],"mappings":";;;AAEA;;;;;;GAMG;AACH,SAAgB,UAAU,CAAE,KAAY,EAAE,OAAe;IACvD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAEtC,IAAI,SAAS,KAAK,SAAS;YACzB,SAAQ;QAEV,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;IAChC,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAXD,gCAWC"}
@@ -0,0 +1,18 @@
1
+ export interface Described {
2
+ namespace: string
3
+ component: string
4
+ version?: string
5
+ entity?: unknown
6
+ operations?: unknown
7
+ events?: unknown
8
+ receivers?: unknown
9
+ extensions?: unknown
10
+ }
11
+
12
+ export interface Node extends Described {
13
+ id: string
14
+ }
15
+
16
+ export interface Input {
17
+ nodes: Record<string, Described>
18
+ }
@@ -0,0 +1,21 @@
1
+ import type { Input, Node } from './lib/types'
2
+
3
+ /**
4
+ * Records the components described by a collector since its last flush.
5
+ *
6
+ * The scope is `objects`, so the caller passes every affected id in `query.ids`
7
+ * and the matching description under `nodes[id]`. Unknown nodes are initialized
8
+ * by the runtime, since the entity is `associated`.
9
+ */
10
+ export function transition (input: Input, objects: Node[]): Node[] {
11
+ for (const node of objects) {
12
+ const described = input.nodes[node.id]
13
+
14
+ if (described === undefined)
15
+ continue
16
+
17
+ Object.assign(node, described)
18
+ }
19
+
20
+ return objects
21
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./operations"
5
+ },
6
+ "include": [
7
+ "source"
8
+ ]
9
+ }
package/cucumber.js ADDED
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ default: {
3
+ paths: ['features/**/*.feature'],
4
+ requireModule: ['ts-node/register'],
5
+ require: ['./features/**/*.ts'],
6
+ failFast: true
7
+ }
8
+ }
@@ -0,0 +1,123 @@
1
+ Feature: Call edges
2
+
3
+ An edge is recorded by the component being called. The caller only declares who
4
+ it is, on the request, so a caller that runs no collector of its own — a service,
5
+ the CLI — still appears on the map. A local call and a remote one are the same.
6
+
7
+ The origin is what tells a direct call apart from the delivery of an event. Which
8
+ events exist and who receives them is declared, so it is a node's business; an
9
+ edge is what actually happened.
10
+
11
+ Scenario: A remote call
12
+ When the `probe.source.relay` is called with:
13
+ """yaml
14
+ input:
15
+ a: 2
16
+ b: 3
17
+ """
18
+ Then the map contains an edge:
19
+ """yaml
20
+ src:
21
+ namespace: probe
22
+ component: source
23
+ operation: relay
24
+ dst:
25
+ namespace: probe
26
+ component: target
27
+ operation: compute
28
+ """
29
+
30
+ Scenario: A call caused by an event
31
+ When the `probe.source.transit` is called with:
32
+ """yaml
33
+ query:
34
+ id: c0ffee00c0ffee00c0ffee00c0ffee00
35
+ input:
36
+ value: 1
37
+ """
38
+ Then the map contains an edge:
39
+ """yaml
40
+ src:
41
+ namespace: probe
42
+ component: source
43
+ event: created
44
+ dst:
45
+ namespace: probe
46
+ component: target
47
+ operation: count
48
+ """
49
+
50
+ Scenario: A call from a service
51
+ When the `probe.target.compute` is called with:
52
+ """yaml
53
+ input:
54
+ a: 1
55
+ b: 1
56
+ source:
57
+ service: cli
58
+ """
59
+ Then the map contains an edge:
60
+ """yaml
61
+ src:
62
+ service: cli
63
+ dst:
64
+ namespace: probe
65
+ component: target
66
+ operation: compute
67
+ """
68
+
69
+ Scenario: A call from an unidentified caller
70
+ When the `probe.target.compute` is called with:
71
+ """yaml
72
+ input:
73
+ a: 1
74
+ b: 1
75
+ """
76
+ Then the map contains an edge:
77
+ """yaml
78
+ src:
79
+ service: unknown
80
+ dst:
81
+ namespace: probe
82
+ component: target
83
+ operation: compute
84
+ """
85
+
86
+ Scenario: An operation returning an error is still an edge
87
+ When the `probe.source.fail` is called with:
88
+ """yaml
89
+ input: null
90
+ """
91
+ Then the map contains an edge:
92
+ """yaml
93
+ dst:
94
+ namespace: probe
95
+ component: source
96
+ operation: fail
97
+ """
98
+
99
+ Scenario: An operation throwing is still an edge
100
+ When the `probe.source.crash` is called with:
101
+ """yaml
102
+ input: null
103
+ """
104
+ Then the map contains an edge:
105
+ """yaml
106
+ dst:
107
+ namespace: probe
108
+ component: source
109
+ operation: crash
110
+ """
111
+
112
+ Scenario: An opted out component produces no edges
113
+ When the `probe.quiet.ping` is called with:
114
+ """yaml
115
+ input:
116
+ a: 1
117
+ """
118
+ Then the map contains no edge:
119
+ """yaml
120
+ dst:
121
+ namespace: probe
122
+ component: quiet
123
+ """
@@ -0,0 +1,70 @@
1
+ Feature: Component descriptions
2
+
3
+ The static half of the map: what each component is, taken from its manifest
4
+ when the composition starts. This is where the event graph lives — which events
5
+ a component publishes, and which event each of its receivers takes — since all
6
+ of it is declared, and none of it needs traffic to be true.
7
+
8
+ Scenario: Describing operations
9
+ Then the map contains a node:
10
+ """yaml
11
+ namespace: probe
12
+ component: target
13
+ operations:
14
+ - endpoint: compute
15
+ type: computation
16
+ scope: none
17
+ input:
18
+ type: object
19
+ properties:
20
+ a: { type: number }
21
+ b: { type: number }
22
+ output:
23
+ type: number
24
+ """
25
+
26
+ Scenario: Describing the entity
27
+ Then the map contains a node:
28
+ """yaml
29
+ namespace: probe
30
+ component: target
31
+ entity:
32
+ storage: "@toa.io/storages.null"
33
+ schema:
34
+ properties:
35
+ counted:
36
+ type: integer
37
+ """
38
+
39
+ Scenario: Describing events
40
+ Then the map contains a node:
41
+ """yaml
42
+ namespace: probe
43
+ component: source
44
+ events:
45
+ - label: created
46
+ - label: updated
47
+ - label: deleted
48
+ - label: sync
49
+ """
50
+
51
+ Scenario: Describing receivers
52
+ Then the map contains a node:
53
+ """yaml
54
+ namespace: probe
55
+ component: target
56
+ receivers:
57
+ - label: probe.source.created
58
+ source: probe.source
59
+ event: created
60
+ operation: count
61
+ conditioned: false
62
+ adaptive: false
63
+ """
64
+
65
+ Scenario: An opted out component is not described
66
+ Then the map contains no node:
67
+ """yaml
68
+ namespace: probe
69
+ component: quiet
70
+ """