@toa.io/definitions 1.0.0-alpha.292 → 1.0.0-alpha.294

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 (147) hide show
  1. package/digest/extensions.configuration.json +1 -1
  2. package/digest/extensions.exposition.json +1 -1
  3. package/package.json +24 -7
  4. package/readme.md +1 -0
  5. package/transpiled/bridges.node/exports.js +25 -2
  6. package/transpiled/bridges.node/exports.js.map +1 -1
  7. package/transpiled/digest/generate.js +23 -3
  8. package/transpiled/digest/generate.js.map +1 -1
  9. package/transpiled/digest/read.d.ts +8 -0
  10. package/transpiled/digest/read.js +11 -0
  11. package/transpiled/digest/read.js.map +1 -1
  12. package/transpiled/extensions.configuration/deployment.js +4 -2
  13. package/transpiled/extensions.configuration/deployment.js.map +1 -1
  14. package/transpiled/extensions.configuration/index.d.ts +1 -0
  15. package/transpiled/extensions.configuration/index.js +1 -0
  16. package/transpiled/extensions.configuration/index.js.map +1 -1
  17. package/transpiled/extensions.configuration/secrets.d.ts +4 -0
  18. package/transpiled/extensions.configuration/secrets.js +42 -0
  19. package/transpiled/extensions.configuration/secrets.js.map +1 -0
  20. package/transpiled/extensions.exposition/index.d.ts +1 -0
  21. package/transpiled/extensions.exposition/index.js +1 -0
  22. package/transpiled/extensions.exposition/index.js.map +1 -1
  23. package/transpiled/extensions.exposition/packages.d.ts +11 -0
  24. package/transpiled/extensions.exposition/packages.js +17 -0
  25. package/transpiled/extensions.exposition/packages.js.map +1 -0
  26. package/transpiled/extensions.storages/index.d.ts +1 -0
  27. package/transpiled/extensions.storages/index.js +1 -0
  28. package/transpiled/extensions.storages/index.js.map +1 -1
  29. package/transpiled/extensions.storages/packages.d.ts +19 -0
  30. package/transpiled/extensions.storages/packages.js +41 -0
  31. package/transpiled/extensions.storages/packages.js.map +1 -0
  32. package/CHANGELOG.md +0 -13
  33. package/source/bindings.amqp/annotation.ts +0 -26
  34. package/source/bindings.amqp/context.ts +0 -68
  35. package/source/bindings.amqp/deployment.ts +0 -14
  36. package/source/bindings.amqp/index.ts +0 -9
  37. package/source/bindings.amqp/instance.ts +0 -3
  38. package/source/bindings.amqp/sources.ts +0 -39
  39. package/source/bindings.loop/index.ts +0 -3
  40. package/source/bridges.bash/const.ts +0 -2
  41. package/source/bridges.bash/define.ts +0 -38
  42. package/source/bridges.bash/index.ts +0 -2
  43. package/source/bridges.node/define.ts +0 -69
  44. package/source/bridges.node/exports.ts +0 -175
  45. package/source/bridges.node/index.ts +0 -6
  46. package/source/bridges.node/operations.ts +0 -127
  47. package/source/bridges.node/sources.ts +0 -44
  48. package/source/definition.ts +0 -38
  49. package/source/digest/generate.ts +0 -77
  50. package/source/digest/read.ts +0 -39
  51. package/source/extensions.cadence/components.ts +0 -6
  52. package/source/extensions.cadence/const.ts +0 -31
  53. package/source/extensions.cadence/context.ts +0 -10
  54. package/source/extensions.cadence/deployment.ts +0 -37
  55. package/source/extensions.cadence/index.ts +0 -8
  56. package/source/extensions.cadence/manifest.ts +0 -64
  57. package/source/extensions.cadence/schemas.ts +0 -10
  58. package/source/extensions.cadence/types.ts +0 -41
  59. package/source/extensions.configuration/components.ts +0 -6
  60. package/source/extensions.configuration/const.ts +0 -30
  61. package/source/extensions.configuration/context.ts +0 -13
  62. package/source/extensions.configuration/deployment.ts +0 -159
  63. package/source/extensions.configuration/epoch.ts +0 -22
  64. package/source/extensions.configuration/index.ts +0 -10
  65. package/source/extensions.configuration/manifest.ts +0 -12
  66. package/source/extensions.configuration/schemas.ts +0 -9
  67. package/source/extensions.exposition/Annotation.ts +0 -91
  68. package/source/extensions.exposition/components.ts +0 -6
  69. package/source/extensions.exposition/const.ts +0 -45
  70. package/source/extensions.exposition/deployment.ts +0 -95
  71. package/source/extensions.exposition/index.ts +0 -16
  72. package/source/extensions.exposition/manifest.ts +0 -56
  73. package/source/extensions.exposition/schemas.ts +0 -16
  74. package/source/extensions.exposition/shortcuts.ts +0 -14
  75. package/source/extensions.exposition/syntax/index.ts +0 -2
  76. package/source/extensions.exposition/syntax/parse.ts +0 -171
  77. package/source/extensions.exposition/syntax/types.ts +0 -69
  78. package/source/extensions.fetch/context.ts +0 -10
  79. package/source/extensions.fetch/index.ts +0 -1
  80. package/source/extensions.introspection/annotation.ts +0 -87
  81. package/source/extensions.introspection/components.ts +0 -13
  82. package/source/extensions.introspection/const.ts +0 -46
  83. package/source/extensions.introspection/deployment.ts +0 -48
  84. package/source/extensions.introspection/index.ts +0 -6
  85. package/source/extensions.introspection/manifest.ts +0 -18
  86. package/source/extensions.introspection/schemas.ts +0 -12
  87. package/source/extensions.realtime/components.ts +0 -5
  88. package/source/extensions.realtime/deployment.ts +0 -89
  89. package/source/extensions.realtime/index.ts +0 -4
  90. package/source/extensions.stash/context.ts +0 -10
  91. package/source/extensions.stash/deployment.ts +0 -22
  92. package/source/extensions.stash/index.ts +0 -2
  93. package/source/extensions.state/context.ts +0 -9
  94. package/source/extensions.state/index.ts +0 -1
  95. package/source/extensions.storages/Annotation.ts +0 -57
  96. package/source/extensions.storages/context.ts +0 -14
  97. package/source/extensions.storages/deployment.ts +0 -91
  98. package/source/extensions.storages/index.ts +0 -9
  99. package/source/extensions.storages/manifest.ts +0 -7
  100. package/source/extensions.storages/schemas.ts +0 -15
  101. package/source/extensions.storages/secrets.ts +0 -22
  102. package/source/extensions.telemetry/const.ts +0 -6
  103. package/source/extensions.telemetry/context.ts +0 -11
  104. package/source/extensions.telemetry/deployment.ts +0 -91
  105. package/source/extensions.telemetry/index.ts +0 -5
  106. package/source/extensions.telemetry/ready.ts +0 -33
  107. package/source/index.ts +0 -2
  108. package/source/storages.mongodb/deployment.ts +0 -22
  109. package/source/storages.mongodb/index.ts +0 -1
  110. package/source/version.ts +0 -10
  111. package/transpiled/bindings.amqp/annotation.test.d.ts +0 -1
  112. package/transpiled/bindings.amqp/annotation.test.js +0 -36
  113. package/transpiled/bindings.amqp/annotation.test.js.map +0 -1
  114. package/transpiled/bindings.amqp/properties.test.d.ts +0 -1
  115. package/transpiled/bindings.amqp/properties.test.js +0 -7
  116. package/transpiled/bindings.amqp/properties.test.js.map +0 -1
  117. package/transpiled/bindings.loop/properties.test.d.ts +0 -1
  118. package/transpiled/bindings.loop/properties.test.js +0 -7
  119. package/transpiled/bindings.loop/properties.test.js.map +0 -1
  120. package/transpiled/bridges.node/exports.test.d.ts +0 -1
  121. package/transpiled/bridges.node/exports.test.js +0 -88
  122. package/transpiled/bridges.node/exports.test.js.map +0 -1
  123. package/transpiled/bridges.node/operations.test.d.ts +0 -1
  124. package/transpiled/bridges.node/operations.test.js +0 -108
  125. package/transpiled/bridges.node/operations.test.js.map +0 -1
  126. package/transpiled/extensions.cadence/manifest.test.d.ts +0 -1
  127. package/transpiled/extensions.cadence/manifest.test.js +0 -41
  128. package/transpiled/extensions.cadence/manifest.test.js.map +0 -1
  129. package/transpiled/extensions.configuration/deployment.test.d.ts +0 -1
  130. package/transpiled/extensions.configuration/deployment.test.js +0 -74
  131. package/transpiled/extensions.configuration/deployment.test.js.map +0 -1
  132. package/transpiled/extensions.configuration/manifest.test.d.ts +0 -1
  133. package/transpiled/extensions.configuration/manifest.test.js +0 -14
  134. package/transpiled/extensions.configuration/manifest.test.js.map +0 -1
  135. package/transpiled/extensions.exposition/manifest.test.d.ts +0 -1
  136. package/transpiled/extensions.exposition/manifest.test.js +0 -38
  137. package/transpiled/extensions.exposition/manifest.test.js.map +0 -1
  138. package/transpiled/extensions.exposition/schemas.test.d.ts +0 -1
  139. package/transpiled/extensions.exposition/schemas.test.js +0 -22
  140. package/transpiled/extensions.exposition/schemas.test.js.map +0 -1
  141. package/transpiled/extensions.exposition/syntax/parse.test.d.ts +0 -1
  142. package/transpiled/extensions.exposition/syntax/parse.test.js +0 -156
  143. package/transpiled/extensions.exposition/syntax/parse.test.js.map +0 -1
  144. package/transpiled/extensions.storages/schemas.test.d.ts +0 -1
  145. package/transpiled/extensions.storages/schemas.test.js +0 -59
  146. package/transpiled/extensions.storages/schemas.test.js.map +0 -1
  147. package/tsconfig.json +0 -10
