@toa.io/norm 1.0.0-alpha.0 → 1.0.0-alpha.102

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/norm",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.0-alpha.102",
4
4
  "description": "Toa declarations normalization and validation",
5
5
  "author": "temich <tema.gurtovoy@gmail.com>",
6
6
  "homepage": "https://github.com/toa-io/toa#readme",
@@ -20,11 +20,10 @@
20
20
  "test": "echo \"Error: run tests from root\" && exit 1"
21
21
  },
22
22
  "dependencies": {
23
- "@toa.io/core": "1.0.0-alpha.0",
24
- "@toa.io/generic": "1.0.0-alpha.0",
25
- "@toa.io/schema": "1.0.0-alpha.0",
26
- "@toa.io/schemas": "1.0.0-alpha.0",
27
- "@toa.io/yaml": "1.0.0-alpha.0"
23
+ "@toa.io/core": "1.0.0-alpha.93",
24
+ "@toa.io/generic": "1.0.0-alpha.93",
25
+ "@toa.io/schemas": "1.0.0-alpha.93",
26
+ "@toa.io/yaml": "1.0.0-alpha.93"
28
27
  },
29
- "gitHead": "06c64546f6292cc07c52f74b31415101037f7616"
28
+ "gitHead": "ce5b6e22c1adbec4cc5d4dc5dd8f6bafc41d93d0"
30
29
  }
@@ -5,7 +5,7 @@ const { expand } = require('@toa.io/schemas')
5
5
  const { resolve } = require('../../shortcuts')
6
6
 
