@reventlessdev/trait-notification 1.0.0-alpha.6 → 1.0.0-alpha.60
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 +7 -7
- package/src/Notification.res +3 -9
- package/src/Notification_Conformance.res +21 -15
- package/src/Notification_Conformance.res.mjs +4 -4
- package/src/Notification_Rule.res +8 -12
- package/src/Notification_Rule.res.mjs +3 -3
- package/src/Notification_Rules.res +22 -24
- package/src/Notification_Scaffold.res +41 -47
- package/src/Notification_Scaffold.res.mjs +35 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/trait-notification",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.60",
|
|
4
4
|
"description": "Notification domain trait: rules, host contract, conformance suite and emitter for a per-recipient contact directory, a kind x channel subscription matrix, and the decision to send, suppress or record a message as undeliverable",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"files": [
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
"README.md"
|
|
12
12
|
],
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"sury": "11.0.0
|
|
15
|
-
"sury-ppx": "11.0.0
|
|
16
|
-
"@reventlessdev/reventless-gwt": "1.0.0-alpha.
|
|
17
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.
|
|
14
|
+
"sury": "11.0.0",
|
|
15
|
+
"sury-ppx": "11.0.0",
|
|
16
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.258",
|
|
17
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.178"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"rescript": "12.3.
|
|
20
|
+
"rescript": "12.3.1"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"rescript": "12.3.
|
|
23
|
+
"rescript": "^12.3.1"
|
|
24
24
|
},
|
|
25
25
|
"publishConfig": {
|
|
26
26
|
"registry": "https://registry.npmjs.org"
|
package/src/Notification.res
CHANGED
|
@@ -19,7 +19,6 @@ What an occurrence *is*. It is told a recipient, a kind, and a reference; it is
|
|
|
19
19
|
never told there was an order. That is why the two relays are the only files a
|
|
20
20
|
graft has to be given, and everything else can be handed over whole.
|
|
21
21
|
*/
|
|
22
|
-
|
|
23
22
|
/**
|
|
24
23
|
This trait's own account of itself — see `AddressGeocoding.declaration` for why the
|
|
25
24
|
version is read rather than written.
|
|
@@ -64,8 +63,8 @@ module type Binding = {
|
|
|
64
63
|
let transactional: category
|
|
65
64
|
let optional: category
|
|
66
65
|
|
|
67
|
-
module Spec: ReventlessGwt.
|
|
68
|
-
module
|
|
66
|
+
module Spec: ReventlessGwt.Decision_GWT.DecisionSpec
|
|
67
|
+
module Decision: ReventlessGwt.Decision_GWT.Decision with module Spec = Spec
|
|
69
68
|
|
|
70
69
|
/** The same facts as the slice **consumes** them, for building history.
|
|
71
70
|
|
|
@@ -120,12 +119,7 @@ module type Binding = {
|
|
|
120
119
|
/** `requested` as it comes out for a `Configured` request. A separate member
|
|
121
120
|
because *which* rule asked is the host's own shape — the trait's fact
|
|
122
121
|
carries no origin at all, so it cannot construct this one. */
|
|
123
|
-
let requestedConfigured: (
|
|
124
|
-
category,
|
|
125
|
-
string,
|
|
126
|
-
Notification_Rules.channel,
|
|
127
|
-
string,
|
|
128
|
-
) => Spec.event
|
|
122
|
+
let requestedConfigured: (category, string, Notification_Rules.channel, string) => Spec.event
|
|
129
123
|
|
|
130
124
|
/** The refusal for managing preferences for somebody nobody has announced. */
|
|
131
125
|
let recipientUnknown: Spec.error
|
|
@@ -6,7 +6,6 @@ What it asserts is the competency, not the host: the directory, the fallback to
|
|
|
6
6
|
the host's posture, and — the part worth being strict about — that the three ways
|
|
7
7
|
to send nothing stay three different facts.
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
9
|
/** The suite's title, composed once and read twice: the suite registers it,
|
|
11
10
|
and `certify-trait` computes the same string to find the run's assertions in
|
|
12
11
|
a test report. Exported rather than inlined so neither side parses the
|
|
@@ -14,7 +13,7 @@ to send nothing stay three different facts.
|
|
|
14
13
|
let suiteName = (host: string) => `${host} conforms to the notification trait`
|
|
15
14
|
|
|
16
15
|
module Make = (B: Notification.Binding) => {
|
|
17
|
-
module G = ReventlessGwt.
|
|
16
|
+
module G = ReventlessGwt.Decision_GWT.Make(B.Spec, B.Decision)
|
|
18
17
|
module R = Notification_Rules
|
|
19
18
|
|
|
20
19
|
let announced = Array.concat(B.Consumed.created, [B.Consumed.announced(B.addressA)])
|
|
@@ -22,9 +21,9 @@ module Make = (B: Notification.Binding) => {
|
|
|
22
21
|
let register = () =>
|
|
23
22
|
G.describe(suiteName(B.Spec.name), () => {
|
|
24
23
|
G.test("an announced contact is recorded", () =>
|
|
25
|
-
G.givenEvents(B.Consumed.created)
|
|
26
|
-
|
|
27
|
-
)
|
|
24
|
+
G.givenEvents(B.Consumed.created)
|
|
25
|
+
->G.whenCmd(B.announce(B.addressA))
|
|
26
|
+
->G.thenEvent(B.announced(B.addressA))
|
|
28
27
|
)
|
|
29
28
|
|
|
30
29
|
// The relay re-announces on every contact event a host publishes, and its
|
|
@@ -36,9 +35,9 @@ module Make = (B: Notification.Binding) => {
|
|
|
36
35
|
)
|
|
37
36
|
|
|
38
37
|
G.test("a changed address is recorded", () =>
|
|
39
|
-
G.givenEvents(announced)
|
|
40
|
-
|
|
41
|
-
)
|
|
38
|
+
G.givenEvents(announced)
|
|
39
|
+
->G.whenCmd(B.announce(B.addressB))
|
|
40
|
+
->G.thenEvent(B.announced(B.addressB))
|
|
42
41
|
)
|
|
43
42
|
|
|
44
43
|
// A person is at the other end of this one, so they are told rather than
|
|
@@ -81,9 +80,7 @@ module Make = (B: Notification.Binding) => {
|
|
|
81
80
|
G.test("a transactional request goes out with no explicit subscription", () =>
|
|
82
81
|
G.givenEvents(announced)
|
|
83
82
|
->G.whenCmd(B.request(B.transactional, "ref-1"))
|
|
84
|
-
->G.thenEvent(
|
|
85
|
-
B.requested(B.transactional, "ref-1", B.announcedChannel, B.addressA),
|
|
86
|
-
)
|
|
83
|
+
->G.thenEvent(B.requested(B.transactional, "ref-1", B.announcedChannel, B.addressA))
|
|
87
84
|
)
|
|
88
85
|
|
|
89
86
|
G.test("the address on the request is the one currently on file", () =>
|
|
@@ -129,7 +126,9 @@ module Make = (B: Notification.Binding) => {
|
|
|
129
126
|
)
|
|
130
127
|
|
|
131
128
|
G.test("a default request for a claimed source is deferred", () =>
|
|
132
|
-
G.givenEvents(
|
|
129
|
+
G.givenEvents(
|
|
130
|
+
Array.concat(announced, [B.Consumed.claimed("other:Source", "second-producer")]),
|
|
131
|
+
)
|
|
133
132
|
->G.whenCmd(
|
|
134
133
|
B.requestFrom(B.transactional, "ref-7", ~source="other:Source", ~origin=Default),
|
|
135
134
|
)
|
|
@@ -140,7 +139,9 @@ module Make = (B: Notification.Binding) => {
|
|
|
140
139
|
// keeps firing everywhere it was not taken over. Without this, a single
|
|
141
140
|
// claim would silence the whole competency.
|
|
142
141
|
G.test("a claim on one source leaves every other source alone", () =>
|
|
143
|
-
G.givenEvents(
|
|
142
|
+
G.givenEvents(
|
|
143
|
+
Array.concat(announced, [B.Consumed.claimed("other:Source", "second-producer")]),
|
|
144
|
+
)
|
|
144
145
|
->G.whenCmd(
|
|
145
146
|
B.requestFrom(B.transactional, "ref-8", ~source=B.defaultSource, ~origin=Default),
|
|
146
147
|
)
|
|
@@ -150,7 +151,9 @@ module Make = (B: Notification.Binding) => {
|
|
|
150
151
|
// The producer that owns the source is the one that must get through, or
|
|
151
152
|
// the handover would silence the entry rather than move it.
|
|
152
153
|
G.test("a configured request for a claimed source goes through", () =>
|
|
153
|
-
G.givenEvents(
|
|
154
|
+
G.givenEvents(
|
|
155
|
+
Array.concat(announced, [B.Consumed.claimed("other:Source", "second-producer")]),
|
|
156
|
+
)
|
|
154
157
|
->G.whenCmd(
|
|
155
158
|
B.requestFrom(B.transactional, "ref-9", ~source="other:Source", ~origin=Configured),
|
|
156
159
|
)
|
|
@@ -163,7 +166,10 @@ module Make = (B: Notification.Binding) => {
|
|
|
163
166
|
G.givenEvents(
|
|
164
167
|
Array.concat(
|
|
165
168
|
announced,
|
|
166
|
-
[
|
|
169
|
+
[
|
|
170
|
+
B.Consumed.claimed("other:Source", "second-producer"),
|
|
171
|
+
B.Consumed.released("other:Source"),
|
|
172
|
+
],
|
|
167
173
|
),
|
|
168
174
|
)
|
|
169
175
|
->G.whenCmd(
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Decision_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Decision_GWT.res.mjs";
|
|
4
4
|
|
|
5
5
|
function suiteName(host) {
|
|
6
6
|
return host + ` conforms to the notification trait`;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function Make(B) {
|
|
10
|
-
let $$let = B.
|
|
11
|
-
let G =
|
|
10
|
+
let $$let = B.Decision;
|
|
11
|
+
let G = Decision_GWT$ReventlessGwt.Make(B.Spec)({
|
|
12
12
|
initialState: $$let.initialState,
|
|
13
13
|
evolve: $$let.evolve,
|
|
14
14
|
decide: $$let.decide
|
|
@@ -56,4 +56,4 @@ export {
|
|
|
56
56
|
suiteName,
|
|
57
57
|
Make,
|
|
58
58
|
}
|
|
59
|
-
/*
|
|
59
|
+
/* Decision_GWT-ReventlessGwt Not a pure module */
|
|
@@ -9,7 +9,6 @@ surface. It is also why the wording is `Reventless.Template` source: readable
|
|
|
9
9
|
text rather than ReScript interpolation, rendered against the payload's schema so
|
|
10
10
|
a semantic formats itself and a `@sensitive` field is withheld.
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
12
|
/** How a field is compared. */
|
|
14
13
|
@schema
|
|
15
14
|
type comparison =
|
|
@@ -165,8 +164,7 @@ let recipientOf = (rule: t, ~payload: JSON.t) => stringAt(payload, rule.recipien
|
|
|
165
164
|
|
|
166
165
|
/** What it is about. Empty is legal — a notification about nothing in particular
|
|
167
166
|
is a real case, and a fabricated subject is worse than an absent one. */
|
|
168
|
-
let subjectOf = (rule: t, ~payload: JSON.t) =>
|
|
169
|
-
stringAt(payload, rule.subjectPath)->Option.getOr("")
|
|
167
|
+
let subjectOf = (rule: t, ~payload: JSON.t) => stringAt(payload, rule.subjectPath)->Option.getOr("")
|
|
170
168
|
|
|
171
169
|
/** The wording to use, the asked-for locale if the rule has it and the first
|
|
172
170
|
otherwise. Which locale to ask for is the caller's — nothing here knows who
|
|
@@ -191,10 +189,7 @@ let render = (source: string, ~payload: JSON.t, ~schema: S.t<'a>) =>
|
|
|
191
189
|
let compose = (rule: t, ~payload: JSON.t, ~schema: S.t<'a>, ~locale: option<string>=?) =>
|
|
192
190
|
switch contentFor(rule, ~locale?) {
|
|
193
191
|
| None => ("", "")
|
|
194
|
-
| Some({subject, body}) => (
|
|
195
|
-
render(subject, ~payload, ~schema),
|
|
196
|
-
render(body, ~payload, ~schema),
|
|
197
|
-
)
|
|
192
|
+
| Some({subject, body}) => (render(subject, ~payload, ~schema), render(body, ~payload, ~schema))
|
|
198
193
|
}
|
|
199
194
|
|
|
200
195
|
/**
|
|
@@ -221,11 +216,12 @@ let validate = (rules: array<t>, ~digestRouted: bool=false, ~sample: JSON.t): ar
|
|
|
221
216
|
note("no wording at all")
|
|
222
217
|
}
|
|
223
218
|
rule.content->Array.forEach(({locale, subject, body}) =>
|
|
224
|
-
[("subject", subject), ("body", body)]->Array.forEach(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
219
|
+
[("subject", subject), ("body", body)]->Array.forEach(
|
|
220
|
+
((which, template)) =>
|
|
221
|
+
switch Reventless.Template.parse(template) {
|
|
222
|
+
| Ok(_) => ()
|
|
223
|
+
| Error(why) => note(`${locale} ${which} does not parse — ${why}`)
|
|
224
|
+
},
|
|
229
225
|
)
|
|
230
226
|
)
|
|
231
227
|
if recipientOf(rule, ~payload=sample) == None {
|
|
@@ -23,11 +23,11 @@ let literalSchema = Sury.union([
|
|
|
23
23
|
})),
|
|
24
24
|
Sury.$schema(s => ({
|
|
25
25
|
TAG: "Number",
|
|
26
|
-
_0: s.m(Sury.
|
|
26
|
+
_0: s.m(Sury.number)
|
|
27
27
|
})),
|
|
28
28
|
Sury.$schema(s => ({
|
|
29
29
|
TAG: "Flag",
|
|
30
|
-
_0: s.m(Sury.
|
|
30
|
+
_0: s.m(Sury.boolean)
|
|
31
31
|
}))
|
|
32
32
|
]);
|
|
33
33
|
|
|
@@ -68,7 +68,7 @@ let deliverySchema = Sury.union([
|
|
|
68
68
|
Sury.literal("Immediate"),
|
|
69
69
|
Sury.$schema(s => ({
|
|
70
70
|
TAG: "Digest",
|
|
71
|
-
windowSeconds: s.m(Sury.
|
|
71
|
+
windowSeconds: s.m(Sury.int32)
|
|
72
72
|
}))
|
|
73
73
|
]);
|
|
74
74
|
|
|
@@ -17,7 +17,6 @@ is the opposite. So the fallback *rule* lives here — an absent choice defers t
|
|
|
17
17
|
the posture — and the *table* is passed in as `~posture`. A trait that hard-coded
|
|
18
18
|
either answer would be wrong for half its hosts.
|
|
19
19
|
*/
|
|
20
|
-
|
|
21
20
|
/** How a recipient is reached. Mirrors `Reventless.Messaging.channel`, which is
|
|
22
21
|
the platform capability's vocabulary; this one is the domain's, so it carries
|
|
23
22
|
a host's schema and travels on the wire. `Notification_Send` maps the two. */
|
|
@@ -72,22 +71,22 @@ let claimedBy = (t, source) =>
|
|
|
72
71
|
|
|
73
72
|
/** What a host asks the competency to do. */
|
|
74
73
|
type op =
|
|
75
|
-
|
|
74
|
+
/** Relayed from whatever the host publishes when it learns where somebody is.
|
|
76
75
|
Not a client's command: a caller who could announce another person's
|
|
77
76
|
address would be redirecting their mail. */
|
|
78
|
-
Announce({channel: channel, address: string})
|
|
77
|
+
| Announce({channel: channel, address: string})
|
|
79
78
|
| Subscribe({category: category, channel: channel})
|
|
80
79
|
| Unsubscribe({category: category, channel: channel})
|
|
81
|
-
|
|
80
|
+
/** Something worth telling them about happened. `reference` is the caller's
|
|
82
81
|
own key for it, echoed back on whichever outcome follows, so the relay
|
|
83
82
|
that asked can tell its work is finished. Opaque here on purpose.
|
|
84
83
|
|
|
85
84
|
`source` says which stream it came from and `origin` says who is asking;
|
|
86
85
|
together they are the whole of the handover — see `decide`. */
|
|
87
|
-
Request({category: category, reference: string, source: source, origin: origin})
|
|
88
|
-
|
|
86
|
+
| Request({category: category, reference: string, source: source, origin: origin})
|
|
87
|
+
/** A second producer takes over one source. Relayed like `Announce`: a
|
|
89
88
|
client that could claim a source would be silencing somebody else's mail. */
|
|
90
|
-
Claim({source: source, by: string})
|
|
89
|
+
| Claim({source: source, by: string})
|
|
91
90
|
| Release({source: source})
|
|
92
91
|
|
|
93
92
|
/** What the competency decided, for the host to name in its own events. */
|
|
@@ -95,18 +94,18 @@ type fact =
|
|
|
95
94
|
| Announced({channel: channel, address: string})
|
|
96
95
|
| Subscribed({category: category, channel: channel})
|
|
97
96
|
| Unsubscribed({category: category, channel: channel})
|
|
98
|
-
|
|
97
|
+
/** The addressed message. `address` is the snapshot delivery uses, which is
|
|
99
98
|
why it is on the fact and not looked up again later. */
|
|
100
|
-
Requested({category: category, reference: string, channel: channel, address: string})
|
|
101
|
-
|
|
102
|
-
Suppressed({category: category, reference: string})
|
|
103
|
-
|
|
99
|
+
| Requested({category: category, reference: string, channel: channel, address: string})
|
|
100
|
+
/** They are reachable and said no. */
|
|
101
|
+
| Suppressed({category: category, reference: string})
|
|
102
|
+
/** They want it and nobody can be reached — no address on file for any
|
|
104
103
|
channel they left enabled. A different fact from `Suppressed` on purpose:
|
|
105
104
|
one is the system working and the other is the system falling short, and
|
|
106
105
|
reporting both the same way hides every delivery gap behind a legitimate
|
|
107
106
|
preference. */
|
|
108
|
-
Undeliverable({category: category, reference: string})
|
|
109
|
-
|
|
107
|
+
| Undeliverable({category: category, reference: string})
|
|
108
|
+
/** Not acted on because another producer owns this source. A third way of
|
|
110
109
|
not sending, and its own fact for the same reason `Suppressed` and
|
|
111
110
|
`Undeliverable` are two rather than one: "they declined", "nobody was
|
|
112
111
|
reachable" and "somebody else has this" are three different things, and a
|
|
@@ -116,7 +115,7 @@ type fact =
|
|
|
116
115
|
TODO row on an outcome; without a fourth one a deferred request retries
|
|
117
116
|
its whole budget and lands in `onExhausted`, which is a slow silent
|
|
118
117
|
failure with nothing in the log to explain it. */
|
|
119
|
-
Deferred({reference: string, source: source})
|
|
118
|
+
| Deferred({reference: string, source: source})
|
|
120
119
|
| Claimed({source: source, by: string})
|
|
121
120
|
| Released({source: source})
|
|
122
121
|
|
|
@@ -223,15 +222,14 @@ let decide = (t, op, ~posture: (category, channel) => bool): result<
|
|
|
223
222
|
|
|
224
223
|
| Request({category, reference}) =>
|
|
225
224
|
let wanted = channels->Array.filter(channel => enabled(t, ~posture, category, channel))
|
|
226
|
-
let addressed =
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
)
|
|
225
|
+
let addressed = wanted->Array.filterMap(channel =>
|
|
226
|
+
addressFor(t, channel)->Option.map(address => Requested({
|
|
227
|
+
category,
|
|
228
|
+
reference,
|
|
229
|
+
channel,
|
|
230
|
+
address,
|
|
231
|
+
}))
|
|
232
|
+
)
|
|
235
233
|
switch addressed {
|
|
236
234
|
| [] =>
|
|
237
235
|
// Wanted-but-unreachable and not-wanted are the two ways to send nothing,
|
|
@@ -15,7 +15,6 @@ is the one thing a trait cannot be told in names.
|
|
|
15
15
|
says is the host's sentence, so the emitted rule table carries a `TODO(graft)`
|
|
16
16
|
marker in place of one — it compiles, runs, and is obvious in a diff.
|
|
17
17
|
*/
|
|
18
|
-
|
|
19
18
|
/**
|
|
20
19
|
The names a graft needs, and nothing else.
|
|
21
20
|
|
|
@@ -137,8 +136,8 @@ let namesOf = (c: config): names => {
|
|
|
137
136
|
delivered: "NotificationDelivered",
|
|
138
137
|
failed: "NotificationFailed",
|
|
139
138
|
unknownError: n ++ "Unknown",
|
|
140
|
-
recipientId:
|
|
141
|
-
|
|
139
|
+
recipientId: n->String.slice(~start=0, ~end=1)->String.toLowerCase ++
|
|
140
|
+
n->String.slice(~start=1, ~end=n->String.length) ++ "Id",
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
143
|
|
|
@@ -154,13 +153,14 @@ let addressB = (c: config) => c.addressB->Option.getOr("new@example.com")
|
|
|
154
153
|
graft, so a host whose component is registered under another name edits one
|
|
155
154
|
line rather than discovering the convention. */
|
|
156
155
|
let subjectTypeOf = (c: config) => {
|
|
157
|
-
let stem =
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
let stem =
|
|
157
|
+
c.occurrenceId->String.endsWith("Id")
|
|
158
|
+
? c.occurrenceId->String.slice(~start=0, ~end=c.occurrenceId->String.length - 2)
|
|
159
|
+
: c.occurrenceId
|
|
160
160
|
switch stem {
|
|
161
161
|
| "" => "Subject"
|
|
162
162
|
| s =>
|
|
163
|
-
|
|
163
|
+
s->String.slice(~start=0, ~end=1)->String.toUpperCase ++
|
|
164
164
|
s->String.slice(~start=1, ~end=s->String.length)
|
|
165
165
|
}
|
|
166
166
|
}
|
|
@@ -349,7 +349,7 @@ let postureArms = (c: config) => {
|
|
|
349
349
|
Array.concat(transactional, [` | _ => false`])
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
-
let
|
|
352
|
+
let sliceDecision = (c: config): string => {
|
|
353
353
|
let n = namesOf(c)
|
|
354
354
|
let id = n.recipientId
|
|
355
355
|
let first = c.categories->Array.get(0)->Option.getOr("Transactional")
|
|
@@ -357,7 +357,7 @@ let sliceBehavior = (c: config): string => {
|
|
|
357
357
|
Array.flatMap(
|
|
358
358
|
[
|
|
359
359
|
[
|
|
360
|
-
`@@reventless.
|
|
360
|
+
`@@reventless.decision`,
|
|
361
361
|
``,
|
|
362
362
|
`// The directory, the matrix and the dispatch decision are the trait's; this file`,
|
|
363
363
|
`// is the mapping onto them, plus the one thing the trait has no opinion about —`,
|
|
@@ -373,19 +373,9 @@ let sliceBehavior = (c: config): string => {
|
|
|
373
373
|
` switch (category, channel) {`,
|
|
374
374
|
],
|
|
375
375
|
postureArms(c),
|
|
376
|
-
[
|
|
377
|
-
` }`,
|
|
378
|
-
``,
|
|
379
|
-
`let categoryKey = (category: category) =>`,
|
|
380
|
-
` switch category {`,
|
|
381
|
-
],
|
|
376
|
+
[` }`, ``, `let categoryKey = (category: category) =>`, ` switch category {`],
|
|
382
377
|
c.categories->Array.map(cat => ` | ${cat} => "${cat}"`),
|
|
383
|
-
[
|
|
384
|
-
` }`,
|
|
385
|
-
``,
|
|
386
|
-
`let categoryOf = (key: string) =>`,
|
|
387
|
-
` switch key {`,
|
|
388
|
-
],
|
|
378
|
+
[` }`, ``, `let categoryOf = (key: string) =>`, ` switch key {`],
|
|
389
379
|
c.categories
|
|
390
380
|
->Array.filter(cat => cat != first)
|
|
391
381
|
->Array.map(cat => ` | "${cat}" => ${cat}`),
|
|
@@ -632,10 +622,10 @@ let claimsSpec = (c: config): string => {
|
|
|
632
622
|
])
|
|
633
623
|
}
|
|
634
624
|
|
|
635
|
-
let
|
|
625
|
+
let claimsDecision = (c: config): string => {
|
|
636
626
|
let n = namesOf(c)
|
|
637
627
|
lines([
|
|
638
|
-
`@@reventless.
|
|
628
|
+
`@@reventless.decision`,
|
|
639
629
|
``,
|
|
640
630
|
`// The claim set is the trait's, folded through the same value the preferences`,
|
|
641
631
|
`// slice folds. Only the claim half is ever populated here.`,
|
|
@@ -725,7 +715,6 @@ let sendSpec = (c: config): string => {
|
|
|
725
715
|
`// Retries are for a provider that is down, not one that has refused. The port's`,
|
|
726
716
|
`// own \`retriable\` rule decides which is which, in the translation next door.`,
|
|
727
717
|
`let maxRetries = 3`,
|
|
728
|
-
`let heartbeatInterval = 60`,
|
|
729
718
|
`let targetName = Some("${n.slice}")`,
|
|
730
719
|
``,
|
|
731
720
|
`// This plugin's own DCB event log.`,
|
|
@@ -773,13 +762,20 @@ let sendTranslation = (c: config): string => {
|
|
|
773
762
|
` item.address`,
|
|
774
763
|
` ->Reventless.Phone.fromString`,
|
|
775
764
|
` ->Result.map(phone => Reventless.Messaging.ToSms(phone))`,
|
|
776
|
-
`
|
|
765
|
+
` // The directory stores a channel beside one flat address, and no push address is`,
|
|
766
|
+
` // one string: two services issue a token, Web Push issues an endpoint with its`,
|
|
767
|
+
` // encryption keys, and which service issued this one is not recorded either. So`,
|
|
768
|
+
` // the pair cannot be re-fused, and refusing says so once rather than guessing a`,
|
|
769
|
+
` // service and failing at whichever provider. A push transport arrives with the`,
|
|
770
|
+
` // stored shape it needs, in the commit that justifies the columns.`,
|
|
771
|
+
` | Push =>`,
|
|
772
|
+
` Error("a push address names its issuing service, and the directory stores one flat address")`,
|
|
777
773
|
` }`,
|
|
778
774
|
``,
|
|
779
775
|
`let translate = async (_id, item: outboundItem, ~capabilities: Reventless.Capabilities.t) =>`,
|
|
780
776
|
` switch recipientFor(item) {`,
|
|
781
|
-
` // An address the directory holds that its own channel
|
|
782
|
-
` //
|
|
777
|
+
` // An address the directory holds that its own channel cannot use. Not retryable`,
|
|
778
|
+
` // and not the provider's fault — the row that holds it needs fixing.`,
|
|
783
779
|
` | Error(why) =>`,
|
|
784
780
|
` Ok(`,
|
|
785
781
|
` Some((`,
|
|
@@ -865,7 +861,7 @@ let conformanceBinding = (c: config): string => {
|
|
|
865
861
|
` let optional: category = ${optional}`,
|
|
866
862
|
``,
|
|
867
863
|
` module Spec = ${n.slice}`,
|
|
868
|
-
` module
|
|
864
|
+
` module Decision = ${n.slice}_Decision`,
|
|
869
865
|
``,
|
|
870
866
|
` let ${id} = "${c.noun->String.toLowerCase}-1"`,
|
|
871
867
|
``,
|
|
@@ -879,9 +875,9 @@ let conformanceBinding = (c: config): string => {
|
|
|
879
875
|
` let announced = (${c.contactField}): Spec.consumedEvent =>`,
|
|
880
876
|
` ${n.announced}({${id}: ${id}, ${c.contactField}: ${c.contactField}})`,
|
|
881
877
|
` let subscribed = (category, channel): Spec.consumedEvent =>`,
|
|
882
|
-
` ${n.subscribed}({${id}: ${id}, category, channel:
|
|
878
|
+
` ${n.subscribed}({${id}: ${id}, category, channel: Decision.channelOf(channel)})`,
|
|
883
879
|
` let unsubscribed = (category, channel): Spec.consumedEvent =>`,
|
|
884
|
-
` ${n.unsubscribed}({${id}: ${id}, category, channel:
|
|
880
|
+
` ${n.unsubscribed}({${id}: ${id}, category, channel: Decision.channelOf(channel)})`,
|
|
885
881
|
` // Written by ${n.claims} and read here across partitions — this slice`,
|
|
886
882
|
` // consumes them and produces neither.`,
|
|
887
883
|
` let claimed = (source, by): Spec.consumedEvent =>`,
|
|
@@ -892,9 +888,9 @@ let conformanceBinding = (c: config): string => {
|
|
|
892
888
|
` let announce = ${c.contactField} =>`,
|
|
893
889
|
` Spec.${n.announceCmd}({${id}: ${id}, ${c.contactField}: ${c.contactField}})`,
|
|
894
890
|
` let subscribe = (category, channel) =>`,
|
|
895
|
-
` Spec.${n.subscribeCmd}({${id}: ${id}, category, channel:
|
|
891
|
+
` Spec.${n.subscribeCmd}({${id}: ${id}, category, channel: Decision.channelOf(channel)})`,
|
|
896
892
|
` let unsubscribe = (category, channel) =>`,
|
|
897
|
-
` Spec.${n.unsubscribeCmd}({${id}: ${id}, category, channel:
|
|
893
|
+
` Spec.${n.unsubscribeCmd}({${id}: ${id}, category, channel: Decision.channelOf(channel)})`,
|
|
898
894
|
` // The wording and the subject are this host's and the trait carries neither, so`,
|
|
899
895
|
` // the suite supplies whatever it likes and asserts nothing about them.`,
|
|
900
896
|
` //`,
|
|
@@ -924,15 +920,15 @@ let conformanceBinding = (c: config): string => {
|
|
|
924
920
|
` let announced = ${c.contactField} =>`,
|
|
925
921
|
` Spec.${n.announced}({${id}: ${id}, ${c.contactField}: ${c.contactField}})`,
|
|
926
922
|
` let subscribed = (category, channel) =>`,
|
|
927
|
-
` Spec.${n.subscribed}({${id}: ${id}, category, channel:
|
|
923
|
+
` Spec.${n.subscribed}({${id}: ${id}, category, channel: Decision.channelOf(channel)})`,
|
|
928
924
|
` let unsubscribed = (category, channel) =>`,
|
|
929
|
-
` Spec.${n.unsubscribed}({${id}: ${id}, category, channel:
|
|
925
|
+
` Spec.${n.unsubscribed}({${id}: ${id}, category, channel: Decision.channelOf(channel)})`,
|
|
930
926
|
` let requestedWith = (category, reference, channel, address, origin) =>`,
|
|
931
927
|
` Spec.${n.requested}({`,
|
|
932
928
|
` ${id}: ${id},`,
|
|
933
929
|
` category,`,
|
|
934
930
|
` reference,`,
|
|
935
|
-
` channel:
|
|
931
|
+
` channel: Decision.channelOf(channel),`,
|
|
936
932
|
` address,`,
|
|
937
933
|
` subjectType: "${subjectTypeOf(c)}",`,
|
|
938
934
|
` subjectRef: "subject-1",`,
|
|
@@ -1005,7 +1001,7 @@ let contactRelayPatch = (c: config): patch => {
|
|
|
1005
1001
|
let n = namesOf(c)
|
|
1006
1002
|
let id = n.recipientId
|
|
1007
1003
|
{
|
|
1008
|
-
into: `${c.chapter}/
|
|
1004
|
+
into: `${c.chapter}/OutboundTranslation/${n.relay}.res (new, plus its _Translation)`,
|
|
1009
1005
|
at: `a new file — the trait cannot write what this host's events mean`,
|
|
1010
1006
|
contents: lines(
|
|
1011
1007
|
Array.flatMap(
|
|
@@ -1038,7 +1034,6 @@ let contactRelayPatch = (c: config): patch => {
|
|
|
1038
1034
|
` | ${n.announceCmd}({${id}: string, ${c.contactField}: string})`,
|
|
1039
1035
|
``,
|
|
1040
1036
|
`let maxRetries = 3`,
|
|
1041
|
-
`let heartbeatInterval = 60`,
|
|
1042
1037
|
`let targetName = Some("${n.slice}")`,
|
|
1043
1038
|
`let sourceNames = ["${c.contactSource}"]`,
|
|
1044
1039
|
`// No external box: this slice reaches nothing outside the plugin.`,
|
|
@@ -1085,7 +1080,7 @@ let intakeRelayPatch = (c: config): patch => {
|
|
|
1085
1080
|
let n = namesOf(c)
|
|
1086
1081
|
let id = n.recipientId
|
|
1087
1082
|
{
|
|
1088
|
-
into: `${c.chapter}/
|
|
1083
|
+
into: `${c.chapter}/Automation/${n.intake}.res (new, plus its _Automation)`,
|
|
1089
1084
|
at: `a new file — the wording is this host's sentence, not the trait's`,
|
|
1090
1085
|
contents: lines([
|
|
1091
1086
|
`// Turns one of this host's occurrences into a request to notify somebody.`,
|
|
@@ -1116,7 +1111,6 @@ let intakeRelayPatch = (c: config): patch => {
|
|
|
1116
1111
|
` })`,
|
|
1117
1112
|
``,
|
|
1118
1113
|
`let maxRetries = 3`,
|
|
1119
|
-
`let heartbeatInterval = 60`,
|
|
1120
1114
|
`let targetName = "${n.slice}"`,
|
|
1121
1115
|
``,
|
|
1122
1116
|
`// ── ${n.intake}_Automation.res ──`,
|
|
@@ -1230,7 +1224,7 @@ let intakeRelayPatch = (c: config): patch => {
|
|
|
1230
1224
|
` ${id},`,
|
|
1231
1225
|
` ${n.intake}.${n.requestCmd}({`,
|
|
1232
1226
|
` ${id}: ${id},`,
|
|
1233
|
-
` category: ${n.slice}
|
|
1227
|
+
` category: ${n.slice}_Decision.categoryOf(rule.category),`,
|
|
1234
1228
|
` reference: id,`,
|
|
1235
1229
|
` subjectType: rule.subjectType,`,
|
|
1236
1230
|
` subjectRef: Rule.subjectOf(rule, ~payload),`,
|
|
@@ -1266,16 +1260,16 @@ let emit = (~config: config, ~into: string, ~tests: string): output => {
|
|
|
1266
1260
|
let n = namesOf(config)
|
|
1267
1261
|
{
|
|
1268
1262
|
files: [
|
|
1269
|
-
{path: `${into}/
|
|
1270
|
-
{path: `${into}/
|
|
1271
|
-
{path: `${into}/
|
|
1263
|
+
{path: `${into}/StateChange/${n.slice}.res`, contents: sliceSpec(config)},
|
|
1264
|
+
{path: `${into}/StateChange/${n.slice}_Decision.res`, contents: sliceDecision(config)},
|
|
1265
|
+
{path: `${into}/StateChange/${n.claims}.res`, contents: claimsSpec(config)},
|
|
1272
1266
|
{
|
|
1273
|
-
path: `${into}/
|
|
1274
|
-
contents:
|
|
1267
|
+
path: `${into}/StateChange/${n.claims}_Decision.res`,
|
|
1268
|
+
contents: claimsDecision(config),
|
|
1275
1269
|
},
|
|
1276
|
-
{path: `${into}/
|
|
1270
|
+
{path: `${into}/OutboundTranslation/${n.send}.res`, contents: sendSpec(config)},
|
|
1277
1271
|
{
|
|
1278
|
-
path: `${into}/
|
|
1272
|
+
path: `${into}/OutboundTranslation/${n.send}_Translation.res`,
|
|
1279
1273
|
contents: sendTranslation(config),
|
|
1280
1274
|
},
|
|
1281
1275
|
{path: `${tests}/NotificationConformance_GWT.res`, contents: conformanceBinding(config)},
|
|
@@ -254,13 +254,13 @@ function postureArms(c) {
|
|
|
254
254
|
return transactional.concat([` | _ => false`]);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
function
|
|
257
|
+
function sliceDecision(c) {
|
|
258
258
|
let n = namesOf(c);
|
|
259
259
|
let id = n.recipientId;
|
|
260
260
|
let first = Stdlib_Option.getOr(c.categories[0], "Transactional");
|
|
261
261
|
return [
|
|
262
262
|
[
|
|
263
|
-
`@@reventless.
|
|
263
|
+
`@@reventless.decision`,
|
|
264
264
|
``,
|
|
265
265
|
`// The directory, the matrix and the dispatch decision are the trait's; this file`,
|
|
266
266
|
`// is the mapping onto them, plus the one thing the trait has no opinion about —`,
|
|
@@ -521,10 +521,10 @@ function claimsSpec(c) {
|
|
|
521
521
|
].join("\n");
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
-
function
|
|
524
|
+
function claimsDecision(c) {
|
|
525
525
|
let n = namesOf(c);
|
|
526
526
|
return [
|
|
527
|
-
`@@reventless.
|
|
527
|
+
`@@reventless.decision`,
|
|
528
528
|
``,
|
|
529
529
|
`// The claim set is the trait's, folded through the same value the preferences`,
|
|
530
530
|
`// slice folds. Only the claim half is ever populated here.`,
|
|
@@ -612,7 +612,6 @@ function sendSpec(c) {
|
|
|
612
612
|
`// Retries are for a provider that is down, not one that has refused. The port's`,
|
|
613
613
|
`// own \`retriable\` rule decides which is which, in the translation next door.`,
|
|
614
614
|
`let maxRetries = 3`,
|
|
615
|
-
`let heartbeatInterval = 60`,
|
|
616
615
|
`let targetName = Some("` + n.slice + `")`,
|
|
617
616
|
``,
|
|
618
617
|
`// This plugin's own DCB event log.`,
|
|
@@ -660,13 +659,20 @@ function sendTranslation(c) {
|
|
|
660
659
|
` item.address`,
|
|
661
660
|
` ->Reventless.Phone.fromString`,
|
|
662
661
|
` ->Result.map(phone => Reventless.Messaging.ToSms(phone))`,
|
|
663
|
-
`
|
|
662
|
+
` // The directory stores a channel beside one flat address, and no push address is`,
|
|
663
|
+
` // one string: two services issue a token, Web Push issues an endpoint with its`,
|
|
664
|
+
` // encryption keys, and which service issued this one is not recorded either. So`,
|
|
665
|
+
` // the pair cannot be re-fused, and refusing says so once rather than guessing a`,
|
|
666
|
+
` // service and failing at whichever provider. A push transport arrives with the`,
|
|
667
|
+
` // stored shape it needs, in the commit that justifies the columns.`,
|
|
668
|
+
` | Push =>`,
|
|
669
|
+
` Error("a push address names its issuing service, and the directory stores one flat address")`,
|
|
664
670
|
` }`,
|
|
665
671
|
``,
|
|
666
672
|
`let translate = async (_id, item: outboundItem, ~capabilities: Reventless.Capabilities.t) =>`,
|
|
667
673
|
` switch recipientFor(item) {`,
|
|
668
|
-
` // An address the directory holds that its own channel
|
|
669
|
-
` //
|
|
674
|
+
` // An address the directory holds that its own channel cannot use. Not retryable`,
|
|
675
|
+
` // and not the provider's fault — the row that holds it needs fixing.`,
|
|
670
676
|
` | Error(why) =>`,
|
|
671
677
|
` Ok(`,
|
|
672
678
|
` Some((`,
|
|
@@ -747,7 +753,7 @@ function conformanceBinding(c) {
|
|
|
747
753
|
` let optional: category = ` + optional,
|
|
748
754
|
``,
|
|
749
755
|
` module Spec = ` + n.slice,
|
|
750
|
-
` module
|
|
756
|
+
` module Decision = ` + n.slice + `_Decision`,
|
|
751
757
|
``,
|
|
752
758
|
` let ` + id + ` = "` + c.noun.toLowerCase() + `-1"`,
|
|
753
759
|
``,
|
|
@@ -761,9 +767,9 @@ function conformanceBinding(c) {
|
|
|
761
767
|
` let announced = (` + c.contactField + `): Spec.consumedEvent =>`,
|
|
762
768
|
` ` + n.announced + `({` + id + `: ` + id + `, ` + c.contactField + `: ` + c.contactField + `})`,
|
|
763
769
|
` let subscribed = (category, channel): Spec.consumedEvent =>`,
|
|
764
|
-
` ` + n.subscribed + `({` + id + `: ` + id + `, category, channel:
|
|
770
|
+
` ` + n.subscribed + `({` + id + `: ` + id + `, category, channel: Decision.channelOf(channel)})`,
|
|
765
771
|
` let unsubscribed = (category, channel): Spec.consumedEvent =>`,
|
|
766
|
-
` ` + n.unsubscribed + `({` + id + `: ` + id + `, category, channel:
|
|
772
|
+
` ` + n.unsubscribed + `({` + id + `: ` + id + `, category, channel: Decision.channelOf(channel)})`,
|
|
767
773
|
` // Written by ` + n.claims + ` and read here across partitions — this slice`,
|
|
768
774
|
` // consumes them and produces neither.`,
|
|
769
775
|
` let claimed = (source, by): Spec.consumedEvent =>`,
|
|
@@ -774,9 +780,9 @@ function conformanceBinding(c) {
|
|
|
774
780
|
` let announce = ` + c.contactField + ` =>`,
|
|
775
781
|
` Spec.` + n.announceCmd + `({` + id + `: ` + id + `, ` + c.contactField + `: ` + c.contactField + `})`,
|
|
776
782
|
` let subscribe = (category, channel) =>`,
|
|
777
|
-
` Spec.` + n.subscribeCmd + `({` + id + `: ` + id + `, category, channel:
|
|
783
|
+
` Spec.` + n.subscribeCmd + `({` + id + `: ` + id + `, category, channel: Decision.channelOf(channel)})`,
|
|
778
784
|
` let unsubscribe = (category, channel) =>`,
|
|
779
|
-
` Spec.` + n.unsubscribeCmd + `({` + id + `: ` + id + `, category, channel:
|
|
785
|
+
` Spec.` + n.unsubscribeCmd + `({` + id + `: ` + id + `, category, channel: Decision.channelOf(channel)})`,
|
|
780
786
|
` // The wording and the subject are this host's and the trait carries neither, so`,
|
|
781
787
|
` // the suite supplies whatever it likes and asserts nothing about them.`,
|
|
782
788
|
` //`,
|
|
@@ -806,15 +812,15 @@ function conformanceBinding(c) {
|
|
|
806
812
|
` let announced = ` + c.contactField + ` =>`,
|
|
807
813
|
` Spec.` + n.announced + `({` + id + `: ` + id + `, ` + c.contactField + `: ` + c.contactField + `})`,
|
|
808
814
|
` let subscribed = (category, channel) =>`,
|
|
809
|
-
` Spec.` + n.subscribed + `({` + id + `: ` + id + `, category, channel:
|
|
815
|
+
` Spec.` + n.subscribed + `({` + id + `: ` + id + `, category, channel: Decision.channelOf(channel)})`,
|
|
810
816
|
` let unsubscribed = (category, channel) =>`,
|
|
811
|
-
` Spec.` + n.unsubscribed + `({` + id + `: ` + id + `, category, channel:
|
|
817
|
+
` Spec.` + n.unsubscribed + `({` + id + `: ` + id + `, category, channel: Decision.channelOf(channel)})`,
|
|
812
818
|
` let requestedWith = (category, reference, channel, address, origin) =>`,
|
|
813
819
|
` Spec.` + n.requested + `({`,
|
|
814
820
|
` ` + id + `: ` + id + `,`,
|
|
815
821
|
` category,`,
|
|
816
822
|
` reference,`,
|
|
817
|
-
` channel:
|
|
823
|
+
` channel: Decision.channelOf(channel),`,
|
|
818
824
|
` address,`,
|
|
819
825
|
` subjectType: "` + subjectTypeOf(c) + `",`,
|
|
820
826
|
` subjectRef: "subject-1",`,
|
|
@@ -879,7 +885,7 @@ function contactRelayPatch(c) {
|
|
|
879
885
|
let n = namesOf(c);
|
|
880
886
|
let id = n.recipientId;
|
|
881
887
|
return {
|
|
882
|
-
into: c.chapter + `/
|
|
888
|
+
into: c.chapter + `/OutboundTranslation/` + n.relay + `.res (new, plus its _Translation)`,
|
|
883
889
|
at: `a new file — the trait cannot write what this host's events mean`,
|
|
884
890
|
contents: [
|
|
885
891
|
[
|
|
@@ -910,7 +916,6 @@ function contactRelayPatch(c) {
|
|
|
910
916
|
` | ` + n.announceCmd + `({` + id + `: string, ` + c.contactField + `: string})`,
|
|
911
917
|
``,
|
|
912
918
|
`let maxRetries = 3`,
|
|
913
|
-
`let heartbeatInterval = 60`,
|
|
914
919
|
`let targetName = Some("` + n.slice + `")`,
|
|
915
920
|
`let sourceNames = ["` + c.contactSource + `"]`,
|
|
916
921
|
`// No external box: this slice reaches nothing outside the plugin.`,
|
|
@@ -952,7 +957,7 @@ function intakeRelayPatch(c) {
|
|
|
952
957
|
let n = namesOf(c);
|
|
953
958
|
let id = n.recipientId;
|
|
954
959
|
return {
|
|
955
|
-
into: c.chapter + `/
|
|
960
|
+
into: c.chapter + `/Automation/` + n.intake + `.res (new, plus its _Automation)`,
|
|
956
961
|
at: `a new file — the wording is this host's sentence, not the trait's`,
|
|
957
962
|
contents: [
|
|
958
963
|
`// Turns one of this host's occurrences into a request to notify somebody.`,
|
|
@@ -983,7 +988,6 @@ function intakeRelayPatch(c) {
|
|
|
983
988
|
` })`,
|
|
984
989
|
``,
|
|
985
990
|
`let maxRetries = 3`,
|
|
986
|
-
`let heartbeatInterval = 60`,
|
|
987
991
|
`let targetName = "` + n.slice + `"`,
|
|
988
992
|
``,
|
|
989
993
|
`// ── ` + n.intake + `_Automation.res ──`,
|
|
@@ -1097,7 +1101,7 @@ function intakeRelayPatch(c) {
|
|
|
1097
1101
|
` ` + id + `,`,
|
|
1098
1102
|
` ` + n.intake + `.` + n.requestCmd + `({`,
|
|
1099
1103
|
` ` + id + `: ` + id + `,`,
|
|
1100
|
-
` category: ` + n.slice + `
|
|
1104
|
+
` category: ` + n.slice + `_Decision.categoryOf(rule.category),`,
|
|
1101
1105
|
` reference: id,`,
|
|
1102
1106
|
` subjectType: rule.subjectType,`,
|
|
1103
1107
|
` subjectRef: Rule.subjectOf(rule, ~payload),`,
|
|
@@ -1128,27 +1132,27 @@ function emit(config, into, tests) {
|
|
|
1128
1132
|
return {
|
|
1129
1133
|
files: [
|
|
1130
1134
|
{
|
|
1131
|
-
path: into + `/
|
|
1135
|
+
path: into + `/StateChange/` + n.slice + `.res`,
|
|
1132
1136
|
contents: sliceSpec(config)
|
|
1133
1137
|
},
|
|
1134
1138
|
{
|
|
1135
|
-
path: into + `/
|
|
1136
|
-
contents:
|
|
1139
|
+
path: into + `/StateChange/` + n.slice + `_Decision.res`,
|
|
1140
|
+
contents: sliceDecision(config)
|
|
1137
1141
|
},
|
|
1138
1142
|
{
|
|
1139
|
-
path: into + `/
|
|
1143
|
+
path: into + `/StateChange/` + n.claims + `.res`,
|
|
1140
1144
|
contents: claimsSpec(config)
|
|
1141
1145
|
},
|
|
1142
1146
|
{
|
|
1143
|
-
path: into + `/
|
|
1144
|
-
contents:
|
|
1147
|
+
path: into + `/StateChange/` + n.claims + `_Decision.res`,
|
|
1148
|
+
contents: claimsDecision(config)
|
|
1145
1149
|
},
|
|
1146
1150
|
{
|
|
1147
|
-
path: into + `/
|
|
1151
|
+
path: into + `/OutboundTranslation/` + n.send + `.res`,
|
|
1148
1152
|
contents: sendSpec(config)
|
|
1149
1153
|
},
|
|
1150
1154
|
{
|
|
1151
|
-
path: into + `/
|
|
1155
|
+
path: into + `/OutboundTranslation/` + n.send + `_Translation.res`,
|
|
1152
1156
|
contents: sendTranslation(config)
|
|
1153
1157
|
},
|
|
1154
1158
|
{
|
|
@@ -1174,9 +1178,9 @@ export {
|
|
|
1174
1178
|
categoryArms,
|
|
1175
1179
|
sliceSpec,
|
|
1176
1180
|
postureArms,
|
|
1177
|
-
|
|
1181
|
+
sliceDecision,
|
|
1178
1182
|
claimsSpec,
|
|
1179
|
-
|
|
1183
|
+
claimsDecision,
|
|
1180
1184
|
sendSpec,
|
|
1181
1185
|
sendTranslation,
|
|
1182
1186
|
conformanceBinding,
|