@toa.io/extensions.configuration 1.0.0-alpha.31 → 1.0.0-alpha.311

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 (104) hide show
  1. package/components/configuration.values/manifest.toa.yaml +151 -0
  2. package/components/configuration.values/migrations/0002-indexes.yaml +7 -0
  3. package/components/configuration.values/operations/create.js +32 -0
  4. package/components/configuration.values/operations/fetch.js +13 -0
  5. package/components/configuration.values/operations/get.js +19 -0
  6. package/components/configuration.values/operations/lib/map.js +22 -0
  7. package/components/configuration.values/operations/lib/resolve.js +24 -0
  8. package/components/configuration.values/operations/list.js +11 -0
  9. package/components/configuration.values/source/create.ts +56 -0
  10. package/components/configuration.values/source/fetch.ts +26 -0
  11. package/components/configuration.values/source/get.ts +32 -0
  12. package/components/configuration.values/source/lib/map.ts +36 -0
  13. package/components/configuration.values/source/lib/resolve.ts +57 -0
  14. package/components/configuration.values/source/list.ts +21 -0
  15. package/components/configuration.values/tsconfig.json +10 -0
  16. package/components/configuration.values/types/index.d.ts +3 -0
  17. package/components/configuration.values/types/toa.d.ts +69 -0
  18. package/package.json +21 -10
  19. package/readme.md +178 -50
  20. package/transpiled/Aspect.d.ts +19 -4
  21. package/transpiled/Aspect.js +62 -9
  22. package/transpiled/Aspect.js.map +1 -1
  23. package/transpiled/Client.d.ts +59 -0
  24. package/transpiled/Client.js +171 -0
  25. package/transpiled/Client.js.map +1 -0
  26. package/transpiled/Composition.d.ts +14 -0
  27. package/transpiled/Composition.js +38 -0
  28. package/transpiled/Composition.js.map +1 -0
  29. package/transpiled/Factory.d.ts +9 -2
  30. package/transpiled/Factory.js +21 -9
  31. package/transpiled/Factory.js.map +1 -1
  32. package/transpiled/Secret.d.ts +15 -0
  33. package/transpiled/Secret.js +26 -0
  34. package/transpiled/Secret.js.map +1 -0
  35. package/transpiled/UI.d.ts +25 -0
  36. package/transpiled/UI.js +173 -0
  37. package/transpiled/UI.js.map +1 -0
  38. package/transpiled/configuration.d.ts +7 -2
  39. package/transpiled/configuration.js +33 -43
  40. package/transpiled/configuration.js.map +1 -1
  41. package/transpiled/index.d.ts +3 -3
  42. package/transpiled/index.js +4 -9
  43. package/transpiled/index.js.map +1 -1
  44. package/ui/dist/_app/env.js +1 -0
  45. package/ui/dist/_app/immutable/assets/0.BGFdDICE.css +2 -0
  46. package/ui/dist/_app/immutable/assets/ui.BghF56l_.css +1 -0
  47. package/ui/dist/_app/immutable/chunks/Bjy-W4x2.js +81 -0
  48. package/ui/dist/_app/immutable/chunks/C3B60XAt.js +6 -0
  49. package/ui/dist/_app/immutable/chunks/CPFWN2yl.js +50 -0
  50. package/ui/dist/_app/immutable/chunks/CcD_ISxM.js +3 -0
  51. package/ui/dist/_app/immutable/chunks/D_toi6Gh.js +8 -0
  52. package/ui/dist/_app/immutable/chunks/PnrO3qAK.js +1 -0
  53. package/ui/dist/_app/immutable/chunks/ecRPYFMN.js +1 -0
  54. package/ui/dist/_app/immutable/chunks/xihTtKlq.js +1 -0
  55. package/ui/dist/_app/immutable/entry/app.DUsdcQBH.js +2 -0
  56. package/ui/dist/_app/immutable/entry/start.6FDvOFn_.js +1 -0
  57. package/ui/dist/_app/immutable/nodes/0.DsgFo43s.js +1 -0
  58. package/ui/dist/_app/immutable/nodes/1.DXKSw8PI.js +1 -0
  59. package/ui/dist/_app/immutable/nodes/2.1zp4Ozb5.js +1 -0
  60. package/ui/dist/_app/immutable/nodes/3.BbXeBPYP.js +1 -0
  61. package/ui/dist/_app/immutable/nodes/4.CXWthKII.js +1 -0
  62. package/ui/dist/_app/version.json +1 -0
  63. package/ui/dist/apple-touch-icon.png +0 -0
  64. package/ui/dist/favicon-96x96.png +0 -0
  65. package/ui/dist/favicon.ico +0 -0
  66. package/ui/dist/index.html +57 -0
  67. package/ui/dist/robots.txt +3 -0
  68. package/notes/consistency.md +0 -69
  69. package/schemas/annotation.cos.yaml +0 -1
  70. package/schemas/manifest.cos.yaml +0 -2
  71. package/source/Aspect.test.ts +0 -15
  72. package/source/Aspect.ts +0 -23
  73. package/source/Factory.ts +0 -12
  74. package/source/configuration.test.ts +0 -90
  75. package/source/configuration.ts +0 -59
  76. package/source/deployment.test.ts +0 -21
  77. package/source/deployment.ts +0 -86
  78. package/source/index.ts +0 -3
  79. package/source/manifest.test.ts +0 -15
  80. package/source/manifest.ts +0 -15
  81. package/source/schemas.ts +0 -9
  82. package/transpiled/Aspect.test.d.ts +0 -1
  83. package/transpiled/Aspect.test.js +0 -15
  84. package/transpiled/Aspect.test.js.map +0 -1
  85. package/transpiled/configuration.test.d.ts +0 -1
  86. package/transpiled/configuration.test.js +0 -64
  87. package/transpiled/configuration.test.js.map +0 -1
  88. package/transpiled/deployment.d.ts +0 -8
  89. package/transpiled/deployment.js +0 -88
  90. package/transpiled/deployment.js.map +0 -1
  91. package/transpiled/deployment.test.d.ts +0 -1
  92. package/transpiled/deployment.test.js +0 -18
  93. package/transpiled/deployment.test.js.map +0 -1
  94. package/transpiled/manifest.d.ts +0 -6
  95. package/transpiled/manifest.js +0 -35
  96. package/transpiled/manifest.js.map +0 -1
  97. package/transpiled/manifest.test.d.ts +0 -1
  98. package/transpiled/manifest.test.js +0 -14
  99. package/transpiled/manifest.test.js.map +0 -1
  100. package/transpiled/schemas.d.ts +0 -3
  101. package/transpiled/schemas.js +0 -33
  102. package/transpiled/schemas.js.map +0 -1
  103. package/transpiled/tsconfig.tsbuildinfo +0 -1
  104. package/tsconfig.json +0 -9
