@toa.io/norm 1.0.0-alpha.19 → 1.0.0-alpha.190

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.19",
3
+ "version": "1.0.0-alpha.190",
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.19",
24
- "@toa.io/generic": "1.0.0-alpha.19",
25
- "@toa.io/schema": "1.0.0-alpha.19",
26
- "@toa.io/schemas": "1.0.0-alpha.19",
27
- "@toa.io/yaml": "1.0.0-alpha.19"
23
+ "@toa.io/core": "1.0.0-alpha.190",
24
+ "@toa.io/generic": "1.0.0-alpha.173",
25
+ "@toa.io/schemas": "1.0.0-alpha.182",
26
+ "@toa.io/yaml": "1.0.0-alpha.182"
28
27
  },
29
- "gitHead": "03c7af7e331dd5774ee53c0e9530535357bac8d2"
28
+ "gitHead": "494b1c8f05c21f377f1152a9d89df5cbbd1001de"
30
29
  }
@@ -14,7 +14,8 @@ const SHORTCUTS = {
14
14
  configuration: '@toa.io/extensions.configuration',
15
15
  state: '@toa.io/extensions.state',
16
16
  stash: '@toa.io/extensions.stash',
17
- storages: '@toa.io/extensions.storages'
17
+ storages: '@toa.io/extensions.storages',
18
+ mail: '@toa.io/extensions.mail'
18
19
  }
19
20
 
20
21
  exports.extensions = extensions
@@ -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
@@ -42,6 +42,11 @@ const collapse = (manifest, prototype) => {
42
42
  delete prototype.entity.schema.properties.id
43
43
  }
44
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
+
45
50
  merge(manifest, { entity, events, extensions })
46
51
  }
47
52
 
@@ -1,11 +1,13 @@
1
1
  'use strict'
2
2
 
3
3
  const { hash } = require('@toa.io/generic')
4
- const assert = require('node:assert')
5
4
 
6
5
  // these defaults are required before validation
7
- const defaults = (manifest) => {
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
13
 
@@ -24,4 +26,13 @@ function protoName (manifest) {
24
26
  return 'proto' + hash(manifest.path)
25
27
  }
26
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
+
27
38
  exports.defaults = defaults
@@ -25,7 +25,12 @@ const createResolver = (properties) => (property) => {
25
25
  function operations (manifest, resolver) {
26
26
  for (const operation of Object.values(manifest.operations)) {
27
27
  if (operation.input !== undefined) operation.input = schema(operation.input, resolver)
28
- if (operation.output !== undefined) operation.output = schema(operation.output, 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)
29
34
  }
30
35
 
31
36
  // forwarding
@@ -3,8 +3,13 @@
3
3
  const { directory: { find } } = require('@toa.io/filesystem')
4
4
  const { resolve } = require('../shortcuts')
5
5
 
6
+ const cache = {}
7
+
6
8
  const extensions = (manifest) => {
7
- if (manifest.extensions === undefined) return
9
+ if (manifest.extensions === undefined)
10
+ manifest.extensions = PREDEFINED
11
+ else
12
+ manifest.extensions = Object.assign({}, PREDEFINED, manifest.extensions)
8
13
 
9
14
  const extensions = manifest.extensions
10
15
 
@@ -14,19 +19,17 @@ const extensions = (manifest) => {
14
19
  // relative path
15
20
  if (key[0] === '.') key = find(key, manifest.path)
16
21
 
17
- const extension = require(key)
22
+ cache[key] ??= require(key)
23
+ const extension = cache[key]
18
24
 
19
25
  if (extension.manifest !== undefined) {
20
26
  declaration = extension.manifest(declaration, manifest)
21
-
22
- if (declaration === undefined) throw new Error(`Extension '${reference}' hasn't returned manifest`)
23
27
  }
24
-
25
- extensions[key] = declaration
26
-
27
- // shortcut was used
28
- if (reference !== key) delete extensions[reference]
29
28
  }
30
29
  }
31
30
 
31
+ const PREDEFINED = {
32
+ '@toa.io/extensions.telemetry': null
33
+ }
34
+
32
35
  exports.extensions = extensions
@@ -6,7 +6,8 @@ const bridge = async (root, manifest) => {
6
6
  await Promise.all([
7
7
  define(root, manifest, 'operations'),
8
8
  define(root, manifest, 'events'),
9
- define(root, manifest, 'receivers')
9
+ define(root, manifest, 'receivers'),
10
+ define(root, manifest, 'guards')
10
11
  ])
11
12
  }
12
13
 
@@ -19,7 +20,7 @@ const define = async (root, manifest, property) => {
19
20
  if (item.bridge === undefined || item.bridge === manifest.bridge) continue // default bridge later
20
21
 
21
22
  const bridge = item.bridge || manifest.bridge
22
- const { define } = require(bridge)
23
+ const define = req(bridge).define
23
24
  const definition = await define[singular](root, endpoint)
24
25
 
25
26
  merge(item, definition)
@@ -44,14 +45,27 @@ const define = async (root, manifest, property) => {
44
45
 
45
46
  const declared = manifest[property][endpoint]
46
47
 
47
- if (declared === undefined) manifest[property][endpoint] = item
48
- else merge(declared, item)
48
+ try {
49
+ if (declared === undefined) manifest[property][endpoint] = item
50
+ else merge(declared, item)
51
+ } catch (error) {
52
+ console.error(`Error merging ${singular} '${endpoint}' in ${root}`)
53
+ throw error
54
+ }
49
55
  }
50
56
  }
51
57
  }
52
58
 
59
+ const cache = {}
60
+
61
+ function req(mod) {
62
+ cache[mod] ??= require(mod)
63
+
64
+ return cache[mod]
65
+ }
66
+
53
67
  const scan = async (bridge, root, property) => {
54
- const { define } = require(bridge)
68
+ const define = req(bridge).define
55
69
 
56
70
  if (property in define)
57
71
  return define[property](root)
@@ -8,7 +8,7 @@ definitions:
8
8
  binding:
9
9
  type: string
10
10
  not:
11
- const: '@toa.io/bindings.loop' # loop is for system use only
11
+ const: "@toa.io/bindings.loop" # loop is for system use only
12
12
 
13
13
  type: object
14
14
  properties:
@@ -17,19 +17,19 @@ properties:
17
17
  nullable: true
18
18
  properties:
19
19
  prototype:
20
- $ref: '#/properties/prototype'
20
+ $ref: "#/properties/prototype"
21
21
  path:
22
22
  type: string
23
23
  operations:
24
24
  type: object
25
25
  propertyNames:
26
- $ref: '#/definitions/name'
26
+ $ref: "#/definitions/name"
27
27
  patternProperties:
28
- '.*':
28
+ ".*":
29
29
  type: object
30
30
  properties:
31
31
  bridge:
32
- $ref: '#/properties/bridge'
32
+ $ref: "#/properties/bridge"
33
33
 
34
34
  path:
35
35
  type: string
@@ -38,19 +38,23 @@ properties:
38
38
  type: object
39
39
  properties:
40
40
  id:
41
- $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]+)?))$
42
43
  label:
