@toa.io/extensions.origins 0.20.0-dev.31 → 0.20.0-dev.34

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 (95) hide show
  1. package/package.json +17 -10
  2. package/readme.md +70 -68
  3. package/schemas/annotation.cos.yaml +3 -0
  4. package/schemas/manifest.cos.yaml +4 -0
  5. package/source/Factory.ts +80 -0
  6. package/source/annotation.test.ts +150 -0
  7. package/source/annotation.ts +85 -0
  8. package/source/extension.test.ts +161 -0
  9. package/source/extension.ts +60 -0
  10. package/source/index.ts +2 -0
  11. package/source/manifest.test.ts +30 -0
  12. package/source/manifest.ts +11 -0
  13. package/source/protocols/amqp/.test/aspect.fixtures.js +1 -1
  14. package/source/protocols/amqp/aspect.js +15 -22
  15. package/source/protocols/http/.aspect/permissions.js +13 -10
  16. package/source/protocols/http/aspect.js +16 -37
  17. package/source/protocols/index.ts +16 -0
  18. package/transpiled/Factory.d.ts +17 -0
  19. package/transpiled/Factory.js +57 -0
  20. package/transpiled/Factory.js.map +1 -0
  21. package/transpiled/annotation.d.ts +10 -0
  22. package/transpiled/annotation.js +92 -0
  23. package/transpiled/annotation.js.map +1 -0
  24. package/transpiled/constants.d.ts +1 -0
  25. package/transpiled/constants.js +3 -0
  26. package/transpiled/constants.js.map +1 -0
  27. package/transpiled/env.d.ts +5 -0
  28. package/transpiled/env.js +40 -0
  29. package/transpiled/env.js.map +1 -0
  30. package/transpiled/extension.d.ts +10 -0
  31. package/transpiled/extension.js +49 -0
  32. package/transpiled/extension.js.map +1 -0
  33. package/transpiled/index.d.ts +2 -0
  34. package/transpiled/index.js +9 -0
  35. package/transpiled/index.js.map +1 -0
  36. package/transpiled/manifest.d.ts +2 -0
  37. package/transpiled/manifest.js +36 -0
  38. package/transpiled/manifest.js.map +1 -0
  39. package/transpiled/protocols/amqp/aspect.d.ts +9 -0
  40. package/transpiled/protocols/amqp/aspect.js +53 -0
  41. package/transpiled/protocols/amqp/aspect.js.map +1 -0
  42. package/transpiled/protocols/amqp/deployment.d.ts +5 -0
  43. package/transpiled/protocols/amqp/deployment.js +55 -0
  44. package/transpiled/protocols/amqp/deployment.js.map +1 -0
  45. package/transpiled/protocols/amqp/id.d.ts +1 -0
  46. package/transpiled/protocols/amqp/id.js +3 -0
  47. package/transpiled/protocols/amqp/id.js.map +1 -0
  48. package/transpiled/protocols/amqp/index.d.ts +5 -0
  49. package/transpiled/protocols/amqp/index.js +10 -0
  50. package/transpiled/protocols/amqp/index.js.map +1 -0
  51. package/transpiled/protocols/amqp/protocols.d.ts +2 -0
  52. package/transpiled/protocols/amqp/protocols.js +3 -0
  53. package/transpiled/protocols/amqp/protocols.js.map +1 -0
  54. package/transpiled/protocols/http/.aspect/permissions.d.ts +6 -0
  55. package/transpiled/protocols/http/.aspect/permissions.js +52 -0
  56. package/transpiled/protocols/http/.aspect/permissions.js.map +1 -0
  57. package/transpiled/protocols/http/aspect.d.ts +10 -0
  58. package/transpiled/protocols/http/aspect.js +88 -0
  59. package/transpiled/protocols/http/aspect.js.map +1 -0
  60. package/transpiled/protocols/http/id.d.ts +1 -0
  61. package/transpiled/protocols/http/id.js +3 -0
  62. package/transpiled/protocols/http/id.js.map +1 -0
  63. package/transpiled/protocols/http/index.d.ts +4 -0
  64. package/transpiled/protocols/http/index.js +8 -0
  65. package/transpiled/protocols/http/index.js.map +1 -0
  66. package/transpiled/protocols/http/protocols.d.ts +2 -0
  67. package/transpiled/protocols/http/protocols.js +3 -0
  68. package/transpiled/protocols/http/protocols.js.map +1 -0
  69. package/transpiled/protocols/index.d.ts +9 -0
  70. package/transpiled/protocols/index.js +10 -0
  71. package/transpiled/protocols/index.js.map +1 -0
  72. package/tsconfig.json +12 -0
  73. package/source/.credentials.js +0 -20
  74. package/source/.deployment/index.js +0 -5
  75. package/source/.deployment/uris.js +0 -37
  76. package/source/.test/constants.js +0 -3
  77. package/source/.test/deployment.fixtures.js +0 -20
  78. package/source/.test/factory.fixtures.js +0 -13
  79. package/source/deployment.js +0 -41
  80. package/source/deployment.test.js +0 -175
  81. package/source/factory.js +0 -44
  82. package/source/factory.test.js +0 -140
  83. package/source/index.js +0 -9
  84. package/source/manifest.js +0 -41
  85. package/source/manifest.test.js +0 -76
  86. package/source/protocols/amqp/aspect.test.js +0 -119
  87. package/source/protocols/http/.aspect/permissions.test.js +0 -23
  88. package/source/protocols/http/aspect.test.js +0 -220
  89. package/source/protocols/index.js +0 -6
  90. package/source/schemas/annotations.cos.yaml +0 -1
  91. package/source/schemas/index.js +0 -8
  92. package/source/schemas/manifest.cos.yaml +0 -2
  93. package/types/amqp.d.ts +0 -9
  94. package/types/deployment.d.ts +0 -7
  95. package/types/http.d.ts +0 -28
