@toa.io/core 1.0.0-alpha.31 → 1.0.0-alpha.310
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 +28 -12
- package/transpiled/abandon.d.ts +9 -0
- package/transpiled/abandon.js +37 -0
- package/transpiled/abandon.js.map +1 -0
- package/transpiled/assignment.d.ts +6 -0
- package/transpiled/assignment.js +25 -0
- package/transpiled/assignment.js.map +1 -0
- package/transpiled/call.d.ts +10 -0
- package/transpiled/call.js +165 -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 +148 -0
- package/transpiled/component.js.map +1 -0
- package/transpiled/composition.d.ts +6 -0
- package/transpiled/composition.js +20 -0
- package/transpiled/composition.js.map +1 -0
- package/transpiled/connector.d.ts +71 -0
- package/transpiled/connector.js +248 -0
- package/transpiled/connector.js.map +1 -0
- package/transpiled/context.d.ts +25 -0
- package/transpiled/context.js +55 -0
- package/transpiled/context.js.map +1 -0
- package/transpiled/contract/component.d.ts +24 -0
- package/transpiled/contract/component.js +48 -0
- package/transpiled/contract/component.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 +3 -0
- package/transpiled/contract/index.js +4 -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 +39 -0
- package/transpiled/contract/request.js +115 -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/deliveries.d.ts +22 -0
- package/transpiled/deliveries.js +31 -0
- package/transpiled/deliveries.js.map +1 -0
- package/transpiled/effect.d.ts +7 -0
- package/transpiled/effect.js +13 -0
- package/transpiled/effect.js.map +1 -0
- package/transpiled/emission.d.ts +10 -0
- package/transpiled/emission.js +16 -0
- package/transpiled/emission.js.map +1 -0
- package/transpiled/encoded.d.ts +16 -0
- package/transpiled/encoded.js +25 -0
- package/transpiled/encoded.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 +137 -0
- package/transpiled/entities/entity.js.map +1 -0
- package/transpiled/entities/factory.d.ts +27 -0
- package/transpiled/entities/factory.js +38 -0
- package/transpiled/entities/factory.js.map +1 -0
- package/transpiled/entities/index.d.ts +5 -0
- package/transpiled/entities/index.js +6 -0
- package/transpiled/entities/index.js.map +1 -0
- package/transpiled/entities/newid.d.ts +11 -0
- package/transpiled/entities/newid.js +41 -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 +53 -0
- package/transpiled/event.js.map +1 -0
- package/transpiled/exceptions.d.ts +104 -0
- package/transpiled/exceptions.js +205 -0
- package/transpiled/exceptions.js.map +1 -0
- package/transpiled/gate.d.ts +40 -0
- package/transpiled/gate.js +84 -0
- package/transpiled/gate.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/halting.d.ts +16 -0
- package/transpiled/halting.js +25 -0
- package/transpiled/halting.js.map +1 -0
- package/transpiled/index.d.ts +41 -0
- package/transpiled/index.js +34 -0
- package/transpiled/index.js.map +1 -0
- package/transpiled/instance.d.ts +10 -0
- package/transpiled/instance.js +30 -0
- package/transpiled/instance.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/measurements.d.ts +20 -0
- package/transpiled/measurements.js +40 -0
- package/transpiled/measurements.js.map +1 -0
- package/transpiled/observation.d.ts +7 -0
- package/transpiled/observation.js +14 -0
- package/transpiled/observation.js.map +1 -0
- package/transpiled/operation.d.ts +69 -0
- package/transpiled/operation.js +174 -0
- package/transpiled/operation.js.map +1 -0
- package/transpiled/outbox.d.ts +45 -0
- package/transpiled/outbox.js +448 -0
- package/transpiled/outbox.js.map +1 -0
- package/transpiled/outbox.measurements.d.ts +4 -0
- package/transpiled/outbox.measurements.js +38 -0
- package/transpiled/outbox.measurements.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 +34 -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 +113 -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 +11 -0
- package/transpiled/remote.js.map +1 -0
- package/transpiled/safety.d.ts +5 -0
- package/transpiled/safety.js +26 -0
- package/transpiled/safety.js.map +1 -0
- package/transpiled/state.d.ts +36 -0
- package/transpiled/state.js +131 -0
- package/transpiled/state.js.map +1 -0
- package/transpiled/trail.d.ts +78 -0
- package/transpiled/trail.js +112 -0
- package/transpiled/trail.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 +58 -0
- package/transpiled/types/atomicity.js +2 -0
- package/transpiled/types/atomicity.js.map +1 -0
- package/transpiled/types/bindings.d.ts +77 -0
- package/transpiled/types/bindings.js +2 -0
- package/transpiled/types/bindings.js.map +1 -0
- package/transpiled/types/bridges.d.ts +41 -0
- package/transpiled/types/bridges.js +2 -0
- package/transpiled/types/bridges.js.map +1 -0
- package/transpiled/types/extensions.d.ts +116 -0
- package/transpiled/types/extensions.js +2 -0
- package/transpiled/types/extensions.js.map +1 -0
- package/transpiled/types/inbox.d.ts +22 -0
- package/transpiled/types/inbox.js +2 -0
- package/transpiled/types/inbox.js.map +1 -0
- package/transpiled/types/index.d.ts +14 -0
- package/transpiled/types/index.js +9 -0
- package/transpiled/types/index.js.map +1 -0
- package/transpiled/types/message.d.ts +16 -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 +54 -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 +119 -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 +146 -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/src/assignment.js +0 -31
- package/src/call.js +0 -42
- package/src/cascade.js +0 -35
- package/src/component.js +0 -41
- package/src/composition.js +0 -25
- package/src/connector.js +0 -183
- package/src/context.js +0 -55
- package/src/contract/conditions.js +0 -21
- package/src/contract/index.js +0 -7
- package/src/contract/reply.js +0 -25
- package/src/contract/request.js +0 -67
- package/src/contract/schemas/error.yaml +0 -9
- package/src/contract/schemas/index.js +0 -7
- package/src/contract/schemas/query.yaml +0 -30
- package/src/discovery.js +0 -44
- package/src/emission.js +0 -23
- package/src/entities/changeset.js +0 -38
- package/src/entities/entity.js +0 -74
- package/src/entities/factory.js +0 -33
- package/src/entities/index.js +0 -5
- package/src/entities/set.js +0 -15
- package/src/event.js +0 -40
- package/src/exceptions.js +0 -100
- package/src/exposition.js +0 -27
- package/src/index.js +0 -47
- package/src/locator.js +0 -54
- package/src/observation.js +0 -20
- package/src/operation.js +0 -69
- package/src/query/criteria.js +0 -41
- package/src/query/options.js +0 -40
- package/src/query.js +0 -41
- package/src/receiver.js +0 -61
- package/src/reflection.js +0 -28
- package/src/remote.js +0 -17
- package/src/state.js +0 -99
- package/src/transition.js +0 -67
- package/src/transmission.js +0 -33
- package/test/call.fixtures.js +0 -27
- package/test/call.test.js +0 -46
- package/test/component.fixtures.js +0 -21
- package/test/component.test.js +0 -40
- package/test/connector.fixtures.js +0 -40
- package/test/connector.test.js +0 -176
- package/test/context.fixtures.js +0 -18
- package/test/context.test.js +0 -29
- package/test/contract/conditions.test.js +0 -26
- package/test/contract/contract.fixtures.js +0 -33
- package/test/contract/request.test.js +0 -112
- package/test/emission.fixtures.js +0 -17
- package/test/emission.test.js +0 -35
- package/test/entities/entity.fixtures.js +0 -29
- package/test/entities/entity.test.js +0 -65
- package/test/entities/factory.fixtures.js +0 -18
- package/test/entities/factory.test.js +0 -48
- package/test/entities/set.fixtures.js +0 -11
- package/test/entities/set.test.js +0 -12
- package/test/event.fixtures.js +0 -29
- package/test/event.test.js +0 -118
- package/test/locator.test.js +0 -113
- package/test/query.fixtures.js +0 -100
- package/test/query.test.js +0 -86
- package/test/receiver.fixtures.js +0 -23
- package/test/receiver.test.js +0 -95
- package/test/reflection.test.js +0 -30
- package/test/state.fixtures.js +0 -47
- package/test/state.test.js +0 -46
- package/test/transmission.fixtures.js +0 -15
- package/test/transmission.test.js +0 -46
- package/types/bindings.d.ts +0 -40
- package/types/bridges.ts +0 -30
- package/types/component.d.ts +0 -9
- package/types/connector.d.ts +0 -18
- package/types/context.d.ts +0 -21
- 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 -29
- package/types/index.ts +0 -14
- package/types/locator.d.ts +0 -13
- package/types/message.d.ts +0 -3
- package/types/operations.d.ts +0 -2
- package/types/query.d.ts +0 -15
- package/types/receiver.d.ts +0 -12
- package/types/reflection.d.ts +0 -14
- package/types/request.d.ts +0 -23
- package/types/state.d.ts +0 -35
- package/types/storages.d.ts +0 -71
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as schemas from './schemas.js';
|
|
2
|
+
import { RequestContractException } from '../exceptions.js';
|
|
3
|
+
import { Contract } from './contract.js';
|
|
4
|
+
export class Request extends Contract {
|
|
5
|
+
discovery = {};
|
|
6
|
+
static Exception = RequestContractException;
|
|
7
|
+
constructor(schema, definition, entity) {
|
|
8
|
+
super(schema);
|
|
9
|
+
for (const key of ['description', 'once', 'stateful', 'input', 'output', 'errors'])
|
|
10
|
+
if (definition[key] !== undefined)
|
|
11
|
+
this.discovery[key] = definition[key];
|
|
12
|
+
/*
|
|
13
|
+
* An operation that states no output states an empty schema, which every reply fits —
|
|
14
|
+
* and which says nothing to whoever reads it. What its type answers does, so that is
|
|
15
|
+
* said here instead. Here and not in the definition, because the definition is what a
|
|
16
|
+
* reply is held to: a projection is a lawful answer, and describing one is not the same
|
|
17
|
+
* as requiring it.
|
|
18
|
+
*/
|
|
19
|
+
if (empty(this.discovery.output)) {
|
|
20
|
+
const answered = answers(definition, entity);
|
|
21
|
+
if (answered !== undefined)
|
|
22
|
+
this.discovery.output = answered;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
static schema(definition, entity) {
|
|
26
|
+
// `source` is not among these: the framework stamps it and whoever reads it takes the keys
|
|
27
|
+
// it knows, so holding it to a schema would only fail calls from a peer that stamps one more
|
|
28
|
+
const schema = {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
/*
|
|
32
|
+
* Listed, and not required. `additionalProperties` already admits it, and a callee skips
|
|
33
|
+
* this contract altogether for an `authentic` request — which every request from a `Call`
|
|
34
|
+
* is — so requiring it would refuse nothing on the side where a missing identity matters,
|
|
35
|
+
* and would refuse every request built by hand on the side where it never is. An
|
|
36
|
+
* operation that declares `once` raises on a request without one instead.
|
|
37
|
+
*/
|
|
38
|
+
id: { type: 'string' },
|
|
39
|
+
authentic: { type: 'boolean' },
|
|
40
|
+
task: { type: 'boolean' },
|
|
41
|
+
// whether the call may reach only a safe operation, which every operation admits
|
|
42
|
+
readonly: { type: 'boolean' },
|
|
43
|
+
// what a caller receives of the output, which every operation admits
|
|
44
|
+
output: { type: 'array', uniqueItems: true, items: { type: 'string' } }
|
|
45
|
+
},
|
|
46
|
+
additionalProperties: true
|
|
47
|
+
};
|
|
48
|
+
const required = [];
|
|
49
|
+
if (definition.input !== undefined) {
|
|
50
|
+
schema.properties.input = definition.input;
|
|
51
|
+
required.push('input');
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
schema.properties.input = { type: 'null' };
|
|
55
|
+
if (entity === undefined)
|
|
56
|
+
definition.query = false;
|
|
57
|
+
if (definition.query === true)
|
|
58
|
+
required.push('query');
|
|
59
|
+
if (definition.query === false)
|
|
60
|
+
schema.properties.query = { type: 'null' };
|
|
61
|
+
if (definition.query !== false) {
|
|
62
|
+
const query = structuredClone(schemas.query);
|
|
63
|
+
query.properties.id = entity?.properties.id;
|
|
64
|
+
if (definition.type === 'observation')
|
|
65
|
+
delete query.properties.version;
|
|
66
|
+
else
|
|
67
|
+
delete query.properties.projection;
|
|
68
|
+
if (definition.type !== 'observation' || definition.scope !== 'objects') {
|
|
69
|
+
delete query.properties.omit;
|
|
70
|
+
delete query.properties.limit;
|
|
71
|
+
}
|
|
72
|
+
else if (query.required === undefined)
|
|
73
|
+
query.required = ['limit'];
|
|
74
|
+
else
|
|
75
|
+
query.required.push('limit');
|
|
76
|
+
schema.properties.query = query;
|
|
77
|
+
}
|
|
78
|
+
if (required.length > 0)
|
|
79
|
+
schema.required = required;
|
|
80
|
+
return schema;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* What an operation of this type answers, where it did not say.
|
|
85
|
+
*
|
|
86
|
+
* A transition, an observation and an assignment work on the Entity Object, so that is what
|
|
87
|
+
* they answer — a set of them where the scope is a set. A computation neither uses the scope
|
|
88
|
+
* nor produces one, and an effect answers whatever it computed, so neither is guessed at.
|
|
89
|
+
* A stream is not a value with a schema, and is not one either.
|
|
90
|
+
*
|
|
91
|
+
* What the entity requires is said as well. It is a description and nothing is held to it —
|
|
92
|
+
* an operation answering a projection says so by declaring its own output — and a shape
|
|
93
|
+
* whose every property reads as optional says less than it knows.
|
|
94
|
+
*/
|
|
95
|
+
function answers(definition, entity) {
|
|
96
|
+
if (entity === undefined || !ENTITY.has(definition.type))
|
|
97
|
+
return undefined;
|
|
98
|
+
const object = {
|
|
99
|
+
type: 'object',
|
|
100
|
+
properties: entity.properties,
|
|
101
|
+
...(entity.required === undefined ? {} : { required: entity.required })
|
|
102
|
+
};
|
|
103
|
+
if (definition.scope === 'objects')
|
|
104
|
+
return { type: 'array', items: object };
|
|
105
|
+
return definition.scope === 'object' || definition.scope === 'changeset'
|
|
106
|
+
? object
|
|
107
|
+
: undefined;
|
|
108
|
+
}
|
|
109
|
+
/** The types whose subject is the Entity Object; see `documentation/design.md`. */
|
|
110
|
+
const ENTITY = new Set(['transition', 'observation', 'assignment']);
|
|
111
|
+
/** A schema that states nothing, which is what an operation saying nothing normalizes to. */
|
|
112
|
+
function empty(schema) {
|
|
113
|
+
return schema === undefined || schema === null || Object.keys(schema).length === 0;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../source/contract/request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const query = {
|
|
2
|
+
type: 'object',
|
|
3
|
+
properties: {
|
|
4
|
+
id: { type: 'string' },
|
|
5
|
+
ids: { type: 'array', uniqueItems: true, minItems: 1, items: { type: 'string' } },
|
|
6
|
+
version: { type: 'integer', minimum: 0 },
|
|
7
|
+
criteria: { type: 'string' },
|
|
8
|
+
search: { type: 'string' },
|
|
9
|
+
sample: { type: 'number' },
|
|
10
|
+
omit: { type: 'integer', minimum: 0 },
|
|
11
|
+
limit: { type: 'integer', minimum: 0 },
|
|
12
|
+
sort: {
|
|
13
|
+
type: 'array',
|
|
14
|
+
uniqueItems: true,
|
|
15
|
+
minItems: 1,
|
|
16
|
+
items: { type: 'string', pattern: '^\\w{1,32}(?::(?:asc|desc))?$' }
|
|
17
|
+
},
|
|
18
|
+
projection: {
|
|
19
|
+
type: 'array',
|
|
20
|
+
uniqueItems: true,
|
|
21
|
+
minItems: 1,
|
|
22
|
+
items: { type: 'string', not: { const: 'id' } }
|
|
23
|
+
},
|
|
24
|
+
deleted: { type: 'boolean' }
|
|
25
|
+
},
|
|
26
|
+
additionalProperties: false
|
|
27
|
+
};
|
|
28
|
+
export const error = {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
code: { anyOf: [{ type: 'integer' }, { type: 'string' }] },
|
|
32
|
+
message: { type: 'string' }
|
|
33
|
+
},
|
|
34
|
+
required: ['code']
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../source/contract/schemas.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,KAAK,GAAe;IAC/B,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACtB,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QACjF,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACxC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC1B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACrC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,IAAI,EAAE;YACJ,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,+BAA+B,EAAE;SACpE;QACD,UAAU,EAAE;YACV,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;SAChD;QACD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KAC7B;IACD,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAe;IAC/B,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC1D,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC5B;IACD,QAAQ,EAAE,CAAC,MAAM,CAAC;CACnB,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The messages this process has taken and not yet finished with.
|
|
3
|
+
*
|
|
4
|
+
* A binding counts one in for as long as it holds a delivery, and that is exactly what its own
|
|
5
|
+
* teardown waits for: a connection cannot close while a message it dispatched is still being
|
|
6
|
+
* handled, and a handler waiting on a call of its own holds it there. So this answers, for the
|
|
7
|
+
* process as a whole, whether a teardown has anything left to wait on.
|
|
8
|
+
*
|
|
9
|
+
* It is not `toa.call.inflight`, which counts the other side — callers waiting. That number is
|
|
10
|
+
* non-zero for a call a gateway made, which blocks no teardown, and zero for a handler held open
|
|
11
|
+
* by a database commit, which blocks one.
|
|
12
|
+
*
|
|
13
|
+
* Ambient, like the instance name and the invocation chain, and for the same reason: a process
|
|
14
|
+
* may carry two copies of this module, and a count kept in one of them answers for half a
|
|
15
|
+
* process.
|
|
16
|
+
*/
|
|
17
|
+
/** One more delivery is being handled. */
|
|
18
|
+
export declare function taken(): void;
|
|
19
|
+
/** One fewer: the handler has returned, however it returned. */
|
|
20
|
+
export declare function done(): void;
|
|
21
|
+
/** How many this process is handling now. */
|
|
22
|
+
export declare function inflight(): number;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The messages this process has taken and not yet finished with.
|
|
3
|
+
*
|
|
4
|
+
* A binding counts one in for as long as it holds a delivery, and that is exactly what its own
|
|
5
|
+
* teardown waits for: a connection cannot close while a message it dispatched is still being
|
|
6
|
+
* handled, and a handler waiting on a call of its own holds it there. So this answers, for the
|
|
7
|
+
* process as a whole, whether a teardown has anything left to wait on.
|
|
8
|
+
*
|
|
9
|
+
* It is not `toa.call.inflight`, which counts the other side — callers waiting. That number is
|
|
10
|
+
* non-zero for a call a gateway made, which blocks no teardown, and zero for a handler held open
|
|
11
|
+
* by a database commit, which blocks one.
|
|
12
|
+
*
|
|
13
|
+
* Ambient, like the instance name and the invocation chain, and for the same reason: a process
|
|
14
|
+
* may carry two copies of this module, and a count kept in one of them answers for half a
|
|
15
|
+
* process.
|
|
16
|
+
*/
|
|
17
|
+
const KEY = Symbol.for('toa.core.deliveries');
|
|
18
|
+
const store = (globalThis[KEY] ??= { count: 0 });
|
|
19
|
+
/** One more delivery is being handled. */
|
|
20
|
+
export function taken() {
|
|
21
|
+
store.count++;
|
|
22
|
+
}
|
|
23
|
+
/** One fewer: the handler has returned, however it returned. */
|
|
24
|
+
export function done() {
|
|
25
|
+
store.count--;
|
|
26
|
+
}
|
|
27
|
+
/** How many this process is handling now. */
|
|
28
|
+
export function inflight() {
|
|
29
|
+
return store.count;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=deliveries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliveries.js","sourceRoot":"","sources":["../source/deliveries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;AAI7C,MAAM,KAAK,GAAG,CAAE,UAAoB,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;AAE3D,0CAA0C;AAC1C,MAAM,UAAU,KAAK;IACnB,KAAK,CAAC,KAAK,EAAE,CAAA;AACf,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,IAAI;IAClB,KAAK,CAAC,KAAK,EAAE,CAAA;AACf,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,QAAQ;IACtB,OAAO,KAAK,CAAC,KAAK,CAAA;AACpB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Observation } from './observation.ts';
|
|
2
|
+
import type { Store } from './operation.ts';
|
|
3
|
+
export declare class Effect extends Observation {
|
|
4
|
+
/** an effect reads for what it does next, which a projected read would leave short */
|
|
5
|
+
protected projects: boolean;
|
|
6
|
+
protected acquire(store: Store): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Observation } from './observation.js';
|
|
2
|
+
export class Effect extends Observation {
|
|
3
|
+
/** an effect reads for what it does next, which a projected read would leave short */
|
|
4
|
+
projects = false;
|
|
5
|
+
async acquire(store) {
|
|
6
|
+
const { query, entity, input } = store.request;
|
|
7
|
+
if (entity === undefined)
|
|
8
|
+
return super.acquire(store);
|
|
9
|
+
store.scope = await this.scope.ensure(query, entity, input);
|
|
10
|
+
store.state = store.scope.get();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=effect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../source/effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAI9C,MAAM,OAAO,MAAO,SAAQ,WAAW;IACrC,sFAAsF;IACnE,QAAQ,GAAY,KAAK,CAAA;IAEzB,KAAK,CAAC,OAAO,CAAC,KAAY;QAC3C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,CAAA;QAE9C,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAErD,KAAK,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAY,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;QAClE,KAAK,CAAC,KAAK,GAAI,KAAK,CAAC,KAAgB,CAAC,GAAG,EAAE,CAAA;IAC7C,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Connector } from './connector.ts';
|
|
2
|
+
import type { Event } from './event.ts';
|
|
3
|
+
import type { Row } from './types/outbox.ts';
|
|
4
|
+
export declare class Emission extends Connector {
|
|
5
|
+
#private;
|
|
6
|
+
/** what a row is outstanding for while this has not published it */
|
|
7
|
+
readonly name = "events";
|
|
8
|
+
constructor(events: Event[]);
|
|
9
|
+
emit(row: Row): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Connector } from './connector.js';
|
|
2
|
+
export class Emission extends Connector {
|
|
3
|
+
/** what a row is outstanding for while this has not published it */
|
|
4
|
+
name = 'events';
|
|
5
|
+
#events;
|
|
6
|
+
constructor(events) {
|
|
7
|
+
super();
|
|
8
|
+
this.#events = events;
|
|
9
|
+
this.depends(events);
|
|
10
|
+
}
|
|
11
|
+
async emit(row) {
|
|
12
|
+
const emission = this.#events.map((e) => e.emit(row));
|
|
13
|
+
await Promise.all(emission);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=emission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emission.js","sourceRoot":"","sources":["../source/emission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI1C,MAAM,OAAO,QAAS,SAAQ,SAAS;IACrC,oEAAoE;IACpD,IAAI,GAAG,QAAQ,CAAA;IAEtB,OAAO,CAAS;IAEzB,YAAmB,MAAe;QAChC,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QAErB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,GAAQ;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAErD,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC7B,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An output a component encoded, which its caller passes on as it is: the bytes of what the
|
|
3
|
+
* operation answered, and what they are encoded in. A caller that writes them somewhere — the
|
|
4
|
+
* gateway writing a response body — spends nothing on reading them.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Encoded {
|
|
7
|
+
readonly bytes: Buffer;
|
|
8
|
+
readonly type: string;
|
|
9
|
+
constructor(bytes: Buffer, type?: string);
|
|
10
|
+
/**
|
|
11
|
+
* Whether a value is an `Encoded`, whichever copy of this package made it. A process may load
|
|
12
|
+
* the package more than once — the gateway image installs it beside the runtime and again beside
|
|
13
|
+
* the extension — and what one copy made is no instance of the other copy's class.
|
|
14
|
+
*/
|
|
15
|
+
static is(value: unknown): value is Encoded;
|
|
16
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** What marks an `Encoded` in every copy of this package, which its class does not: see `is`. */
|
|
2
|
+
const KEY = Symbol.for('toa.core.encoded');
|
|
3
|
+
/**
|
|
4
|
+
* An output a component encoded, which its caller passes on as it is: the bytes of what the
|
|
5
|
+
* operation answered, and what they are encoded in. A caller that writes them somewhere — the
|
|
6
|
+
* gateway writing a response body — spends nothing on reading them.
|
|
7
|
+
*/
|
|
8
|
+
export class Encoded {
|
|
9
|
+
bytes;
|
|
10
|
+
type;
|
|
11
|
+
constructor(bytes, type = 'application/json') {
|
|
12
|
+
this.bytes = bytes;
|
|
13
|
+
this.type = type;
|
|
14
|
+
Object.defineProperty(this, KEY, { value: true });
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Whether a value is an `Encoded`, whichever copy of this package made it. A process may load
|
|
18
|
+
* the package more than once — the gateway image installs it beside the runtime and again beside
|
|
19
|
+
* the extension — and what one copy made is no instance of the other copy's class.
|
|
20
|
+
*/
|
|
21
|
+
static is(value) {
|
|
22
|
+
return typeof value === 'object' && value !== null && KEY in value;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=encoded.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoded.js","sourceRoot":"","sources":["../source/encoded.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;AAE1C;;;;GAIG;AACH,MAAM,OAAO,OAAO;IACF,KAAK,CAAQ;IACb,IAAI,CAAQ;IAE5B,YAAmB,KAAa,EAAE,IAAI,GAAW,kBAAkB;QACjE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAEhB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,EAAE,CAAC,KAAc;QAC7B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,CAAA;IACpE,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Schema } from '@toa.io/schemas';
|
|
2
|
+
import type { Query, Record } from '../types/storages.ts';
|
|
3
|
+
export declare class Changeset {
|
|
4
|
+
#private;
|
|
5
|
+
readonly query: Query;
|
|
6
|
+
constructor(schema: Schema, query: Query);
|
|
7
|
+
get(): object;
|
|
8
|
+
set(value: Record): void;
|
|
9
|
+
export(): object;
|
|
10
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { EntityContractException } from '../exceptions.js';
|
|
2
|
+
export class Changeset {
|
|
3
|
+
query;
|
|
4
|
+
/** the changeset schema: the entity's properties, none of them required */
|
|
5
|
+
#schema;
|
|
6
|
+
#state;
|
|
7
|
+
constructor(schema, query) {
|
|
8
|
+
this.query = query;
|
|
9
|
+
this.#schema = schema;
|
|
10
|
+
this.#state = {};
|
|
11
|
+
}
|
|
12
|
+
get() {
|
|
13
|
+
return this.#state;
|
|
14
|
+
}
|
|
15
|
+
set(value) {
|
|
16
|
+
const error = this.#schema.fit(value);
|
|
17
|
+
if (error !== null)
|
|
18
|
+
throw new EntityContractException(error, value);
|
|
19
|
+
delete value.VERSION;
|
|
20
|
+
value.UPDATED = Date.now();
|
|
21
|
+
this.#state = value;
|
|
22
|
+
}
|
|
23
|
+
export() {
|
|
24
|
+
return this.#state;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=changeset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changeset.js","sourceRoot":"","sources":["../../source/entities/changeset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAI1D,MAAM,OAAO,SAAS;IACJ,KAAK,CAAO;IAE5B,2EAA2E;IAClE,OAAO,CAAQ;IACxB,MAAM,CAAiB;IAEvB,YAAmB,MAAc,EAAE,KAAY;QAC7C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAElB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;IAClB,CAAC;IAEM,GAAG;QACR,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAEM,GAAG,CAAC,KAAa;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAErC,IAAI,KAAK,KAAK,IAAI;YAAE,MAAM,IAAI,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAEnE,OAAQ,KAAyB,CAAC,OAAO,CAAA;QACzC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAE1B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;IACrB,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Schema } from '@toa.io/schemas';
|
|
2
|
+
import type { Guard } from '../guard.ts';
|
|
3
|
+
import type { Record } from '../types/storages.ts';
|
|
4
|
+
import type { Event } from '../types/state.ts';
|
|
5
|
+
export declare class Entity {
|
|
6
|
+
#private;
|
|
7
|
+
deleted: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* A record makes an entity of what a storage holds; a string, or nothing at all, makes a
|
|
10
|
+
* blank one under that identity, out of what the component declared a record starts as.
|
|
11
|
+
*
|
|
12
|
+
* @param blank what the component declares a record holds before anything is written to it
|
|
13
|
+
* @param mutable whether the entity may be modified and committed
|
|
14
|
+
*/
|
|
15
|
+
constructor(schema: Schema, blank: object, argument?: Record | string, guards?: Guard[], mutable?: boolean);
|
|
16
|
+
get(): Record;
|
|
17
|
+
set(value: Record): void;
|
|
18
|
+
event(input?: object): Event;
|
|
19
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { environment } from '@toa.io/generic';
|
|
2
|
+
import { EntityContractException, EntityGuardException } from '../exceptions.js';
|
|
3
|
+
import { newid } from './newid.js';
|
|
4
|
+
export class Entity {
|
|
5
|
+
deleted = false;
|
|
6
|
+
#schema;
|
|
7
|
+
#blank;
|
|
8
|
+
#guards;
|
|
9
|
+
#origin = null;
|
|
10
|
+
#state;
|
|
11
|
+
#mutable = true;
|
|
12
|
+
/**
|
|
13
|
+
* A record makes an entity of what a storage holds; a string, or nothing at all, makes a
|
|
14
|
+
* blank one under that identity, out of what the component declared a record starts as.
|
|
15
|
+
*
|
|
16
|
+
* @param blank what the component declares a record holds before anything is written to it
|
|
17
|
+
* @param mutable whether the entity may be modified and committed
|
|
18
|
+
*/
|
|
19
|
+
// eslint-disable-next-line max-params
|
|
20
|
+
constructor(schema, blank, argument, guards, mutable = true) {
|
|
21
|
+
this.#schema = schema;
|
|
22
|
+
this.#blank = blank;
|
|
23
|
+
this.#guards = guards;
|
|
24
|
+
if (typeof argument === 'object')
|
|
25
|
+
this.#acquire(argument, mutable);
|
|
26
|
+
else
|
|
27
|
+
this.#write(this.#compose(argument ?? newid()));
|
|
28
|
+
}
|
|
29
|
+
get() {
|
|
30
|
+
return this.#state;
|
|
31
|
+
}
|
|
32
|
+
set(value) {
|
|
33
|
+
if (!this.#mutable)
|
|
34
|
+
throw new Error('Entity acquired by a read-only operation cannot be modified');
|
|
35
|
+
this.#guard(value);
|
|
36
|
+
const error = this.#schema.fit(value);
|
|
37
|
+
if (error !== null)
|
|
38
|
+
throw new EntityContractException(error, value);
|
|
39
|
+
this.#revive(value);
|
|
40
|
+
this.#write(value);
|
|
41
|
+
}
|
|
42
|
+
event(input) {
|
|
43
|
+
return {
|
|
44
|
+
origin: this.#origin,
|
|
45
|
+
state: this.#state,
|
|
46
|
+
trailers: this.#state._trailers,
|
|
47
|
+
input
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The origin is the pre-image a commit diffs the new state against. An operation that
|
|
52
|
+
* cannot commit has nothing to diff, so it takes the record as it came from the storage
|
|
53
|
+
* instead of paying for a deep copy of every record it read.
|
|
54
|
+
*/
|
|
55
|
+
#acquire(record, mutable) {
|
|
56
|
+
this.#mutable = mutable;
|
|
57
|
+
if (!mutable) {
|
|
58
|
+
this.#write(record);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
this.#write(structuredClone(record));
|
|
62
|
+
this.#origin = record;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A blank is not validated: what the component declared is fitted once, at boot, and the
|
|
66
|
+
* system properties are the runtime's own. It is copied because every entity the component
|
|
67
|
+
* makes is written over its own.
|
|
68
|
+
*/
|
|
69
|
+
#compose(id) {
|
|
70
|
+
// `REGION` here as well as in `#write`, because a record is validated before it is written
|
|
71
|
+
// and what is composed is about to be written here: it is this region's
|
|
72
|
+
return {
|
|
73
|
+
id,
|
|
74
|
+
VERSION: 0,
|
|
75
|
+
DELETED: null,
|
|
76
|
+
REGION,
|
|
77
|
+
...structuredClone(this.#blank)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
#guard(value) {
|
|
81
|
+
if (this.#guards === undefined)
|
|
82
|
+
return;
|
|
83
|
+
for (const guard of this.#guards) {
|
|
84
|
+
const ok = guard.fit(value, this.#origin);
|
|
85
|
+
if (ok === false)
|
|
86
|
+
throw new EntityGuardException(guard.name, value);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// deletion is only expressed as a new DELETED timestamp,
|
|
90
|
+
// so committing over a tombstone without touching it means revival
|
|
91
|
+
#revive(value) {
|
|
92
|
+
if (this.#origin?.DELETED == null || value.DELETED !== this.#origin.DELETED)
|
|
93
|
+
return;
|
|
94
|
+
value.DELETED = null;
|
|
95
|
+
this.deleted = false;
|
|
96
|
+
}
|
|
97
|
+
#write(value) {
|
|
98
|
+
if (!('_trailers' in value))
|
|
99
|
+
Object.defineProperty(value, '_trailers', {
|
|
100
|
+
writable: false,
|
|
101
|
+
configurable: false,
|
|
102
|
+
enumerable: false,
|
|
103
|
+
value: {}
|
|
104
|
+
});
|
|
105
|
+
/*
|
|
106
|
+
* The system properties are the runtime's to write, and a record does not always come from
|
|
107
|
+
* a storage that wrote them: a component may bring its own, and one that answers with an
|
|
108
|
+
* id and a version has left the rest to whoever asked. Filling them in here is what makes
|
|
109
|
+
* a record's shape the runtime's guarantee rather than a storage's promise, and what lets
|
|
110
|
+
* the entity require them.
|
|
111
|
+
*/
|
|
112
|
+
value.CREATED ??= Date.now();
|
|
113
|
+
value.UPDATED ??= value.CREATED;
|
|
114
|
+
value.VERSION ??= 0;
|
|
115
|
+
value.DELETED ??= null;
|
|
116
|
+
value.REGION ??= REGION;
|
|
117
|
+
if (value.DELETED !== null)
|
|
118
|
+
this.deleted = true;
|
|
119
|
+
// beside the version and the timestamp, and for the same reason: all three say what the
|
|
120
|
+
// write did, so all three change only where there is one. A record read here keeps the
|
|
121
|
+
// region that wrote it, which is not necessarily this one — that is the whole of what it
|
|
122
|
+
// is for, and stamping it on the way in would answer every read with the wrong region.
|
|
123
|
+
if (this.#state !== undefined) {
|
|
124
|
+
value.UPDATED = Date.now();
|
|
125
|
+
value.VERSION++;
|
|
126
|
+
value.REGION = REGION;
|
|
127
|
+
}
|
|
128
|
+
this.#state = value;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The rank of the region this deployment is, from what deployed it. An application that is one
|
|
133
|
+
* region has none and writes `0`, which is what the first region is and what a record written
|
|
134
|
+
* before any of this existed is backfilled with.
|
|
135
|
+
*/
|
|
136
|
+
const REGION = Number(environment.get('TOA_REGION') ?? 0);
|
|
137
|
+
//# sourceMappingURL=entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity.js","sourceRoot":"","sources":["../../source/entities/entity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Entity } from './entity.ts';
|
|
2
|
+
import { EntitySet } from './set.ts';
|
|
3
|
+
import { Changeset } from './changeset.ts';
|
|
4
|
+
import type { Schema } from '@toa.io/schemas';
|
|
5
|
+
import type { Guard } from '../guard.ts';
|
|
6
|
+
import type { Query, Record } from '../types/storages.ts';
|
|
7
|
+
/** The two schemas a component's records are held to, and what a new one starts as. */
|
|
8
|
+
export interface Schemas {
|
|
9
|
+
/** what a stored record must fit */
|
|
10
|
+
entity: Schema;
|
|
11
|
+
/** what a changeset must fit: the same properties, none of them required */
|
|
12
|
+
changeset: Schema;
|
|
13
|
+
}
|
|
14
|
+
export declare class Factory {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(schemas: Schemas, blank: object, guards?: Guard[]);
|
|
17
|
+
/**
|
|
18
|
+
* What these values would make of a record, held to what a record must be. It starts from a
|
|
19
|
+
* blank rather than from the declared properties alone, because what is validated is the
|
|
20
|
+
* record and a record carries what the runtime writes into every one of them.
|
|
21
|
+
*/
|
|
22
|
+
fit(values: object): void;
|
|
23
|
+
init(id?: string): Entity;
|
|
24
|
+
object(record: Record, mutable?: boolean): Entity;
|
|
25
|
+
objects(recordset: Record[], init?: string[], mutable?: boolean): EntitySet;
|
|
26
|
+
changeset(query: Query): Changeset;
|
|
27
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Entity } from './entity.js';
|
|
2
|
+
import { EntitySet } from './set.js';
|
|
3
|
+
import { Changeset } from './changeset.js';
|
|
4
|
+
export class Factory {
|
|
5
|
+
#schemas;
|
|
6
|
+
#blank;
|
|
7
|
+
#guards;
|
|
8
|
+
constructor(schemas, blank, guards) {
|
|
9
|
+
this.#schemas = schemas;
|
|
10
|
+
this.#blank = blank;
|
|
11
|
+
this.#guards = guards;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* What these values would make of a record, held to what a record must be. It starts from a
|
|
15
|
+
* blank rather than from the declared properties alone, because what is validated is the
|
|
16
|
+
* record and a record carries what the runtime writes into every one of them.
|
|
17
|
+
*/
|
|
18
|
+
fit(values) {
|
|
19
|
+
this.#schemas.entity.validate({ ...this.init().get(), ...values }, 'Entity');
|
|
20
|
+
}
|
|
21
|
+
init(id) {
|
|
22
|
+
return new Entity(this.#schemas.entity, this.#blank, id, this.#guards);
|
|
23
|
+
}
|
|
24
|
+
object(record, mutable = true) {
|
|
25
|
+
return new Entity(this.#schemas.entity, this.#blank, record, this.#guards, mutable);
|
|
26
|
+
}
|
|
27
|
+
objects(recordset, init, mutable = true) {
|
|
28
|
+
const set = recordset.map((record) => this.object(record, mutable));
|
|
29
|
+
if (init !== undefined)
|
|
30
|
+
for (const id of init)
|
|
31
|
+
set.unshift(this.init(id));
|
|
32
|
+
return new EntitySet(set);
|
|
33
|
+
}
|
|
34
|
+
changeset(query) {
|
|
35
|
+
return new Changeset(this.#schemas.changeset, query);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../source/entities/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAc1C,MAAM,OAAO,OAAO;IACT,QAAQ,CAAS;IACjB,MAAM,CAAQ;IACd,OAAO,CAAqB;IAErC,YAAmB,OAAgB,EAAE,KAAa,EAAE,MAAgB;QAClE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;QACnB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAED;;;;OAIG;IACI,GAAG,CAAC,MAAc;QACvB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAA;IAC9E,CAAC;IAEM,IAAI,CAAC,EAAW;QACrB,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IACxE,CAAC;IAEM,MAAM,CAAC,MAAc,EAAE,OAAO,GAAG,IAAI;QAC1C,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACrF,CAAC;IAEM,OAAO,CAAC,SAAmB,EAAE,IAAe,EAAE,OAAO,GAAG,IAAI;QACjE,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QAEnE,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,MAAM,EAAE,IAAI,IAAI;gBAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QAEzE,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IAEM,SAAS,CAAC,KAAY;QAC3B,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;IACtD,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/entities/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA"}
|