@toa.io/core 1.0.0-alpha.282 → 1.0.0-alpha.283

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 CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [1.0.0-alpha.283](https://github.com/toa-io/toa/compare/v1.0.0-alpha.282...v1.0.0-alpha.283) (2026-09-04)
7
+
8
+ ### Bug Fixes
9
+
10
+ * **core:** an operation returns the errors it declares, and nothing else ([1c2b819](https://github.com/toa-io/toa/commit/1c2b8193ae7fbe86bc1a25053a6044ee4dd16a4a))
11
+ * **storages:** take `Maybe` from core, not from the deprecated package ([bcaeeb3](https://github.com/toa-io/toa/commit/bcaeeb3c76c89af34e94ff569a210d21b7e87f64))
12
+
13
+ ### Features
14
+
15
+ * **extensions:** an extension declares what it puts on a component's context ([133bc2a](https://github.com/toa-io/toa/commit/133bc2aad1e45a2d4aa68a08a5e44ca48d3b7414))
16
+
17
+
6
18
  # [1.0.0-alpha.282](https://github.com/toa-io/toa/compare/v1.0.0-alpha.281...v1.0.0-alpha.282) (2026-09-03)
7
19
 
8
20
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/core",
3
- "version": "1.0.0-alpha.282",
3
+ "version": "1.0.0-alpha.283",
4
4
  "type": "module",
5
5
  "description": "Toa Core",
6
6
  "author": "temich <tema.gurtovoy@gmail.com>",
@@ -22,10 +22,10 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@rsql/parser": "1.6.0",
25
- "@toa.io/generic": "1.0.0-alpha.282",
25
+ "@toa.io/generic": "1.0.0-alpha.283",
26
26
  "js-yaml": "5.4.1",
27
27
  "openspan": "1.0.0-alpha.277",
28
28
  "uuid": "14.0.2"
29
29
  },
30
- "gitHead": "4007c814725dd015d3bbebb9a28e28a247645c4f"
30
+ "gitHead": "2f52b023bed0ccb2ecdb2b82fe59fbe38bf282e1"
31
31
  }
@@ -1,4 +1,3 @@
1
- import * as schemas from './schemas/index.js'
2
1
  import { Contract } from './contract.js'
3
2
  import { ResponseContractException } from '../exceptions.js'
4
3
 
@@ -25,21 +24,25 @@ export class Reply extends Contract {
25
24
  schema.properties.output = output
26
25
  }
27
26
 
28
- if (errors !== undefined)
29
- schema.properties.error = {
30
- type: 'object',
31
- properties: {
32
- code: {
33
- enum: errors
27
+ /*
28
+ * An error a caller is meant to handle is one the operation states. Where none are
29
+ * stated, an error is not a reply this operation makes — it is a mistake, and the
30
+ * contract says so rather than passing an undeclared code on to whoever called.
31
+ */
32
+ schema.properties.error = errors === undefined
33
+ ? false
34
+ : {
35
+ type: 'object',
36
+ properties: {
37
+ code: {
38
+ enum: errors
39
+ },
40
+ message: {
41
+ type: 'string'
42
+ }
34
43
  },
35
- message: {
36
- type: 'string'
37
- }
38
- },
39
- required: ['code']
40
- }
41
- else
42
- schema.properties.error = schemas.error
44
+ required: ['code']
45
+ }
43
46
 
44
47
  return schema
45
48
  }
@@ -0,0 +1,13 @@
1
+ import type { Request } from './request.js'
2
+
3
+ /**
4
+ * How an endpoint is called. What it resolves to is what the operation declares — `toa types`
5
+ * writes that per operation, and these are what a hand-written context says instead.
6
+ */
7
+ export type Call<Output = any, Input = any> = (request: Request<Input>) => Promise<Output>
8
+
9
+ export type Observation<Output = any, Input = never, Entity = unknown> =
10
+ (request: Request<Input, Entity>) => Promise<Output extends unknown[] ? Output : Output | null>
11
+
12
+ export type Transition<Output = any, Input = never, Entity = unknown> =
13
+ (request: Request<Input, Entity>) => Promise<Output | null>
@@ -47,6 +47,25 @@ export interface Factory {
47
47
  receiver? (receiver: _core.Receiver, locator: _core.Locator): _core.Receiver
48
48
  }
49
49
 
50
+ /**
51
+ * What an extension puts on a component's context, as the extension states it. How it is
52
+ * presented there is the bridge's — a bash bridge has no context to put anything on — and
53
+ * what is declared here is the key and what it holds.
54
+ */
55
+ export interface Contribution {
56
+ /** the key on the context */
57
+ name: string
58
+
59
+ /** what the key holds, as TypeScript */
60
+ type?: string
61
+
62
+ /** what `type` names, by the module it comes from */
63
+ imports?: Record<string, string[]>
64
+
65
+ /** a JSON Schema to read the type from instead, where a component states one */
66
+ schema?: object
67
+ }
68
+
50
69
  export interface Aspect extends _core.Connector {
51
70
  name: string
52
71
 
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Runs on every change to an entity's state, before the contract is applied. `false` refuses
3
+ * the change as `EntityGuard`.
4
+ */
5
+ export type Guard<T, C = unknown> = (state: T, origin: T | null, context: C) => boolean
package/types/index.ts CHANGED
@@ -14,4 +14,8 @@ export type { Exception } from './exception.js'
14
14
  export { Locator } from './locator.js'
15
15
  export type { Receiver } from './receiver.js'
16
16
  export type { Message } from './message.js'
17
- export type { Request, Query, Reply, Source } from './request.js'
17
+ export type { Maybe, Request, Query, Reply, RemoteError, Source } from './request.js'
18
+ export type { Event } from './state.js'
19
+ export type { Guard } from './guard.js'
20
+ export type { Call, Observation, Transition } from './call.js'
21
+ export type { Contribution } from './extensions.js'
@@ -1,6 +1,10 @@
1
1
  import { Exception } from './exception.js'
2
2
 
3
- export interface Query {
3
+ /**
4
+ * What a call asks for. `Entity` is the record it is about, which narrows the projection;
5
+ * left out, any name is accepted.
6
+ */
7
+ export interface Query<Entity = any> {
4
8
  id?: string
5
9
  ids?: Array<string>
6
10
  criteria?: string
@@ -9,7 +13,7 @@ export interface Query {
9
13
  omit?: number
10
14
  limit?: number
11
15
  sort?: Array<string>
12
- projection?: Array<string>
16
+ projection?: Array<string & keyof Entity>
13
17
  version?: number
14
18
  deleted?: boolean
15
19
  }
@@ -22,15 +26,28 @@ export type Source =
22
26
  | { namespace: string, component: string, event: string }
23
27
  | { service: string }
24
28
 
25
- export interface Request {
26
- input?: any
27
- query?: Query
29
+ export interface Request<Input = any, Entity = any> {
30
+ input?: Input
31
+ query?: Query<Entity>
32
+ /** What the operation acquires, where the caller supplies it rather than the storage. */
33
+ entity?: Entity
28
34
  authentic?: boolean
29
35
  task?: boolean
30
36
  telemetry?: string // W3C traceparent
31
37
  source?: Source
32
38
  }
33
39
 
40
+ /**
41
+ * An error an operation declares and returns. A call resolves to it rather than throwing:
42
+ * only an exception is thrown.
43
+ */
44
+ export interface RemoteError<Code extends string = string> extends Error {
45
+ code: Code
46
+ }
47
+
48
+ /** What an operation returns where it may refuse: the value, or the error it refused with. */
49
+ export type Maybe<T> = T | Error
50
+
34
51
  export interface Reply {
35
52
  output?: any
36
53
  error?: object
package/types/state.d.ts CHANGED
@@ -5,12 +5,12 @@ declare namespace toa.core {
5
5
 
6
6
  namespace transition {
7
7
 
8
- type Event = {
8
+ type Event<State = Object, Trailers = Object> = {
9
9
  /** the pre-image; null when the entity did not exist before */
10
- origin: Object | null
11
- state: Object
10
+ origin: State | null
11
+ state: State
12
12
  /** out-of-band values an algorithm wrote into `state._trailers`; must be serializable */
13
- trailers?: Object
13
+ trailers?: Trailers
14
14
  input?: Object
15
15
  }
16
16
 
@@ -35,4 +35,4 @@ declare namespace toa.core {
35
35
  }
36
36
 
37
37
  export type State = toa.core.State
38
- export type Event = toa.core.transition.Event
38
+ export type Event<State = Object, Trailers = Object> = toa.core.transition.Event<State, Trailers>