@@ -1,95 +0,0 @@
1
- import assert from 'node:assert'
2
- import { type Dependency, type Service } from '@toa.io/operations'
3
- import { type Annotation } from './Annotation.js'
4
- import * as schemas from './schemas.js'
5
- import { shortcuts } from './shortcuts.js'
6
- import { components } from './components.js'
7
- import { parse } from './syntax/index.js'
8
- import { DELAY, PORT, PROBE } from './const.js'
9
- import { version } from '../version.js'
10
-
11
- /** Where Toa's release publishes this service's image. An application takes it
12
- * instead of building one when its context says `registry.services: published`. */
13
- export const image = 'ghcr.io/toa-io/extension-exposition-gateway'
14
-
15
- export function deployment(_: unknown, annotation?: Annotation): Dependency {
16
- assert.ok(annotation !== undefined, 'Exposition context annotation is required')
17
- schemas.annotation.validate(annotation)
18
-
19
- const labels = components().labels
20
-
21
- const service: Service = {
22
- group: 'exposition',
23
- name: 'gateway',
24
- image,
25
- port: PORT,
26
- version,
27
- variables: [],
28
- components: labels,
29
- resources: annotation.resources,
30
- ingress: { path: '/', hosts: [] },
31
- probe: {
32
- path: '/.ready',
33
- port: PROBE,
34
- delay: DELAY
35
- }
36
- }
37
-
38
- if (annotation?.['/'] !== undefined) {
39
- const tree = parse(annotation['/'], shortcuts)
40
-
41
- service.variables!.push({
42
- name: 'TOA_EXPOSITION',
43
- value: JSON.stringify(tree)
44
- })
45
- }
46
-
47
- const { debug, authorities } = annotation
48
-
49
- service.ingress!.hosts = Object.values(authorities)
50
-
51
- // leaving these undefined lets the context's own ingress section supply them
52
- if (annotation.class !== undefined) service.ingress!.class = annotation.class
53
-
54
- if (annotation.annotations !== undefined)
55
- service.ingress!.annotations = annotation.annotations
56
-
57
- if (annotation.service?.annotations !== undefined)
58
- service.annotations = annotation.service.annotations
59
-
60
- const properties: Properties = { authorities }
61
-
62
- if (debug === true) properties.debug = true
63
-
64
- if (annotation.protocol !== undefined) properties.protocol = annotation.protocol
65
-
66
- if (annotation.ip !== undefined) properties.ip = annotation.ip
67
-
68
- if (annotation.bouncer !== undefined) properties.bouncer = annotation.bouncer
69
-
70
- if (annotation.oauth !== undefined) properties.oauth = annotation.oauth
71
-
72
- if (annotation.rpc !== undefined) properties.rpc = annotation.rpc
73
-
74
- if (annotation.mcp !== undefined) properties.mcp = annotation.mcp
75
-
76
- service.variables!.push({
77
- name: 'TOA_EXPOSITION_PROPERTIES',
78
- value: JSON.stringify(properties)
79
- })
80
-
81
- // The identity composition nested in this process connects before route discovery settles,
82
- // so telemetry's probe — which tracks that composition — would report ready too early.
83
- // The gateway answers for itself, on the same port telemetry would have used.
84
- service.variables!.push({
85
- name: 'TOA_TELEMETRY_READY',
86
- value: JSON.stringify(false)
87
- })
88
-
89
- return { services: [service] }
90
- }
91
-
92
- type Properties = Pick<
93
- Annotation,
94
- 'authorities' | 'debug' | 'protocol' | 'bouncer' | 'ip' | 'oauth' | 'rpc' | 'mcp'
95
- >
@@ -1,16 +0,0 @@
1
- export { manifest } from './manifest.js'
2
- export { components } from './components.js'
3
- export { deployment, image } from './deployment.js'
4
- export { shortcuts } from './shortcuts.js'
5
- export * from './const.js'
6
- export * as schemas from './schemas.js'
7
- export * as syntax from './syntax/index.js'
8
-
9
- export type {
10
- Annotation,
11
- Bouncer,
12
- MCP as MCPAnnotation,
13
- OAuth,
14
- Protocol,
15
- RPC as RPCAnnotation
16
- } from './Annotation.js'
@@ -1,56 +0,0 @@
1
- import assert from 'node:assert'
2
- import { parse, type Node, type Method, type Query } from './syntax/index.js'
3
- import { shortcuts } from './shortcuts.js'
4
- import * as schemas from './schemas.js'
5
- import type { Manifest } from '@toa.io/norm'
6
-
7
- export function manifest(declaration: object, manifest: Manifest): Node {
8
- assert.ok(
9
- typeof declaration === 'object' && declaration !== null,
10
- 'Exposition declaration must be an object'
11
- )
12
-
13
- declaration = wrap(declaration, manifest.namespace, manifest.name)
14
-
15
- const node = parse(declaration, shortcuts)
16
-
17
- specify(node, manifest)
18
- schemas.node.validate(node)
19
-
20
- return node
21
- }
22
-
23
- function wrap(declaration: object, namespace: string, name: string): object {
24
- const path =
25
- (namespace === undefined || namespace === 'default' ? '' : '/' + namespace) +
26
- '/' +
27
- name
28
-
29
- return { [path]: declaration }
30
- }
31
-
32
- function specify(node: Node, manifest: Manifest): void {
33
- for (const route of node.routes) {
34
- for (const method of route.node.methods) specifyMethod(method, manifest)
35
-
36
- specify(route.node, manifest)
37
- }
38
- }
39
-
40
- function specifyMethod(method: Method, manifest: Manifest): void {
41
- if (method.mapping?.endpoint === undefined) return
42
-
43
- const operation = manifest.operations[method.mapping.endpoint]
44
-
45
- assert.ok(operation !== undefined, `Operation '${method.mapping.endpoint}' not found`)
46
-
47
- if (method.mapping.query === undefined)
48
- method.mapping.query = operation.query === false ? null : ({} as unknown as Query)
49
-
50
- // a page is taken of a collection, and of nothing else: an operation that answers one object
51
- // takes no `omit` and no `limit`, and refuses a request that carries them
52
- method.mapping.paged = operation.type === 'observation' && operation.scope === 'objects'
53
-
54
- method.mapping.namespace = manifest.namespace
55
- method.mapping.component = manifest.name
56
- }
@@ -1,16 +0,0 @@
1
- import { resolve } from 'node:path'
2
- import * as schemas from '@toa.io/schemas'
3
- import type { Schema } from '@toa.io/schemas'
4
- import type { Node } from './syntax/types.js'
5
- import type { Annotation } from './Annotation.js'
6
-
7
- const path = resolve(import.meta.dirname, '../../schemas/extensions.exposition')
8
- const namespace = schemas.namespace(path)
9
-
10
- // what the gateway validates a request by, kept beside what a manifest is validated by
11
- export const querystring: Schema<Record<string, unknown>> =
12
- namespace.schema('querystring')
13
- export const call: Schema<Record<string, unknown>> = namespace.schema('call')
14
-
15
- export const annotation: Schema<Annotation> = namespace.schema('annotation')
16
- export const node: Schema<Node> = namespace.schema('node')
@@ -1,14 +0,0 @@
1
- import type { Shortcuts } from './syntax/index.js'
2
-
3
- /** What a directive may be written as, where the family is implied. */
4
- export const shortcuts: Shortcuts = new Map([
5
- ['anonymous', 'auth:anonymous'],
6
- ['anyone', 'auth:anyone'],
7
- ['id', 'auth:id'],
8
- ['role', 'auth:role'],
9
- ['rule', 'auth:rule'],
10
- ['incept', 'auth:incept'],
11
- ['input', 'io:input'],
12
- ['output', 'io:output'],
13
- ['languages', 'map:languages']
14
- ])
@@ -1,2 +0,0 @@
1
- export * from './parse.js'
2
- export * from './types.js'
@@ -1,171 +0,0 @@
1
- import * as schemas from '../schemas.js'
2
- import {
3
- verbs,
4
- type Node,
5
- type Route,
6
- type Method,
7
- type Mapping,
8
- type Directive,
9
- type Range
10
- } from './types.js'
11
-
12
- export function parse(input: object, shortcuts?: Shortcuts): Node {
13
- const node = parseNode(input, shortcuts)
14
-
15
- schemas.node.validate(node)
16
-
17
- return node
18
- }
19
-
20
- function parseNode(input: object | string, shortcuts?: Shortcuts): Node {
21
- const node = createNode()
22
-
23
- if (typeof input === 'string') {
24
- node.forward = input
25
-
26
- return node
27
- }
28
-
29
- for (const [key, value] of Object.entries(input) as Array<[keyof Node, unknown]>)
30
- switch (key) {
31
- case 'protected':
32
- case 'isolated':
33
- node[key] = value as boolean
34
- break
35
- case 'forward':
36
- node[key] = value as string
37
- break
38
-
39
- default:
40
- // eslint-disable-next-line max-depth
41
- if (key[0] === '/') {
42
- const route = parseRoute(key, value as Node, shortcuts)
43
-
44
- node.routes.push(route)
45
-
46
- continue
47
- }
48
-
49
- // eslint-disable-next-line max-depth
50
- if (verbs.has(key)) {
51
- const method = parseMethod(key, value as Mapping, shortcuts)
52
-
53
- node.methods.push(method)
54
-
55
- continue
56
- }
57
-
58
- // eslint-disable-next-line no-case-declarations
59
- const directive = parseDirective(key, value, shortcuts)
60
-
61
- // eslint-disable-next-line max-depth
62
- if (directive !== null) {
63
- node.directives.push(directive)
64
-
65
- continue
66
- }
67
-
68
- throw new Error(`RTD parse error: unknown key '${key}'`)
69
- }
70
-
71
- return node
72
- }
73
-
74
- export function createNode(): Node {
75
- return {
76
- routes: [],
77
- methods: [],
78
- directives: []
79
- }
80
- }
81
-
82
- function parseRoute(path: string, value: Node, shortcuts?: Shortcuts): Route {
83
- const node = parse(value, shortcuts)
84
-
85
- return createRoute(path, node)
86
- }
87
-
88
- function createRoute(path: string, node: Node): Route {
89
- return { path, node }
90
- }
91
-
92
- function parseMethod(
93
- verb: string,
94
- value: Mapping | string,
95
- shortcuts?: Shortcuts
96
- ): Method {
97
- const mapping = typeof value === 'string' ? { endpoint: value } : value
98
-
99
- parseEndpoint(mapping)
100
- parseQuery(mapping)
101
-
102
- const directives = parseDirectives(mapping, shortcuts)
103
-
104
- return { verb, mapping, directives }
105
- }
106
-
107
- function parseEndpoint(mapping: Mapping): void {
108
- if (mapping.endpoint === undefined) return
109
-
110
- const [endpoiont, component, namespace] = mapping.endpoint.split('.').reverse()
111
-
112
- if (component !== undefined) {
113
- mapping.component = component
114
- mapping.namespace = namespace ?? mapping.namespace ?? 'default'
115
- mapping.endpoint = endpoiont
116
- }
117
- }
118
-
119
- function parseQuery(mapping: any): void {
120
- const query = mapping.query
121
-
122
- if (query === undefined || query === null) return
123
-
124
- if (typeof query.limit === 'number') query.limit = expandRange(query.limit as number)
125
-
126
- if (typeof query.omit === 'number') query.omit = expandRange(query.omit as number)
127
- }
128
-
129
- function parseDirectives(
130
- mapping: Record<string, any>,
131
- shortcuts?: Shortcuts
132
- ): Directive[] {
133
- const directives: Directive[] = []
134
-
135
- for (const [key, value] of Object.entries(mapping)) {
136
- const directive = parseDirective(key, value, shortcuts)
137
-
138
- if (directive === null) continue
139
-
140
- directives.push(directive)
141
-
142
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
143
- delete mapping[key]
144
- }
145
-
146
- return directives
147
- }
148
-
149
- function parseDirective(
150
- key: string,
151
- value: any,
152
- shortcuts?: Shortcuts
153
- ): Directive | null {
154
- if (shortcuts?.has(key) === true) key = shortcuts.get(key)! // eslint-disable-line @typescript-eslint/no-non-null-assertion
155
-
156
- const match = key.match(DIRECTIVE_RX)
157
-
158
- if (match === null) return null
159
-
160
- const { family, name } = match.groups as { family: string; name: string }
161
-
162
- return { family, name, value }
163
- }
164
-
165
- function expandRange(range: number): Range {
166
- return { value: range, range: [range, range] }
167
- }
168
-
169
- const DIRECTIVE_RX = /^(?<family>\w{1,32}):(?<name>\w{1,32})$/
170
-
171
- export type Shortcuts = Map<string, string>
@@ -1,69 +0,0 @@
1
- export interface Node {
2
- protected?: boolean
3
- isolated?: boolean
4
- forward?: string
5
- routes: Route[]
6
- methods: Method[]
7
- directives: Directive[]
8
- }
9
-
10
- export interface Route {
11
- path: string
12
- node: Node
13
- }
14
-
15
- export interface Method {
16
- verb: string
17
- mapping?: Mapping
18
- directives: Directive[]
19
- }
20
-
21
- export interface Directive {
22
- family: string
23
- name: string
24
- value: any
25
- }
26
-
27
- export interface Mapping {
28
- namespace?: string
29
- component?: string
30
- endpoint: string
31
- query?: Query | null
32
-
33
- /**
34
- * Whether the operation this maps to answers a page of a collection, and so takes the
35
- * `omit` and `limit` a page is taken by. Written where the component's manifest is read,
36
- * beside `namespace` and `component`, and not declared.
37
- */
38
- paged?: boolean
39
- }
40
-
41
- export interface Query {
42
- id?: string
43
- criteria?: string
44
- search?: boolean
45
- sample?: number
46
- sort?: string
47
- omit?: Range
48
- limit?: Range
49
- selectors?: string[]
50
- projection?: string[]
51
- parameters?: string[]
52
- deleted?: boolean
53
- }
54
-
55
- export interface Range {
56
- value?: number
57
- range: [number, number]
58
- }
59
-
60
- export const verbs = new Set<string>([
61
- 'GET',
62
- 'HEAD',
63
- 'POST',
64
- 'PUT',
65
- 'PATCH',
66
- 'DELETE',
67
- 'LOCK',
68
- 'UNLOCK'
69
- ])
@@ -1,10 +0,0 @@
1
- import type { Contribution } from '@toa.io/core/types'
2
-
3
- /** What this extension puts on the context of every component, being declared for all. */
4
- export function context(): Contribution {
5
- return {
6
- name: 'fetch',
7
- type: '(input: string | URL | Request, init?: FetchInit) => Promise<Response>',
8
- imports: { '@toa.io/extensions.fetch': ['FetchInit'] }
9
- }
10
- }
@@ -1 +0,0 @@
1
- export { context } from './context.js'
@@ -1,87 +0,0 @@
1
- import { DEFAULT_INTERVAL, DEFAULT_THRESHOLD, DENIED, ENV } from './const.js'
2
- import { environment as variables } from '@toa.io/generic'
3
- import type { Resources } from '@toa.io/operations'
4
-
5
- /** `context.toa.yaml` */
6
- export type Annotation =
7
- | false
8
- | {
9
- /** Capture real payloads. Off by default: this is production data. */
10
- samples?: boolean
11
- /** Flush period, seconds. */
12
- interval?: number
13
- /** Flush as soon as this many distinct edges are buffered. */
14
- threshold?: number
15
- /** Publish the UI. On by default. */
16
- ui?: boolean
17
- resources?: Resources
18
- }
19
-
20
- /** `manifest.toa.yaml` */
21
- export type Declaration =
22
- | false
23
- | {
24
- samples?: boolean
25
- }
26
-
27
- /** What `deployment()` encodes into the environment. */
28
- export interface Options {
29
- samples: boolean
30
- interval: number
31
- threshold: number
32
- ui: boolean
33
- }
34
-
35
- /** The effective per-component decision. */
36
- export interface Settings {
37
- enabled: boolean
38
- samples: boolean
39
- }
40
-
41
- export const DISABLED: Settings = { enabled: false, samples: false }
42
-
43
- export function options(annotation?: Annotation): Options {
44
- const declaration = annotation === undefined || annotation === false ? {} : annotation
45
-
46
- return {
47
- samples: declaration.samples === true,
48
- interval: declaration.interval ?? DEFAULT_INTERVAL,
49
- threshold: declaration.threshold ?? DEFAULT_THRESHOLD,
50
- ui: declaration.ui !== false
51
- }
52
- }
53
-
54
- /** Reads what `deployment()` has put into the environment. */
55
- export function environment(): Options | null {
56
- const value = variables.get(ENV)
57
-
58
- if (value === undefined) return null
59
-
60
- return JSON.parse(value) as Options
61
- }
62
-
63
- export function component(declaration: Declaration | null | undefined): Declaration {
64
- if (declaration === false) return false
65
-
66
- // predefined extensions arrive as null for components that say nothing
67
- if (declaration === null || declaration === undefined) return {}
68
-
69
- return declaration.samples === undefined ? {} : { samples: declaration.samples }
70
- }
71
-
72
- /**
73
- * Both levels must agree, and either can veto: the context is the environment
74
- * ceiling, the manifest is the component's own call. A component handling
75
- * personal data opts out for good, and no context flag overrides that.
76
- */
77
- export function settings(
78
- namespace: string,
79
- declaration: Declaration,
80
- opts: Options | null
81
- ): Settings {
82
- if (opts === null || declaration === false) return DISABLED
83
-
84
- const samples = opts.samples && declaration.samples !== false && !DENIED.has(namespace)
85
-
86
- return { enabled: true, samples }
87
- }
@@ -1,13 +0,0 @@
1
- import { components as digest, type Components } from '../digest/read.js'
2
- import type { Annotation } from './annotation.js'
3
-
4
- /**
5
- * The extension is predefined, so an application that turns introspection off
6
- * must not end up with the explorer components — nor with the exposition
7
- * dependency they bring in.
8
- */
9
- export function components(annotation?: Annotation): Components {
10
- if (annotation === false) return { labels: [], manifests: [] }
11
-
12
- return digest('extensions.introspection')
13
- }
@@ -1,46 +0,0 @@
1
- import { environment } from '@toa.io/generic'
2
-
3
- export const ID = 'introspection'
4
- export const NAMESPACE = 'introspection'
5
-
6
- export const ENV = 'TOA_INTROSPECTION'
7
-
8
- export const NODES = 'nodes'
9
- export const EDGES = 'edges'
10
-
11
- /** Where the UI is mounted; `/introspection/*` belongs to the components' own API. */
12
- export const UI_PATH = '/.introspection'
13
- export const UI_PORT = 8002
14
-
15
- /**
16
- * The port the UI is served on. `UI_PORT` is what a deployment publishes and what the chart
17
- * renders; the variable is for a machine that runs more than one Toa process — a Toa checkout
18
- * beside an application, or two applications — where one of them has to give it up.
19
- */
20
- export const UI_PORT_ENV = 'TOA_INTROSPECTION_UI_PORT'
21
- export function uiPort(): number {
22
- const value = environment.get(UI_PORT_ENV)
23
-
24
- return value === undefined ? UI_PORT : Number(value)
25
- }
26
-
27
- export const DEFAULT_INTERVAL = 300
28
- export const DEFAULT_THRESHOLD = 1024
29
-
30
- /** How often a component re-announces its description, so that removed components fade out. */
31
- export const ANNOUNCE_INTERVAL = 1_800_000
32
-
33
- /**
34
- * `source` arrives over the wire, so the number of distinct edges a process
35
- * can hold must be bounded regardless of what peers send.
36
- */
37
- export const MAX_EDGES = 4096
38
-
39
- /** Never capture samples for these namespaces, whatever the annotation says. */
40
- export const DENIED = new Set(['identity', 'introspection'])
41
-
42
- /** Keys never stored in a sample, even when sampling is on. */
43
- export const REDACTED = /^(password|secret|token|credentials?|key|authorization|cookie)$/i
44
-
45
- /** Serialized size cap of a single sample. */
46
- export const SAMPLE_LIMIT = 4096
@@ -1,48 +0,0 @@
1
- import { options } from './annotation.js'
2
- import { components } from './components.js'
3
- import { version } from '../version.js'
4
- import { ENV, UI_PATH, UI_PORT } from './const.js'
5
- import * as schemas from './schemas.js'
6
- import type { Annotation } from './annotation.js'
7
- import type { Dependency, Instances, Service } from '@toa.io/operations'
8
-
9
- /** Where Toa's release publishes this service's image. An application takes it
10
- * instead of building one when its context says `registry.services: published`. */
11
- export const image = 'ghcr.io/toa-io/extension-introspection-explorer'
12
-
13
- export const standalone = true
14
-
15
- /**
16
- * The explorer hosts the introspection components, exactly as the exposition
17
- * gateway hosts the identity ones. Collection is on unless the context says
18
- * `introspection: false`, and the environment variable is emitted together
19
- * with the service — never on its own, or tasks would pile up in a queue
20
- * nothing consumes.
21
- */
22
- export function deployment(_: Instances<unknown>, annotation?: Annotation): Dependency {
23
- if (annotation === false) return {}
24
-
25
- if (annotation !== undefined) schemas.annotation.validate(annotation)
26
-
27
- const opts = options(annotation)
28
-
29
- const service: Service = {
30
- group: 'introspection',
31
- name: 'explorer',
32
- image,
33
- version,
34
- components: components().labels,
35
- resources: annotation?.resources,
36
- variables: []
37
- }
38
-
39
- if (opts.ui) {
40
- service.port = UI_PORT
41
- service.ingress = { path: UI_PATH }
42
- }
43
-
44
- return {
45
- services: [service],
46
- variables: { global: [{ name: ENV, value: JSON.stringify(opts) }] }
47
- }
48
- }
@@ -1,6 +0,0 @@
1
- export { manifest } from './manifest.js'
2
- export { components } from './components.js'
3
- export { deployment, image, standalone } from './deployment.js'
4
- export * from './annotation.js'
5
- export * from './const.js'
6
- export * as schemas from './schemas.js'
@@ -1,18 +0,0 @@
1
- import { component } from './annotation.js'
2
- import * as schemas from './schemas.js'
3
- import type { Declaration } from './annotation.js'
4
-
5
- /**
6
- * The component level of the annotation.
7
- *
8
- * The extension is predefined, so most components say nothing and the
9
- * declaration arrives as `null` — which still has to produce a value,
10
- * or norm rejects the extension.
11
- */
12
- export function manifest(declaration: Declaration | null | undefined): Declaration {
13
- const normalized = component(declaration)
14
-
15
- if (normalized !== false) schemas.declaration.validate(normalized)
16
-
17
- return normalized
18
- }