@toa.io/core 1.0.0-alpha.283 → 1.0.0-alpha.286
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 +19 -7
- package/source/assignment.ts +27 -0
- package/{src/call.js → source/call.ts} +16 -21
- package/{src/cascade.js → source/cascade.ts} +6 -8
- package/{src/component.js → source/component.ts} +27 -25
- package/{src/composition.js → source/composition.ts} +9 -3
- package/{src/connector.js → source/connector.ts} +36 -55
- package/source/context.ts +67 -0
- package/source/contract/contract.ts +23 -0
- package/{src/contract/reply.js → source/contract/reply.ts} +26 -19
- package/source/contract/request.ts +85 -0
- package/source/contract/schemas.ts +39 -0
- package/{src/discovery.js → source/discovery.ts} +15 -8
- package/source/effect.ts +14 -0
- package/{src/emission.js → source/emission.ts} +5 -3
- package/source/entities/changeset.ts +37 -0
- package/source/entities/entity.ts +137 -0
- package/source/entities/factory.ts +52 -0
- package/source/entities/index.ts +4 -0
- package/{src/entities/newid.js → source/entities/newid.ts} +1 -1
- package/{src/entities/set.js → source/entities/set.ts} +8 -5
- package/source/event.ts +57 -0
- package/{src/exceptions.js → source/exceptions.ts} +52 -33
- package/source/exposition.ts +33 -0
- package/source/guard.ts +16 -0
- package/{src/index.js → source/index.ts} +8 -0
- package/{src/locator.js → source/locator.ts} +17 -30
- package/source/observation.ts +16 -0
- package/source/operation.ts +138 -0
- package/{src/outbox/outbox.js → source/outbox/outbox.ts} +95 -51
- package/source/query/criteria.ts +90 -0
- package/source/query/options.ts +35 -0
- package/{src/query.js → source/query.ts} +14 -17
- package/source/receiver.ts +120 -0
- package/source/reflection.ts +20 -0
- package/source/remote.ts +20 -0
- package/source/state.ts +179 -0
- package/source/transition.ts +79 -0
- package/{src/transmission.js → source/transmission.ts} +8 -8
- package/source/types/atomicity.ts +63 -0
- package/source/types/bindings.ts +59 -0
- package/source/types/bridges.ts +54 -0
- package/source/types/extensions.ts +89 -0
- package/{types → source/types}/index.ts +9 -16
- package/{types/message.d.ts → source/types/message.ts} +2 -1
- package/source/types/operations.ts +31 -0
- package/source/types/outbox.ts +35 -0
- package/source/types/receiver.ts +10 -0
- package/{types/request.d.ts → source/types/request.ts} +8 -9
- package/source/types/state.ts +9 -0
- package/source/types/storages.ts +129 -0
- package/source/unmanaged.ts +8 -0
- package/test/call.fixtures.js +3 -1
- package/test/call.test.js +28 -7
- package/test/component.test.js +10 -5
- package/test/connector.fixtures.js +7 -7
- package/test/connector.test.js +15 -2
- package/test/context.fixtures.js +1 -1
- package/test/context.test.js +4 -4
- package/test/contract/conditions.test.js +6 -2
- package/test/contract/contract.fixtures.js +3 -4
- package/test/contract/request.test.js +68 -34
- package/test/discovery.test.js +10 -3
- package/test/emission.test.js +16 -8
- package/test/entities/entity.fixtures.js +5 -6
- package/test/entities/entity.test.js +54 -20
- package/test/entities/factory.fixtures.js +11 -10
- package/test/entities/factory.test.js +47 -10
- package/test/entities/set.test.js +1 -1
- package/test/event.test.js +29 -11
- package/test/locator.test.js +10 -4
- package/test/outbox.test.js +95 -14
- package/test/query.test.js +76 -7
- package/test/receiver.fixtures.js +2 -2
- package/test/receiver.test.js +53 -27
- package/test/reflection.test.js +3 -3
- package/test/state.fixtures.js +10 -3
- package/test/state.test.js +77 -14
- package/test/transmission.test.js +25 -12
- package/transpiled/assignment.d.ts +6 -0
- package/transpiled/assignment.js +20 -0
- package/transpiled/assignment.js.map +1 -0
- package/transpiled/call.d.ts +10 -0
- package/transpiled/call.js +52 -0
- package/transpiled/call.js.map +1 -0
- package/transpiled/cascade.d.ts +7 -0
- package/transpiled/cascade.js +28 -0
- package/transpiled/cascade.js.map +1 -0
- package/transpiled/component.d.ts +15 -0
- package/transpiled/component.js +61 -0
- package/transpiled/component.js.map +1 -0
- package/transpiled/composition.d.ts +6 -0
- package/transpiled/composition.js +23 -0
- package/transpiled/composition.js.map +1 -0
- package/transpiled/connector.d.ts +47 -0
- package/transpiled/connector.js +143 -0
- package/transpiled/connector.js.map +1 -0
- package/transpiled/context.d.ts +18 -0
- package/transpiled/context.js +41 -0
- package/transpiled/context.js.map +1 -0
- package/transpiled/contract/contract.d.ts +10 -0
- package/transpiled/contract/contract.js +14 -0
- package/transpiled/contract/contract.js.map +1 -0
- package/transpiled/contract/index.d.ts +2 -0
- package/transpiled/contract/index.js +3 -0
- package/transpiled/contract/index.js.map +1 -0
- package/transpiled/contract/reply.d.ts +7 -0
- package/transpiled/contract/reply.js +48 -0
- package/transpiled/contract/reply.js.map +1 -0
- package/transpiled/contract/request.d.ts +24 -0
- package/transpiled/contract/request.js +59 -0
- package/transpiled/contract/request.js.map +1 -0
- package/transpiled/contract/schemas.d.ts +4 -0
- package/transpiled/contract/schemas.js +36 -0
- package/transpiled/contract/schemas.js.map +1 -0
- package/transpiled/discovery.d.ts +12 -0
- package/transpiled/discovery.js +34 -0
- package/transpiled/discovery.js.map +1 -0
- package/transpiled/effect.d.ts +5 -0
- package/transpiled/effect.js +11 -0
- package/transpiled/effect.js.map +1 -0
- package/transpiled/emission.d.ts +8 -0
- package/transpiled/emission.js +14 -0
- package/transpiled/emission.js.map +1 -0
- package/transpiled/entities/changeset.d.ts +10 -0
- package/transpiled/entities/changeset.js +27 -0
- package/transpiled/entities/changeset.js.map +1 -0
- package/transpiled/entities/entity.d.ts +19 -0
- package/transpiled/entities/entity.js +109 -0
- package/transpiled/entities/entity.js.map +1 -0
- package/transpiled/entities/factory.d.ts +22 -0
- package/transpiled/entities/factory.js +34 -0
- package/transpiled/entities/factory.js.map +1 -0
- package/transpiled/entities/index.d.ts +4 -0
- package/transpiled/entities/index.js +5 -0
- package/transpiled/entities/index.js.map +1 -0
- package/transpiled/entities/newid.d.ts +1 -0
- package/transpiled/entities/newid.js +7 -0
- package/transpiled/entities/newid.js.map +1 -0
- package/transpiled/entities/set.d.ts +10 -0
- package/transpiled/entities/set.js +19 -0
- package/transpiled/entities/set.js.map +1 -0
- package/transpiled/event.d.ts +14 -0
- package/transpiled/event.js +38 -0
- package/transpiled/event.js.map +1 -0
- package/transpiled/exceptions.d.ts +61 -0
- package/transpiled/exceptions.js +93 -0
- package/transpiled/exceptions.js.map +1 -0
- package/transpiled/exposition.d.ts +18 -0
- package/transpiled/exposition.js +18 -0
- package/transpiled/exposition.js.map +1 -0
- package/transpiled/guard.d.ts +7 -0
- package/transpiled/guard.js +12 -0
- package/transpiled/guard.js.map +1 -0
- package/transpiled/index.d.ts +35 -0
- package/transpiled/index.js +29 -0
- package/transpiled/index.js.map +1 -0
- package/transpiled/locator.d.ts +12 -0
- package/transpiled/locator.js +32 -0
- package/transpiled/locator.js.map +1 -0
- package/transpiled/observation.d.ts +5 -0
- package/transpiled/observation.js +12 -0
- package/transpiled/observation.js.map +1 -0
- package/transpiled/operation.d.ts +49 -0
- package/transpiled/operation.js +77 -0
- package/transpiled/operation.js.map +1 -0
- package/transpiled/outbox/index.d.ts +1 -0
- package/transpiled/outbox/index.js +2 -0
- package/transpiled/outbox/index.js.map +1 -0
- package/transpiled/outbox/outbox.d.ts +46 -0
- package/transpiled/outbox/outbox.js +267 -0
- package/transpiled/outbox/outbox.js.map +1 -0
- package/transpiled/query/criteria.d.ts +6 -0
- package/transpiled/query/criteria.js +74 -0
- package/transpiled/query/criteria.js.map +1 -0
- package/transpiled/query/options.d.ts +3 -0
- package/transpiled/query/options.js +27 -0
- package/transpiled/query/options.js.map +1 -0
- package/transpiled/query.d.ts +9 -0
- package/transpiled/query.js +57 -0
- package/transpiled/query.js.map +1 -0
- package/transpiled/receiver.d.ts +20 -0
- package/transpiled/receiver.js +92 -0
- package/transpiled/receiver.js.map +1 -0
- package/transpiled/reflection.d.ts +9 -0
- package/transpiled/reflection.js +13 -0
- package/transpiled/reflection.js.map +1 -0
- package/transpiled/remote.d.ts +10 -0
- package/transpiled/remote.js +12 -0
- package/transpiled/remote.js.map +1 -0
- package/transpiled/state.d.ts +33 -0
- package/transpiled/state.js +126 -0
- package/transpiled/state.js.map +1 -0
- package/transpiled/transition.d.ts +14 -0
- package/transpiled/transition.js +51 -0
- package/transpiled/transition.js.map +1 -0
- package/transpiled/transmission.d.ts +8 -0
- package/transpiled/transmission.js +30 -0
- package/transpiled/transmission.js.map +1 -0
- package/transpiled/types/atomicity.d.ts +56 -0
- package/transpiled/types/atomicity.js +2 -0
- package/transpiled/types/atomicity.js.map +1 -0
- package/transpiled/types/bindings.d.ts +42 -0
- package/transpiled/types/bindings.js +2 -0
- package/transpiled/types/bindings.js.map +1 -0
- package/transpiled/types/bridges.d.ts +38 -0
- package/transpiled/types/bridges.js +2 -0
- package/transpiled/types/bridges.js.map +1 -0
- package/transpiled/types/extensions.d.ts +62 -0
- package/transpiled/types/extensions.js +2 -0
- package/transpiled/types/extensions.js.map +1 -0
- package/transpiled/types/index.d.ts +13 -0
- package/transpiled/types/index.js +8 -0
- package/transpiled/types/index.js.map +1 -0
- package/transpiled/types/message.d.ts +5 -0
- package/transpiled/types/message.js +2 -0
- package/transpiled/types/message.js.map +1 -0
- package/transpiled/types/operations.d.ts +15 -0
- package/transpiled/types/operations.js +2 -0
- package/transpiled/types/operations.js.map +1 -0
- package/transpiled/types/outbox.d.ts +28 -0
- package/transpiled/types/outbox.js +2 -0
- package/transpiled/types/outbox.js.map +1 -0
- package/transpiled/types/receiver.d.ts +9 -0
- package/transpiled/types/receiver.js +2 -0
- package/transpiled/types/receiver.js.map +1 -0
- package/transpiled/types/request.d.ts +55 -0
- package/transpiled/types/request.js +2 -0
- package/transpiled/types/request.js.map +1 -0
- package/transpiled/types/state.d.ts +9 -0
- package/transpiled/types/state.js +2 -0
- package/transpiled/types/state.js.map +1 -0
- package/transpiled/types/storages.d.ts +106 -0
- package/transpiled/types/storages.js +2 -0
- package/transpiled/types/storages.js.map +1 -0
- package/transpiled/unmanaged.d.ts +5 -0
- package/transpiled/unmanaged.js +7 -0
- package/transpiled/unmanaged.js.map +1 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/CHANGELOG.md +0 -180
- package/src/assignment.js +0 -28
- package/src/context.js +0 -57
- package/src/contract/contract.js +0 -18
- package/src/contract/request.js +0 -77
- package/src/contract/schemas/error.yaml +0 -9
- package/src/contract/schemas/index.js +0 -11
- package/src/contract/schemas/query.yaml +0 -43
- package/src/contract/schemas/source.yaml +0 -23
- package/src/effect.js +0 -15
- package/src/entities/changeset.js +0 -36
- package/src/entities/entity.js +0 -119
- package/src/entities/factory.js +0 -40
- package/src/entities/index.js +0 -1
- package/src/event.js +0 -54
- package/src/exposition.js +0 -24
- package/src/guard.js +0 -13
- package/src/observation.js +0 -8
- package/src/operation.js +0 -95
- package/src/query/criteria.js +0 -37
- package/src/query/options.js +0 -37
- package/src/receiver.js +0 -123
- package/src/reflection.js +0 -24
- package/src/remote.js +0 -14
- package/src/state.js +0 -138
- package/src/transition.js +0 -61
- package/src/unmanaged.js +0 -7
- package/types/atomicity.d.ts +0 -58
- package/types/bindings.d.ts +0 -42
- package/types/bridges.ts +0 -33
- package/types/call.d.ts +0 -13
- package/types/component.d.ts +0 -12
- package/types/connector.d.ts +0 -18
- package/types/context.d.ts +0 -24
- package/types/entity.d.ts +0 -46
- package/types/event.d.ts +0 -11
- package/types/exception.d.ts +0 -4
- package/types/extensions.d.ts +0 -73
- package/types/guard.d.ts +0 -5
- package/types/locator.d.ts +0 -13
- package/types/operations.d.ts +0 -8
- package/types/outbox.d.ts +0 -53
- package/types/query.d.ts +0 -17
- package/types/receiver.d.ts +0 -12
- package/types/reflection.d.ts +0 -14
- package/types/remote.d.ts +0 -18
- package/types/state.d.ts +0 -38
- package/types/storages.d.ts +0 -96
- /package/{src/contract/index.js → source/contract/index.ts} +0 -0
- /package/{src/outbox/index.js → source/outbox/index.ts} +0 -0
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'path'
|
|
2
|
-
import { readFileSync } from 'node:fs'
|
|
3
|
-
import { yaml } from '@toa.io/generic'
|
|
4
|
-
|
|
5
|
-
export const query = read(resolve(import.meta.dirname, './query.yaml'))
|
|
6
|
-
export const error = read(resolve(import.meta.dirname, './error.yaml'))
|
|
7
|
-
export const source = read(resolve(import.meta.dirname, './source.yaml'))
|
|
8
|
-
|
|
9
|
-
function read (path) {
|
|
10
|
-
return yaml.load(readFileSync(path, 'utf8'))
|
|
11
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
type: object
|
|
2
|
-
properties:
|
|
3
|
-
id:
|
|
4
|
-
type: string
|
|
5
|
-
ids:
|
|
6
|
-
type: array
|
|
7
|
-
uniqueItems: true
|
|
8
|
-
minItems: 1
|
|
9
|
-
items:
|
|
10
|
-
type: string
|
|
11
|
-
version:
|
|
12
|
-
type: integer
|
|
13
|
-
minimum: 0
|
|
14
|
-
criteria:
|
|
15
|
-
type: string
|
|
16
|
-
search:
|
|
17
|
-
type: string
|
|
18
|
-
sample:
|
|
19
|
-
type: number
|
|
20
|
-
omit:
|
|
21
|
-
type: integer
|
|
22
|
-
minimum: 0
|
|
23
|
-
limit:
|
|
24
|
-
type: integer
|
|
25
|
-
minimum: 0
|
|
26
|
-
sort:
|
|
27
|
-
type: array
|
|
28
|
-
uniqueItems: true
|
|
29
|
-
minItems: 1
|
|
30
|
-
items:
|
|
31
|
-
type: string
|
|
32
|
-
pattern: ^\w{1,32}(?::(?:asc|desc))?$
|
|
33
|
-
projection:
|
|
34
|
-
type: array
|
|
35
|
-
uniqueItems: true
|
|
36
|
-
minItems: 1
|
|
37
|
-
items:
|
|
38
|
-
type: string
|
|
39
|
-
not:
|
|
40
|
-
const: id
|
|
41
|
-
deleted:
|
|
42
|
-
type: boolean
|
|
43
|
-
additionalProperties: false
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Origin of a call, see toa.core.Source.
|
|
2
|
-
# Deliberately permissive on required properties: the contract throws on a mismatch,
|
|
3
|
-
# and a strict union would turn a partially stamped source into a failed business call.
|
|
4
|
-
# `additionalProperties: false` combined with `removeAdditional` is what matters here —
|
|
5
|
-
# it strips whatever a peer puts in, bounding the cardinality of the resulting map.
|
|
6
|
-
type: object
|
|
7
|
-
properties:
|
|
8
|
-
namespace:
|
|
9
|
-
type: string
|
|
10
|
-
maxLength: 64
|
|
11
|
-
component:
|
|
12
|
-
type: string
|
|
13
|
-
maxLength: 64
|
|
14
|
-
operation:
|
|
15
|
-
type: string
|
|
16
|
-
maxLength: 64
|
|
17
|
-
event:
|
|
18
|
-
type: string
|
|
19
|
-
maxLength: 64
|
|
20
|
-
service:
|
|
21
|
-
type: string
|
|
22
|
-
maxLength: 64
|
|
23
|
-
additionalProperties: false
|
package/src/effect.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Observation } from './observation.js'
|
|
2
|
-
|
|
3
|
-
export class Effect extends Observation {
|
|
4
|
-
|
|
5
|
-
async acquire (store) {
|
|
6
|
-
const { query, entity, input } = store.request
|
|
7
|
-
|
|
8
|
-
if (entity === undefined)
|
|
9
|
-
return super.acquire(store)
|
|
10
|
-
|
|
11
|
-
store.scope = await this.scope.ensure(query, entity, input)
|
|
12
|
-
store.state = store.scope.get()
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { EntityContractException } from '../exceptions.js'
|
|
2
|
-
|
|
3
|
-
export class Changeset {
|
|
4
|
-
/** @type {toa.core.Query} */
|
|
5
|
-
query
|
|
6
|
-
|
|
7
|
-
#schema
|
|
8
|
-
#state
|
|
9
|
-
|
|
10
|
-
constructor (schema, query) {
|
|
11
|
-
this.query = query
|
|
12
|
-
|
|
13
|
-
this.#schema = schema
|
|
14
|
-
this.#state = {}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
get () {
|
|
18
|
-
return this.#state
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
set (value) {
|
|
22
|
-
const error = this.#schema.match(value)
|
|
23
|
-
|
|
24
|
-
if (error !== null)
|
|
25
|
-
throw new EntityContractException(error, value)
|
|
26
|
-
|
|
27
|
-
delete value._version
|
|
28
|
-
value._updated = Date.now()
|
|
29
|
-
|
|
30
|
-
this.#state = value
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export () {
|
|
34
|
-
return this.#state
|
|
35
|
-
}
|
|
36
|
-
}
|
package/src/entities/entity.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { EntityContractException, EntityGuardException } from '../exceptions.js'
|
|
2
|
-
import { newid } from './newid.js'
|
|
3
|
-
|
|
4
|
-
export class Entity {
|
|
5
|
-
deleted = false
|
|
6
|
-
#schema
|
|
7
|
-
#guards
|
|
8
|
-
#origin = null
|
|
9
|
-
#state
|
|
10
|
-
#mutable = true
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @param {boolean} [mutable] whether the entity may be modified and committed
|
|
14
|
-
*/
|
|
15
|
-
constructor (schema, argument, guards, mutable = true) {
|
|
16
|
-
this.#schema = schema
|
|
17
|
-
this.#guards = guards
|
|
18
|
-
|
|
19
|
-
if (typeof argument === 'object') {
|
|
20
|
-
/*
|
|
21
|
-
* The origin is the pre-image a commit diffs the new state against. An operation
|
|
22
|
-
* that cannot commit has nothing to diff, so it takes the record as it came from
|
|
23
|
-
* the storage instead of paying for a deep copy of every record it read.
|
|
24
|
-
*/
|
|
25
|
-
this.#mutable = mutable
|
|
26
|
-
|
|
27
|
-
if (mutable) {
|
|
28
|
-
this.#set(structuredClone(argument))
|
|
29
|
-
this.#origin = argument
|
|
30
|
-
} else
|
|
31
|
-
this.#set(argument)
|
|
32
|
-
} else {
|
|
33
|
-
const id = argument === undefined ? newid() : argument
|
|
34
|
-
this.#init(id)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
get () {
|
|
39
|
-
return this.#state
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
set (value, optional = false) {
|
|
43
|
-
if (!this.#mutable)
|
|
44
|
-
throw new Error('Entity acquired by a read-only operation cannot be modified')
|
|
45
|
-
|
|
46
|
-
if (!optional)
|
|
47
|
-
this.#guard(value)
|
|
48
|
-
|
|
49
|
-
const error = optional ? this.#schema.fitOptional(value) : this.#schema.fit(value)
|
|
50
|
-
|
|
51
|
-
if (error !== null)
|
|
52
|
-
throw new EntityContractException(error, value)
|
|
53
|
-
|
|
54
|
-
this.#revive(value)
|
|
55
|
-
this.#set(value)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
event (input = undefined) {
|
|
59
|
-
return {
|
|
60
|
-
origin: this.#origin,
|
|
61
|
-
state: this.#state,
|
|
62
|
-
trailers: this.#state._trailers,
|
|
63
|
-
input
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
#init (id) {
|
|
68
|
-
const value = { id, _version: 0 }
|
|
69
|
-
|
|
70
|
-
this.set(value, true)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
#guard (value) {
|
|
74
|
-
if (this.#guards === undefined)
|
|
75
|
-
return
|
|
76
|
-
|
|
77
|
-
for (const guard of this.#guards) {
|
|
78
|
-
const ok = guard.fit(value, this.#origin)
|
|
79
|
-
|
|
80
|
-
if (ok === false)
|
|
81
|
-
throw new EntityGuardException(guard.name, value)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// deletion is only expressed as a new _deleted timestamp,
|
|
86
|
-
// so committing over a tombstone without touching it means revival
|
|
87
|
-
#revive (value) {
|
|
88
|
-
if (this.#origin?._deleted == null || value._deleted !== this.#origin._deleted)
|
|
89
|
-
return
|
|
90
|
-
|
|
91
|
-
value._deleted = null
|
|
92
|
-
this.deleted = false
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
#set (value) {
|
|
96
|
-
if (!('_trailers' in value))
|
|
97
|
-
Object.defineProperty(value, '_trailers', {
|
|
98
|
-
writable: false,
|
|
99
|
-
configurable: false,
|
|
100
|
-
enumerable: false,
|
|
101
|
-
value: {}
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
if (!('_created' in value)) {
|
|
105
|
-
value._created = Date.now()
|
|
106
|
-
value._updated ??= value._created
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if ('_deleted' in value && value._deleted !== null)
|
|
110
|
-
this.deleted = true
|
|
111
|
-
|
|
112
|
-
if (this.#state !== undefined) {
|
|
113
|
-
value._updated = Date.now()
|
|
114
|
-
value._version++
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
this.#state = value
|
|
118
|
-
}
|
|
119
|
-
}
|
package/src/entities/factory.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { newid } from './newid.js'
|
|
2
|
-
import { Entity } from './entity.js'
|
|
3
|
-
import { EntitySet } from './set.js'
|
|
4
|
-
import { Changeset } from './changeset.js'
|
|
5
|
-
|
|
6
|
-
export class Factory {
|
|
7
|
-
#schema
|
|
8
|
-
#guards
|
|
9
|
-
|
|
10
|
-
constructor (schema, guards) {
|
|
11
|
-
this.#schema = schema
|
|
12
|
-
this.#guards = guards
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
fit (values) {
|
|
16
|
-
this.#schema.validate({ id: newid(), ...values }, 'Entity')
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
init (id) {
|
|
20
|
-
return new Entity(this.#schema, id, this.#guards)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
object (record, mutable = true) {
|
|
24
|
-
return new Entity(this.#schema, record, this.#guards, mutable)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
objects (recordset, init, mutable = true) {
|
|
28
|
-
const set = recordset.map((record) => this.object(record, mutable))
|
|
29
|
-
|
|
30
|
-
if (init !== undefined)
|
|
31
|
-
for (const id of init)
|
|
32
|
-
set.unshift(this.init(id))
|
|
33
|
-
|
|
34
|
-
return new EntitySet(set)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
changeset (query) {
|
|
38
|
-
return new Changeset(this.#schema, query)
|
|
39
|
-
}
|
|
40
|
-
}
|
package/src/entities/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { Factory } from './factory.js'
|
package/src/event.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { console, current, encode } from 'openspan'
|
|
2
|
-
import { Connector } from './connector.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @implements {toa.core.Event}
|
|
6
|
-
*/
|
|
7
|
-
export class Event extends Connector {
|
|
8
|
-
/** @type {toa.core.bindings.Emitter} */
|
|
9
|
-
#emitter
|
|
10
|
-
#bridge
|
|
11
|
-
#conditioned
|
|
12
|
-
#subjective
|
|
13
|
-
|
|
14
|
-
/** @type {string} */
|
|
15
|
-
#label
|
|
16
|
-
|
|
17
|
-
constructor (definition, emitter, bridge = undefined) {
|
|
18
|
-
super()
|
|
19
|
-
|
|
20
|
-
this.#conditioned = definition.conditioned
|
|
21
|
-
this.#subjective = definition.subjective
|
|
22
|
-
this.#label = definition.label ?? 'event'
|
|
23
|
-
this.#emitter = emitter
|
|
24
|
-
this.#bridge = bridge
|
|
25
|
-
|
|
26
|
-
this.depends(emitter)
|
|
27
|
-
|
|
28
|
-
if (bridge !== undefined) this.depends(bridge)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async emit (event) {
|
|
32
|
-
if (this.#conditioned === false || await this.#bridge.condition(event) === true) {
|
|
33
|
-
const payload = this.#subjective ? await this.#bridge.payload(event) : event.state
|
|
34
|
-
|
|
35
|
-
/** @type {toa.core.Message} */
|
|
36
|
-
const message = { payload }
|
|
37
|
-
|
|
38
|
-
const options = {
|
|
39
|
-
name: `${this.#label} publish`,
|
|
40
|
-
kind: 'producer',
|
|
41
|
-
attributes: { 'messaging.destination.name': this.#label }
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
await console.span(options, async () => {
|
|
45
|
-
const context = current()
|
|
46
|
-
|
|
47
|
-
if (context !== undefined)
|
|
48
|
-
message.telemetry = encode(context)
|
|
49
|
-
|
|
50
|
-
await this.#emitter.emit(message)
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
package/src/exposition.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Connector } from './connector.js'
|
|
2
|
-
|
|
3
|
-
export class Exposition extends Connector {
|
|
4
|
-
locator
|
|
5
|
-
|
|
6
|
-
#exposition
|
|
7
|
-
|
|
8
|
-
constructor (locator, manifest) {
|
|
9
|
-
super()
|
|
10
|
-
|
|
11
|
-
this.locator = locator
|
|
12
|
-
this.#exposition = expose(manifest)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async invoke () {
|
|
16
|
-
return { output: this.#exposition }
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const expose = (manifest) => {
|
|
21
|
-
const { namespace, name, entity, operations, events } = manifest
|
|
22
|
-
|
|
23
|
-
return { namespace, name, entity, operations, events }
|
|
24
|
-
}
|
package/src/guard.js
DELETED
package/src/observation.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Operation } from './operation.js'
|
|
2
|
-
|
|
3
|
-
export class Observation extends Operation {
|
|
4
|
-
async run (store) {
|
|
5
|
-
if (store.scope === null || (store.scope?.deleted === true && store.request.query?.options?.deleted !== true)) store.reply = null
|
|
6
|
-
else await super.run(store)
|
|
7
|
-
}
|
|
8
|
-
}
|
package/src/operation.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { Connector } from './connector.js'
|
|
2
|
-
import { SystemException, RequestContractException } from './exceptions.js'
|
|
3
|
-
import { Readable } from 'node:stream'
|
|
4
|
-
|
|
5
|
-
export class Operation extends Connector {
|
|
6
|
-
scope
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Whether what this operation acquires may be modified and committed. Only a
|
|
10
|
-
* transition commits, and only a commit needs the pre-image an entity keeps
|
|
11
|
-
* to diff the new state against.
|
|
12
|
-
*
|
|
13
|
-
* @protected
|
|
14
|
-
*/
|
|
15
|
-
mutable = false
|
|
16
|
-
|
|
17
|
-
#cascade
|
|
18
|
-
#contracts
|
|
19
|
-
#query
|
|
20
|
-
#scope
|
|
21
|
-
|
|
22
|
-
constructor (cascade, scope, contracts, query, definition) {
|
|
23
|
-
super()
|
|
24
|
-
|
|
25
|
-
this.scope = scope
|
|
26
|
-
|
|
27
|
-
this.#cascade = cascade
|
|
28
|
-
this.#contracts = contracts
|
|
29
|
-
this.#query = query
|
|
30
|
-
this.#scope = definition.scope
|
|
31
|
-
|
|
32
|
-
this.depends(cascade)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async invoke (request) {
|
|
36
|
-
try {
|
|
37
|
-
if (request.authentic !== true)
|
|
38
|
-
this.#contracts.request.fit(request)
|
|
39
|
-
|
|
40
|
-
if ('query' in request)
|
|
41
|
-
request.query = this.#query.parse(request.query)
|
|
42
|
-
|
|
43
|
-
// validate entity
|
|
44
|
-
if ('entity' in request)
|
|
45
|
-
this.scope.fit(request.entity)
|
|
46
|
-
|
|
47
|
-
const store = { request }
|
|
48
|
-
|
|
49
|
-
return await this.process(store)
|
|
50
|
-
} catch (e) {
|
|
51
|
-
const exception = e instanceof Error ? new SystemException(e) : e
|
|
52
|
-
|
|
53
|
-
return { exception }
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async process (store) {
|
|
58
|
-
await this.acquire(store)
|
|
59
|
-
await this.run(store)
|
|
60
|
-
await this.commit(store)
|
|
61
|
-
|
|
62
|
-
return store.reply
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async acquire (store) {
|
|
66
|
-
if (this.#scope === 'none')
|
|
67
|
-
return
|
|
68
|
-
|
|
69
|
-
const scope = await this.query(store.request.query)
|
|
70
|
-
const raw = scope === null || scope instanceof Readable
|
|
71
|
-
|
|
72
|
-
store.scope = scope
|
|
73
|
-
store.state = raw ? scope : scope.get()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async run (store) {
|
|
77
|
-
const { request, state } = store
|
|
78
|
-
const reply = await this.#cascade.run(request.input, state)
|
|
79
|
-
|
|
80
|
-
// validate reply only on local environments
|
|
81
|
-
if (process.env.TOA_ENV === 'local' && !(reply instanceof Readable))
|
|
82
|
-
this.#contracts.reply.fit(reply)
|
|
83
|
-
|
|
84
|
-
store.reply = reply
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async commit () {}
|
|
88
|
-
|
|
89
|
-
async query (query) {
|
|
90
|
-
if (query === undefined)
|
|
91
|
-
throw new RequestContractException('Request query is required')
|
|
92
|
-
|
|
93
|
-
return this.scope[this.#scope](query, this.mutable)
|
|
94
|
-
}
|
|
95
|
-
}
|
package/src/query/criteria.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { parse } from '@rsql/parser'
|
|
2
|
-
import { QuerySyntaxException } from '../exceptions.js'
|
|
3
|
-
|
|
4
|
-
export const criteria = (criteria, properties) => {
|
|
5
|
-
let ast
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
ast = parse(criteria)
|
|
9
|
-
} catch (e) {
|
|
10
|
-
throw new QuerySyntaxException(e.message)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (properties !== undefined) coerce(ast, properties)
|
|
14
|
-
|
|
15
|
-
return ast
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const coerce = (node, properties) => {
|
|
19
|
-
if (node.type === 'COMPARISON' && node.left?.type === 'SELECTOR' && node.right?.type === 'VALUE') {
|
|
20
|
-
const property = properties[node.left.selector]
|
|
21
|
-
|
|
22
|
-
if (property === undefined) {
|
|
23
|
-
throw new QuerySyntaxException(`Criteria selector '${node.left.selector}' is not defined`)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (COERCE[property.type] !== undefined) { node.right.value = COERCE[property.type](node.right.value) }
|
|
27
|
-
} else {
|
|
28
|
-
if (node.left !== undefined) coerce(node.left, properties)
|
|
29
|
-
if (node.right !== undefined) coerce(node.right, properties)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const COERCE = {
|
|
34
|
-
number: Number.parseFloat,
|
|
35
|
-
integer: Number.parseInt,
|
|
36
|
-
boolean: (value) => value === 'true'
|
|
37
|
-
}
|
package/src/query/options.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { QuerySyntaxException } from '../exceptions.js'
|
|
2
|
-
|
|
3
|
-
export const options = (options, properties, system) => {
|
|
4
|
-
if (options.sort !== undefined) options.sort = sort(options.sort, properties)
|
|
5
|
-
|
|
6
|
-
if (options.projection !== undefined) projection(options.projection, properties)
|
|
7
|
-
|
|
8
|
-
return options
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const sort = (sort, properties) => {
|
|
12
|
-
const result = []
|
|
13
|
-
|
|
14
|
-
for (const sorting of sort) {
|
|
15
|
-
const [property, direction] = sorting.split(':')
|
|
16
|
-
|
|
17
|
-
if (properties[property] === undefined) {
|
|
18
|
-
throw new QuerySyntaxException(`Sort property '${property}' is not defined`)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
result.push([property, direction || 'asc'])
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return result
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const projection = (projection, properties) => {
|
|
28
|
-
for (const property of projection) {
|
|
29
|
-
if (properties[property] === undefined) {
|
|
30
|
-
throw new QuerySyntaxException(`Projection property '${property}' is not defined`)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
for (const property of ['_version', '_created', '_updated', '_deleted'])
|
|
35
|
-
if (!projection.includes(property))
|
|
36
|
-
projection.push(property)
|
|
37
|
-
}
|
package/src/receiver.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { console, decode, run } from 'openspan'
|
|
2
|
-
import { add } from '@toa.io/generic'
|
|
3
|
-
import { Connector } from './connector.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @implements {toa.core.Receiver}
|
|
7
|
-
*/
|
|
8
|
-
export class Receiver extends Connector {
|
|
9
|
-
/** @type {boolean} */
|
|
10
|
-
#conditioned
|
|
11
|
-
|
|
12
|
-
/** @type {boolean} */
|
|
13
|
-
#adaptive
|
|
14
|
-
|
|
15
|
-
/** @type {string} */
|
|
16
|
-
#endpoint
|
|
17
|
-
|
|
18
|
-
/** @type {string} */
|
|
19
|
-
#label
|
|
20
|
-
|
|
21
|
-
/** @type {string} */
|
|
22
|
-
#destination
|
|
23
|
-
|
|
24
|
-
/** @type {unknown[]} */
|
|
25
|
-
#arguments
|
|
26
|
-
|
|
27
|
-
/** @type {toa.core.Source} */
|
|
28
|
-
#origin
|
|
29
|
-
|
|
30
|
-
#local
|
|
31
|
-
|
|
32
|
-
#bridge
|
|
33
|
-
|
|
34
|
-
/** @type {object} */
|
|
35
|
-
#delivery
|
|
36
|
-
|
|
37
|
-
/** @type {object} */
|
|
38
|
-
#processing
|
|
39
|
-
|
|
40
|
-
constructor (definition, local, bridge) {
|
|
41
|
-
super()
|
|
42
|
-
|
|
43
|
-
const { conditioned, adaptive, operation } = definition
|
|
44
|
-
|
|
45
|
-
this.#conditioned = conditioned
|
|
46
|
-
this.#adaptive = adaptive
|
|
47
|
-
this.#endpoint = operation
|
|
48
|
-
this.#label = definition.label ?? operation
|
|
49
|
-
this.#destination = definition.destination ?? this.#label
|
|
50
|
-
this.#arguments = definition.arguments
|
|
51
|
-
this.#origin = definition.origin
|
|
52
|
-
|
|
53
|
-
this.#local = local
|
|
54
|
-
this.#bridge = bridge
|
|
55
|
-
|
|
56
|
-
this.depends(local)
|
|
57
|
-
if (bridge !== undefined) this.depends(bridge)
|
|
58
|
-
|
|
59
|
-
/*
|
|
60
|
-
* The delivery span is created on behalf of the messaging destination, so that
|
|
61
|
-
* each consumer forms its own complete producer/consumer pair, and service graphs
|
|
62
|
-
* display fan-out correctly: producer -> destination -> each consumer
|
|
63
|
-
* (Tempo pairs spans one-to-one, thus multiple consumers can not pair
|
|
64
|
-
* with a single producer span, see grafana/tempo#5408)
|
|
65
|
-
*/
|
|
66
|
-
this.#delivery = {
|
|
67
|
-
name: `${this.#label} deliver`,
|
|
68
|
-
kind: 'producer',
|
|
69
|
-
service: this.#destination,
|
|
70
|
-
attributes: { 'messaging.destination.name': this.#destination }
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
this.#processing = {
|
|
74
|
-
name: `${this.#label} process`,
|
|
75
|
-
kind: 'consumer',
|
|
76
|
-
service: local.locator.id,
|
|
77
|
-
attributes: { 'messaging.destination.name': this.#destination }
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** @hot */
|
|
82
|
-
async receive (message) {
|
|
83
|
-
const { payload, telemetry, ...extensions } = message
|
|
84
|
-
|
|
85
|
-
if (this.#conditioned && await this.#bridge.condition(payload) === false) return
|
|
86
|
-
|
|
87
|
-
const request = await this.#request(payload)
|
|
88
|
-
|
|
89
|
-
add(request, extensions)
|
|
90
|
-
|
|
91
|
-
// set after `add`, so that a message field can not spoof the origin
|
|
92
|
-
if (this.#origin !== undefined) request.source = this.#origin
|
|
93
|
-
|
|
94
|
-
// continue the trace from the producer span
|
|
95
|
-
const remote = telemetry === undefined ? null : decode(telemetry)
|
|
96
|
-
const task = () => this.#process(request)
|
|
97
|
-
|
|
98
|
-
if (remote === null)
|
|
99
|
-
await task()
|
|
100
|
-
else
|
|
101
|
-
await run(remote, task)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async #process (request) {
|
|
105
|
-
return console.span(this.#delivery, async () => console.span(this.#processing, async () => {
|
|
106
|
-
try {
|
|
107
|
-
await this.#local.invoke(this.#endpoint, request)
|
|
108
|
-
} catch (error) {
|
|
109
|
-
console.error('Receiver error', {
|
|
110
|
-
component: this.#local.locator.id,
|
|
111
|
-
endpoint: this.#endpoint,
|
|
112
|
-
error
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
throw error
|
|
116
|
-
}
|
|
117
|
-
}))
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async #request (payload) {
|
|
121
|
-
return this.#adaptive ? await this.#bridge.request(payload, ...(this.#arguments ?? [])) : { input: payload }
|
|
122
|
-
}
|
|
123
|
-
}
|