@@ -1,69 +0,0 @@
1
- # Configuration Consistency
2
-
3
- ![Not Implemented](https://img.shields.io/badge/Not_Implemented-red)
4
-
5
- ## Problem Definition
6
-
7
- At arbitrary moments when the configuration has changed, some distributed operations have started
8
- but haven't yet
9
- finished. This leads to operations that start with certain configuration values but will finish with
10
- another, which may
11
- result in logical problems.
12
-
13
- Given that distributed operations may have arbitrary participants and last for an arbitrary period,
14
- there is no such
15
- single moment when configuration can be safely changed. Thus, it must be a process.
16
-
17
- ## ~~Not a~~ Solution
18
-
19
- 1. Configuration is a single versioned object.
20
- 2. Configuration version value is included in the Uniform Communication Interface.
21
- 3. The first distributed operation participant (which is the one who has received a UCI without the
22
- configuration
23
- version value) must include in the outgoing UCI the configuration version value that it considers
24
- as current.
25
- 4. Non-first distributed operations participants (which is those who has received a UCI with the
26
- configuration version
27
- value) must use the configuration version specified in the UCI.
28
- 5. Non-first distributed operation participants must include in the outgoing UCI the same
29
- configuration version value as
30
- they received in the incoming.
31
-
32
- ## Restrictions
33
-
34
- 1. Configuration updates are always backward compatible.
35
- 2. Configuration updates are always being delivered before algorithm updates.
36
- 1. Including federated deployment, that is: first deliver configuration to all facilities (data
37
- centers, zones,
38
- whatever), then deliver algorithm updates.
39
- 3. Configuration storage and access solution must provide the transactional updates, that is if any
40
- arbitrary
41
- participant observed a certain configuration version, then any other participant is guaranteed to
42
- be able to
43
- subsequently observe that version.
44
- 1. Including federated deployment[^1].
45
-
46
- ## Solution
47
-
48
- The configuration compatibility problem described above is a particular case of a common
49
- compatibility problem for
50
- distributed operation participants. It is not the only configuration that may change while a
51
- distributed operation is
52
- running, but participant algorithms themselves. This leads to the conclusion that this particular
53
- solution must be
54
- propagated to algorithm versions, that is: which system (as a set of algorithms and configuration)
55
- version was used to
56
- start the operation, and that system version must be used to finish the operation.
57
-
58
- This kind of solution results in the need to run all versions of the system with appropriate message
59
- routing. The
60
- implementation complexity of this solution and its operations costs are considered unreasonable.
61
- However, an attempt
62
- will be made to implement this solution with a certain
63
- constraints [#147](https://github.com/toa-io/toa/issues/147).
64
-
65
- [^1]: Since it looks like there is no reasonable way to provide this kind of guarantee without
66
- significant performance
67
- and/or availability impact, it may be implemented as a mechanism with read retries and with a
68
- timeout considered as
69
- “enough for the most of fail-over scenarios”.
@@ -1 +0,0 @@
1
- <object>
@@ -1,2 +0,0 @@
1
- schema: object
2
- defaults?: object
@@ -1,15 +0,0 @@
1
- import { Aspect } from './Aspect'
2
-
3
- it('should return value', async () => {
4
- const configuration = {
5
- foo: 'bar',
6
- bar: {
7
- baz: 'quux'
8
- }
9
- }
10
-
11
- const aspect = new Aspect(configuration)
12
-
13
- expect(aspect.invoke(['foo'])).toStrictEqual(configuration.foo)
14
- expect(aspect.invoke(['bar', 'baz'])).toStrictEqual(configuration.bar.baz)
15
- })
package/source/Aspect.ts DELETED
@@ -1,23 +0,0 @@
1
- import { Connector, type extensions } from '@toa.io/core'
2
-
3
- export class Aspect extends Connector implements extensions.Aspect {
4
- public readonly name = 'configuration'
5
-
6
- private readonly value: object
7
-
8
- public constructor (value: object) {
9
- super()
10
-
11
- this.value = value
12
- }
13
-
14
- public invoke (path: string[]): any {
15
- let cursor: any = this.value
16
-
17
- if (path !== undefined)
18
- for (const segment of path)
19
- cursor = cursor[segment]
20
-
21
- return cursor
22
- }
23
- }
package/source/Factory.ts DELETED
@@ -1,12 +0,0 @@
1
- import { type Locator, type extensions } from '@toa.io/core'
2
- import { Aspect } from './Aspect'
3
- import { type Manifest } from './manifest'
4
- import { get } from './configuration'
5
-
6
- export class Factory implements extensions.Factory {
7
- public aspect (locator: Locator, manifest: Manifest): extensions.Aspect {
8
- const value = get(locator, manifest)
9
-
10
- return new Aspect(value)
11
- }
12
- }
@@ -1,90 +0,0 @@
1
- import { encode } from '@toa.io/generic'
2
- import { Locator } from '@toa.io/core'
3
- import { generate } from 'randomstring'
4
- import { get } from './configuration'
5
- import { type Manifest } from './manifest'
6
-
7
- let locator: Locator
8
- let manifest: Manifest
9
-
10
- beforeEach(() => {
11
- locator = new Locator(generate(), generate())
12
- manifest = { schema: { foo: 'string' } }
13
- })
14
-
15
- afterEach(() => {
16
- for (const name of used)
17
- delete process.env[name]
18
-
19
- used = []
20
- })
21
-
22
- it('should read value', async () => {
23
- manifest.schema = { foo: 'string' }
24
-
25
- const value: object = { foo: generate() }
26
-
27
- set(value)
28
-
29
- const result = get(locator, manifest)
30
-
31
- expect(result).toStrictEqual(value)
32
- })
33
-
34
- it('should return empty object if no value set', async () => {
35
- expect(get(locator, manifest)).toStrictEqual({})
36
- })
37
-
38
- it('should substitute secrets', async () => {
39
- const value: object = { foo: '$BAR' }
40
-
41
- set(value)
42
- set('bar', '_BAR')
43
-
44
- const result = get(locator, manifest)
45
-
46
- expect(result).toStrictEqual({ foo: 'bar' })
47
- })
48
-
49
- it('should use defaults', async () => {
50
- manifest.schema = { foo: 'string', bar: ['number'], 'baz?': 'string' }
51
- manifest.defaults = { foo: 'bar', bar: [1] }
52
-
53
- const values = { bar: [2], baz: 'foo' }
54
-
55
- set(values)
56
-
57
- const result = get(locator, manifest)
58
-
59
- expect(result).toStrictEqual({
60
- foo: 'bar',
61
- bar: [2],
62
- baz: 'foo'
63
- })
64
- })
65
-
66
- it('should validate', async () => {
67
- manifest.schema = { foo: 'hello', bar: 'number' }
68
-
69
- const values = { bar: 5 }
70
-
71
- set(values)
72
-
73
- const result = get(locator, manifest)
74
-
75
- expect(result).toStrictEqual({
76
- foo: 'hello',
77
- bar: 5
78
- })
79
- })
80
-
81
- function set (value: object | string, key = locator.uppercase): void {
82
- const string = typeof value === 'string' ? value : encode(value)
83
- const name = 'TOA_CONFIGURATION_' + key
84
-
85
- process.env[name] = string
86
-
87
- used.push(name)
88
- }
89
-
90
- let used: string[] = []
@@ -1,59 +0,0 @@
1
- import { type Locator } from '@toa.io/core'
2
- import { decode, add } from '@toa.io/generic'
3
- import * as schemas from '@toa.io/schemas'
4
- import { PREFIX, SECRET_RX } from './deployment'
5
- import { type Manifest } from './manifest'
6
- import type { Schema } from '@toa.io/schemas'
7
-
8
- export function get (locator: Locator, manifest: Manifest): Node {
9
- const values = getConfiguration(locator.uppercase)
10
-
11
- substituteSecrets(values)
12
-
13
- if (manifest.defaults !== undefined)
14
- add(values, manifest.defaults)
15
-
16
- const schema: Schema<any> = schemas.schema(manifest.schema)
17
-
18
- schema.validate(values)
19
-
20
- return values
21
- }
22
-
23
- function getConfiguration (suffix: string): Node {
24
- const variable = PREFIX + suffix
25
- const string = process.env[variable]
26
-
27
- if (string === undefined)
28
- return {}
29
- else
30
- return decode(string)
31
- }
32
-
33
- function substituteSecrets (configuration: Node): void {
34
- for (const [key, value] of Object.entries(configuration)) {
35
- if (typeof value === 'object' && value !== null)
36
- substituteSecrets(value as Node)
37
-
38
- if (typeof value !== 'string') continue
39
-
40
- const match = value.match(SECRET_RX)
41
-
42
- if (match === null) continue
43
-
44
- const name = match.groups?.variable
45
-
46
- configuration[key] = getSecret(name!)
47
- }
48
- }
49
-
50
- function getSecret (name: string): string {
51
- const variable = PREFIX + '_' + name
52
- const value = process.env[variable]
53
-
54
- if (value === undefined) throw new Error(`${variable} is not set.`)
55
-
56
- return value
57
- }
58
-
59
- export type Node = Record<string, unknown>
@@ -1,21 +0,0 @@
1
- import { type Annotation, deployment, type Instance } from './deployment'
2
- import { type Manifest } from './manifest'
3
-
4
- it('should validate annotation', async () => {
5
- const wrongType = 'not ok' as unknown as Annotation
6
-
7
- expect(() => deployment([], wrongType)).toThrow('object')
8
- })
9
-
10
- it('should validate values', async () => {
11
- const manifest: Manifest = {
12
- schema: { foo: 'string', bar: 'number' },
13
- defaults: { foo: 'ok', bar: 0 }
14
- }
15
-
16
- const locator = { id: 'component' }
17
- const instances = [{ manifest, locator }] as unknown as Instance[]
18
- const annotation: Annotation = { [locator.id]: { bar: 'not a number' } }
19
-
20
- expect(() => deployment(instances, annotation)).toThrow('number')
21
- })
@@ -1,86 +0,0 @@
1
- import assert from 'node:assert'
2
- import { type Dependency, type Variable, type Variables } from '@toa.io/operations'
3
- import * as schemas from '@toa.io/schemas'
4
- import { encode, overwrite } from '@toa.io/generic'
5
- import { type Manifest } from './manifest'
6
- import * as validators from './schemas'
7
- import type { Schema } from '@toa.io/schemas'
8
- import type { context } from '@toa.io/norm'
9
-
10
- export function deployment (instances: Instance[], annotation: Annotation = {}): Dependency {
11
- validate(annotation, instances)
12
-
13
- const variables: Variables = {}
14
-
15
- for (const instance of instances) {
16
- const values = annotation[instance.locator.id]
17
-
18
- validateInstance(instance, values)
19
-
20
- if (values === undefined) continue
21
-
22
- variables[instance.locator.label] = [{
23
- name: PREFIX + instance.locator.uppercase,
24
- value: encode(values)
25
- }]
26
-
27
- const secrets = createSecrets(values)
28
-
29
- variables[instance.locator.label].push(...secrets)
30
- }
31
-
32
- return { variables }
33
- }
34
-
35
- function createSecrets (values: object): Variable[] {
36
- const secrets: Variable[] = []
37
-
38
- for (const value of Object.values(values)) {
39
- if (typeof value === 'object' && value !== null)
40
- secrets.push(...createSecrets(value as object))
41
-
42
- if (typeof value !== 'string') continue
43
-
44
- const match = value.match(SECRET_RX)
45
-
46
- if (match === null) continue
47
-
48
- const name = match.groups?.variable
49
-
50
- assert.ok(name !== undefined)
51
-
52
- secrets.push({
53
- name: PREFIX + '_' + name,
54
- secret: {
55
- name: 'toa-configuration',
56
- key: name
57
- }
58
- })
59
- }
60
-
61
- return secrets
62
- }
63
-
64
- function validate (annotation: Annotation, instances: Instance[]): void {
65
- validators.annotation.validate(annotation)
66
-
67
- const requested = instances.map((instance) => instance.locator.id)
68
-
69
- for (const id of Object.keys(annotation))
70
- assert.ok(requested.includes(id),
71
- `Component '${id}' does not request configuration or does not exist.`)
72
- }
73
-
74
- function validateInstance (instace: Instance, values: object = {}): void {
75
- const defaults = instace.manifest.defaults ?? {}
76
- const configuration = overwrite(defaults, values)
77
- const schema: Schema<any> = schemas.schema(instace.manifest.schema)
78
-
79
- schema.validate(configuration)
80
- }
81
-
82
- export const SECRET_RX = /^\$(?<variable>[A-Z0-9_]{1,32})$/
83
- export const PREFIX = 'TOA_CONFIGURATION_'
84
-
85
- export type Annotation = Record<string, object>
86
- export type Instance = context.Dependency<Manifest>
package/source/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export { manifest } from './manifest'
2
- export { deployment } from './deployment'
3
- export { Factory } from './Factory'
@@ -1,15 +0,0 @@
1
- import { type Manifest, manifest } from './manifest'
2
-
3
- it('should validate', async () => {
4
- const additional = { schema: {}, foo: 'bar' } as unknown as Manifest
5
-
6
- expect(() => {
7
- manifest(additional)
8
- }).toThrow('not expected')
9
-
10
- const wrongType = { schema: 'not ok' } as unknown as Manifest
11
-
12
- expect(() => {
13
- manifest(wrongType)
14
- }).toThrow('object')
15
- })
@@ -1,15 +0,0 @@
1
- import * as schemas from './schemas'
2
- import { type Node } from './configuration'
3
-
4
- export function manifest (manifest: Manifest): Manifest {
5
- if (manifest.schema === undefined) manifest = { schema: manifest }
6
-
7
- schemas.manifest.validate(manifest)
8
-
9
- return manifest
10
- }
11
-
12
- export interface Manifest {
13
- schema: object
14
- defaults?: Node
15
- }
package/source/schemas.ts DELETED
@@ -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(__dirname, '../schemas')
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 +0,0 @@
1
- export {};
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const Aspect_1 = require("./Aspect");
4
- it('should return value', async () => {
5
- const configuration = {
6
- foo: 'bar',
7
- bar: {
8
- baz: 'quux'
9
- }
10
- };
11
- const aspect = new Aspect_1.Aspect(configuration);
12
- expect(aspect.invoke(['foo'])).toStrictEqual(configuration.foo);
13
- expect(aspect.invoke(['bar', 'baz'])).toStrictEqual(configuration.bar.baz);
14
- });
15
- //# sourceMappingURL=Aspect.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Aspect.test.js","sourceRoot":"","sources":["../source/Aspect.test.ts"],"names":[],"mappings":";;AAAA,qCAAiC;AAEjC,EAAE,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;IACnC,MAAM,aAAa,GAAG;QACpB,GAAG,EAAE,KAAK;QACV,GAAG,EAAE;YACH,GAAG,EAAE,MAAM;SACZ;KACF,CAAA;IAED,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,aAAa,CAAC,CAAA;IAExC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;IAC/D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAC5E,CAAC,CAAC,CAAA"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,64 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const generic_1 = require("@toa.io/generic");
4
- const core_1 = require("@toa.io/core");
5
- const randomstring_1 = require("randomstring");
6
- const configuration_1 = require("./configuration");
7
- let locator;
8
- let manifest;
9
- beforeEach(() => {
10
- locator = new core_1.Locator((0, randomstring_1.generate)(), (0, randomstring_1.generate)());
11
- manifest = { schema: { foo: 'string' } };
12
- });
13
- afterEach(() => {
14
- for (const name of used)
15
- delete process.env[name];
16
- used = [];
17
- });
18
- it('should read value', async () => {
19
- manifest.schema = { foo: 'string' };
20
- const value = { foo: (0, randomstring_1.generate)() };
21
- set(value);
22
- const result = (0, configuration_1.get)(locator, manifest);
23
- expect(result).toStrictEqual(value);
24
- });
25
- it('should return empty object if no value set', async () => {
26
- expect((0, configuration_1.get)(locator, manifest)).toStrictEqual({});
27
- });
28
- it('should substitute secrets', async () => {
29
- const value = { foo: '$BAR' };
30
- set(value);
31
- set('bar', '_BAR');
32
- const result = (0, configuration_1.get)(locator, manifest);
33
- expect(result).toStrictEqual({ foo: 'bar' });
34
- });
35
- it('should use defaults', async () => {
36
- manifest.schema = { foo: 'string', bar: ['number'], 'baz?': 'string' };
37
- manifest.defaults = { foo: 'bar', bar: [1] };
38
- const values = { bar: [2], baz: 'foo' };
39
- set(values);
40
- const result = (0, configuration_1.get)(locator, manifest);
41
- expect(result).toStrictEqual({
42
- foo: 'bar',
43
- bar: [2],
44
- baz: 'foo'
45
- });
46
- });
47
- it('should validate', async () => {
48
- manifest.schema = { foo: 'hello', bar: 'number' };
49
- const values = { bar: 5 };
50
- set(values);
51
- const result = (0, configuration_1.get)(locator, manifest);
52
- expect(result).toStrictEqual({
53
- foo: 'hello',
54
- bar: 5
55
- });
56
- });
57
- function set(value, key = locator.uppercase) {
58
- const string = typeof value === 'string' ? value : (0, generic_1.encode)(value);
59
- const name = 'TOA_CONFIGURATION_' + key;
60
- process.env[name] = string;
61
- used.push(name);
62
- }
63
- let used = [];
64
- //# sourceMappingURL=configuration.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"configuration.test.js","sourceRoot":"","sources":["../source/configuration.test.ts"],"names":[],"mappings":"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"}
@@ -1,8 +0,0 @@
1
- import { type Dependency } from '@toa.io/operations';
2
- import { type Manifest } from './manifest';
3
- import type { context } from '@toa.io/norm';
4
- export declare function deployment(instances: Instance[], annotation?: Annotation): Dependency;
5
- export declare const SECRET_RX: RegExp;
6
- export declare const PREFIX = "TOA_CONFIGURATION_";
7
- export type Annotation = Record<string, object>;
8
- export type Instance = context.Dependency<Manifest>;
@@ -1,88 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.PREFIX = exports.SECRET_RX = exports.deployment = void 0;
30
- const node_assert_1 = __importDefault(require("node:assert"));
31
- const schemas = __importStar(require("@toa.io/schemas"));
32
- const generic_1 = require("@toa.io/generic");
33
- const validators = __importStar(require("./schemas"));
34
- function deployment(instances, annotation = {}) {
35
- validate(annotation, instances);
36
- const variables = {};
37
- for (const instance of instances) {
38
- const values = annotation[instance.locator.id];
39
- validateInstance(instance, values);
40
- if (values === undefined)
41
- continue;
42
- variables[instance.locator.label] = [{
43
- name: exports.PREFIX + instance.locator.uppercase,
44
- value: (0, generic_1.encode)(values)
45
- }];
46
- const secrets = createSecrets(values);
47
- variables[instance.locator.label].push(...secrets);
48
- }
49
- return { variables };
50
- }
51
- exports.deployment = deployment;
52
- function createSecrets(values) {
53
- const secrets = [];
54
- for (const value of Object.values(values)) {
55
- if (typeof value === 'object' && value !== null)
56
- secrets.push(...createSecrets(value));
57
- if (typeof value !== 'string')
58
- continue;
59
- const match = value.match(exports.SECRET_RX);
60
- if (match === null)
61
- continue;
62
- const name = match.groups?.variable;
63
- node_assert_1.default.ok(name !== undefined);
64
- secrets.push({
65
- name: exports.PREFIX + '_' + name,
66
- secret: {
67
- name: 'toa-configuration',
68
- key: name
69
- }
70
- });
71
- }
72
- return secrets;
73
- }
74
- function validate(annotation, instances) {
75
- validators.annotation.validate(annotation);
76
- const requested = instances.map((instance) => instance.locator.id);
77
- for (const id of Object.keys(annotation))
78
- node_assert_1.default.ok(requested.includes(id), `Component '${id}' does not request configuration or does not exist.`);
79
- }
80
- function validateInstance(instace, values = {}) {
81
- const defaults = instace.manifest.defaults ?? {};
82
- const configuration = (0, generic_1.overwrite)(defaults, values);
83
- const schema = schemas.schema(instace.manifest.schema);
84
- schema.validate(configuration);
85
- }
86
- exports.SECRET_RX = /^\$(?<variable>[A-Z0-9_]{1,32})$/;
87
- exports.PREFIX = 'TOA_CONFIGURATION_';
88
- //# sourceMappingURL=deployment.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deployment.js","sourceRoot":"","sources":["../source/deployment.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const deployment_1 = require("./deployment");
4
- it('should validate annotation', async () => {
5
- const wrongType = 'not ok';
6
- expect(() => (0, deployment_1.deployment)([], wrongType)).toThrow('object');
7
- });
8
- it('should validate values', async () => {
9
- const manifest = {
10
- schema: { foo: 'string', bar: 'number' },
11
- defaults: { foo: 'ok', bar: 0 }
12
- };
13
- const locator = { id: 'component' };
14
- const instances = [{ manifest, locator }];
15
- const annotation = { [locator.id]: { bar: 'not a number' } };
16
- expect(() => (0, deployment_1.deployment)(instances, annotation)).toThrow('number');
17
- });
18
- //# sourceMappingURL=deployment.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deployment.test.js","sourceRoot":"","sources":["../source/deployment.test.ts"],"names":[],"mappings":";;AAAA,6CAAyE;AAGzE,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;IAC1C,MAAM,SAAS,GAAG,QAAiC,CAAA;IAEnD,MAAM,CAAC,GAAG,EAAE,CAAC,IAAA,uBAAU,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AAC3D,CAAC,CAAC,CAAA;AAEF,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;IACtC,MAAM,QAAQ,GAAa;QACzB,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE;QACxC,QAAQ,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE;KAChC,CAAA;IAED,MAAM,OAAO,GAAG,EAAE,EAAE,EAAE,WAAW,EAAE,CAAA;IACnC,MAAM,SAAS,GAAG,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAA0B,CAAA;IAClE,MAAM,UAAU,GAAe,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,CAAA;IAExE,MAAM,CAAC,GAAG,EAAE,CAAC,IAAA,uBAAU,EAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AACnE,CAAC,CAAC,CAAA"}