43
- $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]+)?))*$
44
46
 
45
47
  name:
46
- $ref: 'definitions#/definitions/token'
48
+ type: string
49
+ pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
47
50
 
48
51
  namespace:
49
- $ref: 'definitions#/definitions/token'
50
- default: 'default'
52
+ type: string
53
+ pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
54
+ default: "default"
51
55
  not:
52
56
  oneOf:
53
- - const: 'system'
57
+ - const: "system"
54
58
 
55
59
  version:
56
60
  type: string
@@ -60,15 +64,17 @@ properties:
60
64
  properties:
61
65
  image:
62
66
  type: string
67
+ run:
68
+ type: string
63
69
 
64
70
  entity:
65
71
  type: object
66
72
  properties:
67
73
  storage:
68
74
  type: string
69
- default: '@toa.io/storages.mongodb'
75
+ default: "@toa.io/storages.mongodb"
70
76
  schema:
71
- $ref: 'definitions#/definitions/schema'
77
+ $ref: https://json-schema.org/draft/2019-09/schema
72
78
  type: object
73
79
  properties:
74
80
  type:
@@ -78,24 +84,24 @@ properties:
78
84
  type: object
79
85
  propertyNames:
80
86
  oneOf:
81
- - $ref: '#/definitions/name'
87
+ - $ref: "#/definitions/name"
82
88
  - enum: [_version, _created, _updated, _deleted]
83
89
  unique:
84
90
  type: object
85
91
  patternProperties:
86
- '.*':
92
+ ".*":
87
93
  type: array
88
94
  items:
89
95
  type: string
90
96
  index:
91
97
  type: object
92
98
  patternProperties:
93
- '.*':
99
+ ".*":
94
100
  type: object
95
101
  patternProperties:
96
- '.*':
102
+ ".*":
97
103
  type: string
98
- enum: [asc, desc, hash]
104
+ enum: [asc, desc, hash, text]
99
105
  associated:
100
106
  type: boolean
101
107
  default: false
@@ -109,7 +115,7 @@ properties:
109
115
  type: array
110
116
  uniqueItems: true
111
117
  items:
112
- $ref: '#/definitions/binding'
118
+ $ref: "#/definitions/binding"
113
119
 
114
120
  bridge:
115
121
  type: string