7
7
  function entity (manifest) {
8
- if (manifest.entity === undefined) return
8
+ if (!('entity' in manifest)) return
9
9
  if ('schema' in manifest.entity) manifest.entity.schema = expand(manifest.entity.schema)
10
10
 
11
11
  manifest.entity.storage = resolve(manifest.entity.storage)
@@ -7,6 +7,7 @@ const { extensions } = require('./extensions')
7
7
  const { operations } = require('./operations')
8
8
  const { properties } = require('./properties')
9
9
  const { receivers } = require('./receivers')
10
+ const { version } = require('./version')
10
11
 
11
12
  exports.bridge = bridge
12
13
  exports.entity = entity
@@ -15,3 +16,4 @@ exports.extensions = extensions
15
16
  exports.operations = operations
16
17
  exports.properties = properties
17
18
  exports.receivers = receivers
19
+ exports.version = version
@@ -0,0 +1,45 @@
1
+ 'use strict'
2
+
3
+ const { join } = require('node:path')
4
+ const { createHash } = require('node:crypto')
5
+ const fs = require('node:fs/promises')
6
+ const { createReadStream } = require('node:fs')
7
+ const { once } = require('node:events')
8
+
9
+ async function version (manifest) {
10
+ manifest.version ??= await hash(manifest.path)
11
+ }
12
+
13
+ async function hash (path) {
14
+ const hash = await hashd(path)
15
+
16
+ return hash.digest('hex').slice(0, 8)
17
+ }
18
+
19
+ /**
20
+ * @param {string} path
21
+ * @param {import('node:crypto').Hash} hash
22
+ */
23
+ async function hashd (path, hash = createHash('sha256')) {
24
+ const stat = await fs.stat(path)
25
+
26
+ if (stat.isFile()) {
27
+ const stream = createReadStream(path)
28
+
29
+ stream.pipe(hash, { end: false })
30
+
31
+ return await once(stream, 'end')
32
+ }
33
+
34
+ if (stat.isDirectory()) {
35
+ const entries = await fs.opendir(path)
36
+
37
+ for await (const entry of entries) {
38
+ await hashd(join(path, entry.name), hash)
39
+ }
40
+
41
+ return hash
42
+ }
43
+ }
44
+
45
+ exports.version = version
@@ -4,7 +4,7 @@ const operations = (component) => {
4
4
  if (component.operations === undefined) return
5
5
 
6
6
  for (const [endpoint, operation] of Object.entries(component.operations)) {
7
- if (operation.type === 'computation' || operation.type === 'effect')
7
+ if (operation.scope === 'none')
8
8
  operation.query = false
9
9
 
10
10
  if (operation.bindings === undefined) operation.bindings = component.bindings
@@ -34,10 +34,19 @@ const collapse = (manifest, prototype) => {
34
34
  }
35
35
  }
36
36
 
37
- delete prototype.entity?.storage // ???
38
-
39
37
  const { entity, events, extensions } = prototype
40
38
 
39
+ if (manifest.entity?.schema?.properties.id !== undefined && entity?.schema?.properties.id !== undefined) {
40
+ manifest.entity.custom = true
41
+
42
+ delete prototype.entity.schema.properties.id
43
+ }
44
+
45
+ if (prototype.events !== undefined && manifest.events !== undefined)
46
+ for (const event of Object.keys(prototype.events))
47
+ if (event in manifest.events)
48
+ delete prototype.events[event]
49
+
41
50
  merge(manifest, { entity, events, extensions })
42
51
  }
43
52
 
@@ -3,21 +3,36 @@
3
3
  const { hash } = require('@toa.io/generic')
4
4
 
5
5
  // these defaults are required before validation
6
- const defaults = (manifest) => {
7
- if (manifest.prototype === undefined) manifest.prototype = '@toa.io/prototype'
8
- if (manifest.name === undefined) manifest.name = protoName(manifest)
6
+ const defaults = (manifest, proto) => {
7
+ if (manifest.name === undefined)
8
+ if (proto) manifest.name = protoName(manifest)
9
+ else nameAfterDir(manifest)
10
+
9
11
  if (manifest.bindings === undefined) manifest.bindings = ['@toa.io/bindings.amqp']
10
12
  if (manifest.bridge === undefined) manifest.bridge = '@toa.io/bridges.node'
11
- if (manifest.entity === null || manifest.entity === undefined) manifest.entity = { storage: null }
12
- if (manifest.entity.storage === undefined) manifest.entity.storage = '@toa.io/storages.mongodb'
13
- if (manifest.entity.storage === null) manifest.entity.storage = '@toa.io/storages.null'
14
13
 
15
- // TODO: bridge.version()
16
- if (manifest.version === undefined) manifest.version = '0.0.0'
14
+ if ('entity' in manifest) {
15
+ if (manifest.entity.storage === null)
16
+ manifest.entity.storage = '@toa.io/storages.null'
17
+ } else {
18
+ if (manifest.prototype === undefined)
19
+ manifest.prototype = null
20
+ }
21
+
22
+ if (manifest.prototype === undefined) manifest.prototype = '@toa.io/prototype'
17
23
  }
18
24
 
19
25
  function protoName (manifest) {
20
26
  return 'proto' + hash(manifest.path)
21
27
  }
22
28
 
29
+ function nameAfterDir (manifest) {
30
+ const parts = manifest.path.split('/')
31
+ const dirname = parts[parts.length - 1]
32
+ const [name, namespace] = dirname.split('.').reverse()
33
+
34
+ manifest.name = name
35
+ manifest.namespace = namespace
36
+ }
37
+
23
38
  exports.defaults = defaults
@@ -4,13 +4,33 @@ const { merge } = require('@toa.io/generic')
4
4
 
5
5
  const dereference = (manifest) => {
6
6
  // schemas
7
- const property = resolve(manifest.entity.schema.properties)
7
+ const resolver = createResolver(manifest.entity?.schema?.properties)
8
8
 
9
- schema(manifest.entity.schema, property)
9
+ if (manifest.entity !== undefined)
10
+ schema(manifest.entity.schema, resolver)
10
11
 
12
+ if ('operations' in manifest)
13
+ operations(manifest, resolver)
14
+
15
+ }
16
+
17
+ const createResolver = (properties) => (property) => {
18
+ if (properties?.[property] === undefined) {
19
+ throw new Error(`Referenced property '${property}' is not defined`)
20
+ }
21
+
22
+ return properties[property]
23
+ }
24
+
25
+ function operations (manifest, resolver) {
11
26
  for (const operation of Object.values(manifest.operations)) {
12
- if (operation.input !== undefined) operation.input = schema(operation.input, property)
13
- if (operation.output !== undefined) operation.output = schema(operation.output, property)
27
+ if (operation.input !== undefined) operation.input = schema(operation.input, resolver)
28
+
29
+ if (operation.output !== undefined)
30
+ if (Array.isArray(operation.output) && operation.output.length === 1)
31
+ operation.output = [schema(operation.output[0], resolver)]
32
+ else
33
+ operation.output = schema(operation.output, resolver)
14
34
  }
15
35
 
16
36
  // forwarding
@@ -21,14 +41,7 @@ const dereference = (manifest) => {
21
41
  for (const operation of Object.values(manifest.operations)) {
22
42
  delete operation.forwarded
23
43
  }
24
- }
25
-
26
- const resolve = (schema) => (property) => {
27
- if (schema[property] === undefined) {
28
- throw new Error(`Referenced property '${property}' is not defined`)
29
- }
30
44
 
31
- return schema[property]
32
45
  }
33
46
 
34
47
  const schema = (object, resolve) => {
@@ -7,10 +7,11 @@ const {
7
7
  events,
8
8
  receivers,
9
9
  extensions,
10
- properties
10
+ properties,
11
+ version
11
12
  } = require('./.expand')
12
13
 
13
- const expand = (manifest) => {
14
+ async function expand (manifest) {
14
15
  entity(manifest)
15
16
  bridge(manifest)
16
17
  operations(manifest)
@@ -18,6 +19,8 @@ const expand = (manifest) => {
18
19
  receivers(manifest)
19
20
  properties(manifest)
20
21
  extensions(manifest)
22
+
23
+ await version(manifest)
21
24
  }
22
25
 
23
26
  exports.expand = expand
@@ -4,7 +4,10 @@ const { directory: { find } } = require('@toa.io/filesystem')
4
4
  const { resolve } = require('../shortcuts')
5
5
 
6
6
  const extensions = (manifest) => {
7
- if (manifest.extensions === undefined) return
7
+ if (manifest.extensions === undefined)
8
+ manifest.extensions = PREDEFINED
9
+ else
10
+ manifest.extensions = Object.assign({}, PREDEFINED, manifest.extensions)
8
11
 
9
12
  const extensions = manifest.extensions
10
13
 
@@ -29,4 +32,8 @@ const extensions = (manifest) => {
29
32
  }
30
33
  }
31
34
 
35
+ const PREDEFINED = {
36
+ '@toa.io/extensions.telemetry': null
37
+ }
38
+
32
39
  exports.extensions = extensions
@@ -28,6 +28,10 @@ const define = async (root, manifest, property) => {
28
28
 
29
29
  // default bridge
30
30
  const definition = await scan(manifest.bridge, root, property)
31
+
32
+ if (definition === undefined)
33
+ return
34
+
31
35
  const items = Object.entries(definition)
32
36
 
33
37
  if (items.length) {
@@ -40,8 +44,13 @@ const define = async (root, manifest, property) => {
40
44
 
41
45
  const declared = manifest[property][endpoint]
42
46
 
43
- if (declared === undefined) manifest[property][endpoint] = item
44
- else merge(declared, item)
47
+ try {
48
+ if (declared === undefined) manifest[property][endpoint] = item
49
+ else merge(declared, item)
50
+ } catch (error) {
51
+ console.error(`Error merging ${singular} '${endpoint}' in ${root}`)
52
+ throw error
53
+ }
45
54
  }
46
55
  }
47
56
  }
@@ -49,7 +58,9 @@ const define = async (root, manifest, property) => {
49
58
  const scan = async (bridge, root, property) => {
50
59
  const { define } = require(bridge)
51
60
 
52
- return define[property](root)
61
+ if (property in define)
62
+ return define[property](root)
63
+ else return undefined
53
64
  }
54
65
 
55
66
  exports.merge = bridge
@@ -2,6 +2,9 @@ $schema: https://json-schema.org/draft/2019-09/schema
2
2
  $id: https://schemas.toa.io/0.0.0/manifest
3
3
 
4
4
  definitions:
5
+ name:
6
+ type: string
7
+ pattern: ^[a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?$
5
8
  binding:
6
9
  type: string
7
10
  not:
@@ -20,7 +23,7 @@ properties:
20
23
  operations:
21
24
  type: object
22
25
  propertyNames:
23
- $ref: 'definitions#/definitions/name'
26
+ $ref: '#/definitions/name'
24
27
  patternProperties:
25
28
  '.*':
26
29
  type: object
@@ -35,30 +38,41 @@ properties:
35
38
  type: object
36
39
  properties:
37
40
  id:
38
- $ref: 'definitions#/definitions/locator'
41
+ type: string
42
+ pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(\.([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))$
39
43
  label:
40
- $ref: 'definitions#/definitions/label'
44
+ type: string
45
+ pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(-([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))*$
41
46
 
42
47
  name:
43
- $ref: 'definitions#/definitions/token'
48
+ type: string
49
+ pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
44
50
 
45
51
  namespace:
46
- $ref: 'definitions#/definitions/token'
52
+ type: string
53
+ pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
47
54
  default: 'default'
48
55
  not:
49
56
  oneOf:
50
57
  - const: 'system'
51
58
 
52
59
  version:
53
- $ref: 'definitions#/definitions/version'
60
+ type: string
61
+
62
+ build:
63
+ type: object
64
+ properties:
65
+ image:
66
+ type: string
54
67
 
55
68
  entity:
56
69
  type: object
57
70
  properties:
58
71
  storage:
59
72
  type: string
73
+ default: '@toa.io/storages.mongodb'
60
74
  schema:
61
- $ref: 'definitions#/definitions/schema'
75
+ $ref: https://json-schema.org/draft/2019-09/schema
62
76
  type: object
63
77
  properties:
64
78
  type:
@@ -68,9 +82,28 @@ properties:
68
82
  type: object
69
83
  propertyNames:
70
84
  oneOf:
71
- - $ref: 'definitions#/definitions/name'
72
- - enum: [_version]
73
- initialized:
85
+ - $ref: '#/definitions/name'
86
+ - enum: [_version, _created, _updated, _deleted]
87
+ unique:
88
+ type: object
89
+ patternProperties:
90
+ '.*':
91
+ type: array
92
+ items:
93
+ type: string
94
+ index:
95
+ type: object
96
+ patternProperties:
97
+ '.*':
98
+ type: object
99
+ patternProperties:
100
+ '.*':
101
+ type: string
102
+ enum: [asc, desc, hash]
103
+ associated:
104
+ type: boolean
105
+ default: false
106
+ custom:
74
107
  type: boolean
75
108
  default: false
76
109
  required: [schema]
@@ -88,7 +121,7 @@ properties:
88
121
  operations:
89
122
  type: object
90
123
  propertyNames:
91
- $ref: 'definitions#/definitions/name'
124
+ $ref: '#/definitions/name'
92
125
  patternProperties:
93
126
  '.*':
94
127
  type: object
@@ -96,19 +129,24 @@ properties:
96
129
  type:
97
130
  enum: [transition, observation, assignment, computation, effect]
98
131
  scope:
99
- enum: [object, objects, changeset, none]
132
+ enum: [object, objects, changeset, stream, none]
100
133
  concurrency:
101
134
  enum: [none, retry]
102
135
  forward:
103
- $ref: 'definitions#/definitions/name'
136
+ $ref: '#/definitions/name'
104
137
  bridge:
105
138
  type: string
106
139
  bindings:
107
140
  $ref: '#/properties/bindings'
108
141
  input:
109
- $ref: 'definitions#/definitions/schema'
142
+ $ref: https://json-schema.org/draft/2019-09/schema
110
143
  output:
111
- $ref: 'definitions#/definitions/schema'
144
+ $ref: https://json-schema.org/draft/2019-09/schema
145
+ default: { }
146
+ errors:
147
+ type: array
148
+ items:
149
+ type: string
112
150
  query:
113
151
  type: boolean
114
152
  required: [type, scope, bindings]
@@ -145,7 +183,7 @@ properties:
145
183
  then:
146
184
  properties:
147
185
  scope:
148
- enum: [object, objects, none]
186
+ enum: [object, objects, stream, none]
149
187
  query:
150
188
  not:
151
189
  const: false
@@ -176,18 +214,15 @@ properties:
176
214
  then:
177
215
  properties:
178
216
  scope:
179
- const: none
180
217
  default: none
181
- query:
182
- const: false
183
- default: false
218
+ enum: [object, objects, stream, none]
184
219
  additionalProperties: false
185
220
  additionalProperties: false
186
221
 
187
222
  events:
188
223
  type: object
189
224
  propertyNames:
190
- $ref: 'definitions#/definitions/name'
225
+ $ref: '#/definitions/name'
191
226
  patternProperties:
192
227
  '.*':
193
228
  type: object
@@ -214,13 +249,13 @@ properties:
214
249
  type: object
215
250
  properties:
216
251
  operation:
217
- $ref: 'definitions#/definitions/name'
252
+ $ref: '#/definitions/name'
218
253
  bridge:
219
254
  type: string
220
255
  binding:
221
256
  type: string
222
257
  source:
223
- $ref: 'definitions#/definitions/name'
258
+ $ref: '#/definitions/name'
224
259
  not:
225
260
  const: context
226
261
  path:
@@ -231,6 +266,8 @@ properties:
231
266
  adaptive:
232
267
  type: boolean
233
268
  default: false
269
+ arguments:
270
+ type: array
234
271
  required: [operation]
235
272
  additionalProperties: false
236
273
 
@@ -3,15 +3,15 @@
3
3
  const path = require('node:path')
4
4
 
5
5
  const { load } = require('@toa.io/yaml')
6
- const { Schema } = require('@toa.io/schema')
6
+ const schemas = require('@toa.io/schemas')
7
7
 
8
8
  const object = load.sync(path.resolve(__dirname, 'schema.yaml'))
9
- const schema = new Schema(object)
9
+ const schema = schemas.schema(object)
10
10
 
11
11
  const validate = (manifest) => {
12
12
  const error = schema.fit(manifest)
13
13
 
14
- if (error) throw new Error(error.message)
14
+ if (error) throw error
15
15
 
16
16
  if (manifest.events !== undefined) events(manifest)
17
17
  if (manifest.receivers !== undefined) receivers(manifest)
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { resolve } = require('node:path')
4
+
3
5
  const connectors = (context, extracted) => {
4
6
  const connectors = {}
5
7
 
@@ -9,11 +11,16 @@ const connectors = (context, extracted) => {
9
11
  ) ?? []
10
12
 
11
13
  for (const component of components) {
12
- if (connectors[component.entity.storage] === undefined) {
13
- connectors[component.entity.storage] = []
14
- }
14
+ if (component.entity !== undefined) {
15
+ let storage = component.entity.storage
15
16
 
16
- connectors[component.entity.storage].push(component)
17
+ if (storage[0] === '.') {
18
+ storage = resolve(component.path, storage)
19
+ }
20
+
21
+ connectors[storage] ??= []
22
+ connectors[storage].push(component)
23
+ }
17
24
 
18
25
  const bindings = new Set()
19
26
 
@@ -24,6 +24,15 @@ const resolve = (references, annotations) => {
24
24
  }
25
25
  }
26
26
 
27
+ for (const dependency of Object.keys(annotations)) {
28
+ const { module } = load(dependency)
29
+
30
+ if (!module.standalone || (dependency in dependencies))
31
+ continue
32
+
33
+ dependencies[dependency] = []
34
+ }
35
+
27
36
  return dependencies
28
37
  }
29
38
 
@@ -4,13 +4,15 @@ $id: https://schemas.toa.io/0.0.0/context
4
4
  type: object
5
5
  properties:
6
6
  version:
7
- $ref: 'definitions#/definitions/version'
7
+ type: string
8
8
  name:
9
- $ref: 'definitions#/definitions/label'
9
+ type: string
10
+ pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(-([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))*$
10
11
  description:
11
12
  type: string
12
13
  packages:
13
14
  type: string
15
+ default: components/*
14
16
  build:
15
17
  type: object
16
18
  properties:
@@ -20,7 +22,7 @@ properties:
20
22
  type: object
21
23
  properties:
22
24
  version:
23
- $ref: 'definitions#/definitions/version'
25
+ type: string
24
26
  registry:
25
27
  type: string
26
28
  format: uri
@@ -53,14 +55,18 @@ properties:
53
55
  type: object
54
56
  properties:
55
57
  name:
56
- $ref: 'definitions#/definitions/token'
58
+ type: string
59
+ pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
60
+ image:
61
+ type: string
57
62
  components:
58
63
  type: array
59
64
  minItems: 1
60
65
  items:
61
- $ref: 'definitions#/definitions/locator'
66
+ type: string
67
+ pattern: ^([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?)(\.([a-zA-Z]+([_a-zA-Z0-9]*[a-zA-Z0-9]+)?))$
62
68
  required: [name, components]
63
69
  annotations:
64
70
  type: object
65
- required: [runtime, name, packages, registry]
71
+ required: [runtime, name, registry]
66
72
  additionalProperties: false
@@ -3,15 +3,12 @@
3
3
  const { resolve } = require('node:path')
4
4
 
5
5
  const { load } = require('@toa.io/yaml')
6
- const { Schema } = require('@toa.io/schema')
6
+ const schemas = require('@toa.io/schemas')
7
7
 
8
8
  const path = resolve(__dirname, 'schema.yaml')
9
9
  const object = load.sync(path)
10
- const schema = new Schema(object)
10
+ const schema = schemas.schema(object)
11
11
 
12
- /**
13
- * @param {toa.norm.context.Declaration} context
14
- */
15
12
  const validate = (context) => {
16
13
  schema.validate(context)
17
14
  }
package/src/component.js CHANGED
@@ -13,7 +13,6 @@ const {
13
13
  collapse,
14
14
  dereference,
15
15
  defaults,
16
- dependencies,
17
16
  normalize,
18
17
  extensions
19
18
  } = require('./.component')
@@ -21,7 +20,7 @@ const {
21
20
  const component = async (path) => {
22
21
  const manifest = await load(path)
23
22
 
24
- normalize(manifest)
23
+ normalize(manifest, path)
25
24
  validate(manifest)
26
25
  extensions(manifest)
27
26
 
@@ -30,27 +29,27 @@ const component = async (path) => {
30
29
  return manifest
31
30
  }
32
31
 
33
- const load = async (path, base) => {
32
+ const load = async (path, base, proto = false) => {
34
33
  if (base !== undefined) path = find(path, base, MANIFEST)
35
34
 
36
35
  const file = join(path, MANIFEST)
37
- const manifest = /** @type {toa.norm.Component} */ await yaml(file) ?? {}
36
+ const manifest = await yaml(file) ?? {}
38
37
 
39
38
  manifest.path = path
40
39
 
41
- defaults(manifest)
42
- expand(manifest)
40
+ defaults(manifest, proto)
41
+ await expand(manifest)
43
42
 
44
43
  await merge(path, manifest)
45
44
 
46
45
  if (manifest.prototype !== null) {
47
- const prototype = await load(manifest.prototype, path)
46
+ const prototype = await load(manifest.prototype, path, true)
48
47
 
49
48
  collapse(manifest, prototype)
50
49
  }
51
50
 
52
51
  dereference(manifest)
53
- dependencies(manifest)
52
+ // dependencies(manifest)
54
53
 
55
54
  return manifest
56
55
  }
package/src/shortcuts.js CHANGED
@@ -41,6 +41,7 @@ const recognize = (shortcuts, object, group) => {
41
41
  const SHORTCUTS = {
42
42
  amqp: '@toa.io/bindings.amqp',
43
43
  node: '@toa.io/bridges.node',
44
+ bash: '@toa.io/bridges.bash',
44
45
  mongodb: '@toa.io/storages.mongodb',
45
46
  sql: '@toa.io/storages.sql',
46
47
  queues: '@toa.io/storages.queues',
@@ -49,7 +50,8 @@ const SHORTCUTS = {
49
50
  configuration: '@toa.io/extensions.configuration',
50
51
  origins: '@toa.io/extensions.origins',
51
52
  stash: '@toa.io/extensions.stash',
52
- storages: '@toa.io/extensions.storages'
53
+ storages: '@toa.io/extensions.storages',
54
+ telemetry: '@toa.io/extensions.telemetry'
53
55
  }
54
56
 
55
57
  exports.recognize = recognize
@@ -30,19 +30,6 @@ it('should remove prototype property', () => {
30
30
  })
31
31
 
32
32
  describe('entity', () => {
33
- it('should ignore storage', () => {
34
- const source = { entity: { storage: 'foo' } }
35
- const prototype = { entity: { storage: 'bar' } }
36
- const manifest = clone(source)
37
-
38
- collapse(manifest, prototype)
39
- expect(manifest).toStrictEqual(source)
40
-
41
- delete manifest.entity.storage
42
- collapse(manifest, prototype)
43
- expect(manifest).toStrictEqual({ entity: {} })
44
- })
45
-
46
33
  it('should merge entity schema', () => {
47
34
  const manifest = clone(samples.entity.manifest)
48
35
 
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const source = {
4
+ path: '',
4
5
  entity: {
5
6
  schema: {
6
7
  properties: {
@@ -1,5 +1,3 @@
1
- // noinspection JSUnresolvedVariable
2
-
3
1
  'use strict'
4
2
 
5
3
  const clone = require('clone-deep')
@@ -20,13 +18,13 @@ it('should be ok', () => {
20
18
  it('should provide error', () => {
21
19
  manifest.foo = 'bar'
22
20
 
23
- expect(() => validate(manifest)).toThrow(/must NOT have additional property/)
21
+ expect(() => validate(manifest)).toThrow()
24
22
  })
25
23
 
26
24
  it('should not have additional properties', () => {
27
25
  manifest.foo = 'bar'
28
26
 
29
- expect(() => validate(manifest)).toThrow(/must NOT have additional property/)
27
+ expect(() => validate(manifest)).toThrow()
30
28
  })
31
29
 
32
30
  describe('namespace', () => {
@@ -83,13 +81,13 @@ describe('entity', () => {
83
81
 
84
82
  it('should not have additional properties', () => {
85
83
  manifest.entity.foo = 'bar'
86
- expect(() => validate(manifest)).toThrow(/must NOT have additional property/)
84
+ expect(() => validate(manifest)).toThrow()
87
85
  })
88
86
 
89
87
  describe('schema', () => {
90
88
  it('should be required', () => {
91
89
  delete manifest.entity.schema
92
- expect(() => validate(manifest)).toThrow(/must have required property/)
90
+ expect(() => validate(manifest)).toThrow()
93
91
  })
94
92
 
95
93
  it('should be JSON schema object', () => {
@@ -99,7 +97,7 @@ describe('entity', () => {
99
97
 
100
98
  it('should be JSON schema object of type object', () => {
101
99
  manifest.entity.schema = { type: 'integer' }
102
- expect(() => validate(manifest)).toThrow(/must be equal to constant 'object'/)
100
+ expect(() => validate(manifest)).toThrow(/must be equal to constant/)
103
101
 
104
102
  manifest.entity.schema = {}
105
103
  validate(manifest)
@@ -112,15 +110,18 @@ describe('entity', () => {
112
110
  })
113
111
 
114
112
  it('should allow default id', () => {
115
- manifest.entity.schema.properties.id = { type: 'string', pattern: '^[a-fA-F0-9]+$' }
113
+ manifest.entity.schema.properties.id = {
114
+ type: 'string',
115
+ pattern: '^[a-fA-F0-9]+$'
116
+ }
116
117
  expect(() => validate(manifest)).not.toThrow()
117
118
  })
118
119
  })
119
120
 
120
- describe('initialized', () => {
121
+ describe('associated', () => {
121
122
  it('should provide default', () => {
122
123
  expect(() => validate(manifest)).not.toThrow()
123
- expect(manifest.entity.initialized).toBe(false)
124
+ expect(manifest.entity.associated).toBe(false)
124
125
  })
125
126
  })
126
127
  })
@@ -151,7 +152,7 @@ describe('operations', () => {
151
152
 
152
153
  it('should not have additional properties', () => {
153
154
  manifest.operations.get.foo = 'bar'
154
- expect(() => validate(manifest)).toThrow(/additional property/)
155
+ expect(() => validate(manifest)).toThrow()
155
156
  })
156
157
 
157
158
  it('should have type (transition or observation)', () => {
@@ -173,8 +174,7 @@ describe('operations', () => {
173
174
  })
174
175
 
175
176
  it.each([
176
- ['computation', 'compute'],
177
- ['effect', 'affect']
177
+ ['computation', 'compute']
178
178
  ])('should set query: false for %s', async (_, operation) => {
179
179
  validate(manifest)
180
180
 
@@ -18,8 +18,7 @@ const component = (id) => {
18
18
  name,
19
19
  id,
20
20
  label: `${namespace}-${name}`
21
- },
22
- entity: null
21
+ }
23
22
  }
24
23
  }
25
24
 
@@ -21,14 +21,6 @@ describe('runtime', () => {
21
21
  expect(() => validate(context)).toThrow(/required/)
22
22
  })
23
23
 
24
- it('should require version as semver', () => {
25
- delete context.runtime.version
26
- expect(() => validate(context)).toThrow(/required/)
27
-
28
- context.runtime.version = '.'
29
- expect(() => validate(context)).toThrow(/pattern/)
30
- })
31
-
32
24
  it('should require registry to match uri format', () => {
33
25
  context.runtime.registry = 'not-a-uri'
34
26
  expect(() => validate(context)).toThrow(/must match format/)
@@ -80,9 +72,10 @@ it('should require name as label', () => {
80
72
  expect(() => validate(context)).not.toThrow(/pattern/)
81
73
  })
82
74
 
83
- it('should require packages location', () => {
75
+ it('should set default packages location', () => {
84
76
  delete context.packages
85
- expect(() => validate(context)).toThrow(/required/)
77
+ expect(() => validate(context)).not.toThrow()
78
+ expect(context.packages).toBe('components/*')
86
79
  })
87
80
 
88
81
  it('should require registry url', () => {
@@ -4,7 +4,7 @@ type Map = {
4
4
  [id: string]: Component
5
5
  }
6
6
 
7
- type Operation = {
7
+ export type Operation = {
8
8
  type: operations.type
9
9
  scope?: operations.scope
10
10
  bindings?: string[]
@@ -14,9 +14,7 @@ type Operation = {
14
14
  query?: boolean
15
15
  }
16
16
 
17
- type Operations = {
18
- [key: string]: Operation
19
- }
17
+ export type Operations = Record<string, Operation>
20
18
 
21
19
  type Event = {
22
20
  binding: string
@@ -39,7 +37,7 @@ type Receiver = {
39
37
  type Entity = {
40
38
  schema: Object
41
39
  storage?: string
42
- initialized?: boolean
40
+ associated?: boolean
43
41
  }
44
42
 
45
43
  type Declaration = {
@@ -1,5 +1,5 @@
1
1
  import { Manifest } from './component'
2
- import { Locator } from '@toa.io/core/types'
2
+ import { Locator } from '@toa.io/core'
3
3
  import type { Declaration } from './context/declaration'
4
4
 
5
5
  interface Runtime{