@@ -0,0 +1,161 @@
1
+ import { generate } from 'randomstring'
2
+ import { encode } from 'msgpackr'
3
+ import { Locator } from '@toa.io/core'
4
+ import { deployment, type Instance } from './extension'
5
+ import type { Annotation, Properties } from './annotation'
6
+ import type { Manifest } from './manifest'
7
+ import type { Dependency } from '@toa.io/operations'
8
+
9
+ const locator = new Locator(generate(), generate())
10
+ const NAMESPACE = locator.namespace.toUpperCase()
11
+ const NAME = locator.name.toUpperCase()
12
+
13
+ it('should deploy pointer variables', async () => {
14
+ const manifest: Manifest = { queue: null }
15
+ const instance = { locator, manifest } as unknown as Instance
16
+ const url = 'amqp://host-' + generate()
17
+
18
+ const annotation: Annotation = {
19
+ [locator.id]: {
20
+ queue: url
21
+ }
22
+ }
23
+
24
+ const deploy = deployment([instance], annotation)
25
+
26
+ const expected: Dependency = {
27
+ variables: {
28
+ [locator.label]: expect.arrayContaining([
29
+ {
30
+ name: `TOA_ORIGINS_${NAMESPACE}_${NAME}_QUEUE`,
31
+ value: url
32
+ }
33
+ ])
34
+ }
35
+ }
36
+
37
+ expect(deploy)
38
+ .toMatchObject(expected)
39
+ })
40
+
41
+ it('should deploy default origin', async () => {
42
+ const example = 'http://api.example.com'
43
+ const manifest: Manifest = { example }
44
+ const instance = { locator, manifest } as unknown as Instance
45
+ const annotation: Annotation = {}
46
+ const deploy = deployment([instance], annotation)
47
+
48
+ const expected: Dependency = {
49
+ variables: {
50
+ [locator.label]: expect.arrayContaining([
51
+ {
52
+ name: `TOA_ORIGINS_${NAMESPACE}_${NAME}_EXAMPLE`,
53
+ value: example
54
+ }
55
+ ])
56
+ }
57
+ }
58
+
59
+ expect(deploy)
60
+ .toMatchObject(expected)
61
+ })
62
+
63
+ it('should deploy properties', async () => {
64
+ const manifest: Manifest = {}
65
+ const instance = { locator, manifest } as unknown as Instance
66
+ const properties: Properties = {
67
+ '.http': {
68
+ '/^http:\\/\\/\\w+api.example.com/': true
69
+ }
70
+ }
71
+
72
+ const annotation: Annotation = {
73
+ [locator.id]: properties
74
+ }
75
+
76
+ const deploy = deployment([instance], annotation)
77
+ const value = encode(properties).toString('base64')
78
+
79
+ const expected: Dependency = {
80
+ variables: {
81
+ [locator.label]: expect.arrayContaining([
82
+ {
83
+ name: `TOA_ORIGINS_${NAMESPACE}_${NAME}__PROPERTIES`,
84
+ value
85
+ }
86
+ ])
87
+ }
88
+ }
89
+
90
+ expect(deploy)
91
+ .toMatchObject(expected)
92
+ })
93
+
94
+ it('should deploy properties with null manifest', async () => {
95
+ const manifest: Manifest = null
96
+ const instance = { locator, manifest } as unknown as Instance
97
+ const properties: Properties = {
98
+ '.http': {
99
+ '/^http:\\/\\/\\w+api.example.com/': true
100
+ }
101
+ }
102
+
103
+ const annotation: Annotation = {
104
+ [locator.id]: properties
105
+ }
106
+
107
+ const deploy = deployment([instance], annotation)
108
+ const value = encode(properties).toString('base64')
109
+
110
+ const expected: Dependency = {
111
+ variables: {
112
+ [locator.label]: expect.arrayContaining([
113
+ {
114
+ name: `TOA_ORIGINS_${NAMESPACE}_${NAME}__PROPERTIES`,
115
+ value
116
+ }
117
+ ])
118
+ }
119
+ }
120
+
121
+ expect(deploy)
122
+ .toMatchObject(expected)
123
+ })
124
+
125
+ it('should deploy credentials for amqp', async () => {
126
+ const manifest: Manifest = { queue: null }
127
+ const instance = { locator, manifest } as unknown as Instance
128
+ const url = 'amqp://host-' + generate()
129
+
130
+ const annotation: Annotation = {
131
+ [locator.id]: {
132
+ queue: url
133
+ }
134
+ }
135
+
136
+ const deploy = deployment([instance], annotation)
137
+
138
+ const expected: Dependency = {
139
+ variables: {
140
+ [locator.label]: expect.arrayContaining([
141
+ {
142
+ name: `TOA_ORIGINS_${NAMESPACE}_${NAME}_QUEUE_USERNAME`,
143
+ secret: {
144
+ name: `toa-origins-${locator.label}-queue`,
145
+ key: 'username'
146
+ }
147
+ },
148
+ {
149
+ name: `TOA_ORIGINS_${NAMESPACE}_${NAME}_QUEUE_PASSWORD`,
150
+ secret: {
151
+ name: `toa-origins-${locator.label}-queue`,
152
+ key: 'password'
153
+ }
154
+ }
155
+ ])
156
+ }
157
+ }
158
+
159
+ expect(deploy)
160
+ .toMatchObject(expected)
161
+ })
@@ -0,0 +1,60 @@
1
+ import { encode } from 'msgpackr'
2
+ import { createVariables, type Request } from '@toa.io/pointer'
3
+ import { merge } from '@toa.io/generic'
4
+ import { normalize, split, type Annotation, type Properties, type Origins } from './annotation'
5
+ import { type Manifest, validate } from './manifest'
6
+ import type { Locator } from '@toa.io/core'
7
+ import type { Dependency, Variables } from '@toa.io/operations'
8
+ import type { context } from '@toa.io/norm'
9
+
10
+ export function deployment (instances: Instance[], annotation: Annotation = {}): Dependency {
11
+ normalize(instances, annotation)
12
+
13
+ const variables: Variables = {}
14
+
15
+ for (const instance of instances) {
16
+ const component = annotation[instance.locator.id]
17
+ const { origins, properties } = split(component)
18
+ const instanceVariables = createInstanceVariables(instance, origins)
19
+ const propertiesVariable = createPropertiesVariable(instance.locator, properties)
20
+
21
+ merge(variables, instanceVariables)
22
+ merge(variables, propertiesVariable)
23
+ }
24
+
25
+ return { variables }
26
+ }
27
+
28
+ export function manifest (manifest: Manifest): Manifest {
29
+ validate(manifest)
30
+
31
+ return manifest
32
+ }
33
+
34
+ function createInstanceVariables (instance: Instance, origins: Origins): Variables {
35
+ if (instance.manifest === null) return {}
36
+
37
+ const label: string = instance.locator.label
38
+ const id = ID_PREFIX + label
39
+ const selectors = Object.keys(instance.manifest)
40
+ const request: Request = { group: label, selectors }
41
+
42
+ return createVariables(id, origins, [request])
43
+ }
44
+
45
+ function createPropertiesVariable (locator: Locator, properties: Properties): Variables {
46
+ const name = ENV_PREFIX + locator.uppercase + PROPERTIES_SUFFIX
47
+ const value = encode(properties).toString('base64')
48
+
49
+ return {
50
+ [locator.label]: [
51
+ { name, value }
52
+ ]
53
+ }
54
+ }
55
+
56
+ export const ID_PREFIX = 'origins-'
57
+ export const ENV_PREFIX = 'TOA_ORIGINS_'
58
+ export const PROPERTIES_SUFFIX = '__PROPERTIES'
59
+
60
+ export type Instance = context.Dependency<Manifest>
@@ -0,0 +1,2 @@
1
+ export { deployment, manifest } from './extension'
2
+ export { Factory } from './Factory'
@@ -0,0 +1,30 @@
1
+ import { type Manifest, validate } from './manifest'
2
+
3
+ let manifest: Manifest
4
+
5
+ it('should not throw if valid', async () => {
6
+ manifest = {
7
+ one: 'http://localhost',
8
+ two: null
9
+ }
10
+
11
+ expect(run).not.toThrow()
12
+ })
13
+
14
+ it('should throw if not a uri', async () => {
15
+ manifest = {
16
+ one: 'not a URI'
17
+ }
18
+
19
+ expect(run).toThrow('must match format')
20
+ })
21
+
22
+ it('should not throw on null manifest', async () => {
23
+ manifest = null
24
+
25
+ expect(run).not.toThrow()
26
+ })
27
+
28
+ function run (): void {
29
+ validate(manifest)
30
+ }
@@ -0,0 +1,11 @@
1
+ import { resolve } from 'node:path'
2
+ import * as schemas from '@toa.io/schemas'
3
+
4
+ export function validate (manifest: Manifest): void {
5
+ if (manifest !== null) schema.validate(manifest)
6
+ }
7
+
8
+ const path = resolve(__dirname, '../schemas/manifest.cos.yaml')
9
+ const schema = schemas.schema(path)
10
+
11
+ export type Manifest = Record<string, string | null> | null
@@ -9,7 +9,7 @@ const originCount = random(5) + 2
9
9
  for (let j = 0; j < originCount; j++) {
10
10
  const origin = generate()
11
11
 
12
- manifest[origin] = 'amqp://' + generate()
12
+ manifest[origin] = ['amqp://' + generate()]
13
13
  }
