@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,39 +0,0 @@
1
- import { readFileSync } from 'node:fs'
2
- import { resolve } from 'node:path'
3
-
4
- /**
5
- * The components an extension ships, as the digest of their manifests generated when this
6
- * package was built. A deploy reads them from here, because the extension is not installed
7
- * beside it; a running service reads them from the extension, where their code is.
8
- */
9
- export function components(suffix: string, filter?: (label: string) => boolean): Components {
10
- const manifests = digest(suffix).filter((manifest) => filter?.(manifest.label) ?? true)
11
-
12
- return {
13
- labels: manifests.map((manifest) => manifest.label),
14
- manifests: manifests.map((manifest) => structuredClone(manifest.manifest))
15
- }
16
- }
17
-
18
- function digest(suffix: string): Entry[] {
19
- cache[suffix] ??= JSON.parse(readFileSync(resolve(ROOT, suffix + '.json'), 'utf8'))
20
-
21
- return cache[suffix]
22
- }
23
-
24
- const cache: Record<string, Entry[]> = {}
25
-
26
- /** `transpiled/digest/read.js` → `digest/` */
27
- const ROOT = resolve(import.meta.dirname, '../../digest')
28
-
29
- export interface Components {
30
- /** what a chart names each component's workload by: `identity-basic` */
31
- labels: string[]
32
- /** the manifests as norm reads them, with `path` as a package-relative specifier */
33
- manifests: object[]
34
- }
35
-
36
- export interface Entry {
37
- label: string
38
- manifest: object
39
- }
@@ -1,6 +0,0 @@
1
- import { components as digest, type Components } from '../digest/read.js'
2
-
3
- /** The components this extension ships, which run inside its own service. */
4
- export function components(): Components {
5
- return digest('extensions.cadence')
6
- }
@@ -1,31 +0,0 @@
1
- import { environment } from '@toa.io/generic'
2
-
3
- /** The component the extension ships to hold delayed calls. */
4
- export const NAMESPACE = 'cadence'
5
- export const COMPONENT = 'metronome'
6
-
7
- /**
8
- * Constant, never configuration: a row carries its lane, so lowering this would leave rows in
9
- * lanes nobody reads any more. It is also the ceiling on replicas dispatching, and a power of
10
- * two so that the common replica counts divide evenly. The outbox says the same of its own.
11
- *
12
- * A scan asks for its lanes as a set and sorts on `due`, which is the index's second key, so
13
- * the plan that serves it explodes the set into one scan per lane and merges them in order.
14
- * MongoDB stops exploding past `internalQueryMaxScansToExplode`, 200 by default, and falls
15
- * back to sorting the whole result in memory — so this staying well under that is not
16
- * incidental.
17
- */
18
- export const LANES = 128
19
-
20
- /** seconds between passes over the calls waiting to be made, and how far ahead each reaches */
21
- export const DISCRETENESS = 60
22
-
23
- /** rows one scan brings back */
24
- export const BATCH = 200
25
-
26
- /** A number from the environment, where a deployment or a test suite states one. */
27
- export function number(variable: string, fallback: number): number {
28
- const value = Number(environment.get(variable))
29
-
30
- return Number.isNaN(value) || value <= 0 ? fallback : value
31
- }
@@ -1,10 +0,0 @@
1
- import type { Contribution } from '@toa.io/core/types'
2
-
3
- /** What this extension puts on the context of a component that declares it. */
4
- export function context(): Contribution {
5
- return {
6
- name: 'delay',
7
- type: 'Delay',
8
- imports: { '@toa.io/extensions.cadence': ['Delay'] }
9
- }
10
- }
@@ -1,37 +0,0 @@
1
- import { components } from './components.js'
2
- import { version } from '../version.js'
3
- import { DISCRETENESS, NAMESPACE } from './const.js'
4
- import * as schemas from './schemas.js'
5
- import type { Annotation } from './types.js'
6
- import type { Dependency, Service, Variable } from '@toa.io/operations'
7
-
8
- /**
9
- * The component that keeps delayed calls runs in a service of its own, the way the identity
10
- * components run in the gateway. A composition may claim it and run it in its own pods instead.
11
- */
12
- export function deployment(_: unknown, annotation?: Annotation | null): Dependency {
13
- schemas.annotation.validate<Annotation | null>(
14
- annotation ?? null,
15
- 'Invalid cadence annotation'
16
- )
17
-
18
- // stated in seconds and carried in milliseconds, so that what an application writes is what
19
- // the rest of a manifest is written in
20
- const discreteness = (annotation?.discreteness ?? DISCRETENESS) * 1000
21
- const variables: Variable[] = [
22
- { name: 'TOA_CADENCE_DISCRETENESS', value: String(discreteness) }
23
- ]
24
-
25
- const service: Service = {
26
- group: NAMESPACE,
27
- name: 'metronome',
28
- version,
29
- components: components().labels,
30
- variables
31
- }
32
-
33
- return { services: [service] }
34
- }
35
-
36
- /** The extension is deployed for the sake of `delay`, which nothing has to declare to use. */
37
- export const standalone = true
@@ -1,8 +0,0 @@
1
- export { manifest } from './manifest.js'
2
- export { components } from './components.js'
3
- export { deployment, standalone } from './deployment.js'
4
- export { context } from './context.js'
5
- export * from './const.js'
6
- export * as schemas from './schemas.js'
7
-
8
- export type { Annotation, Declaration, Delay, Options, Pulse } from './types.js'
@@ -1,64 +0,0 @@
1
- import * as schemas from './schemas.js'
2
- import type { Declaration } from './types.js'
3
- import type { Manifest } from '@toa.io/norm'
4
-
5
- /**
6
- * The `cadence:` block of a component manifest: the operations called on a cadence, by the
7
- * operation each one calls. Norm hands over the whole manifest, so what the declaration refers
8
- * to is checked here rather than left to fail at boot.
9
- *
10
- * A component that declares nothing still has a declaration. `cadence: ~` is how one that only
11
- * delays calls says so, and it has to produce a value or norm rejects the extension.
12
- */
13
- export function manifest(
14
- declaration: Declaration | null | undefined,
15
- component: Manifest
16
- ): Declaration {
17
- const normalized: Record<string, unknown> = expand(declaration)
18
-
19
- schemas.declaration.validate<Declaration>(normalized, 'Invalid cadence declaration')
20
-
21
- for (const [endpoint, pulse] of Object.entries(normalized)) {
22
- const operation = component.operations?.[endpoint]
23
-
24
- if (operation === undefined)
25
- throw new Error(`Pulse refers to undefined operation '${endpoint}'`)
26
-
27
- if (!TYPES.has(operation.type))
28
- throw new Error(
29
- `Pulse '${endpoint}' must refer to an operation of the allowed types: ` +
30
- [...TYPES].join(', ')
31
- )
32
-
33
- if (pulse.intervals > pulse.cycle)
34
- throw new Error(
35
- `Pulse '${endpoint}' splits a cycle of ${pulse.cycle} seconds into ` +
36
- `${pulse.intervals} intervals, which is less than a second each`
37
- )
38
- }
39
-
40
- return normalized
41
- }
42
-
43
- /** A pulse whose cycle is not split has nothing to state but the cycle. */
44
- function expand(declaration: Declaration | null | undefined): Record<string, unknown> {
45
- if (declaration === null || declaration === undefined) return {}
46
-
47
- // a cycle nothing splits is one interval, which is what the shorthand declares
48
- return Object.fromEntries(
49
- Object.entries(declaration).map(([endpoint, pulse]) => {
50
- const declared: Record<string, unknown> =
51
- typeof pulse === 'number' ? { cycle: pulse } : { ...pulse }
52
-
53
- declared.intervals ??= 1
54
-
55
- return [endpoint, declared]
56
- })
57
- )
58
- }
59
-
60
- /**
61
- * The types a receiver may refer to. An operation that produces no side effects has nothing to
62
- * be called periodically for.
63
- */
64
- const TYPES = new Set(['transition', 'assignment', 'effect', 'unmanaged'])
@@ -1,10 +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 { Annotation, Declaration } from './types.js'
5
-
6
- const path = resolve(import.meta.dirname, '../../schemas/extensions.cadence')
7
- const namespace = schemas.namespace(path)
8
-
9
- export const declaration: Schema<Declaration> = namespace.schema('declaration')
10
- export const annotation: Schema<Annotation> = namespace.schema('annotation')
@@ -1,41 +0,0 @@
1
- /** What one component declares under `cadence:`, by the operation each one calls. */
2
- export type Declaration = Record<string, Pulse>
3
-
4
- export interface Pulse {
5
- /** seconds one whole cycle takes */
6
- cycle: number
7
-
8
- /** intervals the cycle is split into; the gap between calls is `cycle / intervals` */
9
- intervals: number
10
- }
11
-
12
- /** `context.delay` — a call to be made later, answering the id that cancels it. */
13
- export interface Delay {
14
- (endpoint: string, request: object | null, options: Options): Promise<string>
15
-
16
- /** Raises where the id was never issued. */
17
- cancel: (id: string) => Promise<void>
18
- }
19
-
20
- export interface Options {
21
- /** milliseconds from now */
22
- interval: number
23
-
24
- /**
25
- * Milliseconds the call may be late and still be made, or `null` for no bound at all.
26
- *
27
- * Stated rather than defaulted, because only the caller knows whether a late call is still
28
- * the right call: an unpaid order expires on time or not at all, and a report is wanted
29
- * whenever it can be had. Nothing else in the system can tell those apart.
30
- *
31
- * An upper bound on lateness, not a promise of timeliness. It is bounded below by how often
32
- * a dispatcher scans, so a bound shorter than that is one nothing can honour.
33
- */
34
- overdue: number | null
35
- }
36
-
37
- /** What an application states under `cadence:` in its context. */
38
- export interface Annotation {
39
- /** seconds between passes over the calls waiting to be made */
40
- discreteness?: number
41
- }
@@ -1,6 +0,0 @@
1
- import { components as digest, type Components } from '../digest/read.js'
2
-
3
- /** The values component, which runs in the service of its own. */
4
- export function components(): Components {
5
- return digest('extensions.configuration')
6
- }
@@ -1,30 +0,0 @@
1
- import { environment } from '@toa.io/generic'
2
- import type { Source } from '@toa.io/core/types'
3
-
4
- /** Per-component variables: the local override and the secrets. */
5
- export const PREFIX = 'TOA_CONFIGURATION_'
6
-
7
- /** The map of every configured component, on the values service. */
8
- export const VALUES = 'TOA_CONFIGURATION_VALUES'
9
-
10
- export const SECRET_RX = /^\$(?<variable>[A-Z0-9_]{1,32})$/
11
-
12
- /** Where the UI is mounted; `/configuration/*` belongs to the component's own API. */
13
- export const UI_PATH = '/.configuration'
14
- export const UI_PORT = 8003
15
-
16
- /**
17
- * The port the UI is served on. `UI_PORT` is what a deployment publishes and what the chart
18
- * renders; the variable is for a machine that runs more than one Toa process — a Toa checkout
19
- * beside an application, or two applications — where one of them has to give it up.
20
- */
21
- export const UI_PORT_ENV = 'TOA_CONFIGURATION_UI_PORT'
22
- export function uiPort(): number {
23
- const value = environment.get(UI_PORT_ENV)
24
-
25
- return value === undefined ? UI_PORT : Number(value)
26
- }
27
-
28
- export const EVENT = 'configuration.values.created'
29
-
30
- export const SOURCE: Source = { service: 'configuration' }
@@ -1,13 +0,0 @@
1
- import type { Manifest } from './manifest.js'
2
- import type { Contribution } from '@toa.io/core/types'
3
-
4
- /** What this extension puts on the context of a component that declares it. */
5
- export function context(declaration: Manifest): Contribution {
6
- const contribution: Contribution = { name: 'configuration', schema: declaration.schema }
7
-
8
- // a value the schema declares a secret is one on the context, not a string
9
- if (JSON.stringify(declaration.schema).includes('"secret"'))
10
- contribution.imports = { '@toa.io/extensions.configuration': ['Secret'] }
11
-
12
- return contribution
13
- }
@@ -1,159 +0,0 @@
1
- import assert from 'node:assert'
2
- import {
3
- type Dependency,
4
- type Resources,
5
- type Service,
6
- type Variable,
7
- type Variables
8
- } from '@toa.io/operations'
9
- import { add } from '@toa.io/generic'
10
- import { components } from './components.js'
11
- import { version } from '../version.js'
12
- import { EVENT, PREFIX, SECRET_RX, UI_PATH, UI_PORT, VALUES } from './const.js'
13
- import { epoch } from './epoch.js'
14
- import * as validators from './schemas.js'
15
- import type { Manifest } from './manifest.js'
16
- import type { context } from '@toa.io/norm'
17
-
18
- /** Where Toa's release publishes this service's image. An application takes it
19
- * instead of building one when its context says `registry.services: published`. */
20
- export const image = 'ghcr.io/toa-io/extension-configuration-values'
21
-
22
- export function deployment(
23
- instances: Instance[],
24
- annotation: Annotation = {}
25
- ): Dependency {
26
- const { resources, values } = split(annotation)
27
-
28
- annotation = prepare(values, instances)
29
-
30
- const variables: Variables = {}
31
-
32
- for (const instance of instances) {
33
- const values = annotation[instance.locator.id]
34
-
35
- if (values === undefined) continue
36
-
37
- const secrets = createSecrets(values)
38
-
39
- if (secrets.length > 0) variables[instance.locator.label] = secrets
40
- }
41
-
42
- const service: Service = {
43
- group: 'configuration',
44
- name: 'values',
45
- image,
46
- version,
47
- components: components().labels,
48
- resources,
49
- // the service that holds the values also serves the page that reads them
50
- port: UI_PORT,
51
- ingress: { path: UI_PATH },
52
- variables: [
53
- {
54
- name: VALUES,
55
- value: JSON.stringify(describe(instances, annotation))
56
- }
57
- ]
58
- }
59
-
60
- return { services: [service], variables, events: [EVENT] }
61
- }
62
-
63
- /** What the values service is given: the epoch, the schema and the defaults of every component. */
64
- export function describe(instances: Instance[], annotation: Annotation = {}): Values {
65
- annotation = prepare(split(annotation).values, instances)
66
-
67
- const values: Values = {}
68
-
69
- for (const { locator, manifest } of instances) {
70
- const deployed = annotation[locator.id]
71
-
72
- values[locator.id] = {
73
- epoch: epoch(manifest.schema),
74
- schema: manifest.schema,
75
- // what the Context says stands over what the manifest declares, value by value: a
76
- // deployment that names one of them does not thereby unset the rest
77
- defaults:
78
- deployed === undefined
79
- ? manifest.defaults
80
- : add(structuredClone(deployed), manifest.defaults ?? {})
81
- }
82
- }
83
-
84
- return values
85
- }
86
-
87
- function createSecrets(values: object): Variable[] {
88
- const secrets: Variable[] = []
89
-
90
- for (const value of Object.values(values)) {
91
- if (typeof value === 'object' && value !== null)
92
- secrets.push(...createSecrets(value as object))
93
-
94
- if (typeof value !== 'string') continue
95
-
96
- const match = value.match(SECRET_RX)
97
-
98
- if (match === null) continue
99
-
100
- const name = match.groups?.variable
101
-
102
- assert.ok(name !== undefined)
103
-
104
- secrets.push({
105
- name: PREFIX + '_' + name,
106
- secret: {
107
- name: 'toa-configuration',
108
- key: name
109
- }
110
- })
111
- }
112
-
113
- return secrets
114
- }
115
-
116
- /**
117
- * The service's own resources, and the component values that are the rest of the annotation.
118
- *
119
- * Every key here names a component, so the one option the service has of its own needs a
120
- * name that cannot be mistaken for one. `resources` is reserved: a component actually
121
- * called that is written with its namespace, `default.resources`, which is what an id is
122
- * anyway — the bare form is the shorthand.
123
- */
124
- function split(annotation: Annotation): { resources?: Resources; values: Annotation } {
125
- validators.annotation.validate(annotation)
126
-
127
- const { resources, ...values } = annotation as Annotation & { resources?: Resources }
128
-
129
- return { resources, values }
130
- }
131
-
132
- /** Validated, keyed by full component ids, and checked against the components that ask. */
133
- function prepare(annotation: Annotation, instances: Instance[]): Annotation {
134
- const normalized: Annotation = {}
135
- const requested = instances.map((instance) => instance.locator.id)
136
-
137
- for (const [key, values] of Object.entries(annotation)) {
138
- const id = key.includes('.') ? key : 'default.' + key
139
-
140
- assert.ok(
141
- requested.includes(id),
142
- `Component '${id}' does not request configuration or does not exist.`
143
- )
144
-
145
- normalized[id] = values
146
- }
147
-
148
- return normalized
149
- }
150
-
151
- export type Annotation = Record<string, object>
152
- export type Instance = context.Dependency<Manifest>
153
- export type Values = Record<string, Entry>
154
-
155
- export interface Entry {
156
- epoch: string
157
- schema: object
158
- defaults?: object
159
- }
@@ -1,22 +0,0 @@
1
- import { createHash } from 'node:crypto'
2
-
3
- /** The same for the same schema, whatever the key order it was written in. */
4
- export function epoch(schema: object): string {
5
- return createHash('sha256').update(canonical(schema)).digest('hex')
6
- }
7
-
8
- function canonical(value: unknown): string {
9
- if (Array.isArray(value)) return '[' + value.map(canonical).join(',') + ']'
10
-
11
- if (value !== null && typeof value === 'object') {
12
- const object = value as Record<string, unknown>
13
- const keys = Object.keys(object)
14
- .filter((key) => object[key] !== undefined)
15
- .sort()
16
- const entries = keys.map((key) => JSON.stringify(key) + ':' + canonical(object[key]))
17
-
18
- return '{' + entries.join(',') + '}'
19
- }
20
-
21
- return JSON.stringify(value) ?? 'null'
22
- }
@@ -1,10 +0,0 @@
1
- export { manifest } from './manifest.js'
2
- export { components } from './components.js'
3
- export { deployment, describe, image } from './deployment.js'
4
- export { epoch } from './epoch.js'
5
- export { context } from './context.js'
6
- export * from './const.js'
7
- export * as schemas from './schemas.js'
8
-
9
- export type { Manifest } from './manifest.js'
10
- export type { Annotation, Entry, Instance, Values } from './deployment.js'
@@ -1,12 +0,0 @@
1
- import * as schemas from './schemas.js'
2
-
3
- export function manifest(manifest: Manifest): Manifest {
4
- schemas.manifest.validate(manifest)
5
-
6
- return manifest
7
- }
8
-
9
- export interface Manifest {
10
- schema: object
11
- defaults?: Record<string, unknown>
12
- }
@@ -1,9 +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
-
5
- const path = resolve(import.meta.dirname, '../../schemas/extensions.configuration')
6
- const namespace = schemas.namespace(path)
7
-
8
- export const manifest: Schema<any> = namespace.schema('manifest')
9
- export const annotation: Schema<any> = namespace.schema('annotation')
@@ -1,91 +0,0 @@
1
- import type { Resources } from '@toa.io/operations'
2
-
3
- /** What the gateway speaks upstream. */
4
- export type Protocol = 'h1' | 'h2c'
5
-
6
- export interface Annotation {
7
- authorities: Record<string, string>
8
-
9
- /**
10
- * `h2c` requires an ingress controller that proxies cleartext HTTP/2 upstream.
11
- * See `documentation/protocol.md`.
12
- */
13
- protocol?: Protocol
14
- class?: string
15
- resources?: Resources
16
- annotations?: Record<string, string>
17
-
18
- /** The Service, as opposed to the Ingress that `annotations` above describes. */
19
- service?: { annotations?: Record<string, string> }
20
-
21
- debug?: boolean
22
-
23
- /** The header the client address is read from; the connection's without one. See `ip.md`. */
24
- ip?: string
25
-
26
- /** Failed authentications an address may make; none are metered unless set. See `identity.md`. */
27
- bouncer?: Bouncer
28
-
29
- /** The authorization server this context exposes; none is exposed without it. */
30
- oauth?: OAuth
31
-
32
- /** JSON-RPC at `/.rpc`; none is served without it. See `documentation/rpc.md`. */
33
- rpc?: RPC
34
-
35
- /** MCP at `/.mcp`; none is served without it. See `documentation/mcp.md`. */
36
- mcp?: MCP
37
- '/'?: object // parsed and validated by RTD.syntax.parse
38
- }
39
-
40
- export interface OAuth {
41
- /**
42
- * Where a client sends the user to consent. The one endpoint of the flow that needs a
43
- * person, and so the one this extension does not serve: an application builds it.
44
- */
45
- authorize: string
46
-
47
- /** Paths a token may be restricted to, each advertised as a protected resource. */
48
- resources?: string[]
49
-
50
- /** What a client may ask for. Each is a role, or a scope within one. */
51
- scopes?: string[]
52
-
53
- /** Origins whose Client ID Metadata Documents may be read. None are without it. */
54
- trust?: string[]
55
-
56
- /** Dynamic Client Registration, off unless opened. */
57
- registration?: 'open' | 'closed'
58
- }
59
-
60
- export interface RPC {
61
- /**
62
- * Calls one request may carry, 32 by default. One request is one authentication and one
63
- * reply however many calls it makes, so what a caller may ask for at once is bounded.
64
- */
65
- batch?: number
66
- }
67
-
68
- export interface MCP {
69
- /** What the server calls itself, which a client shows a user. */
70
- name: string
71
-
72
- /** What a model is told before it calls anything here. */
73
- instructions?: string
74
-
75
- /**
76
- * Browser origins the endpoint answers, which the revision requires against DNS rebinding.
77
- * None are admitted without it; a request carrying no `Origin` is not a browser's.
78
- */
79
- origins?: string[]
80
-
81
- /** Whether the endpoint answers without a credential. It does not unless it says so. */
82
- anonymous?: boolean
83
- }
84
-
85
- export interface Bouncer {
86
- /** what an address may fail at once, 20 by default */
87
- attempts?: number
88
-
89
- /** seconds it takes to earn them back, 60 by default */
90
- interval?: number
91
- }
@@ -1,6 +0,0 @@
1
- import { components as digest, type Components } from '../digest/read.js'
2
-
3
- /** The identity components, which run inside the gateway. */
4
- export function components(): Components {
5
- return digest('extensions.exposition')
6
- }
@@ -1,45 +0,0 @@
1
- export const BRANCH_TTL = 1_800_000
2
-
3
- /** The broadcast the gateway and its tenants share. */
4
- export const CHANNEL = 'exposition'
5
-
6
- /** The replicas of the gateway decide together, whatever context they serve. */
7
- export const ATOM_GROUP = 'exposition'
8
-
9
- /**
10
- * Where JSON-RPC is served, for every procedure at once. Pinned rather than configured: a
11
- * path an application could choose is a path it could collide with a route of its own.
12
- */
13
- export const RPC = '/.rpc'
14
-
15
- /** Calls one request may carry where the annotation does not say. */
16
- export const BATCH = 32
17
-
18
- /**
19
- * Where the Model Context Protocol is served. Pinned for the reason `/.rpc` is: a path an
20
- * application could choose is a path it could collide with a route of its own.
21
- */
22
- export const MCP = '/.mcp'
23
-
24
- /**
25
- * Where the resource tree and the page that reads it are served. Pinned for the reason
26
- * `/.rpc` is: a path an application could choose is a path it could collide with a route of
27
- * its own. Unlike those two it is not annotated — every entry it carries is what `OPTIONS`
28
- * on that path already answers to the same caller, and what it adds is the enumeration.
29
- */
30
- export const DISCOVERY = '/.discovery'
31
-
32
- /** Where the gateway serves. */
33
- export const PORT = 8000
34
-
35
- /**
36
- * Reserved for the readiness probe. `8001` is the Telemetry readiness probe's, and `toa export`
37
- * refuses a port claimed twice — `toa mono` and a local run put every service in one process.
38
- */
39
- export const PROBE = 8004
40
-
41
- /**
42
- * The initial delay of the readiness probe. The server does not sleep for it: whoever
43
- * probes is the one that waits, and doing it here as well only delayed the process twice.
44
- */
45
- export const DELAY = 3 // seconds