@@ -117,27 +123,40 @@ properties:
117
123
  operations:
118
124
  type: object
119
125
  propertyNames:
120
- $ref: '#/definitions/name'
126
+ $ref: "#/definitions/name"
121
127
  patternProperties:
122
- '.*':
128
+ ".*":
123
129
  type: object
124
130
  properties:
125
131
  type:
126
- enum: [transition, observation, assignment, computation, effect]
132
+ enum:
133
+ [
134
+ transition,
135
+ observation,
136
+ assignment,
137
+ computation,
138
+ effect,
139
+ unmanaged,
140
+ ]
127
141
  scope:
128
- enum: [object, objects, changeset, none]
142
+ enum: [object, objects, changeset, stream, none]
129
143
  concurrency:
130
144
  enum: [none, retry]
131
145
  forward:
132
- $ref: '#/definitions/name'
146
+ $ref: "#/definitions/name"
133
147
  bridge:
134
148
  type: string
135
149
  bindings:
136
- $ref: '#/properties/bindings'
150
+ $ref: "#/properties/bindings"
137
151
  input:
138
- $ref: 'definitions#/definitions/schema'
152
+ $ref: https://json-schema.org/draft/2019-09/schema
139
153
  output:
140
- $ref: 'definitions#/definitions/schema'
154
+ $ref: https://json-schema.org/draft/2019-09/schema
155
+ default: {}
156
+ errors:
157
+ type: array
158
+ items:
159
+ type: string
141
160
  query:
142
161
  type: boolean
143
162
  required: [type, scope, bindings]
@@ -174,7 +193,7 @@ properties:
174
193
  then:
175
194
  properties:
176
195
  scope:
177
- enum: [object, objects, none]
196
+ enum: [object, objects, stream, none]
178
197
  query:
179
198
  not:
180
199
  const: false
@@ -189,7 +208,7 @@ properties:
189
208
  - if: # computation
190
209
  properties:
191
210
  type:
192
- const: computation
211
+ enum: [computation, unmanaged]
193
212
  then:
194
213
  properties:
195
214
  scope:
@@ -205,20 +224,17 @@ properties:
205
224
  then:
206
225
  properties:
207
226
  scope:
208
- const: none
209
227
  default: none
210
- query:
211
- const: false
212
- default: false
228
+ enum: [object, objects, stream, none]
213
229
  additionalProperties: false
214
230
  additionalProperties: false
215
231
 
216
232
  events:
217
233
  type: object
218
234
  propertyNames:
219
- $ref: 'definitions#/definitions/name'
235
+ $ref: "#/definitions/name"
220
236
  patternProperties:
221
- '.*':
237
+ ".*":
222
238
  type: object
223
239
  properties:
224
240
  bridge:
@@ -226,7 +242,7 @@ properties:
226
242
  path:
227
243
  type: string
228
244
  binding:
229
- $ref: '#/definitions/binding'
245
+ $ref: "#/definitions/binding"
230
246
  conditioned:
231
247
  type: boolean
232
248
  default: false
@@ -239,17 +255,17 @@ properties:
239
255
  receivers:
240
256
  type: object
241
257
  patternProperties:
242
- '.*':
258
+ ".*":
243
259
  type: object
244
260
  properties:
245
261
  operation:
246
- $ref: 'definitions#/definitions/name'
262
+ $ref: "#/definitions/name"
247
263
  bridge:
248
264
  type: string
249
265
  binding:
250
266
  type: string
251
267
  source:
252
- $ref: 'definitions#/definitions/name'
268
+ $ref: "#/definitions/name"
253
269
  not:
254
270
  const: context
255
271
  path:
@@ -260,9 +276,22 @@ properties:
260
276
  adaptive:
261
277
  type: boolean
262
278
  default: false
279
+ arguments:
280
+ type: array
263
281
  required: [operation]
264
282
  additionalProperties: false
265
283
 
284
+ guards:
285
+ type: object
286
+ patternProperties:
287
+ ".*":
288
+ type: object
289
+ properties:
290
+ bridge: { type: string }
291
+ path: { type: string }
292
+ required: [bridge, path]
293
+ additionalProperties: false
294
+
266
295
  extensions:
267
296
  type: object
268
297
 
@@ -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)
@@ -32,11 +32,11 @@ const receivers = (manifest) => {
32
32
  }
33
33
 
34
34
  if (!TYPES.has(manifest.operations[receiver.operation].type)) {
35
- throw new Error(`Receiver '${locator}' must refer to an operation of one of the allowed types: ${Array.from(TYPES).join(', ')}`)
35
+ throw new Error(`Receiver '${locator}' must refer to an operation of the allowed types: ${Array.from(TYPES).join(', ')}`)
36
36
  }
37
37
  }
38
38
  }