14
14
 
15
15
  exports.manifest = manifest
@@ -2,32 +2,25 @@
2
2
 
3
3
  const { assert } = require('comq')
4
4
  const { Connector } = require('@toa.io/core')
5
- const { shards } = require('@toa.io/generic')
5
+ const protocol = require('./index')
6
6
 
7
- const { id } = require('./id')
8
-
9
- /**
10
- * @implements {toa.origins.amqp.Aspect}
11
- */
12
7
  class Aspect extends Connector {
13
- name = id
14
- /** @type {toa.origins.Manifest} */
15
- #manifest
8
+ name = protocol.id
9
+
10
+ #resolve
16
11
 
17
12
  /** @type {Record<string, Partial<comq.IO>>} */
18
13
  #origins = {}
19
14
 
20
- /**
21
- * @param {toa.origins.Manifest} manifest
22
- */
23
- constructor (manifest) {
15
+ constructor (resolve) {
24
16
  super()
25
17
 
26
- this.#manifest = manifest
18
+ this.#resolve = resolve
27
19
  }
28
20
 
29
21
  async open () {
30
- const promises = Object.entries(this.#manifest).map(this.#open)
22
+ const cfg = await this.#resolve()
23
+ const promises = Object.entries(cfg.origins).map(this.#open)
31
24
 
32
25
  await Promise.all(promises)
33
26
  }
@@ -39,11 +32,14 @@ class Aspect extends Connector {
39
32
  }
40
33
 
41
34
  async invoke (origin, method, ...args) {
35
+ if (this.#origins[origin]?.[method] === undefined) {
36
+ throw new Error(`Origin "${origin}" or method "${method}" is undefined`)
37
+ }
38
+
42
39
  return this.#origins[origin][method](...args)
43
40
  }
44
41
 
45
- #open = async ([origin, reference]) => {
46
- const references = shards(reference)
42
+ #open = async ([origin, references]) => {
47
43
  const io = await assert(...references)
48
44
 
49
45
  this.#origins[origin] = restrict(io)
@@ -67,11 +63,8 @@ function restrict (io) {
67
63
  }
68
64
  }
69
65
 
70
- /**
71
- * @param {toa.origins.Manifest} manifest
72
- */
73
- function create (manifest) {
74
- return new Aspect(manifest)
66
+ function create (resolve) {
67
+ return new Aspect(resolve)
75
68
  }
76
69
 
77
70
  exports.create = create
@@ -1,23 +1,26 @@
1
1
  'use strict'
2
2
 
3
3
  const { echo } = require('@toa.io/generic')
4
+ const { Connector } = require('@toa.io/core')
4
5
 
5
- /**
6
- * @implements {toa.origins.http.Permissions}
7
- */
8
- class Permissions {
9
- #default = process.env.TOA_DEV === '1'
10
-
6
+ class Permissions extends Connector {
11
7
  /** @type {RegExp[]} */
12
8
  #allowances = []
13
9
 
14
10
  /** @type {RegExp[]} */
15
11
  #denials = []
16
12
 
17
- /**
18
- * @param {toa.origins.http.Properties} properties
19
- */
20
- constructor (properties) {
13
+ #resolve
14
+
15
+ constructor (resolve) {
16
+ super()
17
+
18
+ this.#resolve = resolve
19
+ }
20
+
21
+ async open () {
22
+ const { properties } = await this.#resolve()
23
+
21
24
  if (properties !== undefined) this.#parse(properties)
22
25
  }
23
26
 
@@ -1,41 +1,35 @@
1
1
  'use strict'
2
2
 
3
- /**
4
- * @typedef {import('node-fetch').RequestInit} Request
5
- * @typedef {import('node-fetch').Response} Response
6
- */
7
-
8
3
  const fetch = require('node-fetch')
9
4
 
10
5
  const { Connector } = require('@toa.io/core')
11
6
  const { retry } = require('@toa.io/generic')
12
7
 
13
8
  const { Permissions } = require('./.aspect/permissions')
14
- const { id } = require('./id')
15
9
  const protocols = require('./protocols')
10
+ const protocol = require('./index')
16
11
 
17
- /**
18
- * @implements {toa.origins.http.Aspect}
19
- */
20
12
  class Aspect extends Connector {
21
13
  /** @readonly */
22
- name = id
14
+ name = protocol.id
23
15
 
24
- /** @type {toa.origins.Manifest} */
16
+ #resolve
25
17
  #origins
26
-
27
- /** @type {toa.origins.http.Permissions} */
28
18
  #permissions
29
19
 
30
- /**
31
- * @param {toa.origins.Manifest} manifest
32
- * @param {toa.origins.http.Permissions} permissions
33
- */
34
- constructor (manifest, permissions) {
20
+ constructor (resolve, permissions) {
35
21
  super()
36
22
 
37
- this.#origins = manifest
23
+ this.#resolve = resolve
38
24
  this.#permissions = permissions
25
+
26
+ this.depends(permissions)
27
+ }
28
+
29
+ async open () {
30
+ const { origins } = await this.#resolve()
31
+
32
+ this.#origins = origins
39
33
  }
40
34
 
41
35
  async invoke (name, path, request, options) {
@@ -56,23 +50,12 @@ class Aspect extends Connector {
56
50
  return this.#request(url.href, request, options?.retry)
57
51
  }
58
52
 
59
- /**
60
- * @param {string} url
61
- * @param {Request} request
62
- * @return {Promise<Response>}
63
- */
64
53
  async #invokeURL (url, request) {
65
54
  if (this.#permissions.test(url) === false) throw new Error(`URL '${url}' is not allowed`)
66
55
 
67
56
  return this.#request(url, request)
68
57
  }
69
58
 
70
- /**
71
- * @param {string} url
72
- * @param {Request} request
73
- * @param {toa.generic.retry.Options} [options]
74
- * @return {Promise<Response>}
75
- */
76
59
  async #request (url, request, options) {
77
60
  const call = () => fetch(url, request)
78
61
 
@@ -117,14 +100,10 @@ function isAbsoluteURL (path) {
117
100
 
118
101
  const PLACEHOLDER = /\*/g
119
102
 
120
- /**
121
- * @param {toa.origins.Manifest} manifest
122
- * @param {toa.origins.http.Properties} [properties]
123
- */
124
- function create (manifest, properties) {
125
- const permissions = new Permissions(properties)
103
+ function create (resolve) {
104
+ const permissions = new Permissions(resolve)
126
105
 
127
- return new Aspect(manifest, permissions)
106
+ return new Aspect(resolve, permissions)
128
107
  }
129
108
 
130
109
  exports.create = create
@@ -0,0 +1,16 @@
1
+ 'use strict'
2
+
3
+ import { type Resolver } from '../Factory'
4
+ import amqp from './amqp'
5
+ import http from './http'
6
+ import type { extensions } from '@toa.io/core'
7
+
8
+ export const protocols: Protocol[] = [http, amqp]
9
+
10
+ export interface Protocol {
11
+ id: ProtocolID
12
+ protocols: string[]
13
+ create: (resolver: Resolver) => extensions.Aspect
14
+ }
15
+
16
+ export type ProtocolID = 'http' | 'amqp'
@@ -0,0 +1,17 @@
1
+ import { type URIMap } from '@toa.io/pointer';
2
+ import type { Locator, extensions } from '@toa.io/core';
3
+ import type { Manifest } from './manifest';
4
+ export declare class Factory implements extensions.Factory {
5
+ aspect(locator: Locator, manifest: Manifest): extensions.Aspect[];
6
+ private createAspect;
7
+ private resolver;
8
+ private getURIs;
9
+ private filterOrigins;
10
+ private readOrigin;
11
+ private getProperties;
12
+ }
13
+ export interface Configuration {
14
+ origins: URIMap;
15
+ properties: Record<string, boolean>;
16
+ }
17
+ export type Resolver = () => Promise<Configuration>;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Factory = void 0;
4
+ const msgpackr_1 = require("msgpackr");
5
+ const pointer_1 = require("@toa.io/pointer");
6
+ const generic_1 = require("@toa.io/generic");
7
+ const protocols_1 = require("./protocols");
8
+ const extension_1 = require("./extension");
9
+ class Factory {
10
+ aspect(locator, manifest) {
11
+ return protocols_1.protocols.map((protocol) => this.createAspect(locator, manifest, protocol));
12
+ }
13
+ createAspect(locator, manifest, protocol) {
14
+ const resolver = this.resolver(locator, manifest, protocol);
15
+ return protocol.create(resolver);
16
+ }
17
+ resolver(locator, manifest, protocol) {
18
+ return (0, generic_1.memo)(async () => {
19
+ const uris = await this.getURIs(locator, manifest);
20
+ const allProperties = this.getProperties(locator);
21
+ const origins = this.filterOrigins(uris, protocol.protocols);
22
+ const properties = allProperties['.' + protocol.id] ?? {};
23
+ return { origins, properties };
24
+ });
25
+ }
26
+ async getURIs(locator, manifest) {
27
+ const map = {};
28
+ if (manifest === null)
29
+ return map;
30
+ for (const [name, value] of Object.entries(manifest))
31
+ map[name] = value !== null ? [value] : await this.readOrigin(locator, name);
32
+ return map;
33
+ }
34
+ filterOrigins(uris, protocols) {
35
+ const filtered = {};
36
+ for (const [name, references] of Object.entries(uris)) {
37
+ const url = new URL(references[0]);
38
+ if (protocols.includes(url.protocol))
39
+ filtered[name] = references;
40
+ }
41
+ return filtered;
42
+ }
43
+ async readOrigin(locator, name) {
44
+ const id = extension_1.ID_PREFIX + locator.label;
45
+ return await (0, pointer_1.resolve)(id, name);
46
+ }
47
+ getProperties(locator) {
48
+ const variable = extension_1.ENV_PREFIX + locator.uppercase + extension_1.PROPERTIES_SUFFIX;
49
+ const value = process.env[variable];
50
+ if (value === undefined)
51
+ return {};
52
+ const buffer = Buffer.from(value, 'base64');
53
+ return (0, msgpackr_1.decode)(buffer);
54
+ }
55
+ }
56
+ exports.Factory = Factory;
57
+ //# sourceMappingURL=Factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Factory.js","sourceRoot":"","sources":["../source/Factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Instance } from './extension';
2
+ export declare function normalize(instances: Instance[], annotation: Annotation): void;
3
+ export declare function split(component: Component): {
4
+ origins: Origins;
5
+ properties: Properties;
6
+ };
7
+ export type Component = Origins | Properties;
8
+ export type Annotation = Record<string, Component>;
9
+ export type Properties = Partial<Record<'.http', Record<string, boolean>>>;
10
+ export type Origins = Record<string, string | string[]>;
@@ -0,0 +1,92 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.split = exports.normalize = void 0;
27
+ const node_path_1 = require("node:path");
28
+ const schemas = __importStar(require("@toa.io/schemas"));
29
+ const protocols_1 = require("./protocols");
30
+ function normalize(instances, annotation) {
31
+ schema.validate(annotation);
32
+ mergeDefaults(annotation, instances);
33
+ checkProtocols(annotation);
34
+ }
35
+ exports.normalize = normalize;
36
+ function split(component) {
37
+ const origins = {};
38
+ const properties = {};
39
+ for (const [key, value] of Object.entries(component))
40
+ if (key[0] === '.')
41
+ properties[key] = value;
42
+ else
43
+ origins[key] = value;
44
+ return { origins, properties };
45
+ }
46
+ exports.split = split;
47
+ function mergeDefaults(annotation, instances) {
48
+ for (const instance of instances) {
49
+ const component = annotation[instance.locator.id] ?? {};
50
+ annotation[instance.locator.id] = mergeInstance(component, instance);
51
+ }
52
+ }
53
+ function mergeInstance(origins, instance) {
54
+ const id = instance.locator.id;
55
+ if (instance.manifest === null)
56
+ return origins;
57
+ for (const [origin, value] of Object.entries(instance.manifest))
58
+ if (origins[origin] === undefined)
59
+ if (value === null)
60
+ throw new Error(`Origin '${origin}' is not defined for '${id}'`);
61
+ else
62
+ origins[origin] = value;
63
+ return origins;
64
+ }
65
+ function checkProtocols(annotation) {
66
+ for (const component of Object.values(annotation)) {
67
+ const { origins } = split(component);
68
+ const urlSets = Object.values(origins);
69
+ for (const urls of urlSets)
70
+ checkURLs(Array.isArray(urls) ? urls : [urls]);
71
+ }
72
+ }
73
+ function checkURLs(urls) {
74
+ let id = null;
75
+ for (const url of urls) {
76
+ const protocol = resolveProtocol(url);
77
+ if (id === null)
78
+ id = protocol.id;
79
+ else if (id !== protocol.id)
80
+ throw new Error(`Origin has inconsistent protocols: ${id}, ${protocol.id}`);
81
+ }
82
+ }
83
+ function resolveProtocol(reference) {
84
+ const url = new URL(reference);
85
+ for (const protocol of protocols_1.protocols)
86
+ if (protocol.protocols.includes(url.protocol))
87
+ return protocol;
88
+ throw new Error(`Protocol '${url.protocol}' is not supported.`);
89
+ }
90
+ const path = (0, node_path_1.resolve)(__dirname, '../schemas/annotation.cos.yaml');
91
+ const schema = schemas.schema(path);
92
+ //# sourceMappingURL=annotation.js.map