@toa.io/core 1.0.0-alpha.28 → 1.0.0-alpha.282
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +168 -0
- package/package.json +8 -10
- package/src/assignment.js +5 -8
- package/src/call.js +35 -9
- package/src/cascade.js +9 -11
- package/src/component.js +61 -21
- package/src/composition.js +3 -7
- package/src/connector.js +29 -22
- package/src/context.js +8 -6
- package/src/contract/contract.js +18 -0
- package/src/contract/index.js +2 -7
- package/src/contract/reply.js +36 -15
- package/src/contract/request.js +20 -10
- package/src/contract/schemas/index.js +9 -5
- package/src/contract/schemas/query.yaml +14 -1
- package/src/contract/schemas/source.yaml +23 -0
- package/src/discovery.js +15 -13
- package/src/effect.js +15 -0
- package/src/emission.js +2 -6
- package/src/entities/changeset.js +7 -14
- package/src/entities/entity.js +75 -29
- package/src/entities/factory.js +21 -14
- package/src/entities/index.js +1 -5
- package/src/entities/newid.js +9 -0
- package/src/entities/set.js +13 -4
- package/src/event.js +21 -7
- package/src/exceptions.js +53 -39
- package/src/exposition.js +5 -8
- package/src/guard.js +13 -0
- package/src/index.js +28 -47
- package/src/locator.js +2 -6
- package/src/observation.js +3 -15
- package/src/operation.js +40 -14
- package/src/outbox/index.js +1 -0
- package/src/outbox/outbox.js +296 -0
- package/src/query/criteria.js +3 -7
- package/src/query/options.js +5 -8
- package/src/query.js +36 -7
- package/src/receiver.js +76 -18
- package/src/reflection.js +2 -6
- package/src/remote.js +9 -12
- package/src/state.js +89 -50
- package/src/transition.js +13 -25
- package/src/transmission.js +15 -10
- package/src/unmanaged.js +7 -0
- package/test/call.fixtures.js +8 -12
- package/test/call.test.js +21 -9
- package/test/component.fixtures.js +5 -8
- package/test/component.test.js +22 -10
- package/test/connector.fixtures.js +10 -8
- package/test/connector.test.js +59 -38
- package/test/context.fixtures.js +8 -12
- package/test/context.test.js +18 -7
- package/test/contract/conditions.test.js +11 -9
- package/test/contract/contract.fixtures.js +12 -16
- package/test/contract/request.test.js +84 -34
- package/test/discovery.test.js +64 -0
- package/test/emission.fixtures.js +6 -10
- package/test/emission.test.js +29 -12
- package/test/entities/entity.fixtures.js +7 -11
- package/test/entities/entity.test.js +70 -49
- package/test/entities/factory.fixtures.js +22 -10
- package/test/entities/factory.test.js +29 -15
- package/test/entities/set.fixtures.js +6 -8
- package/test/entities/set.test.js +6 -5
- package/test/event.fixtures.js +9 -14
- package/test/event.test.js +57 -31
- package/test/locator.test.js +25 -24
- package/test/outbox.test.js +121 -0
- package/test/query.fixtures.js +1 -5
- package/test/query.test.js +42 -14
- package/test/receiver.fixtures.js +9 -12
- package/test/receiver.test.js +45 -22
- package/test/reflection.test.js +7 -6
- package/test/state.fixtures.js +25 -30
- package/test/state.test.js +72 -19
- package/test/transmission.fixtures.js +4 -6
- package/test/transmission.test.js +33 -15
- package/types/atomicity.d.ts +58 -0
- package/types/bindings.d.ts +8 -6
- package/types/bridges.ts +5 -2
- package/types/component.d.ts +7 -4
- package/types/context.d.ts +6 -3
- package/types/entity.d.ts +4 -4
- package/types/event.d.ts +1 -1
- package/types/extensions.d.ts +35 -10
- package/types/index.ts +16 -13
- package/types/message.d.ts +1 -0
- package/types/operations.d.ts +6 -0
- package/types/outbox.d.ts +53 -0
- package/types/query.d.ts +2 -0
- package/types/receiver.d.ts +2 -2
- package/types/reflection.d.ts +1 -1
- package/types/remote.d.ts +18 -0
- package/types/request.d.ts +16 -1
- package/types/state.d.ts +11 -8
- package/types/storages.d.ts +36 -11
- package/src/contract/conditions.js +0 -21
package/types/extensions.d.ts
CHANGED
|
@@ -1,28 +1,53 @@
|
|
|
1
|
-
import * as _core from './index'
|
|
2
|
-
import * as _component from './component'
|
|
3
|
-
import * as _context from './context'
|
|
4
|
-
import * as _storages from './storages'
|
|
5
|
-
import * as _bindings from './bindings'
|
|
1
|
+
import * as _core from './index.js'
|
|
2
|
+
import * as _component from './component.js'
|
|
3
|
+
import * as _context from './context.js'
|
|
4
|
+
import * as _storages from './storages.js'
|
|
5
|
+
import * as _bindings from './bindings.js'
|
|
6
|
+
import { Manifest } from '@toa.io/norm'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* What the process hosting an extension provides to it: the counterpart of a component's
|
|
10
|
+
* `Context`. What is returned is a connector the extension depends on.
|
|
11
|
+
*/
|
|
12
|
+
export interface Host {
|
|
13
|
+
/** a component of the context, by locator */
|
|
14
|
+
remote (locator: _core.Locator, source?: _core.Source): Promise<_core.Remote>
|
|
15
|
+
|
|
16
|
+
/** a channel of the messaging binding */
|
|
17
|
+
broadcast<T = unknown> (channel: string, group?: string): Promise<_bindings.Broadcast<T>>
|
|
18
|
+
|
|
19
|
+
/** components to run inside the extension's own process */
|
|
20
|
+
composition (paths: string[]): Promise<_core.Connector>
|
|
21
|
+
|
|
22
|
+
/** a consumer of an event of the context, `namespace.component.event` */
|
|
23
|
+
receive (label: string, receiver: _core.Receiver): Promise<_core.Connector>
|
|
24
|
+
|
|
25
|
+
/** what the replicas of one group decide together */
|
|
26
|
+
atom (group: string): _core.atomicity.Atom
|
|
27
|
+
}
|
|
6
28
|
|
|
7
|
-
export interface Factory{
|
|
8
|
-
tenant? (locator: _core.Locator, manifest: object):
|
|
29
|
+
export interface Factory {
|
|
30
|
+
tenant? (locator: _core.Locator, manifest: object, component: Manifest):
|
|
31
|
+
_core.Connector | Promise<_core.Connector>
|
|
9
32
|
|
|
10
33
|
aspect? (locator: _core.Locator, manifest: object | null): Aspect | Aspect[]
|
|
11
34
|
|
|
12
|
-
service? (name?: string): _core.Connector | null
|
|
35
|
+
service? (name?: string): _core.Connector | null | Promise<_core.Connector | null>
|
|
13
36
|
|
|
14
37
|
component? (component: _component.Component): _component.Component
|
|
15
38
|
|
|
16
39
|
context? (context: _context.Context): _context.Context
|
|
17
40
|
|
|
41
|
+
manage? (composition: _core.Connector): _core.Connector
|
|
42
|
+
|
|
18
43
|
storage? (storage: _storages.Storage): _storages.Storage
|
|
19
44
|
|
|
20
|
-
emitter? (emitter: _bindings.Emitter, label: string): _bindings.Emitter
|
|
45
|
+
emitter? (emitter: _bindings.Emitter, label: string, locator: _core.Locator): _bindings.Emitter
|
|
21
46
|
|
|
22
47
|
receiver? (receiver: _core.Receiver, locator: _core.Locator): _core.Receiver
|
|
23
48
|
}
|
|
24
49
|
|
|
25
|
-
export interface Aspect extends _core.Connector{
|
|
50
|
+
export interface Aspect extends _core.Connector {
|
|
26
51
|
name: string
|
|
27
52
|
|
|
28
53
|
invoke (...args: any[]): any
|
package/types/index.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
export * as bindings from './bindings'
|
|
2
|
-
export * as extensions from './extensions'
|
|
3
|
-
export * as storages from './storages'
|
|
4
|
-
export * as
|
|
5
|
-
export * as
|
|
1
|
+
export * as bindings from './bindings.js'
|
|
2
|
+
export * as extensions from './extensions.js'
|
|
3
|
+
export * as storages from './storages.js'
|
|
4
|
+
export * as outbox from './outbox.js'
|
|
5
|
+
export * as atomicity from './atomicity.js'
|
|
6
|
+
export * as bridges from './bridges.js'
|
|
7
|
+
export * as operations from './operations.js'
|
|
6
8
|
|
|
7
|
-
export type { Component } from './component'
|
|
8
|
-
export {
|
|
9
|
-
export
|
|
10
|
-
export type {
|
|
11
|
-
export {
|
|
12
|
-
export
|
|
13
|
-
export type {
|
|
14
|
-
export type {
|
|
9
|
+
export type { Component } from './component.js'
|
|
10
|
+
export type { Remote } from './remote.js'
|
|
11
|
+
export { Connector } from './connector.js'
|
|
12
|
+
export type { Context } from './context.js'
|
|
13
|
+
export type { Exception } from './exception.js'
|
|
14
|
+
export { Locator } from './locator.js'
|
|
15
|
+
export type { Receiver } from './receiver.js'
|
|
16
|
+
export type { Message } from './message.js'
|
|
17
|
+
export type { Request, Query, Reply, Source } from './request.js'
|
package/types/message.d.ts
CHANGED
package/types/operations.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
|
+
import { Request } from './request.js'
|
|
2
|
+
|
|
1
3
|
export type type = 'transition' | 'observation' | 'assignment' | 'computation' | 'effect'
|
|
2
4
|
export type scope = 'object' | 'objects' | 'changeset'
|
|
5
|
+
|
|
6
|
+
export class Operation {
|
|
7
|
+
invoke<T = any> (request: Request): Promise<T>
|
|
8
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as _state from './state.js'
|
|
2
|
+
import * as _atomicity from './atomicity.js'
|
|
3
|
+
|
|
4
|
+
declare namespace toa.core {
|
|
5
|
+
|
|
6
|
+
namespace outbox {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The intent to publish, committed with the state change it belongs to. Everything about
|
|
10
|
+
* it is core's: the storage writes it and, where the images are the write's own, fills
|
|
11
|
+
* `event.origin` and `event.state` in.
|
|
12
|
+
*/
|
|
13
|
+
interface Row {
|
|
14
|
+
id: string
|
|
15
|
+
|
|
16
|
+
/** which replica pumps this row; carries no other meaning, and no ordering */
|
|
17
|
+
lane: number
|
|
18
|
+
|
|
19
|
+
published: boolean
|
|
20
|
+
|
|
21
|
+
/** not before this */
|
|
22
|
+
pending: number
|
|
23
|
+
|
|
24
|
+
event: _state.Event
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** What a storage offers when it can commit a row atomically with the entity. */
|
|
28
|
+
interface Storage {
|
|
29
|
+
insert (row: Row, session?: unknown): Promise<void>
|
|
30
|
+
|
|
31
|
+
insertMany (rows: Row[], session?: unknown): Promise<void>
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* One page of what is due, still unpublished, and in one of the given lanes, in the
|
|
35
|
+
* order the rows were written. `after` continues from the last id of the page before.
|
|
36
|
+
*/
|
|
37
|
+
pending (lanes: number[], now: number, limit: number, after?: string): Promise<Row[]>
|
|
38
|
+
|
|
39
|
+
settle (ids: string[]): Promise<void>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type Row = toa.core.outbox.Row
|
|
47
|
+
export type Storage = toa.core.outbox.Storage
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A lane is a slot of `atomicity`: which replica pumps a row, and nothing else. The outbox is
|
|
51
|
+
* the first thing to claim slots this way, not the last.
|
|
52
|
+
*/
|
|
53
|
+
export type Atom = _atomicity.Atom
|
package/types/query.d.ts
CHANGED
package/types/receiver.d.ts
CHANGED
package/types/reflection.d.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Component } from './component.js'
|
|
2
|
+
|
|
3
|
+
export class Remote extends Component {
|
|
4
|
+
explain (endpoint: string): Promise<Explanation>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
interface Explanation {
|
|
8
|
+
input: Schema | null
|
|
9
|
+
output: Schema | null
|
|
10
|
+
errors?: string[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface Schema {
|
|
14
|
+
type: string
|
|
15
|
+
properties: {
|
|
16
|
+
[key: string]: Schema
|
|
17
|
+
}
|
|
18
|
+
}
|
package/types/request.d.ts
CHANGED
|
@@ -1,19 +1,34 @@
|
|
|
1
|
-
import { Exception } from './exception'
|
|
1
|
+
import { Exception } from './exception.js'
|
|
2
2
|
|
|
3
3
|
export interface Query {
|
|
4
4
|
id?: string
|
|
5
|
+
ids?: Array<string>
|
|
5
6
|
criteria?: string
|
|
7
|
+
search?: string
|
|
8
|
+
sample?: number
|
|
6
9
|
omit?: number
|
|
7
10
|
limit?: number
|
|
8
11
|
sort?: Array<string>
|
|
9
12
|
projection?: Array<string>
|
|
10
13
|
version?: number
|
|
14
|
+
deleted?: boolean
|
|
11
15
|
}
|
|
12
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Origin of a call. Stamped by the caller, sanitized by the request contract.
|
|
19
|
+
*/
|
|
20
|
+
export type Source =
|
|
21
|
+
| { namespace: string, component: string, operation: string }
|
|
22
|
+
| { namespace: string, component: string, event: string }
|
|
23
|
+
| { service: string }
|
|
24
|
+
|
|
13
25
|
export interface Request {
|
|
14
26
|
input?: any
|
|
15
27
|
query?: Query
|
|
16
28
|
authentic?: boolean
|
|
29
|
+
task?: boolean
|
|
30
|
+
telemetry?: string // W3C traceparent
|
|
31
|
+
source?: Source
|
|
17
32
|
}
|
|
18
33
|
|
|
19
34
|
export interface Reply {
|
package/types/state.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import * as _entity from './entity'
|
|
2
|
-
import * as _storages from './storages'
|
|
1
|
+
import * as _entity from './entity.js'
|
|
2
|
+
import * as _storages from './storages.js'
|
|
3
3
|
|
|
4
4
|
declare namespace toa.core {
|
|
5
5
|
|
|
6
6
|
namespace transition {
|
|
7
7
|
|
|
8
8
|
type Event = {
|
|
9
|
-
|
|
9
|
+
/** the pre-image; null when the entity did not exist before */
|
|
10
|
+
origin: Object | null
|
|
10
11
|
state: Object
|
|
11
|
-
|
|
12
|
+
/** out-of-band values an algorithm wrote into `state._trailers`; must be serializable */
|
|
13
|
+
trailers?: Object
|
|
14
|
+
input?: Object
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
}
|
|
@@ -16,17 +19,17 @@ declare namespace toa.core {
|
|
|
16
19
|
interface State {
|
|
17
20
|
init(id: string): _entity.Entity
|
|
18
21
|
|
|
19
|
-
object(query: _storages.Query): Promise<_entity.Entity>
|
|
22
|
+
object(query: _storages.Query, mutable?: boolean): Promise<_entity.Entity>
|
|
20
23
|
|
|
21
|
-
objects(query: _storages.Query): Promise<_entity.Entity[]>
|
|
24
|
+
objects(query: _storages.Query, mutable?: boolean): Promise<_entity.Entity[]>
|
|
22
25
|
|
|
23
26
|
changeset(query: _storages.Query): _entity.Changeset
|
|
24
27
|
|
|
25
28
|
none(): null
|
|
26
29
|
|
|
27
|
-
commit(entity: _entity.Entity): Promise<boolean>
|
|
30
|
+
commit(entity: _entity.Entity, input?: Object): Promise<boolean>
|
|
28
31
|
|
|
29
|
-
apply(changeset: _entity.Changeset): Promise<
|
|
32
|
+
apply(changeset: _entity.Changeset, input?: Object): Promise<_storages.Record>
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
}
|
package/types/storages.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// noinspection ES6UnusedImports
|
|
2
2
|
|
|
3
|
-
import { Locator } from './locator'
|
|
4
|
-
import { Connector } from './connector'
|
|
3
|
+
import { Locator } from './locator.js'
|
|
4
|
+
import { Connector } from './connector.js'
|
|
5
|
+
import * as outbox from './outbox.js'
|
|
5
6
|
|
|
6
7
|
declare namespace toa.core {
|
|
7
8
|
|
|
@@ -30,36 +31,60 @@ declare namespace toa.core {
|
|
|
30
31
|
id?: string
|
|
31
32
|
version?: number
|
|
32
33
|
criteria?: ast.Node
|
|
34
|
+
search?: string
|
|
35
|
+
sample?: number
|
|
33
36
|
options?: Object
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
interface Migration {
|
|
37
|
-
disconnect(): Promise<void>
|
|
40
|
+
disconnect (): Promise<void>
|
|
38
41
|
|
|
39
|
-
database(name: string): Promise<void>
|
|
42
|
+
database (name: string): Promise<void>
|
|
40
43
|
|
|
41
|
-
table(database: string, locator: Locator, schema: Object, reset?: boolean): Promise<string>
|
|
44
|
+
table (database: string, locator: Locator, schema: Object, reset?: boolean): Promise<string>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface Options {
|
|
48
|
+
/** whether this component publishes anything, and so needs an outbox */
|
|
49
|
+
outbox?: boolean
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
interface Factory {
|
|
45
|
-
storage(locator: Locator, properties?: object): Storage
|
|
53
|
+
storage (locator: Locator, properties?: object, options?: Options): Storage
|
|
46
54
|
|
|
47
|
-
migration?(driver?: string): Migration
|
|
55
|
+
migration? (driver?: string): Migration
|
|
48
56
|
}
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
interface Storage extends Connector {
|
|
52
60
|
// object observation
|
|
53
|
-
get?(query: storages.Query): Promise<storages.Record | null>
|
|
61
|
+
get? (query: storages.Query): Promise<storages.Record | null>
|
|
54
62
|
|
|
55
63
|
// objects observation
|
|
56
|
-
find?(query: storages.Query): Promise<storages.Record[]>
|
|
64
|
+
find? (query: storages.Query): Promise<storages.Record[]>
|
|
57
65
|
|
|
58
66
|
// commit
|
|
59
|
-
store?(record: storages.Record): Promise<boolean>
|
|
67
|
+
store? (record: storages.Record, row?: outbox.Row): Promise<boolean>
|
|
68
|
+
|
|
69
|
+
// mass commit
|
|
70
|
+
massStore? (records: storages.Record[], rows?: outbox.Row[]): Promise<boolean>
|
|
60
71
|
|
|
61
72
|
// assignment
|
|
62
|
-
upsert?(query: storages.Query, changeset: Object,
|
|
73
|
+
upsert? (query: storages.Query, changeset: Object, row?: outbox.Row): Promise<storages.Record>
|
|
74
|
+
|
|
75
|
+
// atomic get-or-create
|
|
76
|
+
ensure? (query: storages.Query, properties: Object, record: storages.Record, row?: outbox.Row): Promise<storages.Record>
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Present only where a row can be committed atomically with the entity. Its absence is
|
|
80
|
+
* what makes the runtime fall back to publishing inline, so a storage that cannot do
|
|
81
|
+
* this must not offer it: a row written outside the transaction would be a second write
|
|
82
|
+
* with a crash window in front of it, which is the defect the outbox exists to close.
|
|
83
|
+
*
|
|
84
|
+
* The row schema is the connector's own — it also owns `pending` and `settle` — and
|
|
85
|
+
* never crosses this boundary.
|
|
86
|
+
*/
|
|
87
|
+
outbox?: outbox.Storage
|
|
63
88
|
}
|
|
64
89
|
|
|
65
90
|
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { SystemException } = require('../exceptions')
|
|
4
|
-
|
|
5
|
-
class Conditions {
|
|
6
|
-
#schema
|
|
7
|
-
|
|
8
|
-
constructor (schema) {
|
|
9
|
-
this.#schema = schema
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
fit (value) {
|
|
13
|
-
const error = this.#schema.fit(value)
|
|
14
|
-
|
|
15
|
-
if (error !== null) throw new this.constructor.Exception(error)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static Exception = SystemException
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
exports.Conditions = Conditions
|