39
39
 
40
- const TYPES = new Set(['transition', 'effect'])
40
+ const TYPES = new Set(['transition', 'assignment', 'effect', 'unmanaged'])
41
41
 
42
42
  exports.validate = validate
@@ -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
 
@@ -6,7 +6,8 @@ properties:
6
6
  version:
7
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:
@@ -46,7 +47,7 @@ properties:
46
47
  - linux/amd64
47
48
  - linux/arm/v7
48
49
  - linux/arm64
49
- required: [base, platforms]
50
+ # required: [base]
50
51
  compositions:
51
52
  type: array
52
53
  minItems: 1
@@ -54,14 +55,16 @@ properties:
54
55
  type: object
55
56
  properties:
56
57
  name:
57
- $ref: 'definitions#/definitions/token'
58
+ type: string
59
+ pattern: ^[a-zA-Z]([a-zA-Z0-9]{1,31})?$
58
60
  image:
59
61
  type: string
60
62
  components:
61
63
  type: array
62
64
  minItems: 1
63
65
  items:
64
- $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]+)?))$
65
68
  required: [name, components]
66
69
  annotations:
67
70
  type: object
@@ -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
@@ -20,7 +20,7 @@ const {
20
20
  const component = async (path) => {
21
21
  const manifest = await load(path)
22
22
 
23
- normalize(manifest)
23
+ normalize(manifest, path)
24
24
  validate(manifest)
25
25
  extensions(manifest)
26
26
 
@@ -29,21 +29,21 @@ const component = async (path) => {
29
29
  return manifest
30
30
  }
31
31
 
32
- const load = async (path, base) => {
32
+ const load = async (path, base, proto = false) => {
33
33
  if (base !== undefined) path = find(path, base, MANIFEST)
34
34
 
35
35
  const file = join(path, MANIFEST)
36
- const manifest = /** @type {toa.norm.Component} */ await yaml(file) ?? {}
36
+ const manifest = await yaml(file) ?? {}
37
37
 
38
38
  manifest.path = path
39
39
 
40
- defaults(manifest)
40
+ defaults(manifest, proto)
41
41
  await expand(manifest)
42
42
 
43
43
  await merge(path, manifest)
44
44
 
45
45
  if (manifest.prototype !== null) {
46
- const prototype = await load(manifest.prototype, path)
46
+ const prototype = await load(manifest.prototype, path, true)
47
47
 
48
48
  collapse(manifest, prototype)
49
49
  }
package/src/shortcuts.js CHANGED
@@ -50,7 +50,9 @@ const SHORTCUTS = {
50
50
  configuration: '@toa.io/extensions.configuration',
51
51
  origins: '@toa.io/extensions.origins',
52
52
  stash: '@toa.io/extensions.stash',
53
- storages: '@toa.io/extensions.storages'
53
+ storages: '@toa.io/extensions.storages',
54
+ telemetry: '@toa.io/extensions.telemetry',
55
+ mail: '@toa.io/extensions.mail'
54
56
  }
55
57
 
56
58
  exports.recognize = recognize
@@ -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)
@@ -154,7 +152,7 @@ describe('operations', () => {
154
152
 
155
153
  it('should not have additional properties', () => {
156
154
  manifest.operations.get.foo = 'bar'
157
- expect(() => validate(manifest)).toThrow(/additional property/)
155
+ expect(() => validate(manifest)).toThrow()
158
156
  })
159
157
 
160
158
  it('should have type (transition or observation)', () => {
@@ -176,8 +174,7 @@ describe('operations', () => {
176
174
  })
177
175
 
178
176
  it.each([
179
- ['computation', 'compute'],
180
- ['effect', 'affect']
177
+ ['computation', 'compute']
181
178
  ])('should set query: false for %s', async (_, operation) => {
182
179
  validate(manifest)
183
180
 
@@ -250,7 +247,7 @@ describe('receivers', () => {
250
247
  it('should throw if transition points to observation', () => {
251
248
  manifest.receivers['foo.bar.happened'].operation = 'get'
252
249
 
253
- expect(() => validate(manifest)).toThrow(/one of the allowed types/)
250
+ expect(() => validate(manifest)).toThrow(/of the allowed types/)
254
251
  })
255
252
 
256
253
  it('should throw if source has a name `context`', async () => {
@@ -45,12 +45,6 @@ describe('registry', () => {
45
45
  expect(() => validate(context)).toThrow(/required property 'registry'/)
46
46
  })
47
47
 
48
- it('should require base', () => {
49
- delete context.registry.base
50
-
51
- expect(() => validate(context)).toThrow(/required property 'base'/)
52
- })
53
-
54
48
  it('should set default platforms', () => {
55
49
  delete context.registry.platforms
56
50