@toa.io/pointer 1.0.0-alpha.29 → 1.0.0-alpha.292
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/package.json +6 -9
- package/readme.md +1 -1
- package/schemas/urimap.cos.yaml +14 -2
- package/source/Deployment.ts +9 -30
- package/source/annotation.test.ts +34 -28
- package/source/annotation.ts +16 -12
- package/source/createVariables.test.ts +61 -59
- package/source/createVariables.ts +8 -5
- package/source/index.ts +6 -6
- package/source/naming.ts +4 -8
- package/source/resolve.ts +15 -18
- package/transpiled/Deployment.js +7 -28
- package/transpiled/Deployment.js.map +1 -1
- package/transpiled/annotation.d.ts +1 -1
- package/transpiled/annotation.js +6 -33
- package/transpiled/annotation.js.map +1 -1
- package/transpiled/createVariables.d.ts +2 -2
- package/transpiled/createVariables.js +5 -9
- package/transpiled/createVariables.js.map +1 -1
- package/transpiled/index.d.ts +6 -6
- package/transpiled/index.js +4 -34
- package/transpiled/index.js.map +1 -1
- package/transpiled/naming.js +4 -13
- package/transpiled/naming.js.map +1 -1
- package/transpiled/resolve.d.ts +1 -1
- package/transpiled/resolve.js +8 -12
- package/transpiled/resolve.js.map +1 -1
- package/tsconfig.json +2 -1
- package/tsconfig.tsbuildinfo +1 -0
- package/transpiled/tsconfig.tsbuildinfo +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
# [1.0.0-alpha.292](https://github.com/toa-io/toa/compare/v1.0.0-alpha.291...v1.0.0-alpha.292) (2026-09-07)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @toa.io/pointer
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [1.0.0-alpha.291](https://github.com/toa-io/toa/compare/v1.0.0-alpha.290...v1.0.0-alpha.291) (2026-09-07)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @toa.io/pointer
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# [1.0.0-alpha.289](https://github.com/toa-io/toa/compare/v1.0.0-alpha.288...v1.0.0-alpha.289) (2026-09-07)
|
|
23
|
+
|
|
24
|
+
* A deploy moves only what changed, and a component sees none of the runtime's environment (#1073) ([f38e3db](https://github.com/toa-io/toa/commit/f38e3db533f24db866c57bfa1ef294eff1eaf499)), closes [#1073](https://github.com/toa-io/toa/issues/1073) [#1064](https://github.com/toa-io/toa/issues/1064) [#1066](https://github.com/toa-io/toa/issues/1066) [#1067](https://github.com/toa-io/toa/issues/1067) [#1068](https://github.com/toa-io/toa/issues/1068) [#1069](https://github.com/toa-io/toa/issues/1069) [#1071](https://github.com/toa-io/toa/issues/1071) [#1070](https://github.com/toa-io/toa/issues/1070) [#1072](https://github.com/toa-io/toa/issues/1072)
|
|
25
|
+
|
|
26
|
+
### BREAKING CHANGES
|
|
27
|
+
|
|
28
|
+
* a component that read `process.env.TOA_*` reads `context` instead;
|
|
29
|
+
`echo(input)` no longer substitutes from the environment; a bash operation sees no
|
|
30
|
+
`TOA_*`; images no longer set `USER node` — see migrations/289.md.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# [1.0.0-alpha.287](https://github.com/toa-io/toa/compare/v1.0.0-alpha.286...v1.0.0-alpha.287) (2026-09-06)
|
|
34
|
+
|
|
35
|
+
**Note:** Version bump only for package @toa.io/pointer
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/pointer",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.292",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "Toa Pointer",
|
|
5
6
|
"homepage": "https://toa.io",
|
|
6
7
|
"author": {
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
"url": "https://github.com/toa-io/toa/issues"
|
|
17
18
|
},
|
|
18
19
|
"engines": {
|
|
19
|
-
"node": ">=
|
|
20
|
+
"node": ">= 24.0.0"
|
|
20
21
|
},
|
|
21
22
|
"publishConfig": {
|
|
22
23
|
"access": "public"
|
|
@@ -24,15 +25,11 @@
|
|
|
24
25
|
"main": "transpiled/index.js",
|
|
25
26
|
"types": "transpiled/index.d.ts",
|
|
26
27
|
"dependencies": {
|
|
27
|
-
"@toa.io/generic": "1.0.0-alpha.
|
|
28
|
-
"@toa.io/schemas": "1.0.0-alpha.
|
|
28
|
+
"@toa.io/generic": "1.0.0-alpha.292",
|
|
29
|
+
"@toa.io/schemas": "1.0.0-alpha.292"
|
|
29
30
|
},
|
|
30
31
|
"scripts": {
|
|
31
32
|
"transpile": "tsc"
|
|
32
33
|
},
|
|
33
|
-
"
|
|
34
|
-
"preset": "ts-jest",
|
|
35
|
-
"testEnvironment": "node"
|
|
36
|
-
},
|
|
37
|
-
"gitHead": "186d0e17c12a9016b8076edf925963cbb32b9219"
|
|
34
|
+
"gitHead": "0f6aa3ad9dbec86bb632a7975ea61d1dde1d8fc5"
|
|
38
35
|
}
|
package/readme.md
CHANGED
|
@@ -72,7 +72,7 @@ amqp:
|
|
|
72
72
|
URL resolution for the example above is as follows:
|
|
73
73
|
|
|
74
74
|
| Selector | Result | Description |
|
|
75
|
-
|
|
75
|
+
| ----------------- | ------------------------------------ | ------------------ |
|
|
76
76
|
| `dummies.dummy` | `amqp://d1.rmq.example.com` | Exact match |
|
|
77
77
|
| `dummies.another` | `amqp://all-dummies.rmq.example.com` | Partial match |
|
|
78
78
|
| `what.ever` | `amqp://default.rmq.example.com` | No match (default) |
|
package/schemas/urimap.cos.yaml
CHANGED
|
@@ -1,2 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
properties:
|
|
2
|
+
.:
|
|
3
|
+
type: array
|
|
4
|
+
items:
|
|
5
|
+
type: string
|
|
6
|
+
format: uri
|
|
7
|
+
additionalProperties: false
|
|
8
|
+
type: object
|
|
9
|
+
patternProperties:
|
|
10
|
+
^[a-zA-Z0-9]{1,32}(\.[a-zA-Z0-9]{1,32}){0,3}$:
|
|
11
|
+
type: array
|
|
12
|
+
items:
|
|
13
|
+
type: string
|
|
14
|
+
format: uri
|
package/source/Deployment.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { nameVariable, nameSecret } from './naming'
|
|
2
|
-
import { resolveRecord } from './resolve'
|
|
1
|
+
import { nameVariable, nameSecret } from './naming.js'
|
|
2
|
+
import { resolveRecord } from './resolve.js'
|
|
3
3
|
import type { Variables, Variable } from '@toa.io/operations'
|
|
4
4
|
|
|
5
5
|
export class Deployment {
|
|
6
6
|
private readonly id: string
|
|
7
7
|
private readonly annotation: URIMap
|
|
8
8
|
|
|
9
|
-
public constructor
|
|
9
|
+
public constructor(id: string, annotation: URIMap) {
|
|
10
10
|
this.id = id
|
|
11
11
|
this.annotation = annotation
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
public export
|
|
14
|
+
public export(requests: Request[]): Variables {
|
|
15
15
|
const variables: Variables = {}
|
|
16
16
|
|
|
17
17
|
for (const request of requests)
|
|
@@ -20,7 +20,7 @@ export class Deployment {
|
|
|
20
20
|
return variables
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
private createVariables
|
|
23
|
+
private createVariables(selectors: string[]): Variable[] {
|
|
24
24
|
const variables: Variable[] = []
|
|
25
25
|
|
|
26
26
|
for (const selector of selectors) {
|
|
@@ -33,7 +33,7 @@ export class Deployment {
|
|
|
33
33
|
return variables
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
private createVariable
|
|
36
|
+
private createVariable(selector: string): Variable {
|
|
37
37
|
const name = nameVariable(this.id, selector)
|
|
38
38
|
const { references } = this.resolveRecord(selector)
|
|
39
39
|
const value = references.join(' ')
|
|
@@ -41,17 +41,13 @@ export class Deployment {
|
|
|
41
41
|
return { name, value }
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
private createSecrets
|
|
44
|
+
private createSecrets(selector: string): Variable[] {
|
|
45
45
|
const variables: Variable[] = []
|
|
46
46
|
const { key, references } = this.resolveRecord(selector)
|
|
47
47
|
|
|
48
48
|
const protocol = new URL(references[0]).protocol
|
|
49
49
|
|
|
50
|
-
if (insecureProtocols.includes(protocol))
|
|
51
|
-
return []
|
|
52
|
-
|
|
53
|
-
if (protocol in specialProtocols)
|
|
54
|
-
return specialProtocols[protocol](references)
|
|
50
|
+
if (insecureProtocols.includes(protocol)) return []
|
|
55
51
|
|
|
56
52
|
for (const token of ['username', 'password']) {
|
|
57
53
|
const varName = nameVariable(this.id, selector, token)
|
|
@@ -69,7 +65,7 @@ export class Deployment {
|
|
|
69
65
|
return variables
|
|
70
66
|
}
|
|
71
67
|
|
|
72
|
-
private resolveRecord
|
|
68
|
+
private resolveRecord(selector: string): AnnotationRecord {
|
|
73
69
|
return resolveRecord(this.annotation, selector)
|
|
74
70
|
}
|
|
75
71
|
}
|
|
@@ -86,21 +82,4 @@ export interface AnnotationRecord {
|
|
|
86
82
|
|
|
87
83
|
const insecureProtocols = ['http:', 'https:', 'redis:']
|
|
88
84
|
|
|
89
|
-
const specialProtocols: Record<string, (references: string[]) => Variable[]> = {
|
|
90
|
-
'pubsub:': (references: string[]) => {
|
|
91
|
-
const path = new URL(references[0]).pathname
|
|
92
|
-
const [, , project] = path.split('/')
|
|
93
|
-
const name = nameVariable('ORIGINS_PUBSUB_', project)
|
|
94
|
-
|
|
95
|
-
return [{
|
|
96
|
-
name,
|
|
97
|
-
secret: {
|
|
98
|
-
name: 'toa-origins-pubsub',
|
|
99
|
-
key: project,
|
|
100
|
-
optional: true
|
|
101
|
-
}
|
|
102
|
-
} satisfies Variable]
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
85
|
export type URIMap = Record<string, string[]>
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { normalize } from './annotation.js'
|
|
2
5
|
|
|
3
6
|
describe('normalize', () => {
|
|
4
7
|
it('should expand default shards', async () => {
|
|
5
8
|
const declaration = 'amqp://rmq{0-2}.example.com'
|
|
6
9
|
const annotation = normalize(declaration)
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
.
|
|
10
|
-
'.'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
})
|
|
11
|
+
assert.deepStrictEqual(annotation, {
|
|
12
|
+
'.': [
|
|
13
|
+
'amqp://rmq0.example.com',
|
|
14
|
+
'amqp://rmq1.example.com',
|
|
15
|
+
'amqp://rmq2.example.com'
|
|
16
|
+
]
|
|
17
|
+
})
|
|
16
18
|
})
|
|
17
19
|
|
|
18
20
|
it('should expand shards within array', async () => {
|
|
@@ -22,15 +24,14 @@ describe('normalize', () => {
|
|
|
22
24
|
|
|
23
25
|
const annotation = normalize(declaration)
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
})
|
|
27
|
+
assert.deepStrictEqual(annotation, {
|
|
28
|
+
foo: [
|
|
29
|
+
'amqp://rmq.example.com',
|
|
30
|
+
'amqp://rmq0.example.com',
|
|
31
|
+
'amqp://rmq1.example.com',
|
|
32
|
+
'amqp://rmq2.example.com'
|
|
33
|
+
]
|
|
34
|
+
})
|
|
34
35
|
})
|
|
35
36
|
})
|
|
36
37
|
|
|
@@ -38,29 +39,34 @@ describe('validation', () => {
|
|
|
38
39
|
it('should pass', async () => {
|
|
39
40
|
const declaration = 'http://localhost'
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
.not.toThrow()
|
|
42
|
+
assert.doesNotThrow(() => normalize(declaration))
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
it('should throw if non-uri', async () => {
|
|
46
46
|
const declaration = 'non uri'
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
assert.throws(
|
|
49
|
+
() => normalize(declaration),
|
|
50
|
+
(error: any) => /must match format/.test(error.message)
|
|
51
|
+
)
|
|
50
52
|
})
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
async (
|
|
54
|
+
for (const credentials of ['user:pass', 'user', ':pass'])
|
|
55
|
+
it('should throw if uri has credentials', async () => {
|
|
54
56
|
const declaration = `http://${credentials}@localhost`
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
assert.throws(
|
|
59
|
+
() => normalize(declaration),
|
|
60
|
+
(error: any) => /must not contain credentials/.test(error.message)
|
|
61
|
+
)
|
|
58
62
|
})
|
|
59
63
|
|
|
60
64
|
it('should throw if key is not deployable', async () => {
|
|
61
65
|
const declaration = { 'foo bar': 'http://localhost' }
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
assert.throws(
|
|
68
|
+
() => normalize(declaration),
|
|
69
|
+
(error: any) => /not expected/.test(error.message)
|
|
70
|
+
)
|
|
65
71
|
})
|
|
66
72
|
})
|
package/source/annotation.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { resolve } from 'node:path'
|
|
|
2
2
|
import * as schemas from '@toa.io/schemas'
|
|
3
3
|
import { shards } from '@toa.io/generic'
|
|
4
4
|
import type { Schema } from '@toa.io/schemas'
|
|
5
|
-
import type { URIMap } from './Deployment'
|
|
5
|
+
import type { URIMap } from './Deployment.js'
|
|
6
6
|
|
|
7
|
-
export function normalize
|
|
7
|
+
export function normalize(declaration: Declaration): URIMap {
|
|
8
8
|
const map: URIMap = {}
|
|
9
9
|
|
|
10
10
|
if (declaration === undefined) return map
|
|
@@ -21,27 +21,31 @@ export function normalize (declaration: Declaration): URIMap {
|
|
|
21
21
|
return map
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function format
|
|
24
|
+
function format(values: string[]): string[] {
|
|
25
25
|
return values.map(shards).flat()
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function validate
|
|
28
|
+
function validate(map: URIMap): void {
|
|
29
29
|
schema.validate(map)
|
|
30
30
|
|
|
31
|
-
for (const uris of Object.values(map))
|
|
32
|
-
for (const uri of uris)
|
|
33
|
-
checkCredentials(uri)
|
|
31
|
+
for (const uris of Object.values(map)) for (const uri of uris) checkCredentials(uri)
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
function checkCredentials
|
|
34
|
+
function checkCredentials(uri: string): void {
|
|
37
35
|
const url = new URL(uri)
|
|
38
36
|
|
|
39
37
|
if (url.username !== '' || url.password !== '')
|
|
40
|
-
throw new Error(
|
|
41
|
-
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Pointer URI '${uri}' must not contain credentials. ` +
|
|
40
|
+
'Please refer to the "Credentials" section of the documentation for more information.'
|
|
41
|
+
)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
const path = resolve(
|
|
44
|
+
const path = resolve(import.meta.dirname, '../schemas/urimap.cos.yaml')
|
|
45
45
|
const schema: Schema<URIMap> = schemas.schema(path)
|
|
46
46
|
|
|
47
|
-
export type Declaration =
|
|
47
|
+
export type Declaration =
|
|
48
|
+
| string
|
|
49
|
+
| string[]
|
|
50
|
+
| Record<string, string | string[]>
|
|
51
|
+
| undefined
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
4
|
+
|
|
1
5
|
import { generate } from 'randomstring'
|
|
2
|
-
import { createVariables } from './createVariables'
|
|
6
|
+
import { createVariables } from './createVariables.js'
|
|
3
7
|
import type { Variable, Variables } from '@toa.io/operations'
|
|
4
|
-
import type { Request } from './Deployment'
|
|
8
|
+
import type { Request } from './Deployment.js'
|
|
5
9
|
|
|
6
10
|
it('should create from selector', async () => {
|
|
7
11
|
const id = generate()
|
|
@@ -11,14 +15,15 @@ it('should create from selector', async () => {
|
|
|
11
15
|
const variables = createVariables(id, annotation, [request])
|
|
12
16
|
|
|
13
17
|
const expectation: Variables = {
|
|
14
|
-
[request.group]: [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
[request.group]: [
|
|
19
|
+
{
|
|
20
|
+
name: `TOA_${id.toUpperCase()}_${selector.toUpperCase()}`,
|
|
21
|
+
value: annotation[selector]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
.toStrictEqual(expectation)
|
|
26
|
+
assert.deepStrictEqual(variables, expectation)
|
|
22
27
|
})
|
|
23
28
|
|
|
24
29
|
it('should create from partial match', async () => {
|
|
@@ -30,18 +35,15 @@ it('should create from partial match', async () => {
|
|
|
30
35
|
const variables = createVariables(id, annotation, [request])
|
|
31
36
|
|
|
32
37
|
const expectation: Variables = {
|
|
33
|
-
[request.group]: [
|
|
34
|
-
|
|
35
|
-
selector
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
value: annotation[key]
|
|
40
|
-
}]
|
|
38
|
+
[request.group]: [
|
|
39
|
+
{
|
|
40
|
+
name: `TOA_${id.toUpperCase()}_${selector.replace('.', '_').toUpperCase()}`,
|
|
41
|
+
value: annotation[key]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
.toStrictEqual(expectation)
|
|
46
|
+
assert.deepStrictEqual(variables, expectation)
|
|
45
47
|
})
|
|
46
48
|
|
|
47
49
|
it('should create from default', async () => {
|
|
@@ -52,14 +54,15 @@ it('should create from default', async () => {
|
|
|
52
54
|
const variables = createVariables(id, annotation, [request])
|
|
53
55
|
|
|
54
56
|
const expectation: Variables = {
|
|
55
|
-
[request.group]: [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
[request.group]: [
|
|
58
|
+
{
|
|
59
|
+
name: `TOA_${id.toUpperCase()}_${selector.toUpperCase()}`,
|
|
60
|
+
value: annotation
|
|
61
|
+
}
|
|
62
|
+
]
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
.toStrictEqual(expectation)
|
|
65
|
+
assert.deepStrictEqual(variables, expectation)
|
|
63
66
|
})
|
|
64
67
|
|
|
65
68
|
it('should create from array', async () => {
|
|
@@ -71,14 +74,15 @@ it('should create from array', async () => {
|
|
|
71
74
|
const variables = createVariables(id, annotation, [request])
|
|
72
75
|
|
|
73
76
|
const expectation: Variables = {
|
|
74
|
-
[request.group]: [
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
[request.group]: [
|
|
78
|
+
{
|
|
79
|
+
name: `TOA_${id.toUpperCase()}_${selector.toUpperCase()}`,
|
|
80
|
+
value: values.join(' ')
|
|
81
|
+
}
|
|
82
|
+
]
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
.toStrictEqual(expectation)
|
|
85
|
+
assert.deepStrictEqual(variables, expectation)
|
|
82
86
|
})
|
|
83
87
|
|
|
84
88
|
it('should create from default array', async () => {
|
|
@@ -90,14 +94,15 @@ it('should create from default array', async () => {
|
|
|
90
94
|
const variables = createVariables(id, annotation, [request])
|
|
91
95
|
|
|
92
96
|
const expectation: Variables = {
|
|
93
|
-
[request.group]: [
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
[request.group]: [
|
|
98
|
+
{
|
|
99
|
+
name: `TOA_${id.toUpperCase()}_${selector.toUpperCase()}`,
|
|
100
|
+
value: values.join(' ')
|
|
101
|
+
}
|
|
102
|
+
]
|
|
97
103
|
}
|
|
98
104
|
|
|
99
|
-
|
|
100
|
-
.toStrictEqual(expectation)
|
|
105
|
+
assert.deepStrictEqual(variables, expectation)
|
|
101
106
|
})
|
|
102
107
|
|
|
103
108
|
it('should throw if selector cannot be resolved', async () => {
|
|
@@ -106,8 +111,10 @@ it('should throw if selector cannot be resolved', async () => {
|
|
|
106
111
|
const annotation = {}
|
|
107
112
|
const request: Request = { group: generate(), selectors: [selector] }
|
|
108
113
|
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
assert.throws(
|
|
115
|
+
() => createVariables(id, annotation, [request]),
|
|
116
|
+
(error: any) => /cannot be resolved\./.test(error.message)
|
|
117
|
+
)
|
|
111
118
|
})
|
|
112
119
|
|
|
113
120
|
it('should create credential secrets for annotation keys', async () => {
|
|
@@ -135,35 +142,30 @@ it('should create credential secrets for annotation keys', async () => {
|
|
|
135
142
|
const secrets2 = createExpectedSecrets(id, namespace, selector2)
|
|
136
143
|
const secrets3 = createExpectedSecrets(id, '.', selector3)
|
|
137
144
|
|
|
138
|
-
const
|
|
139
|
-
[group]: expect.arrayContaining([
|
|
140
|
-
...secrets1,
|
|
141
|
-
...secrets2,
|
|
142
|
-
...secrets3
|
|
143
|
-
])
|
|
144
|
-
}
|
|
145
|
+
const expected = [...secrets1, ...secrets2, ...secrets3]
|
|
145
146
|
|
|
146
|
-
|
|
147
|
+
// the group holds every expected secret, in whatever order it built them
|
|
148
|
+
for (const secret of expected)
|
|
149
|
+
assert.ok(variables[group].some((one: any) => isDeepStrictEqual(one, secret)))
|
|
147
150
|
})
|
|
148
151
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const variables = createVariables(id, annotation, [request])
|
|
152
|
+
for (const protocol of ['http:', 'redis:'])
|
|
153
|
+
it(`should not create credetial secrets for ${protocol}`, async () => {
|
|
154
|
+
const id = generate()
|
|
155
|
+
const selector = generate()
|
|
156
|
+
const annotation = { [selector]: uri(protocol) }
|
|
157
|
+
const request: Request = { group: generate(), selectors: [selector] }
|
|
158
|
+
const variables = createVariables(id, annotation, [request])
|
|
157
159
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
})
|
|
160
|
+
for (const variable of variables[request.group])
|
|
161
|
+
assert.strictEqual(variable.secret, undefined)
|
|
162
|
+
})
|
|
161
163
|
|
|
162
|
-
function uri
|
|
164
|
+
function uri(protocol = 'http:'): string {
|
|
163
165
|
return protocol + '//host-' + generate()
|
|
164
166
|
}
|
|
165
167
|
|
|
166
|
-
function createExpectedSecrets
|
|
168
|
+
function createExpectedSecrets(id: string, key: string, selector: string): Variable[] {
|
|
167
169
|
key = key === '.' ? '.default' : '-' + key.replaceAll('.', '-')
|
|
168
170
|
selector = selector.replaceAll('.', '_').toUpperCase()
|
|
169
171
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { Deployment, type Request } from './Deployment'
|
|
2
|
-
import { normalize } from './annotation'
|
|
1
|
+
import { Deployment, type Request } from './Deployment.js'
|
|
2
|
+
import { normalize } from './annotation.js'
|
|
3
3
|
import type { Variables } from '@toa.io/operations'
|
|
4
|
-
import type { Declaration } from './annotation'
|
|
4
|
+
import type { Declaration } from './annotation.js'
|
|
5
5
|
|
|
6
|
-
export function createVariables
|
|
7
|
-
|
|
6
|
+
export function createVariables(
|
|
7
|
+
id: string,
|
|
8
|
+
declaration: Declaration,
|
|
9
|
+
requests: Request[]
|
|
10
|
+
): Variables {
|
|
8
11
|
const annotation = normalize(declaration)
|
|
9
12
|
const deployment = new Deployment(id, annotation)
|
|
10
13
|
|
package/source/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { createVariables } from './createVariables'
|
|
2
|
-
export { resolve, resolveRecord } from './resolve'
|
|
3
|
-
export { normalize } from './annotation'
|
|
4
|
-
export * as naming from './naming'
|
|
1
|
+
export { createVariables } from './createVariables.js'
|
|
2
|
+
export { resolve, resolveRecord } from './resolve.js'
|
|
3
|
+
export { normalize } from './annotation.js'
|
|
4
|
+
export * as naming from './naming.js'
|
|
5
5
|
|
|
6
|
-
export type { Declaration } from './annotation'
|
|
7
|
-
export type { Request, URIMap } from './Deployment'
|
|
6
|
+
export type { Declaration } from './annotation.js'
|
|
7
|
+
export type { Request, URIMap } from './Deployment.js'
|
package/source/naming.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
export function nameVariable
|
|
2
|
-
return 'TOA_' + segments.join('_')
|
|
3
|
-
.replaceAll(/[-.]/g, '_')
|
|
4
|
-
.toUpperCase()
|
|
1
|
+
export function nameVariable(...segments: string[]): string {
|
|
2
|
+
return 'TOA_' + segments.join('_').replaceAll(/[-.]/g, '_').toUpperCase()
|
|
5
3
|
}
|
|
6
4
|
|
|
7
|
-
export function nameSecret
|
|
8
|
-
return 'toa-' + segments.join('-')
|
|
9
|
-
.replaceAll('.', '-')
|
|
10
|
-
.replace(/--$/, '.default')
|
|
5
|
+
export function nameSecret(...segments: string[]): string {
|
|
6
|
+
return 'toa-' + segments.join('-').replaceAll('.', '-').replace(/--$/, '.default')
|
|
11
7
|
}
|
package/source/resolve.ts
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import { nameVariable } from './naming'
|
|
2
|
-
import { type AnnotationRecord, type URIMap } from './Deployment'
|
|
1
|
+
import { nameVariable } from './naming.js'
|
|
2
|
+
import { type AnnotationRecord, type URIMap } from './Deployment.js'
|
|
3
|
+
import { environment } from '@toa.io/generic'
|
|
3
4
|
|
|
4
|
-
export function resolve
|
|
5
|
+
export function resolve(id: string, selector: string): string[] {
|
|
5
6
|
const variable = nameVariable(id, selector)
|
|
6
|
-
const value =
|
|
7
|
+
const value = environment.get(variable)
|
|
7
8
|
|
|
8
|
-
if (value === undefined)
|
|
9
|
-
throw new Error(`${variable} is not set.`)
|
|
9
|
+
if (value === undefined) throw new Error(`${variable} is not set.`)
|
|
10
10
|
|
|
11
11
|
const urls = value.split(' ')
|
|
12
12
|
|
|
13
13
|
return withCredentials(variable, urls)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export function resolveRecord
|
|
17
|
-
if (selector in uris)
|
|
18
|
-
return getRecord(uris, selector)
|
|
16
|
+
export function resolveRecord(uris: URIMap, selector: string): AnnotationRecord {
|
|
17
|
+
if (selector in uris) return getRecord(uris, selector)
|
|
19
18
|
|
|
20
19
|
const segments = selector.split('.')
|
|
21
20
|
|
|
@@ -25,20 +24,18 @@ export function resolveRecord (uris: URIMap, selector: string): AnnotationRecord
|
|
|
25
24
|
if (current in uris) return getRecord(uris, current)
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
if ('.' in uris)
|
|
29
|
-
|
|
30
|
-
else
|
|
31
|
-
throw new Error(`Selector '${selector}' cannot be resolved.`)
|
|
27
|
+
if ('.' in uris) return getRecord(uris, '.')
|
|
28
|
+
else throw new Error(`Selector '${selector}' cannot be resolved.`)
|
|
32
29
|
}
|
|
33
30
|
|
|
34
|
-
function withCredentials
|
|
35
|
-
const username =
|
|
36
|
-
const password =
|
|
31
|
+
function withCredentials(variable: string, urls: string[]): string[] {
|
|
32
|
+
const username = environment.get(variable + '_USERNAME') ?? ''
|
|
33
|
+
const password = environment.get(variable + '_PASSWORD') ?? ''
|
|
37
34
|
|
|
38
35
|
return urls.map((url) => addCredentials(url, username, password))
|
|
39
36
|
}
|
|
40
37
|
|
|
41
|
-
function addCredentials
|
|
38
|
+
function addCredentials(ref: string, username: string, password: string): string {
|
|
42
39
|
const url = new URL(ref)
|
|
43
40
|
|
|
44
41
|
url.username = username
|
|
@@ -47,7 +44,7 @@ function addCredentials (ref: string, username: string, password: string): strin
|
|
|
47
44
|
return url.href
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
function getRecord
|
|
47
|
+
function getRecord(uris: URIMap, key: string): AnnotationRecord {
|
|
51
48
|
return {
|
|
52
49
|
key,
|
|
53
50
|
references: uris[key]
|