diff --git a/go/seats/meshbroker/contract.go b/go/seats/meshbroker/contract.go index 5313b13..fa7fad7 100644 --- a/go/seats/meshbroker/contract.go +++ b/go/seats/meshbroker/contract.go @@ -3,18 +3,22 @@ // Package meshbroker is the contract of the seat "mesh-broker", defined whole (seats/mesh-broker/seat.json): The mesh's bus, and the bus state modules ask of it in requires (design 25 § 12). create, apply, recreate and drop are granted to the bus module's own credential alone. package meshbroker +import "time" + // Seat is the seat's name. const Seat = "mesh-broker" const ( - VerbList = "list" - VerbShow = "show" - VerbCheck = "check" - VerbOrphans = "orphans" - VerbCreate = "create" - VerbApply = "apply" - VerbRecreate = "recreate" - VerbDrop = "drop" + VerbList = "list" + VerbShow = "show" + VerbCheck = "check" + VerbOrphans = "orphans" + VerbCreate = "create" + VerbApply = "apply" + VerbRecreate = "recreate" + VerbDrop = "drop" + VerbSnapshotKept = "snapshot-kept" + VerbRestoreKept = "restore-kept" ) const ( @@ -31,7 +35,7 @@ const ( // Verbs is every verb the seat serves, in its definition's order: a new copy each call. func Verbs() []string { - return []string{VerbList, VerbShow, VerbCheck, VerbOrphans, VerbCreate, VerbApply, VerbRecreate, VerbDrop} + return []string{VerbList, VerbShow, VerbCheck, VerbOrphans, VerbCreate, VerbApply, VerbRecreate, VerbDrop, VerbSnapshotKept, VerbRestoreKept} } // Events is every event published on the seat's subject: a new copy each call. @@ -72,10 +76,30 @@ const SubjectRecreated = "mesh.seat.mesh-broker.event.recreated" // SubjectDropped is where dropped is published. const SubjectDropped = "mesh.seat.mesh-broker.event.dropped" +// Aside is live kept data a restore set aside, never removed but by discard-aside. +type Aside struct { + // when it was set aside + At *time.Time `json:"at,omitempty"` + // the form it held + Form int64 `json:"form,omitempty"` + // its id, for discard-aside + ID string `json:"id"` + // the kept data + Kept string `json:"kept"` + // the module + Module string `json:"module"` + // the name it is kept under on the bus + Name string `json:"name"` + // its size in bytes + Size int64 `json:"size,omitempty"` +} + // Binding is the binding a module receives in its membership for one entry (ADR 0595 §1, §7). type Binding struct { // the entry's name on the bus BusName string `json:"bus-name"` + // the bus name of the state's -objects, where its large values go (design 47 G 58, 399) + Objects string `json:"objects,omitempty"` // how the bus keeps it StorageType string `json:"storage-type"` // its subjects, for a stream @@ -183,6 +207,44 @@ const ( HeldTemplate = "" ) +// KeptPointCatchUp is the catch-up tool and its arguments the restore point records (design 47 G 406). +type KeptPointCatchUp struct { + Arguments map[string]any `json:"arguments,omitempty"` + Tool string `json:"tool"` +} + +// KeptPointConsumersItem is a type of the contract. +type KeptPointConsumersItem struct { + // the durable consumer + Consumer string `json:"consumer"` + // its acknowledged position + Sequence int64 `json:"sequence"` + // the stream + Stream string `json:"stream"` +} + +// KeptPoint is a restore point of one module's kept data on the bus, whole, with its consumers' positions. +type KeptPoint struct { + // when it was taken + At *time.Time `json:"at,omitempty"` + // the catch-up tool and its arguments the restore point records (design 47 G 406) + CatchUp *KeptPointCatchUp `json:"catch-up,omitempty"` + // each durable consumer the module reads with, and its position + Consumers []KeptPointConsumersItem `json:"consumers,omitempty"` + // the fingerprint the restore point is taken before + Fingerprint string `json:"fingerprint"` + // its form, the number the holder raises when it changes how it writes it (0 when undeclared) + Form int64 `json:"form"` + // the kept data, its local name in the module's manifest + Kept string `json:"kept"` + // the module + Module string `json:"module"` + // its size in bytes + Size int64 `json:"size,omitempty"` + // the restore point's name + Snapshot string `json:"snapshot"` +} + // Named is a type of the contract. type Named struct { // the entry's local name @@ -335,6 +397,64 @@ type DropAnswer struct { Snapshot string `json:"snapshot,omitempty"` } +// SnapshotKeptInputCatchUp is the catch-up tool the newer manifest declares beside the kept data and its arguments whole, recorded in the restore point (design 47 G 299, 406). +type SnapshotKeptInputCatchUp struct { + Arguments map[string]any `json:"arguments,omitempty"` + Tool string `json:"tool"` +} + +// SnapshotKeptInput is what snapshot-kept takes. +type SnapshotKeptInput struct { + // the catch-up tool the newer manifest declares beside the kept data and its arguments whole, recorded in the restore point (design 47 G 299, 406) + CatchUp *SnapshotKeptInputCatchUp `json:"catch-up,omitempty"` + // the fingerprint the restore point is taken before + Fingerprint string `json:"fingerprint"` + // its form, the number the holder raises when it changes how it writes it (0 when undeclared) + Form int64 `json:"form"` + // the kept data, its local name in the module's manifest + Kept string `json:"kept"` + // the module + Module string `json:"module"` + // why it is taken + Why string `json:"why,omitempty"` +} + +// SnapshotKeptAnswer is what snapshot-kept answers. +type SnapshotKeptAnswer struct { + // why it failed; set alone + Error string `json:"error,omitempty"` + Point *KeptPoint `json:"point,omitempty"` +} + +// RestoreKeptInput is what restore-kept takes. +type RestoreKeptInput struct { + // set the live data aside and restore nothing + AsideOnly bool `json:"aside-only,omitempty"` + // the name of data set aside: remove it and restore nothing + DiscardAside string `json:"discard-aside,omitempty"` + // the fingerprint the restore point is taken before + Fingerprint string `json:"fingerprint"` + // its form, the number the holder raises when it changes how it writes it (0 when undeclared) + Form int64 `json:"form"` + // the kept data, its local name in the module's manifest + Kept string `json:"kept"` + // the module + Module string `json:"module"` + // the restore point's name; not with aside-only or discard-aside + Snapshot string `json:"snapshot,omitempty"` + // why + Why string `json:"why,omitempty"` +} + +// RestoreKeptAnswer is what restore-kept answers. +type RestoreKeptAnswer struct { + Aside *Aside `json:"aside,omitempty"` + // why it failed; set alone + Error string `json:"error,omitempty"` + // the restore point is the live data now + Restored bool `json:"restored,omitempty"` +} + // CreatedEvent is the body of the event created. type CreatedEvent = Said diff --git a/go/seats/meshbroker/contract_test.go b/go/seats/meshbroker/contract_test.go index 03c1f9c..84b09e9 100644 --- a/go/seats/meshbroker/contract_test.go +++ b/go/seats/meshbroker/contract_test.go @@ -41,6 +41,12 @@ func TestFixtures(t *testing.T) { decode: func(b []byte) (any, error) { var v DropInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, {name: "list answers every entry", subject: "", given: "{\"entries\":[{\"bus-name\":\"mesh-knowledge_ledger\",\"fill\":{\"bytes\":2048,\"cap\":67108864,\"count\":10},\"local-name\":\"ledger\",\"module\":\"mesh-knowledge\",\"options\":{\"max-mib\":64},\"settings\":{\"max-mib\":64},\"storage-type\":\"ledger\",\"template\":\"ledger\"}]}", wire: "{\"entries\":[{\"bus-name\":\"mesh-knowledge_ledger\",\"fill\":{\"bytes\":2048,\"cap\":67108864,\"count\":10},\"local-name\":\"ledger\",\"module\":\"mesh-knowledge\",\"options\":{\"max-mib\":64},\"settings\":{\"max-mib\":64},\"storage-type\":\"ledger\",\"template\":\"ledger\"}]}", decode: func(b []byte) (any, error) { var v ListAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "snapshot-kept answers the restore point", subject: "", given: "{\"point\":{\"at\":\"2026-11-09T20:00:00Z\",\"consumers\":[{\"consumer\":\"novox_mesh-delivery-indexer\",\"sequence\":4711,\"stream\":\"forge\"}],\"fingerprint\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"form\":1,\"kept\":\"catalog-revisions\",\"module\":\"mesh-delivery-indexer\",\"size\":1048576,\"snapshot\":\"kept-mesh-delivery-indexer-catalog-revisions-1-aaaa\"}}", wire: "{\"point\":{\"at\":\"2026-11-09T20:00:00Z\",\"consumers\":[{\"consumer\":\"novox_mesh-delivery-indexer\",\"sequence\":4711,\"stream\":\"forge\"}],\"fingerprint\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"form\":1,\"kept\":\"catalog-revisions\",\"module\":\"mesh-delivery-indexer\",\"size\":1048576,\"snapshot\":\"kept-mesh-delivery-indexer-catalog-revisions-1-aaaa\"}}", + decode: func(b []byte) (any, error) { var v SnapshotKeptAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "snapshot-kept answers an error", subject: "", given: "{\"error\":\"the object store catalog-revisions is not on the bus\"}", wire: "{\"error\":\"the object store catalog-revisions is not on the bus\"}", + decode: func(b []byte) (any, error) { var v SnapshotKeptAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "restore-kept answers what it set aside", subject: "", given: "{\"aside\":{\"at\":\"2026-11-09T21:00:00Z\",\"form\":2,\"id\":\"aside-1\",\"kept\":\"catalog-revisions\",\"module\":\"mesh-delivery-indexer\",\"name\":\"catalog-revisions-aside-20261109\",\"size\":2097152},\"restored\":true}", wire: "{\"aside\":{\"at\":\"2026-11-09T21:00:00Z\",\"form\":2,\"id\":\"aside-1\",\"kept\":\"catalog-revisions\",\"module\":\"mesh-delivery-indexer\",\"name\":\"catalog-revisions-aside-20261109\",\"size\":2097152},\"restored\":true}", + decode: func(b []byte) (any, error) { var v RestoreKeptAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, } for _, c := range cases { v, err := c.decode([]byte(c.given)) diff --git a/go/seats/meshmoduleassigner/contract.go b/go/seats/meshmoduleassigner/contract.go index e4ca190..2451180 100644 --- a/go/seats/meshmoduleassigner/contract.go +++ b/go/seats/meshmoduleassigner/contract.go @@ -423,9 +423,13 @@ type NodeDecided struct { // PlacedModule is one module placed on a node. type PlacedModule struct { // by provision, the provider each requirement that keeps data is bound to - Bindings map[string]Provider `json:"bindings,omitempty"` - HasLayer bool `json:"has-layer,omitempty"` - HasMeshWide bool `json:"has-mesh-wide,omitempty"` + Bindings map[string]Provider `json:"bindings,omitempty"` + // the watched branch this node runs the module from; absent, the first watched branch of the module's registration (design 47 G 14) + Branch string `json:"branch,omitempty"` + // the fingerprint of the build the node runs; absent, the newest delivered of the branch (design 47 G 78, 402) + Build string `json:"build,omitempty"` + HasLayer bool `json:"has-layer,omitempty"` + HasMeshWide bool `json:"has-mesh-wide,omitempty"` // this node's settings layer of the module's assignments Layer map[string]any `json:"layer,omitempty"` // the whole mesh's settings layer of the module's assignments @@ -475,9 +479,13 @@ type ProposalChangeKeys struct { // ProposalChange is one change of a proposal. type ProposalChange struct { Bindings map[string]Provider `json:"bindings,omitempty"` - Claim string `json:"claim,omitempty"` - Decided *NodeDecided `json:"decided,omitempty"` - Field string `json:"field,omitempty"` + // for place, the watched branch the node runs the module from; absent, the first watched branch of the module's registration (design 47 G 14) + Branch string `json:"branch,omitempty"` + // for place, the build of that branch the node runs, a return to an earlier build being this one value; absent, the newest delivered of the branch (ADR 0666 section 24) + Build string `json:"build,omitempty"` + Claim string `json:"claim,omitempty"` + Decided *NodeDecided `json:"decided,omitempty"` + Field string `json:"field,omitempty"` // the public halves of a joining node's keys Keys *ProposalChangeKeys `json:"keys,omitempty"` Kind string `json:"kind,omitempty"` diff --git a/go/seats/meshmoduleassigner/contract_test.go b/go/seats/meshmoduleassigner/contract_test.go index 29ddac3..b5f4fa0 100644 --- a/go/seats/meshmoduleassigner/contract_test.go +++ b/go/seats/meshmoduleassigner/contract_test.go @@ -41,12 +41,24 @@ func TestFixtures(t *testing.T) { err := json.Unmarshal(b, &v) return v, err }, subjectIs: nil}, + {name: "a module's key on a watched branch and a build", subject: "", given: "{\"node\":\"ace\",\"placed\":{\"branch\":\"beta\",\"build\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"plex\"},\"v\":1}", wire: "{\"node\":\"ace\",\"placed\":{\"branch\":\"beta\",\"build\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"plex\"},\"v\":1}", + decode: func(b []byte) (any, error) { + var v AssignmentsByNodeModuleValue + err := json.Unmarshal(b, &v) + return v, err + }, subjectIs: nil}, {name: "an open proposal", subject: "", given: "{\"at\":\"2026-11-05T12:00:00Z\",\"base\":{\"ace\":3},\"by\":\"operator\",\"changes\":[{\"module\":\"plex\",\"node\":\"ace\",\"op\":\"place\",\"ports\":{\"32400\":32400}}],\"id\":\"p-20261105t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"move plex\"}", wire: "{\"at\":\"2026-11-05T12:00:00Z\",\"base\":{\"ace\":3},\"by\":\"operator\",\"changes\":[{\"module\":\"plex\",\"node\":\"ace\",\"op\":\"place\",\"ports\":{\"32400\":32400}}],\"id\":\"p-20261105t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"move plex\"}", decode: func(b []byte) (any, error) { var v ProposalsByProposalValue err := json.Unmarshal(b, &v) return v, err }, subjectIs: nil}, + {name: "a proposal placing a module on a watched branch at an earlier build", subject: "", given: "{\"at\":\"2026-11-10T12:00:00Z\",\"base\":{\"ace\":3},\"by\":\"operator\",\"changes\":[{\"branch\":\"beta\",\"build\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"nats\",\"node\":\"ace\",\"op\":\"place\"}],\"id\":\"p-20261110t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"run nats from beta, back one build\"}", wire: "{\"at\":\"2026-11-10T12:00:00Z\",\"base\":{\"ace\":3},\"by\":\"operator\",\"changes\":[{\"branch\":\"beta\",\"build\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"nats\",\"node\":\"ace\",\"op\":\"place\"}],\"id\":\"p-20261110t120000-aabbccdd\",\"state\":\"answering\",\"why\":\"run nats from beta, back one build\"}", + decode: func(b []byte) (any, error) { + var v ProposalsByProposalValue + err := json.Unmarshal(b, &v) + return v, err + }, subjectIs: nil}, {name: "a candidate", subject: "", given: "{\"proposal\":\"p-20261105t120000-aabbccdd\",\"v\":1}", wire: "{\"proposal\":\"p-20261105t120000-aabbccdd\",\"v\":1}", decode: func(b []byte) (any, error) { var v CandidatesByProposalNodeValue diff --git a/go/seats/nodeengine/contract.go b/go/seats/nodeengine/contract.go index 26dc404..081ecee 100644 --- a/go/seats/nodeengine/contract.go +++ b/go/seats/nodeengine/contract.go @@ -1,6 +1,6 @@ // Code generated by seatgen from the seat definitions; DO NOT EDIT. -// Package nodeengine is the contract of the seat "node-engine", defined whole (seats/node-engine/seat.json): The node seat every node's engine holds (novox/hq ADR 0563, ADR 0618 §3, §4): its hand acts on the operator's warrant, its read-only judgements, its compositions and what it reads of a manifest. Each verb is answered on this node's subject, mesh.seat.node-engine.tool.., and each event is published on mesh.seat.node-engine.event.., the node's name its last token. +// Package nodeengine is the contract of the seat "node-engine", defined whole (seats/node-engine/seat.json): The node seat every node's engine holds (novox/hq ADR 0563, ADR 0618 §3, §4): its hand acts on the operator's warrant, its read-only judgements, its compositions and what it reads of a manifest. Each verb is answered on this node's subject, mesh.seat.node-engine.tool.., and each event is published on mesh.seat.node-engine.event.., the node's name its last token, or, for an event whose subject names , there (composed., running..): the grants part grants a node's account only its own node's subjects (ADR 0363 §2). package nodeengine import ( @@ -28,6 +28,7 @@ const ( VerbManifestReads = "manifest-reads" VerbSeatList = "seat-list" VerbSeatListAgain = "seat-list-again" + VerbProcessBuilds = "process-builds" ) const ( @@ -35,16 +36,19 @@ const ( EventDone = "done" EventRefused = "refused" EventManifestReadsChanged = "manifest-reads-changed" + EventComposed = "composed" + EventRunning = "running" + EventCapabilitiesChanged = "capabilities-changed" ) // Verbs is every verb the seat serves, in its definition's order: a new copy each call. func Verbs() []string { - return []string{VerbHandOver, VerbAccessAct, VerbJudgeDirectories, VerbSetuidSearch, VerbRootFree, VerbActs, VerbPackages, VerbComposition, VerbCompose, VerbComposeCandidate, VerbManifestReads, VerbSeatList, VerbSeatListAgain} + return []string{VerbHandOver, VerbAccessAct, VerbJudgeDirectories, VerbSetuidSearch, VerbRootFree, VerbActs, VerbPackages, VerbComposition, VerbCompose, VerbComposeCandidate, VerbManifestReads, VerbSeatList, VerbSeatListAgain, VerbProcessBuilds} } // Events is every event published on the seat's subject: a new copy each call. func Events() []string { - return []string{EventAsked, EventDone, EventRefused, EventManifestReadsChanged} + return []string{EventAsked, EventDone, EventRefused, EventManifestReadsChanged, EventComposed, EventRunning, EventCapabilitiesChanged} } // Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects. @@ -67,6 +71,31 @@ func SubjectManifestReadsChanged(caller string) string { return "mesh.seat.node-engine.event.manifest-reads-changed." + caller } +// SubjectComposed is where composed is published, on mesh.seat.node-engine.event.composed.. +func SubjectComposed(node string) string { return "mesh.seat.node-engine.event.composed." + node } + +// SubjectComposedAll hears every composed. +const SubjectComposedAll = "mesh.seat.node-engine.event.composed.*" + +// StreamRunning is the stream running is kept in. +const StreamRunning = "SEAT_node-engine_running" + +// SubjectRunning is where running is published, on mesh.seat.node-engine.event.running... +func SubjectRunning(node, module string) string { + return "mesh.seat.node-engine.event.running." + node + "." + module +} + +// SubjectRunningAll hears every running. +const SubjectRunningAll = "mesh.seat.node-engine.event.running.*.*" + +// SubjectCapabilitiesChanged is where capabilities-changed is published, on mesh.seat.node-engine.event.capabilities-changed.. +func SubjectCapabilitiesChanged(node string) string { + return "mesh.seat.node-engine.event.capabilities-changed." + node +} + +// SubjectCapabilitiesChangedAll hears every capabilities-changed. +const SubjectCapabilitiesChangedAll = "mesh.seat.node-engine.event.capabilities-changed.*" + const ( StateHave = "have" StateComposed = "composed" @@ -523,6 +552,34 @@ type CandidateRefusal struct { Why string `json:"why"` } +// CapabilitiesChanged is a node's capabilities changed, which the assigner places by. +type CapabilitiesChanged struct { + // when, RFC 3339 + At time.Time `json:"at"` + // its capabilities now + Capabilities []string `json:"capabilities"` + // the node + Node string `json:"node"` + // the layout's version + V int64 `json:"v"` +} + +// Composed is an entry composed on a node (design 47 *What each step says*). +type Composed struct { + // when, RFC 3339 + At time.Time `json:"at"` + // the digest of the composition (design 47 G 404) + Digest string `json:"digest"` + // the fingerprint of the want composed + Fingerprint string `json:"fingerprint"` + // the module + Module string `json:"module"` + // the node + Node string `json:"node"` + // the layout's version + V int64 `json:"v"` +} + // DeclaredGroup is a group. type DeclaredGroup struct { Gid int64 `json:"gid"` @@ -742,6 +799,38 @@ type PlacedDataItem struct { Protection string `json:"protection,omitempty"` } +// ProcessBuild is the build one process of a module was started with. +type ProcessBuild struct { + // the fingerprint handed to it in MESH_FINGERPRINT; empty when it was started without one + Fingerprint string `json:"fingerprint,omitempty"` + // service or container + Kind string `json:"kind"` + // the module + Module string `json:"module"` + // the service's unit or the container's name + Process string `json:"process"` + // when it was started, RFC 3339 + Started *time.Time `json:"started,omitempty"` + // why its build is unknown: started before the node-engine handed MESH_FINGERPRINT, or the value could not be read + Unknown string `json:"unknown,omitempty"` +} + +// The values of ProcessBuild's kind. +const ( + ProcessBuildKindService = "service" + ProcessBuildKindContainer = "container" +) + +// ProcessBuilds is what process-builds answers. +type ProcessBuilds struct { + // why they could not be read + Error string `json:"error,omitempty"` + // the node + Node string `json:"node"` + // every process the node-engine started, by module + Processes []ProcessBuild `json:"processes"` +} + // PullWait is the pull from a store a failed apply waits on. type PullWait struct { // when the pull began @@ -796,6 +885,24 @@ type RootVerdict struct { Why string `json:"why"` } +// Running is a module running healthy on a node at a build: what the node-engines of other nodes and the grants part decide a seat's pass from (ADR 0660 §2), kept last per subject with no age limit. +type Running struct { + // when it was seen running healthy, RFC 3339 + At time.Time `json:"at"` + // the fingerprint of the build it runs; none with stopped + Fingerprint string `json:"fingerprint,omitempty"` + // the digest of that build's manifest, the indexer's manifest of it, read by digest from the catalog half + Manifest string `json:"manifest,omitempty"` + // the module + Module string `json:"module"` + // the node + Node string `json:"node"` + // true when the module no longer runs on the node: no fingerprint or manifest then (design 47 G 365, 404); mesh-sdk's SeatsToPassOn counts such a module as not running there + Stopped bool `json:"stopped,omitempty"` + // the layout's version + V int64 `json:"v"` +} + // Said is the answer of a read-only judgement. type Said struct { // the node @@ -1217,6 +1324,15 @@ type SeatListAgainInput struct { // SeatListAgainAnswer is what seat-list-again answers. type SeatListAgainAnswer = SeatList +// ProcessBuildsInput is what process-builds takes. +type ProcessBuildsInput struct { + // only this module's processes + Module string `json:"module,omitempty"` +} + +// ProcessBuildsAnswer is what process-builds answers. +type ProcessBuildsAnswer = ProcessBuilds + // AskedEvent is the body of the event asked. type AskedEvent = ActSaid @@ -1229,6 +1345,15 @@ type RefusedEvent = ActSaid // ManifestReadsChangedEvent is the body of the event manifest-reads-changed. type ManifestReadsChangedEvent = ManifestReadsChanged +// ComposedEvent is the body of the event composed. +type ComposedEvent = Composed + +// RunningEvent is the body of the event running. +type RunningEvent = Running + +// CapabilitiesChangedEvent is the body of the event capabilities-changed. +type CapabilitiesChangedEvent = CapabilitiesChanged + // HaveByNodeModuleValue is one value of the state have under the key .. type HaveByNodeModuleValue struct { Build string `json:"build,omitempty"` diff --git a/go/seats/nodeengine/contract_test.go b/go/seats/nodeengine/contract_test.go index 5ca811b..e2ed2d8 100644 --- a/go/seats/nodeengine/contract_test.go +++ b/go/seats/nodeengine/contract_test.go @@ -35,6 +35,18 @@ func TestFixtures(t *testing.T) { err := json.Unmarshal(b, &v) return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.manifest-reads-changed\\.[A-Za-z0-9_-]+$")}, + {name: "composed is said", subject: "mesh.seat.node-engine.event.composed.ace", given: "{\"at\":\"2026-11-09T20:00:00Z\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"fingerprint\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"nats\",\"node\":\"ace\",\"v\":1}", wire: "{\"at\":\"2026-11-09T20:00:00Z\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"fingerprint\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"module\":\"nats\",\"node\":\"ace\",\"v\":1}", + decode: func(b []byte) (any, error) { var v ComposedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.composed\\.[^.*> ]+$")}, + {name: "running is said, its node and module in its subject", subject: "mesh.seat.node-engine.event.running.ace.nats", given: "{\"at\":\"2026-11-09T20:01:00Z\",\"fingerprint\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"manifest\":\"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"module\":\"nats\",\"node\":\"ace\",\"v\":1}", wire: "{\"at\":\"2026-11-09T20:01:00Z\",\"fingerprint\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"manifest\":\"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"module\":\"nats\",\"node\":\"ace\",\"v\":1}", + decode: func(b []byte) (any, error) { var v RunningEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.running\\.[^.*> ]+\\.[^.*> ]+$")}, + {name: "running says a module stopped on the node, with no fingerprint", subject: "mesh.seat.node-engine.event.running.ace.nats", given: "{\"at\":\"2026-11-11T09:00:00Z\",\"module\":\"nats\",\"node\":\"ace\",\"stopped\":true,\"v\":1}", wire: "{\"at\":\"2026-11-11T09:00:00Z\",\"module\":\"nats\",\"node\":\"ace\",\"stopped\":true,\"v\":1}", + decode: func(b []byte) (any, error) { var v RunningEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.running\\.[^.*> ]+\\.[^.*> ]+$")}, + {name: "capabilities-changed is said", subject: "mesh.seat.node-engine.event.capabilities-changed.ace", given: "{\"at\":\"2026-11-09T20:02:00Z\",\"capabilities\":[\"build-go\",\"docker\"],\"node\":\"ace\",\"v\":1}", wire: "{\"at\":\"2026-11-09T20:02:00Z\",\"capabilities\":[\"build-go\",\"docker\"],\"node\":\"ace\",\"v\":1}", + decode: func(b []byte) (any, error) { + var v CapabilitiesChangedEvent + err := json.Unmarshal(b, &v) + return v, err + }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.capabilities-changed\\.[^.*> ]+$")}, {name: "the finding of a seat list unread, as the engine writes it", subject: "", given: "{\"at\":\"2026-11-05T14:00:00Z\",\"key\":\"machine.ace.seat-list-unread\",\"kind\":\"seat-list-unread\",\"observer\":\"mesh-host\",\"severity\":\"warning\",\"source\":\"node-engine.seat-list\",\"subject\":{\"id\":\"ace\",\"machine\":\"ace\",\"scope\":\"machine\"},\"summary\":\"the seat list has not been read for five minutes\",\"v\":1}", wire: "{\"at\":\"2026-11-05T14:00:00Z\",\"key\":\"machine.ace.seat-list-unread\",\"kind\":\"seat-list-unread\",\"observer\":\"mesh-host\",\"severity\":\"warning\",\"source\":\"node-engine.seat-list\",\"subject\":{\"id\":\"ace\",\"machine\":\"ace\",\"scope\":\"machine\"},\"summary\":\"the seat list has not been read for five minutes\",\"v\":1}", decode: func(b []byte) (any, error) { var v FindingsByKeyValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, {name: "a node's packages, present and absent (captured from ace, shortened)", subject: "", given: "{\"node\":\"ace\",\"packages\":[{\"absent\":false,\"modules\":[\"avahi\"],\"package\":\"avahi\"},{\"absent\":false,\"modules\":[\"mesh-build-go\",\"mesh-build-node\"],\"package\":\"bubblewrap\"},{\"absent\":true,\"modules\":[\"time-sync\"],\"package\":\"ntp\"}]}", wire: "{\"node\":\"ace\",\"packages\":[{\"absent\":false,\"modules\":[\"avahi\"],\"package\":\"avahi\"},{\"absent\":false,\"modules\":[\"mesh-build-go\",\"mesh-build-node\"],\"package\":\"bubblewrap\"},{\"absent\":true,\"modules\":[\"time-sync\"],\"package\":\"ntp\"}]}", @@ -91,6 +103,12 @@ func TestFixtures(t *testing.T) { decode: func(b []byte) (any, error) { var v SeatListAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, {name: "seat-list-again answers the error when the read failed", subject: "", given: "{\"error\":\"seatlist: no answer\",\"health\":\"the seat list is held from the bootstrap\",\"status\":{\"heard\":false,\"held\":[{\"seat\":\"node-engine\",\"source\":\"bootstrap\"}],\"waiting\":[\"node-engine\"]}}", wire: "{\"error\":\"seatlist: no answer\",\"health\":\"the seat list is held from the bootstrap\",\"status\":{\"heard\":false,\"held\":[{\"seat\":\"node-engine\",\"source\":\"bootstrap\"}],\"waiting\":[\"node-engine\"]}}", decode: func(b []byte) (any, error) { var v SeatListAgainAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "process-builds asks one module", subject: "", given: "{\"module\":\"nats\"}", wire: "{\"module\":\"nats\"}", + decode: func(b []byte) (any, error) { var v ProcessBuildsInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "process-builds answers each process's build", subject: "", given: "{\"node\":\"ace\",\"processes\":[{\"fingerprint\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"kind\":\"service\",\"module\":\"nats\",\"process\":\"nats.service\",\"started\":\"2026-11-09T19:00:00Z\"},{\"kind\":\"container\",\"module\":\"route-proxy\",\"process\":\"route-proxy\",\"started\":\"2026-11-01T08:00:00Z\",\"unknown\":\"started before the node-engine handed MESH_FINGERPRINT\"}]}", wire: "{\"node\":\"ace\",\"processes\":[{\"fingerprint\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"kind\":\"service\",\"module\":\"nats\",\"process\":\"nats.service\",\"started\":\"2026-11-09T19:00:00Z\"},{\"kind\":\"container\",\"module\":\"route-proxy\",\"process\":\"route-proxy\",\"started\":\"2026-11-01T08:00:00Z\",\"unknown\":\"started before the node-engine handed MESH_FINGERPRINT\"}]}", + decode: func(b []byte) (any, error) { var v ProcessBuildsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "process-builds answers an error", subject: "", given: "{\"error\":\"the service manager did not answer\",\"node\":\"ace\",\"processes\":[]}", wire: "{\"error\":\"the service manager did not answer\",\"node\":\"ace\",\"processes\":[]}", + decode: func(b []byte) (any, error) { var v ProcessBuildsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, } for _, c := range cases { v, err := c.decode([]byte(c.given)) diff --git a/health-and-repair/go/seats/meshconditions/contract.go b/health-and-repair/go/seats/meshconditions/contract.go index 0757680..7406782 100644 --- a/health-and-repair/go/seats/meshconditions/contract.go +++ b/health-and-repair/go/seats/meshconditions/contract.go @@ -7,6 +7,7 @@ import ( "bytes" "encoding/json" "errors" + "strings" "time" ) @@ -23,6 +24,7 @@ const ( EventConditionRaised = "condition-raised" EventConditionChanged = "condition-changed" EventConditionCleared = "condition-cleared" + EventFindingsAsked = "findings-asked" ) // Verbs is every verb the seat serves, in its definition's order: a new copy each call. @@ -32,7 +34,7 @@ func Verbs() []string { // Events is every event published on the seat's subject: a new copy each call. func Events() []string { - return []string{EventConditionRaised, EventConditionChanged, EventConditionCleared} + return []string{EventConditionRaised, EventConditionChanged, EventConditionCleared, EventFindingsAsked} } // Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects. @@ -50,9 +52,16 @@ const SubjectConditionChanged = "mesh.seat.mesh-conditions.event.condition-chang // SubjectConditionCleared is where condition-cleared is published. const SubjectConditionCleared = "mesh.seat.mesh-conditions.event.condition-cleared" +// StreamFindingsAsked is the stream findings-asked is kept in. +const StreamFindingsAsked = "SEAT_mesh-conditions_findings-asked" + +// SubjectFindingsAsked is where findings-asked is published. +const SubjectFindingsAsked = "mesh.seat.mesh-conditions.event.findings-asked" + const ( - StateConditions = "conditions" - StateFindings = "findings" + StateConditions = "conditions" + StateFindings = "findings" + StateFindingsViews = "findings-views" ) // ConditionsByKeyKey is the key of one value of the state conditions under the form "". @@ -117,6 +126,42 @@ func DecodeFindingsByKeyValue(raw []byte) (FindingsByKeyValue, error) { return v, nil } +// FindingsViewsByObserverNodeKey is the key of one value of the state findings-views under the form ".". +func FindingsViewsByObserverNodeKey(observer, node string) string { return observer + "." + node } + +// ParseFindingsViewsByObserverNodeKey reads the parts of a key of the form ".", in the order of the form; the last result is false for a key of another form. +func ParseFindingsViewsByObserverNodeKey(key string) (string, string, bool) { + rest := key + v0, after0, found0 := strings.Cut(rest, ".") + if !found0 || v0 == "" { + return "", "", false + } + rest = after0 + if rest == "" { + return "", "", false + } + v2 := rest + rest = "" + if rest != "" { + return "", "", false + } + return v0, v2, true +} + +// DecodeFindingsViewsByObserverNodeValue reads one value of the state findings-views under the form ".", refusing a field FindingsViewsByObserverNodeValue does not know and any text after the value. +func DecodeFindingsViewsByObserverNodeValue(raw []byte) (FindingsViewsByObserverNodeValue, error) { + var v FindingsViewsByObserverNodeValue + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.DisallowUnknownFields() + if err := dec.Decode(&v); err != nil { + return v, err + } + if dec.More() { + return v, errors.New("text after the value") + } + return v, nil +} + // Action is one answer the operator may give from a notification. type Action struct { Arguments map[string]string `json:"arguments,omitempty"` @@ -273,6 +318,8 @@ type SilenceAnswer = map[string]any // ResyncInput is what resync takes. type ResyncInput struct { + // ask this observer alone; none asks all + Module string `json:"module,omitempty"` } // ResyncAnswer is what resync answers. @@ -287,6 +334,17 @@ type ConditionChangedEvent = ConditionEvent // ConditionClearedEvent is the body of the event condition-cleared. type ConditionClearedEvent = ConditionEvent +// FindingsAskedEvent is the body of the event findings-asked. +type FindingsAskedEvent struct { + // the ask's id + Ask string `json:"ask"` + At time.Time `json:"at"` + // who asked: the keeper, or the person or session that called resync + By string `json:"by"` + // to ask one observer; none asks all + Module string `json:"module,omitempty"` +} + // ConditionsByKeyValueGapsItem is a type of the contract. type ConditionsByKeyValueGapsItem struct { Cleared *time.Time `json:"cleared,omitempty"` @@ -361,6 +419,8 @@ type FindingsByKeyValue struct { Needs string `json:"needs,omitempty"` // the module that wrote it Observer string `json:"observer"` + // the module the finding is about, when not the observer + Owner string `json:"owner,omitempty"` // the key's last part when it is not the kind Ref string `json:"ref,omitempty"` Resolved string `json:"resolved,omitempty"` @@ -376,6 +436,8 @@ type FindingsByKeyValue struct { Summary string `json:"summary"` // layout version, 1 V int64 `json:"v"` + // what it waits on: a person, a part or a call + WaitingOn string `json:"waiting-on,omitempty"` } // The values of FindingsByKeyValue's severity. @@ -383,3 +445,22 @@ const ( FindingsByKeyValueSeverityUrgent = "urgent" FindingsByKeyValueSeverityWarning = "warning" ) + +// FindingsViewsByObserverNodeValueStated is the last findings-stated set. +type FindingsViewsByObserverNodeValueStated struct { + At *time.Time `json:"at,omitempty"` + Findings []map[string]any `json:"findings,omitempty"` +} + +// FindingsViewsByObserverNodeValue is one value of the state findings-views under the key .. +type FindingsViewsByObserverNodeValue struct { + // the open asks + Asks []string `json:"asks,omitempty"` + Node string `json:"node"` + Observer string `json:"observer"` + // the keys it cannot judge yet + Pending []string `json:"pending,omitempty"` + // the last findings-stated set + Stated *FindingsViewsByObserverNodeValueStated `json:"stated,omitempty"` + V int64 `json:"v"` +} diff --git a/health-and-repair/go/seats/meshconditions/contract_test.go b/health-and-repair/go/seats/meshconditions/contract_test.go index fc0717f..2a769d7 100644 --- a/health-and-repair/go/seats/meshconditions/contract_test.go +++ b/health-and-repair/go/seats/meshconditions/contract_test.go @@ -17,6 +17,10 @@ func TestFixtures(t *testing.T) { decode func([]byte) (any, error) subjectIs *regexp.Regexp }{ + {name: "the keeper asks one observer to state its findings", subject: "mesh.seat.mesh-conditions.event.findings-asked", given: "{\"ask\":\"a-20261111t100000\",\"at\":\"2026-11-11T10:00:00Z\",\"by\":\"jochen\",\"module\":\"mesh-host\"}", wire: "{\"ask\":\"a-20261111t100000\",\"at\":\"2026-11-11T10:00:00Z\",\"by\":\"jochen\",\"module\":\"mesh-host\"}", + decode: func(b []byte) (any, error) { var v FindingsAskedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-conditions\\.event\\.findings-asked$")}, + {name: "the keeper asks every observer", subject: "mesh.seat.mesh-conditions.event.findings-asked", given: "{\"ask\":\"a-20261111t100100\",\"at\":\"2026-11-11T10:01:00Z\",\"by\":\"mesh-conditions\"}", wire: "{\"ask\":\"a-20261111t100100\",\"at\":\"2026-11-11T10:01:00Z\",\"by\":\"mesh-conditions\"}", + decode: func(b []byte) (any, error) { var v FindingsAskedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-conditions\\.event\\.findings-asked$")}, {name: "a condition raised from a finding, as the keeper holds it (captured; empty fields left out)", subject: "", given: "{\"count\":1,\"evidence\":[{\"at\":\"2026-10-26T20:19:41.474823121Z\",\"said\":\"mesh-build-node on ace uses mesh-build-node.cache as found: used as found: owned by 10005:10005, mode 700, as found; mesh-build-node, mode 0711 was declared and not given it — `ace/node-engine.hand-over` with the directory's path, then your yes on your channel, with its path, hands it to the mesh\"}],\"explanation\":\"Needs you: hand the directory over from the control-node, as the operator; the details name it and the line to type. A directory of mesh-build-node was already on ace, with another owner or mode than mesh-build-node declares.\",\"headline\":\"mesh-build-node waits for a directory on ace\",\"key\":\"module.mesh-build-node.ace.directory-used-as-found\",\"kind\":\"directory-used-as-found\",\"last-observed\":\"2026-10-26T20:19:41.474823121Z\",\"needs\":\"hand the directory over from the control-node, as the operator; the details name it and the line to type.\",\"observations\":1,\"raised\":\"2026-10-31T08:19:57.076843727Z\",\"resolved\":\"mesh-build-node's directory on ace is the mesh's\",\"resolver\":\"self\",\"severity\":\"warning\",\"source\":\"health-report\",\"subject\":{\"id\":\"mesh-build-node.ace\",\"machine\":\"ace\",\"scope\":\"module\"},\"summary\":\"mesh-build-node on ace uses mesh-build-node.cache as found: used as found: owned by 10005:10005, mode 700, as found; mesh-build-node, mode 0711 was declared and not given it — `ace/node-engine.hand-over` with the directory's path, then your yes on your channel, with its path, hands it to the mesh\"}", wire: "{\"count\":1,\"evidence\":[{\"at\":\"2026-10-26T20:19:41.474823121Z\",\"said\":\"mesh-build-node on ace uses mesh-build-node.cache as found: used as found: owned by 10005:10005, mode 700, as found; mesh-build-node, mode 0711 was declared and not given it — `ace/node-engine.hand-over` with the directory's path, then your yes on your channel, with its path, hands it to the mesh\"}],\"explanation\":\"Needs you: hand the directory over from the control-node, as the operator; the details name it and the line to type. A directory of mesh-build-node was already on ace, with another owner or mode than mesh-build-node declares.\",\"headline\":\"mesh-build-node waits for a directory on ace\",\"key\":\"module.mesh-build-node.ace.directory-used-as-found\",\"kind\":\"directory-used-as-found\",\"last-observed\":\"2026-10-26T20:19:41.474823121Z\",\"needs\":\"hand the directory over from the control-node, as the operator; the details name it and the line to type.\",\"observations\":1,\"raised\":\"2026-10-31T08:19:57.076843727Z\",\"resolved\":\"mesh-build-node's directory on ace is the mesh's\",\"resolver\":\"self\",\"severity\":\"warning\",\"source\":\"health-report\",\"subject\":{\"id\":\"mesh-build-node.ace\",\"machine\":\"ace\",\"scope\":\"module\"},\"summary\":\"mesh-build-node on ace uses mesh-build-node.cache as found: used as found: owned by 10005:10005, mode 700, as found; mesh-build-node, mode 0711 was declared and not given it — `ace/node-engine.hand-over` with the directory's path, then your yes on your channel, with its path, hands it to the mesh\"}", decode: func(b []byte) (any, error) { var v ConditionsByKeyValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, {name: "a condition with an empty evidence trail of headline (captured; empty fields left out)", subject: "", given: "{\"count\":1,\"evidence\":[{\"at\":\"2026-10-30T13:03:46.432309782Z\",\"said\":\"The backup of postgres failed on ace\"}],\"explanation\":\"Needs you: answer whether to back up again or go on without a backup. The backup before applying postgres at 978b5db8cb4e on ace failed: node-backup.now could not be asked: not asked: nothing on this machine answers mesh.seat.node-backup.tool.now.ace.\",\"headline\":\"The backup of postgres failed on ace\",\"key\":\"module.ace.postgres.978b5db8cb4ef746ce68d82cc616d1439a53266d335e60f368dc44c4cb25610f.backup\",\"kind\":\"backup\",\"last-observed\":\"2026-10-30T13:03:46.432309782Z\",\"needs\":\"answer whether to back up again or go on without a backup\",\"observations\":1,\"raised\":\"2026-10-31T08:19:57.069818178Z\",\"resolver\":\"self\",\"severity\":\"warning\",\"source\":\"assigner.backup\",\"subject\":{\"id\":\"ace.postgres.978b5db8cb4ef746ce68d82cc616d1439a53266d335e60f368dc44c4cb25610f\",\"machine\":\"ace\",\"scope\":\"module\"},\"summary\":\"The backup of postgres failed on ace\"}", wire: "{\"count\":1,\"evidence\":[{\"at\":\"2026-10-30T13:03:46.432309782Z\",\"said\":\"The backup of postgres failed on ace\"}],\"explanation\":\"Needs you: answer whether to back up again or go on without a backup. The backup before applying postgres at 978b5db8cb4e on ace failed: node-backup.now could not be asked: not asked: nothing on this machine answers mesh.seat.node-backup.tool.now.ace.\",\"headline\":\"The backup of postgres failed on ace\",\"key\":\"module.ace.postgres.978b5db8cb4ef746ce68d82cc616d1439a53266d335e60f368dc44c4cb25610f.backup\",\"kind\":\"backup\",\"last-observed\":\"2026-10-30T13:03:46.432309782Z\",\"needs\":\"answer whether to back up again or go on without a backup\",\"observations\":1,\"raised\":\"2026-10-31T08:19:57.069818178Z\",\"resolver\":\"self\",\"severity\":\"warning\",\"source\":\"assigner.backup\",\"subject\":{\"id\":\"ace.postgres.978b5db8cb4ef746ce68d82cc616d1439a53266d335e60f368dc44c4cb25610f\",\"machine\":\"ace\",\"scope\":\"module\"},\"summary\":\"The backup of postgres failed on ace\"}", diff --git a/health-and-repair/go/seats/meshwatchdogs/contract.go b/health-and-repair/go/seats/meshwatchdogs/contract.go index 7c1ec32..91207e1 100644 --- a/health-and-repair/go/seats/meshwatchdogs/contract.go +++ b/health-and-repair/go/seats/meshwatchdogs/contract.go @@ -22,11 +22,49 @@ const ( VerbResync = "resync" ) +const ( + EventMachineAway = "machine-away" + EventMachineBack = "machine-back" +) + // Verbs is every verb the seat serves, in its definition's order: a new copy each call. func Verbs() []string { return []string{VerbSignals, VerbStuck, VerbPresence, VerbDeadLetters, VerbResync} } +// Events is every event published on the seat's subject: a new copy each call. +func Events() []string { + return []string{EventMachineAway, EventMachineBack} +} + +// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects. +const ( + Family = "mesh-watchdogs.events" + FamilyMaxAgeDays = 7 +) + +// StreamMachineAway is the stream machine-away is kept in. +const StreamMachineAway = "SEAT_mesh-watchdogs_machine-away" + +// SubjectMachineAway is where machine-away is published, on mesh.seat.mesh-watchdogs.event.machine-away.. +func SubjectMachineAway(machine string) string { + return "mesh.seat.mesh-watchdogs.event.machine-away." + machine +} + +// SubjectMachineAwayAll hears every machine-away. +const SubjectMachineAwayAll = "mesh.seat.mesh-watchdogs.event.machine-away.*" + +// StreamMachineBack is the stream machine-back is kept in. +const StreamMachineBack = "SEAT_mesh-watchdogs_machine-back" + +// SubjectMachineBack is where machine-back is published, on mesh.seat.mesh-watchdogs.event.machine-back.. +func SubjectMachineBack(machine string) string { + return "mesh.seat.mesh-watchdogs.event.machine-back." + machine +} + +// SubjectMachineBackAll hears every machine-back. +const SubjectMachineBackAll = "mesh.seat.mesh-watchdogs.event.machine-back.*" + const ( StatePresence = "presence" StatePulse = "pulse" @@ -256,6 +294,28 @@ type ResyncInput struct { // ResyncAnswer is what resync answers. type ResyncAnswer = map[string]any +// MachineAwayEvent is the body of the event machine-away. +type MachineAwayEvent struct { + At time.Time `json:"at"` + // when the machine was last heard + LastHeard time.Time `json:"last-heard"` + // the machine whose presence changed + Machine string `json:"machine"` + // the layout's version + V int64 `json:"v"` +} + +// MachineBackEvent is the body of the event machine-back. +type MachineBackEvent struct { + At time.Time `json:"at"` + // when the machine was last heard + LastHeard time.Time `json:"last-heard"` + // the machine whose presence changed + Machine string `json:"machine"` + // the layout's version + V int64 `json:"v"` +} + // PresenceByNodeValue is one value of the state presence under the key . type PresenceByNodeValue struct { Online bool `json:"online"` diff --git a/health-and-repair/go/seats/meshwatchdogs/contract_test.go b/health-and-repair/go/seats/meshwatchdogs/contract_test.go index 564f824..7b3018b 100644 --- a/health-and-repair/go/seats/meshwatchdogs/contract_test.go +++ b/health-and-repair/go/seats/meshwatchdogs/contract_test.go @@ -17,6 +17,10 @@ func TestFixtures(t *testing.T) { decode func([]byte) (any, error) subjectIs *regexp.Regexp }{ + {name: "a machine's presence expired", subject: "mesh.seat.mesh-watchdogs.event.machine-away.g14", given: "{\"at\":\"2026-11-11T10:00:00Z\",\"last-heard\":\"2026-11-11T09:58:00Z\",\"machine\":\"g14\",\"v\":1}", wire: "{\"at\":\"2026-11-11T10:00:00Z\",\"last-heard\":\"2026-11-11T09:58:00Z\",\"machine\":\"g14\",\"v\":1}", + decode: func(b []byte) (any, error) { var v MachineAwayEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-watchdogs\\.event\\.machine-away\\.[^.*> ]+$")}, + {name: "a machine heard again", subject: "mesh.seat.mesh-watchdogs.event.machine-back.g14", given: "{\"at\":\"2026-11-11T10:30:00Z\",\"last-heard\":\"2026-11-11T10:30:00Z\",\"machine\":\"g14\",\"v\":1}", wire: "{\"at\":\"2026-11-11T10:30:00Z\",\"last-heard\":\"2026-11-11T10:30:00Z\",\"machine\":\"g14\",\"v\":1}", + decode: func(b []byte) (any, error) { var v MachineBackEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-watchdogs\\.event\\.machine-back\\.[^.*> ]+$")}, {name: "a node's agent online (captured)", subject: "", given: "{\"online\":true,\"v\":1}", wire: "{\"online\":true,\"v\":1}", decode: func(b []byte) (any, error) { var v PresenceByNodeValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, {name: "a delivery part's instance online (captured)", subject: "", given: "{\"online\":true,\"v\":1}", wire: "{\"online\":true,\"v\":1}", diff --git a/health-and-repair/seats/mesh-watchdogs/seat.json b/health-and-repair/seats/mesh-watchdogs/seat.json index d94c9a1..b532d27 100644 --- a/health-and-repair/seats/mesh-watchdogs/seat.json +++ b/health-and-repair/seats/mesh-watchdogs/seat.json @@ -235,6 +235,10 @@ } } ], + "family": { + "name": "mesh-watchdogs.events", + "max-age-days": 7 + }, "states": [ { "name": "presence", diff --git a/health-and-repair/ts/seats/meshconditions/src/index.ts b/health-and-repair/ts/seats/meshconditions/index.d.ts similarity index 68% rename from health-and-repair/ts/seats/meshconditions/src/index.ts rename to health-and-repair/ts/seats/meshconditions/index.d.ts index a18cdf0..1366690 100644 --- a/health-and-repair/ts/seats/meshconditions/src/index.ts +++ b/health-and-repair/ts/seats/meshconditions/index.d.ts @@ -2,62 +2,56 @@ // The contract of the seat "mesh-conditions", defined whole (seats/mesh-conditions/seat.json): What is wrong with the mesh now (ADR 0564): the open conditions raised from the observers' findings and cleared when a finding goes. -export const seat = "mesh-conditions"; +export declare const seat: "mesh-conditions"; -export const verbs = { - conditions: "conditions", - silence: "silence", - resync: "resync", -} as const; +export declare const verbs: { + readonly conditions: "conditions"; + readonly silence: "silence"; + readonly resync: "resync"; +}; -export const events = { - conditionRaised: "condition-raised", - conditionChanged: "condition-changed", - conditionCleared: "condition-cleared", -} as const; +export declare const events: { + readonly conditionRaised: "condition-raised"; + readonly conditionChanged: "condition-changed"; + readonly conditionCleared: "condition-cleared"; + readonly findingsAsked: "findings-asked"; +}; -export const family = { name: "mesh-conditions.events", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "mesh-conditions.events"; readonly maxAgeDays: 7 }; -export const conditionRaisedSubject = "mesh.seat.mesh-conditions.event.condition-raised"; +export declare const conditionRaisedSubject: "mesh.seat.mesh-conditions.event.condition-raised"; -export const conditionChangedSubject = "mesh.seat.mesh-conditions.event.condition-changed"; +export declare const conditionChangedSubject: "mesh.seat.mesh-conditions.event.condition-changed"; -export const conditionClearedSubject = "mesh.seat.mesh-conditions.event.condition-cleared"; +export declare const conditionClearedSubject: "mesh.seat.mesh-conditions.event.condition-cleared"; -export const states = { - conditions: "conditions", - findings: "findings", -} as const; +export declare const findingsAskedStream: "SEAT_mesh-conditions_findings-asked"; + +export declare const findingsAskedSubject: "mesh.seat.mesh-conditions.event.findings-asked"; + +export declare const states: { + readonly conditions: "conditions"; + readonly findings: "findings"; + readonly findingsViews: "findings-views"; +}; /** The key of one value of the state conditions under the form "". */ -export function conditionsByKeyKey(key: string): string { - return key; -} +export declare function conditionsByKeyKey(key: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseConditionsByKeyKey(_key: string): { key: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const key = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { key }; -} +export declare function parseConditionsByKeyKey(_key: string): { key: string } | undefined; /** The key of one value of the state findings under the form "". */ -export function findingsByKeyKey(key: string): string { - return key; -} +export declare function findingsByKeyKey(key: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseFindingsByKeyKey(_key: string): { key: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const key = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { key }; -} +export declare function parseFindingsByKeyKey(_key: string): { key: string } | undefined; + +/** The key of one value of the state findings-views under the form ".". */ +export declare function findingsViewsByObserverNodeKey(observer: string, node: string): string; + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export declare function parseFindingsViewsByObserverNodeKey(_key: string): { observer: string; node: string } | undefined; /** one answer the operator may give from a notification */ export interface Action { @@ -182,6 +176,8 @@ export type SilenceAnswer = Record; /** is what resync takes. */ export interface ResyncInput { + /** ask this observer alone; none asks all */ + "module"?: string; } /** is what resync answers. */ @@ -196,6 +192,17 @@ export type ConditionChangedEvent = ConditionEvent; /** is the body of the event condition-cleared. */ export type ConditionClearedEvent = ConditionEvent; +/** is the body of the event findings-asked. */ +export interface FindingsAskedEvent { + /** the ask's id */ + "ask": string; + "at": string; + /** who asked: the keeper, or the person or session that called resync */ + "by": string; + /** to ask one observer; none asks all */ + "module"?: string; +} + export interface ConditionsByKeyValueGapsItem { "cleared"?: string; "reopened"?: string; @@ -261,6 +268,8 @@ export interface FindingsByKeyValue { "needs"?: string; /** the module that wrote it */ "observer": string; + /** the module the finding is about, when not the observer */ + "owner"?: string; /** the key's last part when it is not the kind */ "ref"?: string; "resolved"?: string; @@ -276,5 +285,26 @@ export interface FindingsByKeyValue { "summary": string; /** layout version, 1 */ "v": number; + /** what it waits on: a person, a part or a call */ + "waiting-on"?: string; +} + +/** the last findings-stated set */ +export interface FindingsViewsByObserverNodeValueStated { + "at"?: string; + "findings"?: Record[]; +} + +/** is one value of the state findings-views under the key .. */ +export interface FindingsViewsByObserverNodeValue { + /** the open asks */ + "asks"?: string[]; + "node": string; + "observer": string; + /** the keys it cannot judge yet */ + "pending"?: string[]; + /** the last findings-stated set */ + "stated"?: FindingsViewsByObserverNodeValueStated; + "v": number; } diff --git a/health-and-repair/ts/seats/meshconditions/index.js b/health-and-repair/ts/seats/meshconditions/index.js new file mode 100644 index 0000000..115101a --- /dev/null +++ b/health-and-repair/ts/seats/meshconditions/index.js @@ -0,0 +1,86 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-conditions", defined whole (seats/mesh-conditions/seat.json): What is wrong with the mesh now (ADR 0564): the open conditions raised from the observers' findings and cleared when a finding goes. + +export const seat = "mesh-conditions"; + +export const verbs = { + conditions: "conditions", + silence: "silence", + resync: "resync", +}; + +export const events = { + conditionRaised: "condition-raised", + conditionChanged: "condition-changed", + conditionCleared: "condition-cleared", + findingsAsked: "findings-asked", +}; + +export const family = { name: "mesh-conditions.events", maxAgeDays: 7 }; + +export const conditionRaisedSubject = "mesh.seat.mesh-conditions.event.condition-raised"; + +export const conditionChangedSubject = "mesh.seat.mesh-conditions.event.condition-changed"; + +export const conditionClearedSubject = "mesh.seat.mesh-conditions.event.condition-cleared"; + +export const findingsAskedStream = "SEAT_mesh-conditions_findings-asked"; + +export const findingsAskedSubject = "mesh.seat.mesh-conditions.event.findings-asked"; + +export const states = { + conditions: "conditions", + findings: "findings", + findingsViews: "findings-views", +}; + +/** The key of one value of the state conditions under the form "". */ +export function conditionsByKeyKey(key) { + return key; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseConditionsByKeyKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const key = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { key }; +} + +/** The key of one value of the state findings under the form "". */ +export function findingsByKeyKey(key) { + return key; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseFindingsByKeyKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const key = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { key }; +} + +/** The key of one value of the state findings-views under the form ".". */ +export function findingsViewsByObserverNodeKey(observer, node) { + return observer + "." + node; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseFindingsViewsByObserverNodeKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const observer = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { observer, node }; +} + diff --git a/health-and-repair/ts/seats/meshconditions/package-lock.json b/health-and-repair/ts/seats/meshconditions/package-lock.json index 6aa81e6..6ee6716 100644 --- a/health-and-repair/ts/seats/meshconditions/package-lock.json +++ b/health-and-repair/ts/seats/meshconditions/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-health-and-repair-contracts-mesh-conditions", + "name": "@novox/mesh-contracts-health-and-repair-mesh-conditions", "packages": { "": { - "name": "@novox/mesh-health-and-repair-contracts-mesh-conditions", + "name": "@novox/mesh-contracts-health-and-repair-mesh-conditions", "version": "0.1.0" } }, diff --git a/health-and-repair/ts/seats/meshconditions/package.json b/health-and-repair/ts/seats/meshconditions/package.json index 0be4987..d2efa33 100644 --- a/health-and-repair/ts/seats/meshconditions/package.json +++ b/health-and-repair/ts/seats/meshconditions/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-conditions, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-health-and-repair-contracts-mesh-conditions", + "name": "@novox/mesh-contracts-health-and-repair-mesh-conditions", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/health-and-repair/ts/seats/meshhandacts/src/index.ts b/health-and-repair/ts/seats/meshhandacts/index.d.ts similarity index 71% rename from health-and-repair/ts/seats/meshhandacts/src/index.ts rename to health-and-repair/ts/seats/meshhandacts/index.d.ts index 0b4ea7b..02f6433 100644 --- a/health-and-repair/ts/seats/meshhandacts/src/index.ts +++ b/health-and-repair/ts/seats/meshhandacts/index.d.ts @@ -2,60 +2,38 @@ // The contract of the seat "mesh-hand-acts", defined whole (seats/mesh-hand-acts/seat.json): Acts done by hand, recorded with who, why and cause (ADR 0565): the log every module records through. -export const seat = "mesh-hand-acts"; +export declare const seat: "mesh-hand-acts"; -export const verbs = { - handAct: "hand-act", - handActs: "hand-acts", - warranted: "warranted", -} as const; +export declare const verbs: { + readonly handAct: "hand-act"; + readonly handActs: "hand-acts"; + readonly warranted: "warranted"; +}; -export const events = { - actRecorded: "act-recorded", -} as const; +export declare const events: { + readonly actRecorded: "act-recorded"; +}; -export const family = { name: "mesh-hand-acts.events", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "mesh-hand-acts.events"; readonly maxAgeDays: 7 }; -export const actRecordedSubject = "mesh.seat.mesh-hand-acts.event.act-recorded"; +export declare const actRecordedSubject: "mesh.seat.mesh-hand-acts.event.act-recorded"; -export const states = { - acts: "acts", - warrants: "warrants", -} as const; +export declare const states: { + readonly acts: "acts"; + readonly warrants: "warrants"; +}; /** The key of one value of the state acts under the form "". */ -export function actsByIDKey(id: string): string { - return id; -} +export declare function actsByIDKey(id: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseActsByIDKey(_key: string): { id: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const id = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { id }; -} +export declare function parseActsByIDKey(_key: string): { id: string } | undefined; /** The key of one value of the state warrants under the form ".". */ -export function warrantsByAskerAskKey(asker: string, ask: string): string { - return asker + "." + ask; -} +export declare function warrantsByAskerAskKey(asker: string, ask: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parseWarrantsByAskerAskKey(_key: string): { asker: string; ask: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const asker = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const ask = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { asker, ask }; -} +export declare function parseWarrantsByAskerAskKey(_key: string): { asker: string; ask: string } | undefined; /** one act done by hand */ export interface Act { diff --git a/health-and-repair/ts/seats/meshhandacts/index.js b/health-and-repair/ts/seats/meshhandacts/index.js new file mode 100644 index 0000000..4461e8d --- /dev/null +++ b/health-and-repair/ts/seats/meshhandacts/index.js @@ -0,0 +1,59 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-hand-acts", defined whole (seats/mesh-hand-acts/seat.json): Acts done by hand, recorded with who, why and cause (ADR 0565): the log every module records through. + +export const seat = "mesh-hand-acts"; + +export const verbs = { + handAct: "hand-act", + handActs: "hand-acts", + warranted: "warranted", +}; + +export const events = { + actRecorded: "act-recorded", +}; + +export const family = { name: "mesh-hand-acts.events", maxAgeDays: 7 }; + +export const actRecordedSubject = "mesh.seat.mesh-hand-acts.event.act-recorded"; + +export const states = { + acts: "acts", + warrants: "warrants", +}; + +/** The key of one value of the state acts under the form "". */ +export function actsByIDKey(id) { + return id; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseActsByIDKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const id = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { id }; +} + +/** The key of one value of the state warrants under the form ".". */ +export function warrantsByAskerAskKey(asker, ask) { + return asker + "." + ask; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseWarrantsByAskerAskKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const asker = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const ask = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { asker, ask }; +} + diff --git a/health-and-repair/ts/seats/meshhandacts/package-lock.json b/health-and-repair/ts/seats/meshhandacts/package-lock.json index c94f1e5..29a7c2a 100644 --- a/health-and-repair/ts/seats/meshhandacts/package-lock.json +++ b/health-and-repair/ts/seats/meshhandacts/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-health-and-repair-contracts-mesh-hand-acts", + "name": "@novox/mesh-contracts-health-and-repair-mesh-hand-acts", "packages": { "": { - "name": "@novox/mesh-health-and-repair-contracts-mesh-hand-acts", + "name": "@novox/mesh-contracts-health-and-repair-mesh-hand-acts", "version": "0.1.0" } }, diff --git a/health-and-repair/ts/seats/meshhandacts/package.json b/health-and-repair/ts/seats/meshhandacts/package.json index 20ebafd..cfb4c3f 100644 --- a/health-and-repair/ts/seats/meshhandacts/package.json +++ b/health-and-repair/ts/seats/meshhandacts/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-hand-acts, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-health-and-repair-contracts-mesh-hand-acts", + "name": "@novox/mesh-contracts-health-and-repair-mesh-hand-acts", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/health-and-repair/ts/seats/meshhealers/src/index.ts b/health-and-repair/ts/seats/meshhealers/index.d.ts similarity index 69% rename from health-and-repair/ts/seats/meshhealers/src/index.ts rename to health-and-repair/ts/seats/meshhealers/index.d.ts index 3840537..392573b 100644 --- a/health-and-repair/ts/seats/meshhealers/src/index.ts +++ b/health-and-repair/ts/seats/meshhealers/index.d.ts @@ -2,56 +2,38 @@ // The contract of the seat "mesh-healers", defined whole (seats/mesh-healers/seat.json): The healers (ADR 0564): each a registered response to one kind of condition, within a budget and the mesh-wide brake. -export const seat = "mesh-healers"; +export declare const seat: "mesh-healers"; -export const verbs = { - healers: "healers", - heal: "heal", - drill: "drill", -} as const; +export declare const verbs: { + readonly healers: "healers"; + readonly heal: "heal"; + readonly drill: "drill"; +}; -export const events = { - healerActed: "healer-acted", -} as const; +export declare const events: { + readonly healerActed: "healer-acted"; +}; -export const family = { name: "mesh-healers.events", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "mesh-healers.events"; readonly maxAgeDays: 7 }; -export const healerActedSubject = "mesh.seat.mesh-healers.event.healer-acted"; +export declare const healerActedSubject: "mesh.seat.mesh-healers.event.healer-acted"; -export const states = { - attempts: "attempts", - would: "would", -} as const; +export declare const states: { + readonly attempts: "attempts"; + readonly would: "would"; +}; /** The key of one value of the state attempts under the form "". */ -export function attemptsByAttemptKey(attempt: string): string { - return attempt; -} +export declare function attemptsByAttemptKey(attempt: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseAttemptsByAttemptKey(_key: string): { attempt: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const attempt = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { attempt }; -} +export declare function parseAttemptsByAttemptKey(_key: string): { attempt: string } | undefined; /** The key of one value of the state would under the form "". */ -export function wouldByWouldKey(would: string): string { - return would; -} +export declare function wouldByWouldKey(would: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseWouldByWouldKey(_key: string): { would: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const would = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { would }; -} +export declare function parseWouldByWouldKey(_key: string): { would: string } | undefined; /** is what healers takes. */ export interface HealersInput { diff --git a/health-and-repair/ts/seats/meshhealers/index.js b/health-and-repair/ts/seats/meshhealers/index.js new file mode 100644 index 0000000..05659bd --- /dev/null +++ b/health-and-repair/ts/seats/meshhealers/index.js @@ -0,0 +1,55 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-healers", defined whole (seats/mesh-healers/seat.json): The healers (ADR 0564): each a registered response to one kind of condition, within a budget and the mesh-wide brake. + +export const seat = "mesh-healers"; + +export const verbs = { + healers: "healers", + heal: "heal", + drill: "drill", +}; + +export const events = { + healerActed: "healer-acted", +}; + +export const family = { name: "mesh-healers.events", maxAgeDays: 7 }; + +export const healerActedSubject = "mesh.seat.mesh-healers.event.healer-acted"; + +export const states = { + attempts: "attempts", + would: "would", +}; + +/** The key of one value of the state attempts under the form "". */ +export function attemptsByAttemptKey(attempt) { + return attempt; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseAttemptsByAttemptKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const attempt = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { attempt }; +} + +/** The key of one value of the state would under the form "". */ +export function wouldByWouldKey(would) { + return would; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseWouldByWouldKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const would = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { would }; +} + diff --git a/health-and-repair/ts/seats/meshhealers/package-lock.json b/health-and-repair/ts/seats/meshhealers/package-lock.json index 9a26d5f..073e379 100644 --- a/health-and-repair/ts/seats/meshhealers/package-lock.json +++ b/health-and-repair/ts/seats/meshhealers/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-health-and-repair-contracts-mesh-healers", + "name": "@novox/mesh-contracts-health-and-repair-mesh-healers", "packages": { "": { - "name": "@novox/mesh-health-and-repair-contracts-mesh-healers", + "name": "@novox/mesh-contracts-health-and-repair-mesh-healers", "version": "0.1.0" } }, diff --git a/health-and-repair/ts/seats/meshhealers/package.json b/health-and-repair/ts/seats/meshhealers/package.json index 3d48314..e9834aa 100644 --- a/health-and-repair/ts/seats/meshhealers/package.json +++ b/health-and-repair/ts/seats/meshhealers/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-healers, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-health-and-repair-contracts-mesh-healers", + "name": "@novox/mesh-contracts-health-and-repair-mesh-healers", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/health-and-repair/ts/seats/meshselfcheck/src/index.ts b/health-and-repair/ts/seats/meshselfcheck/index.d.ts similarity index 79% rename from health-and-repair/ts/seats/meshselfcheck/src/index.ts rename to health-and-repair/ts/seats/meshselfcheck/index.d.ts index b76fc1d..256f61b 100644 --- a/health-and-repair/ts/seats/meshselfcheck/src/index.ts +++ b/health-and-repair/ts/seats/meshselfcheck/index.d.ts @@ -2,20 +2,20 @@ // The contract of the seat "mesh-self-check", defined whole (seats/mesh-self-check/seat.json): The mesh checking itself (ADR 0564): probes run every five minutes, each failure a finding the seat's conditions raise. -export const seat = "mesh-self-check"; +export declare const seat: "mesh-self-check"; -export const verbs = { - doctor: "doctor", - probes: "probes", -} as const; +export declare const verbs: { + readonly doctor: "doctor"; + readonly probes: "probes"; +}; -export const events = { - checked: "checked", -} as const; +export declare const events: { + readonly checked: "checked"; +}; -export const family = { name: "mesh-self-check.events", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "mesh-self-check.events"; readonly maxAgeDays: 7 }; -export const checkedSubject = "mesh.seat.mesh-self-check.event.checked"; +export declare const checkedSubject: "mesh.seat.mesh-self-check.event.checked"; /** one probe's verdict */ export interface ProbeVerdict { diff --git a/health-and-repair/ts/seats/meshselfcheck/index.js b/health-and-repair/ts/seats/meshselfcheck/index.js new file mode 100644 index 0000000..b74b201 --- /dev/null +++ b/health-and-repair/ts/seats/meshselfcheck/index.js @@ -0,0 +1,19 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-self-check", defined whole (seats/mesh-self-check/seat.json): The mesh checking itself (ADR 0564): probes run every five minutes, each failure a finding the seat's conditions raise. + +export const seat = "mesh-self-check"; + +export const verbs = { + doctor: "doctor", + probes: "probes", +}; + +export const events = { + checked: "checked", +}; + +export const family = { name: "mesh-self-check.events", maxAgeDays: 7 }; + +export const checkedSubject = "mesh.seat.mesh-self-check.event.checked"; + diff --git a/health-and-repair/ts/seats/meshselfcheck/package-lock.json b/health-and-repair/ts/seats/meshselfcheck/package-lock.json index 1590123..644ccbe 100644 --- a/health-and-repair/ts/seats/meshselfcheck/package-lock.json +++ b/health-and-repair/ts/seats/meshselfcheck/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-health-and-repair-contracts-mesh-self-check", + "name": "@novox/mesh-contracts-health-and-repair-mesh-self-check", "packages": { "": { - "name": "@novox/mesh-health-and-repair-contracts-mesh-self-check", + "name": "@novox/mesh-contracts-health-and-repair-mesh-self-check", "version": "0.1.0" } }, diff --git a/health-and-repair/ts/seats/meshselfcheck/package.json b/health-and-repair/ts/seats/meshselfcheck/package.json index f0027c9..4cabb52 100644 --- a/health-and-repair/ts/seats/meshselfcheck/package.json +++ b/health-and-repair/ts/seats/meshselfcheck/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-self-check, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-health-and-repair-contracts-mesh-self-check", + "name": "@novox/mesh-contracts-health-and-repair-mesh-self-check", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/health-and-repair/ts/seats/meshwatchdogs/src/index.ts b/health-and-repair/ts/seats/meshwatchdogs/index.d.ts similarity index 64% rename from health-and-repair/ts/seats/meshwatchdogs/src/index.ts rename to health-and-repair/ts/seats/meshwatchdogs/index.d.ts index 8f12999..ebe31a0 100644 --- a/health-and-repair/ts/seats/meshwatchdogs/src/index.ts +++ b/health-and-repair/ts/seats/meshwatchdogs/index.d.ts @@ -2,95 +2,64 @@ // The contract of the seat "mesh-watchdogs", defined whole (seats/mesh-watchdogs/seat.json): The watchman's seat (ADR 0564, ADR 0433): signals that expire unless renewed, what stopped moving, who is present, the dead letters. -export const seat = "mesh-watchdogs"; +export declare const seat: "mesh-watchdogs"; -export const verbs = { - signals: "signals", - stuck: "stuck", - presence: "presence", - deadLetters: "dead-letters", - resync: "resync", -} as const; +export declare const verbs: { + readonly signals: "signals"; + readonly stuck: "stuck"; + readonly presence: "presence"; + readonly deadLetters: "dead-letters"; + readonly resync: "resync"; +}; -export const states = { - presence: "presence", - pulse: "pulse", - stuck: "stuck", -} as const; +export declare const events: { + readonly machineAway: "machine-away"; + readonly machineBack: "machine-back"; +}; + +export declare const family: { readonly name: "mesh-watchdogs.events"; readonly maxAgeDays: 7 }; + +export declare const machineAwayStream: "SEAT_mesh-watchdogs_machine-away"; + +export declare function machineAwaySubject(machine: string): string; + +export declare const machineAwaySubjectAll: "mesh.seat.mesh-watchdogs.event.machine-away.*"; + +export declare const machineBackStream: "SEAT_mesh-watchdogs_machine-back"; + +export declare function machineBackSubject(machine: string): string; + +export declare const machineBackSubjectAll: "mesh.seat.mesh-watchdogs.event.machine-back.*"; + +export declare const states: { + readonly presence: "presence"; + readonly pulse: "pulse"; + readonly stuck: "stuck"; +}; /** The key of one value of the state presence under the form "". */ -export function presenceByNodeKey(node: string): string { - return node; -} +export declare function presenceByNodeKey(node: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parsePresenceByNodeKey(_key: string): { node: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const node = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node }; -} +export declare function parsePresenceByNodeKey(_key: string): { node: string } | undefined; /** The key of one value of the state presence under the form "part..". */ -export function presenceByPartPartInstanceKey(part: string, instance: string): string { - return "part." + part + "." + instance; -} +export declare function presenceByPartPartInstanceKey(part: string, instance: string): string; /** The parts of a key of the form "part..", or undefined for a key of another form. */ -export function parsePresenceByPartPartInstanceKey(_key: string): { part: string; instance: string } | undefined { - let _rest = _key; - if (!_rest.startsWith("part.")) return undefined; - _rest = _rest.slice(5); - const _at1 = _rest.indexOf("."); - if (_at1 <= 0) return undefined; - const part = _rest.slice(0, _at1); - _rest = _rest.slice(_at1 + 1); - if (_rest === "") return undefined; - const instance = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { part, instance }; -} +export declare function parsePresenceByPartPartInstanceKey(_key: string): { part: string; instance: string } | undefined; /** The key of one value of the state pulse under the form ".". */ -export function pulseByBucketKeyKey(bucket: string, key: string): string { - return bucket + "." + key; -} +export declare function pulseByBucketKeyKey(bucket: string, key: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parsePulseByBucketKeyKey(_key: string): { bucket: string; key: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const bucket = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const key = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { bucket, key }; -} +export declare function parsePulseByBucketKeyKey(_key: string): { bucket: string; key: string } | undefined; /** The key of one value of the state stuck under the form ".". */ -export function stuckByBucketKeyKey(bucket: string, key: string): string { - return bucket + "." + key; -} +export declare function stuckByBucketKeyKey(bucket: string, key: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parseStuckByBucketKeyKey(_key: string): { bucket: string; key: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const bucket = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const key = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { bucket, key }; -} +export declare function parseStuckByBucketKeyKey(_key: string): { bucket: string; key: string } | undefined; /** is what signals takes. */ export interface SignalsInput { @@ -169,6 +138,28 @@ export interface ResyncInput { /** is what resync answers. */ export type ResyncAnswer = Record; +/** is the body of the event machine-away. */ +export interface MachineAwayEvent { + "at": string; + /** when the machine was last heard */ + "last-heard": string; + /** the machine whose presence changed */ + "machine": string; + /** the layout's version */ + "v": number; +} + +/** is the body of the event machine-back. */ +export interface MachineBackEvent { + "at": string; + /** when the machine was last heard */ + "last-heard": string; + /** the machine whose presence changed */ + "machine": string; + /** the layout's version */ + "v": number; +} + /** is one value of the state presence under the key . */ export interface PresenceByNodeValue { "online": boolean; diff --git a/health-and-repair/ts/seats/meshwatchdogs/index.js b/health-and-repair/ts/seats/meshwatchdogs/index.js new file mode 100644 index 0000000..b5b1e88 --- /dev/null +++ b/health-and-repair/ts/seats/meshwatchdogs/index.js @@ -0,0 +1,117 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-watchdogs", defined whole (seats/mesh-watchdogs/seat.json): The watchman's seat (ADR 0564, ADR 0433): signals that expire unless renewed, what stopped moving, who is present, the dead letters. + +export const seat = "mesh-watchdogs"; + +export const verbs = { + signals: "signals", + stuck: "stuck", + presence: "presence", + deadLetters: "dead-letters", + resync: "resync", +}; + +export const events = { + machineAway: "machine-away", + machineBack: "machine-back", +}; + +export const family = { name: "mesh-watchdogs.events", maxAgeDays: 7 }; + +export const machineAwayStream = "SEAT_mesh-watchdogs_machine-away"; + +export function machineAwaySubject(machine) { + return "mesh.seat.mesh-watchdogs.event.machine-away." + machine; +} + +export const machineAwaySubjectAll = "mesh.seat.mesh-watchdogs.event.machine-away.*"; + +export const machineBackStream = "SEAT_mesh-watchdogs_machine-back"; + +export function machineBackSubject(machine) { + return "mesh.seat.mesh-watchdogs.event.machine-back." + machine; +} + +export const machineBackSubjectAll = "mesh.seat.mesh-watchdogs.event.machine-back.*"; + +export const states = { + presence: "presence", + pulse: "pulse", + stuck: "stuck", +}; + +/** The key of one value of the state presence under the form "". */ +export function presenceByNodeKey(node) { + return node; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parsePresenceByNodeKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node }; +} + +/** The key of one value of the state presence under the form "part..". */ +export function presenceByPartPartInstanceKey(part, instance) { + return "part." + part + "." + instance; +} + +/** The parts of a key of the form "part..", or undefined for a key of another form. */ +export function parsePresenceByPartPartInstanceKey(_key) { + let _rest = _key; + if (!_rest.startsWith("part.")) return undefined; + _rest = _rest.slice(5); + const _at1 = _rest.indexOf("."); + if (_at1 <= 0) return undefined; + const part = _rest.slice(0, _at1); + _rest = _rest.slice(_at1 + 1); + if (_rest === "") return undefined; + const instance = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { part, instance }; +} + +/** The key of one value of the state pulse under the form ".". */ +export function pulseByBucketKeyKey(bucket, key) { + return bucket + "." + key; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parsePulseByBucketKeyKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const bucket = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const key = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { bucket, key }; +} + +/** The key of one value of the state stuck under the form ".". */ +export function stuckByBucketKeyKey(bucket, key) { + return bucket + "." + key; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseStuckByBucketKeyKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const bucket = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const key = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { bucket, key }; +} + diff --git a/health-and-repair/ts/seats/meshwatchdogs/package-lock.json b/health-and-repair/ts/seats/meshwatchdogs/package-lock.json index b236c0c..dc100c5 100644 --- a/health-and-repair/ts/seats/meshwatchdogs/package-lock.json +++ b/health-and-repair/ts/seats/meshwatchdogs/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-health-and-repair-contracts-mesh-watchdogs", + "name": "@novox/mesh-contracts-health-and-repair-mesh-watchdogs", "packages": { "": { - "name": "@novox/mesh-health-and-repair-contracts-mesh-watchdogs", + "name": "@novox/mesh-contracts-health-and-repair-mesh-watchdogs", "version": "0.1.0" } }, diff --git a/health-and-repair/ts/seats/meshwatchdogs/package.json b/health-and-repair/ts/seats/meshwatchdogs/package.json index 9dc0933..763e007 100644 --- a/health-and-repair/ts/seats/meshwatchdogs/package.json +++ b/health-and-repair/ts/seats/meshwatchdogs/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-watchdogs, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-health-and-repair-contracts-mesh-watchdogs", + "name": "@novox/mesh-contracts-health-and-repair-mesh-watchdogs", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/identity-and-access/go/seats/meshgrants/contract.go b/identity-and-access/go/seats/meshgrants/contract.go new file mode 100644 index 0000000..a2c3e2c --- /dev/null +++ b/identity-and-access/go/seats/meshgrants/contract.go @@ -0,0 +1,139 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// Package meshgrants is the contract of the seat "mesh-grants", defined whole (seats/mesh-grants/seat.json): Who may say what on the bus: the grants part composes each module's membership, its buckets, logs and streams, the bus's user list and grants (design 47 'The grants part'). An acting part of the step grant (ADR 0656 1): an entry whose grant waits for its new version is held on its running build within the bound, said by wait-held and wait-ended; a store passing 80 % of its cap is said by filling, and back below 70 % by room; grants-for answers the grants a candidate would compose (design 47 G 331, 441). +package meshgrants + +import "time" + +// Seat is the seat's name. +const Seat = "mesh-grants" + +const ( + VerbGrantsFor = "grants-for" +) + +const ( + EventWaitHeld = "wait-held" + EventWaitEnded = "wait-ended" + EventFilling = "filling" + EventRoom = "room" +) + +// Verbs is every verb the seat serves, in its definition's order: a new copy each call. +func Verbs() []string { + return []string{VerbGrantsFor} +} + +// Events is every event published on the seat's subject: a new copy each call. +func Events() []string { + return []string{EventWaitHeld, EventWaitEnded, EventFilling, EventRoom} +} + +// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects. +const ( + Family = "mesh-grants.events" + FamilyMaxAgeDays = 7 +) + +// SubjectWaitHeld is where wait-held is published. +const SubjectWaitHeld = "mesh.seat.mesh-grants.event.wait-held" + +// SubjectWaitEnded is where wait-ended is published. +const SubjectWaitEnded = "mesh.seat.mesh-grants.event.wait-ended" + +// SubjectFilling is where filling is published. +const SubjectFilling = "mesh.seat.mesh-grants.event.filling" + +// SubjectRoom is where room is published. +const SubjectRoom = "mesh.seat.mesh-grants.event.room" + +// Fill is a store's fill against its cap. +type Fill struct { + At *time.Time `json:"at,omitempty"` + Bytes int64 `json:"bytes"` + // bytes + Cap int64 `json:"cap"` + // the store + Store string `json:"store"` +} + +// Grant is a type of the contract. +type Grant struct { + // the bus subject + Subject string `json:"subject"` + // the verb or event the grant is for + Verb string `json:"verb"` +} + +// GrantsForModulesItem is a type of the contract. +type GrantsForModulesItem struct { + Added []Grant `json:"added"` + Module string `json:"module"` + Removed []Grant `json:"removed"` +} + +// GrantsFor is the grants a candidate would compose, per module, added and removed against the branch's newest. +type GrantsFor struct { + // why it could not be answered: the catalog half of the candidate is not held + Error string `json:"error,omitempty"` + Modules []GrantsForModulesItem `json:"modules,omitempty"` +} + +// Wait is a granting wait the grants part holds: an entry whose grant waits until the grants part's new version runs (design 47 *Each step's wait is its own part's*). +type Wait struct { + // a duration such as 10m + Bound string `json:"bound"` + // on a release, who released it and why + By string `json:"by,omitempty"` + // when the new version's build was done, as the builder's build.ended says; the bound's clock starts there (design 47 G 266) + ClockFrom time.Time `json:"clock-from"` + // the entry's fingerprint, whose grant waits + Fp string `json:"fp,omitempty"` + // on wait-ended: ran or released + How string `json:"how,omitempty"` + // the entry that waits + Module string `json:"module"` + // the acting part waited for + Part string `json:"part"` + Since time.Time `json:"since"` + // the step, grant + Step string `json:"step"` + // its new version's fingerprint + Version string `json:"version"` +} + +// The values of Wait's how. +const ( + WaitHowRan = "ran" + WaitHowReleased = "released" +) + +// The values of Wait's step. +const ( + WaitStepGrant = "grant" +) + +// GrantsForInput is what grants-for takes. +type GrantsForInput struct { + // its watched branch + Branch string `json:"branch"` + // or the id of a run + Run string `json:"run,omitempty"` + // the candidate's source revision + Source string `json:"source,omitempty"` +} + +// GrantsForAnswer is what grants-for answers. +type GrantsForAnswer = GrantsFor + +// WaitHeldEvent is the body of the event wait-held. +type WaitHeldEvent = Wait + +// WaitEndedEvent is the body of the event wait-ended. +type WaitEndedEvent = Wait + +// FillingEvent is the body of the event filling. +type FillingEvent = Fill + +// RoomEvent is the body of the event room. +type RoomEvent = Fill diff --git a/identity-and-access/go/seats/meshgrants/contract_test.go b/identity-and-access/go/seats/meshgrants/contract_test.go new file mode 100644 index 0000000..ef84ac6 --- /dev/null +++ b/identity-and-access/go/seats/meshgrants/contract_test.go @@ -0,0 +1,58 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +package meshgrants + +import ( + "encoding/json" + "reflect" + "regexp" + "testing" +) + +// TestFixtures reads every fixture of seats/mesh-grants/fixtures: each decodes into its type, a field the type does not +// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's. +func TestFixtures(t *testing.T) { + cases := []struct { + name, subject, given, wire string + decode func([]byte) (any, error) + subjectIs *regexp.Regexp + }{ + {name: "a granting wait held", subject: "mesh.seat.mesh-grants.event.wait-held", given: "{\"bound\":\"10m\",\"clock-from\":\"2026-11-09T20:55:00Z\",\"fp\":\"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"module\":\"mesh-tools\",\"part\":\"mesh-grants\",\"since\":\"2026-11-09T21:00:00Z\",\"step\":\"grant\",\"version\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}", wire: "{\"bound\":\"10m\",\"clock-from\":\"2026-11-09T20:55:00Z\",\"fp\":\"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"module\":\"mesh-tools\",\"part\":\"mesh-grants\",\"since\":\"2026-11-09T21:00:00Z\",\"step\":\"grant\",\"version\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}", + decode: func(b []byte) (any, error) { var v WaitHeldEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-grants\\.event\\.wait-held$")}, + {name: "a granting wait released", subject: "mesh.seat.mesh-grants.event.wait-ended", given: "{\"bound\":\"10m\",\"by\":\"jochen: the new grants part is stuck\",\"clock-from\":\"2026-11-09T20:55:00Z\",\"fp\":\"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"how\":\"released\",\"module\":\"mesh-tools\",\"part\":\"mesh-grants\",\"since\":\"2026-11-09T21:00:00Z\",\"step\":\"grant\",\"version\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}", wire: "{\"bound\":\"10m\",\"by\":\"jochen: the new grants part is stuck\",\"clock-from\":\"2026-11-09T20:55:00Z\",\"fp\":\"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"how\":\"released\",\"module\":\"mesh-tools\",\"part\":\"mesh-grants\",\"since\":\"2026-11-09T21:00:00Z\",\"step\":\"grant\",\"version\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}", + decode: func(b []byte) (any, error) { var v WaitEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-grants\\.event\\.wait-ended$")}, + {name: "filling is said past 80 %", subject: "mesh.seat.mesh-grants.event.filling", given: "{\"at\":\"2026-11-11T09:00:00Z\",\"bytes\":161061273,\"cap\":201326592,\"store\":\"SEAT_mesh-pipeline-runner_pipeline-ended\"}", wire: "{\"at\":\"2026-11-11T09:00:00Z\",\"bytes\":161061273,\"cap\":201326592,\"store\":\"SEAT_mesh-pipeline-runner_pipeline-ended\"}", + decode: func(b []byte) (any, error) { var v FillingEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-grants\\.event\\.filling$")}, + {name: "room is said below 70 %", subject: "mesh.seat.mesh-grants.event.room", given: "{\"at\":\"2026-11-11T10:00:00Z\",\"bytes\":100663296,\"cap\":201326592,\"store\":\"SEAT_mesh-pipeline-runner_pipeline-ended\"}", wire: "{\"at\":\"2026-11-11T10:00:00Z\",\"bytes\":100663296,\"cap\":201326592,\"store\":\"SEAT_mesh-pipeline-runner_pipeline-ended\"}", + decode: func(b []byte) (any, error) { var v RoomEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.mesh-grants\\.event\\.room$")}, + {name: "grants-for answers the grants a candidate adds", subject: "", given: "{\"modules\":[{\"added\":[{\"subject\":\"mesh.seat.node-engine.verb.manifest-reads\",\"verb\":\"manifest-reads\"}],\"module\":\"mesh-tools\",\"removed\":[]}]}", wire: "{\"modules\":[{\"added\":[{\"subject\":\"mesh.seat.node-engine.verb.manifest-reads\",\"verb\":\"manifest-reads\"}],\"module\":\"mesh-tools\",\"removed\":[]}]}", + decode: func(b []byte) (any, error) { var v GrantsForAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "grants-for asks a source revision on a branch", subject: "", given: "{\"branch\":\"main\",\"source\":\"a1b2c3d4\"}", wire: "{\"branch\":\"main\",\"source\":\"a1b2c3d4\"}", + decode: func(b []byte) (any, error) { var v GrantsForInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + } + for _, c := range cases { + v, err := c.decode([]byte(c.given)) + if err != nil { + t.Errorf("%s: does not decode: %v", c.name, err) + continue + } + back, err := json.Marshal(v) + if err != nil { + t.Errorf("%s: does not encode: %v", c.name, err) + continue + } + var got, want any + if err := json.Unmarshal(back, &got); err != nil { + t.Fatal(err) + } + if err := json.Unmarshal([]byte(c.wire), &want); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire) + } + if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) { + t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs) + } + } +} diff --git a/identity-and-access/go/seats/meshgrants/go.mod b/identity-and-access/go/seats/meshgrants/go.mod new file mode 100644 index 0000000..44a020b --- /dev/null +++ b/identity-and-access/go/seats/meshgrants/go.mod @@ -0,0 +1,3 @@ +module git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshgrants + +go 1.26.0 diff --git a/identity-and-access/ts/seats/meshgrants/index.d.ts b/identity-and-access/ts/seats/meshgrants/index.d.ts new file mode 100644 index 0000000..167e2b8 --- /dev/null +++ b/identity-and-access/ts/seats/meshgrants/index.d.ts @@ -0,0 +1,105 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-grants", defined whole (seats/mesh-grants/seat.json): Who may say what on the bus: the grants part composes each module's membership, its buckets, logs and streams, the bus's user list and grants (design 47 'The grants part'). An acting part of the step grant (ADR 0656 1): an entry whose grant waits for its new version is held on its running build within the bound, said by wait-held and wait-ended; a store passing 80 % of its cap is said by filling, and back below 70 % by room; grants-for answers the grants a candidate would compose (design 47 G 331, 441). + +export declare const seat: "mesh-grants"; + +export declare const verbs: { + readonly grantsFor: "grants-for"; +}; + +export declare const events: { + readonly waitHeld: "wait-held"; + readonly waitEnded: "wait-ended"; + readonly filling: "filling"; + readonly room: "room"; +}; + +export declare const family: { readonly name: "mesh-grants.events"; readonly maxAgeDays: 7 }; + +export declare const waitHeldSubject: "mesh.seat.mesh-grants.event.wait-held"; + +export declare const waitEndedSubject: "mesh.seat.mesh-grants.event.wait-ended"; + +export declare const fillingSubject: "mesh.seat.mesh-grants.event.filling"; + +export declare const roomSubject: "mesh.seat.mesh-grants.event.room"; + +/** a store's fill against its cap */ +export interface Fill { + "at"?: string; + "bytes": number; + /** bytes */ + "cap": number; + /** the store */ + "store": string; +} + +export interface Grant { + /** the bus subject */ + "subject": string; + /** the verb or event the grant is for */ + "verb": string; +} + +export interface GrantsForModulesItem { + "added": Grant[]; + "module": string; + "removed": Grant[]; +} + +/** the grants a candidate would compose, per module, added and removed against the branch's newest */ +export interface GrantsFor { + /** why it could not be answered: the catalog half of the candidate is not held */ + "error"?: string; + "modules"?: GrantsForModulesItem[]; +} + +/** a granting wait the grants part holds: an entry whose grant waits until the grants part's new version runs (design 47 *Each step's wait is its own part's*) */ +export interface Wait { + /** a duration such as 10m */ + "bound": string; + /** on a release, who released it and why */ + "by"?: string; + /** when the new version's build was done, as the builder's build.ended says; the bound's clock starts there (design 47 G 266) */ + "clock-from": string; + /** the entry's fingerprint, whose grant waits */ + "fp"?: string; + /** on wait-ended: ran or released */ + "how"?: "ran" | "released"; + /** the entry that waits */ + "module": string; + /** the acting part waited for */ + "part": string; + "since": string; + /** the step, grant */ + "step": "grant"; + /** its new version's fingerprint */ + "version": string; +} + +/** is what grants-for takes. */ +export interface GrantsForInput { + /** its watched branch */ + "branch": string; + /** or the id of a run */ + "run"?: string; + /** the candidate's source revision */ + "source"?: string; +} + +/** is what grants-for answers. */ +export type GrantsForAnswer = GrantsFor; + +/** is the body of the event wait-held. */ +export type WaitHeldEvent = Wait; + +/** is the body of the event wait-ended. */ +export type WaitEndedEvent = Wait; + +/** is the body of the event filling. */ +export type FillingEvent = Fill; + +/** is the body of the event room. */ +export type RoomEvent = Fill; + diff --git a/identity-and-access/ts/seats/meshgrants/index.js b/identity-and-access/ts/seats/meshgrants/index.js new file mode 100644 index 0000000..e19f333 --- /dev/null +++ b/identity-and-access/ts/seats/meshgrants/index.js @@ -0,0 +1,27 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-grants", defined whole (seats/mesh-grants/seat.json): Who may say what on the bus: the grants part composes each module's membership, its buckets, logs and streams, the bus's user list and grants (design 47 'The grants part'). An acting part of the step grant (ADR 0656 1): an entry whose grant waits for its new version is held on its running build within the bound, said by wait-held and wait-ended; a store passing 80 % of its cap is said by filling, and back below 70 % by room; grants-for answers the grants a candidate would compose (design 47 G 331, 441). + +export const seat = "mesh-grants"; + +export const verbs = { + grantsFor: "grants-for", +}; + +export const events = { + waitHeld: "wait-held", + waitEnded: "wait-ended", + filling: "filling", + room: "room", +}; + +export const family = { name: "mesh-grants.events", maxAgeDays: 7 }; + +export const waitHeldSubject = "mesh.seat.mesh-grants.event.wait-held"; + +export const waitEndedSubject = "mesh.seat.mesh-grants.event.wait-ended"; + +export const fillingSubject = "mesh.seat.mesh-grants.event.filling"; + +export const roomSubject = "mesh.seat.mesh-grants.event.room"; + diff --git a/identity-and-access/ts/seats/meshgrants/package-lock.json b/identity-and-access/ts/seats/meshgrants/package-lock.json new file mode 100644 index 0000000..f57a656 --- /dev/null +++ b/identity-and-access/ts/seats/meshgrants/package-lock.json @@ -0,0 +1,12 @@ +{ + "lockfileVersion": 3, + "name": "@novox/mesh-contracts-identity-and-access-mesh-grants", + "packages": { + "": { + "name": "@novox/mesh-contracts-identity-and-access-mesh-grants", + "version": "0.1.0" + } + }, + "requires": true, + "version": "0.1.0" +} diff --git a/identity-and-access/ts/seats/meshgrants/package.json b/identity-and-access/ts/seats/meshgrants/package.json new file mode 100644 index 0000000..a4a8fce --- /dev/null +++ b/identity-and-access/ts/seats/meshgrants/package.json @@ -0,0 +1,18 @@ +{ + "description": "The contract of the seat mesh-grants, generated from its definition.", + "exports": { + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } + }, + "files": [ + "index.js", + "index.d.ts", + "parts" + ], + "name": "@novox/mesh-contracts-identity-and-access-mesh-grants", + "type": "module", + "types": "./index.d.ts", + "version": "0.1.0" +} diff --git a/identity-and-access/ts/seats/meshnodeenroller/src/index.ts b/identity-and-access/ts/seats/meshnodeenroller/index.d.ts similarity index 70% rename from identity-and-access/ts/seats/meshnodeenroller/src/index.ts rename to identity-and-access/ts/seats/meshnodeenroller/index.d.ts index 1312a13..2314949 100644 --- a/identity-and-access/ts/seats/meshnodeenroller/src/index.ts +++ b/identity-and-access/ts/seats/meshnodeenroller/index.d.ts @@ -2,74 +2,52 @@ // The contract of the seat "mesh-node-enroller", defined whole (seats/mesh-node-enroller/seat.json): The seat that enrols a new machine on the operator's Approve and a one-time token (ADR 0587). Renamed from mesh-enrolment (ADR 0634 §9). -export const seat = "mesh-node-enroller"; +export declare const seat: "mesh-node-enroller"; -export const verbs = { - issue: "issue", - redeem: "redeem", - confirm: "confirm", - revoke: "revoke", - tokens: "tokens", - again: "again", -} as const; +export declare const verbs: { + readonly issue: "issue"; + readonly redeem: "redeem"; + readonly confirm: "confirm"; + readonly revoke: "revoke"; + readonly tokens: "tokens"; + readonly again: "again"; +}; -export const events = { - enrolmentIssued: "enrolment-issued", - nodeEnrolled: "node-enrolled", - enrolmentRefused: "enrolment-refused", - enrolmentRevoked: "enrolment-revoked", - enrolmentExpired: "enrolment-expired", -} as const; +export declare const events: { + readonly enrolmentIssued: "enrolment-issued"; + readonly nodeEnrolled: "node-enrolled"; + readonly enrolmentRefused: "enrolment-refused"; + readonly enrolmentRevoked: "enrolment-revoked"; + readonly enrolmentExpired: "enrolment-expired"; +}; -export const family = { name: "mesh-node-enroller.events", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "mesh-node-enroller.events"; readonly maxAgeDays: 7 }; -export const enrolmentIssuedSubject = "mesh.seat.mesh-node-enroller.event.enrolment-issued"; +export declare const enrolmentIssuedSubject: "mesh.seat.mesh-node-enroller.event.enrolment-issued"; -export const nodeEnrolledSubject = "mesh.seat.mesh-node-enroller.event.node-enrolled"; +export declare const nodeEnrolledSubject: "mesh.seat.mesh-node-enroller.event.node-enrolled"; -export const enrolmentRefusedSubject = "mesh.seat.mesh-node-enroller.event.enrolment-refused"; +export declare const enrolmentRefusedSubject: "mesh.seat.mesh-node-enroller.event.enrolment-refused"; -export const enrolmentRevokedSubject = "mesh.seat.mesh-node-enroller.event.enrolment-revoked"; +export declare const enrolmentRevokedSubject: "mesh.seat.mesh-node-enroller.event.enrolment-revoked"; -export const enrolmentExpiredSubject = "mesh.seat.mesh-node-enroller.event.enrolment-expired"; +export declare const enrolmentExpiredSubject: "mesh.seat.mesh-node-enroller.event.enrolment-expired"; -export const states = { - enrolments: "enrolments", -} as const; +export declare const states: { + readonly enrolments: "enrolments"; +}; /** The key of one value of the state enrolments under the form "node.". */ -export function enrolmentsByNodeNodeKey(node: string): string { - return "node." + node; -} +export declare function enrolmentsByNodeNodeKey(node: string): string; /** The parts of a key of the form "node.", or undefined for a key of another form. */ -export function parseEnrolmentsByNodeNodeKey(_key: string): { node: string } | undefined { - let _rest = _key; - if (!_rest.startsWith("node.")) return undefined; - _rest = _rest.slice(5); - if (_rest === "") return undefined; - const node = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node }; -} +export declare function parseEnrolmentsByNodeNodeKey(_key: string): { node: string } | undefined; /** The key of one value of the state enrolments under the form "address.
". */ -export function enrolmentsByAddressAddressKey(address: string): string { - return "address." + address; -} +export declare function enrolmentsByAddressAddressKey(address: string): string; /** The parts of a key of the form "address.
", or undefined for a key of another form. */ -export function parseEnrolmentsByAddressAddressKey(_key: string): { address: string } | undefined { - let _rest = _key; - if (!_rest.startsWith("address.")) return undefined; - _rest = _rest.slice(8); - if (_rest === "") return undefined; - const address = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { address }; -} +export declare function parseEnrolmentsByAddressAddressKey(_key: string): { address: string } | undefined; /** one open enrolment */ export interface Enrolment { diff --git a/identity-and-access/ts/seats/meshnodeenroller/index.js b/identity-and-access/ts/seats/meshnodeenroller/index.js new file mode 100644 index 0000000..23a4fb7 --- /dev/null +++ b/identity-and-access/ts/seats/meshnodeenroller/index.js @@ -0,0 +1,73 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-node-enroller", defined whole (seats/mesh-node-enroller/seat.json): The seat that enrols a new machine on the operator's Approve and a one-time token (ADR 0587). Renamed from mesh-enrolment (ADR 0634 §9). + +export const seat = "mesh-node-enroller"; + +export const verbs = { + issue: "issue", + redeem: "redeem", + confirm: "confirm", + revoke: "revoke", + tokens: "tokens", + again: "again", +}; + +export const events = { + enrolmentIssued: "enrolment-issued", + nodeEnrolled: "node-enrolled", + enrolmentRefused: "enrolment-refused", + enrolmentRevoked: "enrolment-revoked", + enrolmentExpired: "enrolment-expired", +}; + +export const family = { name: "mesh-node-enroller.events", maxAgeDays: 7 }; + +export const enrolmentIssuedSubject = "mesh.seat.mesh-node-enroller.event.enrolment-issued"; + +export const nodeEnrolledSubject = "mesh.seat.mesh-node-enroller.event.node-enrolled"; + +export const enrolmentRefusedSubject = "mesh.seat.mesh-node-enroller.event.enrolment-refused"; + +export const enrolmentRevokedSubject = "mesh.seat.mesh-node-enroller.event.enrolment-revoked"; + +export const enrolmentExpiredSubject = "mesh.seat.mesh-node-enroller.event.enrolment-expired"; + +export const states = { + enrolments: "enrolments", +}; + +/** The key of one value of the state enrolments under the form "node.". */ +export function enrolmentsByNodeNodeKey(node) { + return "node." + node; +} + +/** The parts of a key of the form "node.", or undefined for a key of another form. */ +export function parseEnrolmentsByNodeNodeKey(_key) { + let _rest = _key; + if (!_rest.startsWith("node.")) return undefined; + _rest = _rest.slice(5); + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node }; +} + +/** The key of one value of the state enrolments under the form "address.
". */ +export function enrolmentsByAddressAddressKey(address) { + return "address." + address; +} + +/** The parts of a key of the form "address.
", or undefined for a key of another form. */ +export function parseEnrolmentsByAddressAddressKey(_key) { + let _rest = _key; + if (!_rest.startsWith("address.")) return undefined; + _rest = _rest.slice(8); + if (_rest === "") return undefined; + const address = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { address }; +} + diff --git a/identity-and-access/ts/seats/meshnodeenroller/package-lock.json b/identity-and-access/ts/seats/meshnodeenroller/package-lock.json index 8e7f57d..97f7071 100644 --- a/identity-and-access/ts/seats/meshnodeenroller/package-lock.json +++ b/identity-and-access/ts/seats/meshnodeenroller/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-identity-and-access-contracts-mesh-node-enroller", + "name": "@novox/mesh-contracts-identity-and-access-mesh-node-enroller", "packages": { "": { - "name": "@novox/mesh-identity-and-access-contracts-mesh-node-enroller", + "name": "@novox/mesh-contracts-identity-and-access-mesh-node-enroller", "version": "0.1.0" } }, diff --git a/identity-and-access/ts/seats/meshnodeenroller/package.json b/identity-and-access/ts/seats/meshnodeenroller/package.json index 88192fc..7308ad7 100644 --- a/identity-and-access/ts/seats/meshnodeenroller/package.json +++ b/identity-and-access/ts/seats/meshnodeenroller/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-node-enroller, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-identity-and-access-contracts-mesh-node-enroller", + "name": "@novox/mesh-contracts-identity-and-access-mesh-node-enroller", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/identity-and-access/ts/seats/meshvault/src/index.ts b/identity-and-access/ts/seats/meshvault/index.d.ts similarity index 78% rename from identity-and-access/ts/seats/meshvault/src/index.ts rename to identity-and-access/ts/seats/meshvault/index.d.ts index e3f2c11..9179ae9 100644 --- a/identity-and-access/ts/seats/meshvault/src/index.ts +++ b/identity-and-access/ts/seats/meshvault/index.d.ts @@ -2,131 +2,84 @@ // The contract of the seat "mesh-vault", defined whole (seats/mesh-vault/seat.json): The mesh's secrets. accept and move-asks, which no holder served and nothing called, are left out (ADR 0620 §3). The vault's own events stay under its own subjects (ADR 0620 §2). -export const seat = "mesh-vault"; +export declare const seat: "mesh-vault"; -export const verbs = { - get: "get", - secretAsk: "secret-ask", - issued: "issued", - rotate: "rotate", - moveIn: "move-in", - nodeKey: "node-key", - own: "own", - issueAccount: "issue-account", - sign: "sign", - enrolmentToken: "enrolment-token", - nodeAccount: "node-account", - rotateNode: "rotate-node", - nodeAccountConfirm: "node-account-confirm", - abandon: "abandon", - retire: "retire", -} as const; +export declare const verbs: { + readonly get: "get"; + readonly secretAsk: "secret-ask"; + readonly issued: "issued"; + readonly rotate: "rotate"; + readonly moveIn: "move-in"; + readonly nodeKey: "node-key"; + readonly own: "own"; + readonly issueAccount: "issue-account"; + readonly sign: "sign"; + readonly enrolmentToken: "enrolment-token"; + readonly nodeAccount: "node-account"; + readonly rotateNode: "rotate-node"; + readonly nodeAccountConfirm: "node-account-confirm"; + readonly abandon: "abandon"; + readonly retire: "retire"; +}; -export const holderEvents = { - provisioned: "provisioned", - rotated: "rotated", - secretChanged: "secret-changed", - accountHashed: "account-hashed", - ownReplaced: "own-replaced", - accountIssued: "account-issued", - signed: "signed", - rotationBegun: "rotation-begun", - nodeAccountReady: "node-account-ready", - rotationDone: "rotation-done", - ownRetired: "own-retired", -} as const; +export declare const holderEvents: { + readonly provisioned: "provisioned"; + readonly rotated: "rotated"; + readonly secretChanged: "secret-changed"; + readonly accountHashed: "account-hashed"; + readonly ownReplaced: "own-replaced"; + readonly accountIssued: "account-issued"; + readonly signed: "signed"; + readonly rotationBegun: "rotation-begun"; + readonly nodeAccountReady: "node-account-ready"; + readonly rotationDone: "rotation-done"; + readonly ownRetired: "own-retired"; +}; -export function provisionedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.provisioned"; -} +export declare function provisionedHolderSubject(holder: string): string; -export function rotatedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.rotated"; -} +export declare function rotatedHolderSubject(holder: string): string; -export function secretChangedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.secret-changed"; -} +export declare function secretChangedHolderSubject(holder: string): string; -export function accountHashedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.account-hashed"; -} +export declare function accountHashedHolderSubject(holder: string): string; -export function ownReplacedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.own-replaced"; -} +export declare function ownReplacedHolderSubject(holder: string): string; -export function accountIssuedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.account-issued"; -} +export declare function accountIssuedHolderSubject(holder: string): string; -export function signedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.signed"; -} +export declare function signedHolderSubject(holder: string): string; -export function rotationBegunHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.rotation-begun"; -} +export declare function rotationBegunHolderSubject(holder: string): string; -export function nodeAccountReadyHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.node-account-ready"; -} +export declare function nodeAccountReadyHolderSubject(holder: string): string; -export function rotationDoneHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.rotation-done"; -} +export declare function rotationDoneHolderSubject(holder: string): string; -export function ownRetiredHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.own-retired"; -} +export declare function ownRetiredHolderSubject(holder: string): string; -export const states = { - signers: "signers", - nodeLogins: "node-logins", -} as const; +export declare const states: { + readonly signers: "signers"; + readonly nodeLogins: "node-logins"; +}; /** The key of one value of the state signers under the form "key". */ -export function signersByKeyKey(): string { - return "key"; -} +export declare function signersByKeyKey(): string; /** The parts of a key of the form "key", or undefined for a key of another form. */ -export function parseSignersByKeyKey(_key: string): { } | undefined { - let _rest = _key; - if (!_rest.startsWith("key")) return undefined; - _rest = _rest.slice(3); - if (_rest !== "") return undefined; - return { }; -} +export declare function parseSignersByKeyKey(_key: string): { } | undefined; /** The key of one value of the state signers under the form "authority". */ -export function signersByAuthorityKey(): string { - return "authority"; -} +export declare function signersByAuthorityKey(): string; /** The parts of a key of the form "authority", or undefined for a key of another form. */ -export function parseSignersByAuthorityKey(_key: string): { } | undefined { - let _rest = _key; - if (!_rest.startsWith("authority")) return undefined; - _rest = _rest.slice(9); - if (_rest !== "") return undefined; - return { }; -} +export declare function parseSignersByAuthorityKey(_key: string): { } | undefined; /** The key of one value of the state node-logins under the form "". */ -export function nodeLoginsByNodeKey(node: string): string { - return node; -} +export declare function nodeLoginsByNodeKey(node: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseNodeLoginsByNodeKey(_key: string): { node: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const node = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node }; -} +export declare function parseNodeLoginsByNodeKey(_key: string): { node: string } | undefined; /** is what get takes. */ export interface GetInput { diff --git a/identity-and-access/ts/seats/meshvault/index.js b/identity-and-access/ts/seats/meshvault/index.js new file mode 100644 index 0000000..793695b --- /dev/null +++ b/identity-and-access/ts/seats/meshvault/index.js @@ -0,0 +1,130 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-vault", defined whole (seats/mesh-vault/seat.json): The mesh's secrets. accept and move-asks, which no holder served and nothing called, are left out (ADR 0620 §3). The vault's own events stay under its own subjects (ADR 0620 §2). + +export const seat = "mesh-vault"; + +export const verbs = { + get: "get", + secretAsk: "secret-ask", + issued: "issued", + rotate: "rotate", + moveIn: "move-in", + nodeKey: "node-key", + own: "own", + issueAccount: "issue-account", + sign: "sign", + enrolmentToken: "enrolment-token", + nodeAccount: "node-account", + rotateNode: "rotate-node", + nodeAccountConfirm: "node-account-confirm", + abandon: "abandon", + retire: "retire", +}; + +export const holderEvents = { + provisioned: "provisioned", + rotated: "rotated", + secretChanged: "secret-changed", + accountHashed: "account-hashed", + ownReplaced: "own-replaced", + accountIssued: "account-issued", + signed: "signed", + rotationBegun: "rotation-begun", + nodeAccountReady: "node-account-ready", + rotationDone: "rotation-done", + ownRetired: "own-retired", +}; + +export function provisionedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.provisioned"; +} + +export function rotatedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.rotated"; +} + +export function secretChangedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.secret-changed"; +} + +export function accountHashedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.account-hashed"; +} + +export function ownReplacedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.own-replaced"; +} + +export function accountIssuedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.account-issued"; +} + +export function signedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.signed"; +} + +export function rotationBegunHolderSubject(holder) { + return "mesh.mod." + holder + ".event.rotation-begun"; +} + +export function nodeAccountReadyHolderSubject(holder) { + return "mesh.mod." + holder + ".event.node-account-ready"; +} + +export function rotationDoneHolderSubject(holder) { + return "mesh.mod." + holder + ".event.rotation-done"; +} + +export function ownRetiredHolderSubject(holder) { + return "mesh.mod." + holder + ".event.own-retired"; +} + +export const states = { + signers: "signers", + nodeLogins: "node-logins", +}; + +/** The key of one value of the state signers under the form "key". */ +export function signersByKeyKey() { + return "key"; +} + +/** The parts of a key of the form "key", or undefined for a key of another form. */ +export function parseSignersByKeyKey(_key) { + let _rest = _key; + if (!_rest.startsWith("key")) return undefined; + _rest = _rest.slice(3); + if (_rest !== "") return undefined; + return { }; +} + +/** The key of one value of the state signers under the form "authority". */ +export function signersByAuthorityKey() { + return "authority"; +} + +/** The parts of a key of the form "authority", or undefined for a key of another form. */ +export function parseSignersByAuthorityKey(_key) { + let _rest = _key; + if (!_rest.startsWith("authority")) return undefined; + _rest = _rest.slice(9); + if (_rest !== "") return undefined; + return { }; +} + +/** The key of one value of the state node-logins under the form "". */ +export function nodeLoginsByNodeKey(node) { + return node; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseNodeLoginsByNodeKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node }; +} + diff --git a/identity-and-access/ts/seats/meshvault/package-lock.json b/identity-and-access/ts/seats/meshvault/package-lock.json index c7aa797..76cfe8c 100644 --- a/identity-and-access/ts/seats/meshvault/package-lock.json +++ b/identity-and-access/ts/seats/meshvault/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-identity-and-access-contracts-mesh-vault", + "name": "@novox/mesh-contracts-identity-and-access-mesh-vault", "packages": { "": { - "name": "@novox/mesh-identity-and-access-contracts-mesh-vault", + "name": "@novox/mesh-contracts-identity-and-access-mesh-vault", "version": "0.1.0" } }, diff --git a/identity-and-access/ts/seats/meshvault/package.json b/identity-and-access/ts/seats/meshvault/package.json index 39944e5..a40e57a 100644 --- a/identity-and-access/ts/seats/meshvault/package.json +++ b/identity-and-access/ts/seats/meshvault/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-vault, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-identity-and-access-contracts-mesh-vault", + "name": "@novox/mesh-contracts-identity-and-access-mesh-vault", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/operator-and-conversation/go/seats/operatorchannel/contract.go b/operator-and-conversation/go/seats/operatorchannel/contract.go index 3e36498..4fd1a6d 100644 --- a/operator-and-conversation/go/seats/operatorchannel/contract.go +++ b/operator-and-conversation/go/seats/operatorchannel/contract.go @@ -15,11 +15,12 @@ import ( const Seat = "operator-channel" const ( - VerbOpen = "open" - VerbHistory = "history" - VerbNotify = "notify" - VerbTell = "tell" - VerbAsks = "asks" + VerbOpen = "open" + VerbHistory = "history" + VerbNotify = "notify" + VerbTell = "tell" + VerbAsks = "asks" + VerbAskAgain = "ask-again" ) const ( @@ -34,7 +35,7 @@ const ( // Verbs is every verb the seat serves, in its definition's order: a new copy each call. func Verbs() []string { - return []string{VerbOpen, VerbHistory, VerbNotify, VerbTell, VerbAsks} + return []string{VerbOpen, VerbHistory, VerbNotify, VerbTell, VerbAsks, VerbAskAgain} } // Events is every event published on the seat's subject: a new copy each call. @@ -433,15 +434,17 @@ type AsksInput struct { Key string `json:"key,omitempty"` // only the asks opened at or after this time, RFC 3339 Since string `json:"since,omitempty"` - // open (open and held), ended or all; none is open when no key or since is given, else all + // open (open, held and held-back), ended or all; none is open when no key or since is given, else all State string `json:"state,omitempty"` } // AsksAnswerAsksItem is a type of the contract. type AsksAnswerAsksItem struct { + // when the ask was held back, RFC 3339; present while its state is held-back + HeldSince string `json:"held-since,omitempty"` // . Key string `json:"key"` - // how the ask stands: open, held, or how it ended (answered, expired, cancelled) + // how the ask stands: open, held (no ready channel), held-back (kept open behind the asker's newer asks, ADR 0666 §12), or how it ended (answered, expired, cancelled) State string `json:"state"` } @@ -455,6 +458,19 @@ type AsksAnswer struct { Matched int64 `json:"matched,omitempty"` } +// AskAgainInput is what ask-again takes. +type AskAgainInput struct { + // . of the held-back ask + Key string `json:"key"` +} + +// AskAgainAnswer is what ask-again answers. +type AskAgainAnswer struct { + // why it was not offered; set alone + Error string `json:"error,omitempty"` + State string `json:"state,omitempty"` +} + // AskAccept is the body of ask. type AskAccept = Ask @@ -512,12 +528,14 @@ type AsksByAskerIDValue struct { Expires string `json:"expires"` // its headline Headline string `json:"headline"` + // when the ask was held back, RFC 3339; present while its state is held-back + HeldSince string `json:"held-since,omitempty"` // . Key string `json:"key"` // the channels it was offered on OfferedOn []string `json:"offered_on,omitempty"` // when it was opened, RFC 3339 Opened string `json:"opened"` - // how it stands: open, chosen, expired, cancelled, replaced or refused + // how it stands: open, held-back (kept open behind the asker's newer asks, ADR 0666 §12), chosen, expired, cancelled, replaced or refused State string `json:"state"` } diff --git a/operator-and-conversation/go/seats/operatorchannel/contract_test.go b/operator-and-conversation/go/seats/operatorchannel/contract_test.go index 440ac8a..aa1bd95 100644 --- a/operator-and-conversation/go/seats/operatorchannel/contract_test.go +++ b/operator-and-conversation/go/seats/operatorchannel/contract_test.go @@ -35,6 +35,8 @@ func TestFixtures(t *testing.T) { decode: func(b []byte) (any, error) { var v AsksByAskerIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, {name: "an ask its asker took back (captured)", subject: "", given: "{\"answer\":\"cancelled: its asker took it back\",\"asker\":\"mesh-delivery-teller\",\"asker_told\":true,\"expires\":\"2026-11-06T10:04:01Z\",\"headline\":\"Check failed - merge into main\",\"key\":\"mesh-delivery-teller.merge-feat_registry_milestone-3a038b9f8b4d-4-4da6ee3cd9d5\",\"offered_on\":[\"telegram\"],\"opened\":\"2026-11-05T10:14:04Z\",\"state\":\"cancelled\"}", wire: "{\"answer\":\"cancelled: its asker took it back\",\"asker\":\"mesh-delivery-teller\",\"asker_told\":true,\"expires\":\"2026-11-06T10:04:01Z\",\"headline\":\"Check failed - merge into main\",\"key\":\"mesh-delivery-teller.merge-feat_registry_milestone-3a038b9f8b4d-4-4da6ee3cd9d5\",\"offered_on\":[\"telegram\"],\"opened\":\"2026-11-05T10:14:04Z\",\"state\":\"cancelled\"}", decode: func(b []byte) (any, error) { var v AsksByAskerIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "a fourth ask, the asker's oldest held back behind newer ones", subject: "", given: "{\"asker\":\"mesh-delivery-teller\",\"expires\":\"2026-11-11T10:00:00Z\",\"headline\":\"Check failed - merge into main\",\"held-since\":\"2026-11-10T10:30:00Z\",\"key\":\"mesh-delivery-teller.b-1\",\"opened\":\"2026-11-10T10:00:00Z\",\"state\":\"held-back\"}", wire: "{\"asker\":\"mesh-delivery-teller\",\"expires\":\"2026-11-11T10:00:00Z\",\"headline\":\"Check failed - merge into main\",\"held-since\":\"2026-11-10T10:30:00Z\",\"key\":\"mesh-delivery-teller.b-1\",\"opened\":\"2026-11-10T10:00:00Z\",\"state\":\"held-back\"}", + decode: func(b []byte) (any, error) { var v AsksByAskerIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, } for _, c := range cases { v, err := c.decode([]byte(c.given)) diff --git a/operator-and-conversation/ts/seats/operatorchannel/src/index.ts b/operator-and-conversation/ts/seats/operatorchannel/index.d.ts similarity index 81% rename from operator-and-conversation/ts/seats/operatorchannel/src/index.ts rename to operator-and-conversation/ts/seats/operatorchannel/index.d.ts index ea709f8..43690c4 100644 --- a/operator-and-conversation/ts/seats/operatorchannel/src/index.ts +++ b/operator-and-conversation/ts/seats/operatorchannel/index.d.ts @@ -2,84 +2,58 @@ // The contract of the seat "operator-channel", defined whole (seats/operator-channel/seat.json): Asking a person and answering on a channel (ADR 0259): held by the router, the messenger module, whose manifest declares the seat; written from that seat entry (design 26). -export const seat = "operator-channel"; +export declare const seat: "operator-channel"; -export const verbs = { - open: "open", - history: "history", - notify: "notify", - tell: "tell", - asks: "asks", -} as const; +export declare const verbs: { + readonly open: "open"; + readonly history: "history"; + readonly notify: "notify"; + readonly tell: "tell"; + readonly asks: "asks"; + readonly askAgain: "ask-again"; +}; -export const accepts = { - ask: "ask", - cancel: "cancel", - condition: "condition", -} as const; +export declare const accepts: { + readonly ask: "ask"; + readonly cancel: "cancel"; + readonly condition: "condition"; +}; -export const events = { - decided: "decided", -} as const; +export declare const events: { + readonly decided: "decided"; +}; -export const family = { name: "operator-channel.decided", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "operator-channel.decided"; readonly maxAgeDays: 7 }; -export function decidedSubject(caller: string): string { - return "mesh.seat.operator-channel.event.decided." + caller; -} +export declare function decidedSubject(caller: string): string; -export function askSubject(caller: string): string { - return "mesh.seat.operator-channel.accept.ask." + caller; -} +export declare function askSubject(caller: string): string; -export function cancelSubject(caller: string): string { - return "mesh.seat.operator-channel.accept.cancel." + caller; -} +export declare function cancelSubject(caller: string): string; -export function conditionSubject(caller: string): string { - return "mesh.seat.operator-channel.accept.condition." + caller; -} +export declare function conditionSubject(caller: string): string; -export const holderEvents = { - refused: "refused", - offered: "offered", - closed: "closed", -} as const; +export declare const holderEvents: { + readonly refused: "refused"; + readonly offered: "offered"; + readonly closed: "closed"; +}; -export function refusedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.refused"; -} +export declare function refusedHolderSubject(holder: string): string; -export function offeredHolderSubject(holder: string): string { - return "mesh.stream." + holder + ".event.offered"; -} +export declare function offeredHolderSubject(holder: string): string; -export function closedHolderSubject(holder: string): string { - return "mesh.stream." + holder + ".event.closed"; -} +export declare function closedHolderSubject(holder: string): string; -export const states = { - asks: "asks", -} as const; +export declare const states: { + readonly asks: "asks"; +}; /** The key of one value of the state asks under the form ".". */ -export function asksByAskerIDKey(asker: string, id: string): string { - return asker + "." + id; -} +export declare function asksByAskerIDKey(asker: string, id: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parseAsksByAskerIDKey(_key: string): { asker: string; id: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const asker = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const id = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { asker, id }; -} +export declare function parseAsksByAskerIDKey(_key: string): { asker: string; id: string } | undefined; export interface Ask { /** what it is about: a newer ask about it replaces the older */ @@ -370,14 +344,16 @@ export interface AsksInput { "key"?: string; /** only the asks opened at or after this time, RFC 3339 */ "since"?: string; - /** open (open and held), ended or all; none is open when no key or since is given, else all */ + /** open (open, held and held-back), ended or all; none is open when no key or since is given, else all */ "state"?: string; } export interface AsksAnswerAsksItem { + /** when the ask was held back, RFC 3339; present while its state is held-back */ + "held-since"?: string; /** . */ "key": string; - /** how the ask stands: open, held, or how it ended (answered, expired, cancelled) */ + /** how the ask stands: open, held (no ready channel), held-back (kept open behind the asker's newer asks, ADR 0666 §12), or how it ended (answered, expired, cancelled) */ "state": string; } @@ -391,6 +367,19 @@ export interface AsksAnswer { "matched"?: number; } +/** is what ask-again takes. */ +export interface AskAgainInput { + /** . of the held-back ask */ + "key": string; +} + +/** is what ask-again answers. */ +export interface AskAgainAnswer { + /** why it was not offered; set alone */ + "error"?: string; + "state"?: string; +} + /** is the body of ask. */ export type AskAccept = Ask; @@ -439,13 +428,15 @@ export interface AsksByAskerIDValue { "expires": string; /** its headline */ "headline": string; + /** when the ask was held back, RFC 3339; present while its state is held-back */ + "held-since"?: string; /** . */ "key": string; /** the channels it was offered on */ "offered_on"?: string[]; /** when it was opened, RFC 3339 */ "opened": string; - /** how it stands: open, chosen, expired, cancelled, replaced or refused */ + /** how it stands: open, held-back (kept open behind the asker's newer asks, ADR 0666 §12), chosen, expired, cancelled, replaced or refused */ "state": string; } diff --git a/operator-and-conversation/ts/seats/operatorchannel/index.js b/operator-and-conversation/ts/seats/operatorchannel/index.js new file mode 100644 index 0000000..927f895 --- /dev/null +++ b/operator-and-conversation/ts/seats/operatorchannel/index.js @@ -0,0 +1,84 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "operator-channel", defined whole (seats/operator-channel/seat.json): Asking a person and answering on a channel (ADR 0259): held by the router, the messenger module, whose manifest declares the seat; written from that seat entry (design 26). + +export const seat = "operator-channel"; + +export const verbs = { + open: "open", + history: "history", + notify: "notify", + tell: "tell", + asks: "asks", + askAgain: "ask-again", +}; + +export const accepts = { + ask: "ask", + cancel: "cancel", + condition: "condition", +}; + +export const events = { + decided: "decided", +}; + +export const family = { name: "operator-channel.decided", maxAgeDays: 7 }; + +export function decidedSubject(caller) { + return "mesh.seat.operator-channel.event.decided." + caller; +} + +export function askSubject(caller) { + return "mesh.seat.operator-channel.accept.ask." + caller; +} + +export function cancelSubject(caller) { + return "mesh.seat.operator-channel.accept.cancel." + caller; +} + +export function conditionSubject(caller) { + return "mesh.seat.operator-channel.accept.condition." + caller; +} + +export const holderEvents = { + refused: "refused", + offered: "offered", + closed: "closed", +}; + +export function refusedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.refused"; +} + +export function offeredHolderSubject(holder) { + return "mesh.stream." + holder + ".event.offered"; +} + +export function closedHolderSubject(holder) { + return "mesh.stream." + holder + ".event.closed"; +} + +export const states = { + asks: "asks", +}; + +/** The key of one value of the state asks under the form ".". */ +export function asksByAskerIDKey(asker, id) { + return asker + "." + id; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseAsksByAskerIDKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const asker = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const id = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { asker, id }; +} + diff --git a/operator-and-conversation/ts/seats/operatorchannel/package-lock.json b/operator-and-conversation/ts/seats/operatorchannel/package-lock.json index 3061cb7..27e7d93 100644 --- a/operator-and-conversation/ts/seats/operatorchannel/package-lock.json +++ b/operator-and-conversation/ts/seats/operatorchannel/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-operator-and-conversation-contracts-operator-channel", + "name": "@novox/mesh-contracts-operator-and-conversation-operator-channel", "packages": { "": { - "name": "@novox/mesh-operator-and-conversation-contracts-operator-channel", + "name": "@novox/mesh-contracts-operator-and-conversation-operator-channel", "version": "0.1.0" } }, diff --git a/operator-and-conversation/ts/seats/operatorchannel/package.json b/operator-and-conversation/ts/seats/operatorchannel/package.json index 945f309..1cba008 100644 --- a/operator-and-conversation/ts/seats/operatorchannel/package.json +++ b/operator-and-conversation/ts/seats/operatorchannel/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat operator-channel, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-operator-and-conversation-contracts-operator-channel", + "name": "@novox/mesh-contracts-operator-and-conversation-operator-channel", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/provisioning/ts/seats/meshprovisioner/src/index.ts b/provisioning/ts/seats/meshprovisioner/index.d.ts similarity index 68% rename from provisioning/ts/seats/meshprovisioner/src/index.ts rename to provisioning/ts/seats/meshprovisioner/index.d.ts index 23c0e47..f262167 100644 --- a/provisioning/ts/seats/meshprovisioner/src/index.ts +++ b/provisioning/ts/seats/meshprovisioner/index.d.ts @@ -2,85 +2,34 @@ // The contract of the seat "mesh-provisioner", defined whole (seats/mesh-provisioner/seat.json): The provisioner (ADR 0349): which domain answers which kind of placeholder, what each module needs, what is applied where. -export const seat = "mesh-provisioner"; +export declare const seat: "mesh-provisioner"; -export const verbs = { - provisioning: "provisioning", -} as const; +export declare const verbs: { + readonly provisioning: "provisioning"; +}; -export const states = { - plans: "plans", - provisions: "provisions", -} as const; +export declare const states: { + readonly plans: "plans"; + readonly provisions: "provisions"; +}; /** The key of one value of the state plans under the form ".". */ -export function plansByNodeModuleKey(node: string, module: string): string { - return node + "." + module; -} +export declare function plansByNodeModuleKey(node: string, module: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parsePlansByNodeModuleKey(_key: string): { node: string; module: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const module = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node, module }; -} +export declare function parsePlansByNodeModuleKey(_key: string): { node: string; module: string } | undefined; /** The key of one value of the state provisions under the form "..". */ -export function provisionsByNodeConsumerProvisionKey(node: string, consumer: string, provision: string): string { - return node + "." + consumer + "." + provision; -} +export declare function provisionsByNodeConsumerProvisionKey(node: string, consumer: string, provision: string): string; /** The parts of a key of the form "..", or undefined for a key of another form. */ -export function parseProvisionsByNodeConsumerProvisionKey(_key: string): { node: string; consumer: string; provision: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - const _at2 = _rest.indexOf("."); - if (_at2 <= 0) return undefined; - const consumer = _rest.slice(0, _at2); - _rest = _rest.slice(_at2 + 1); - if (_rest === "") return undefined; - const provision = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node, consumer, provision }; -} +export declare function parseProvisionsByNodeConsumerProvisionKey(_key: string): { node: string; consumer: string; provision: string } | undefined; /** The key of one value of the state provisions under the form "...". */ -export function provisionsByNodeConsumerProvisionLocalKey(node: string, consumer: string, provision: string, local: string): string { - return node + "." + consumer + "." + provision + "." + local; -} +export declare function provisionsByNodeConsumerProvisionLocalKey(node: string, consumer: string, provision: string, local: string): string; /** The parts of a key of the form "...", or undefined for a key of another form. */ -export function parseProvisionsByNodeConsumerProvisionLocalKey(_key: string): { node: string; consumer: string; provision: string; local: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - const _at2 = _rest.indexOf("."); - if (_at2 <= 0) return undefined; - const consumer = _rest.slice(0, _at2); - _rest = _rest.slice(_at2 + 1); - const _at4 = _rest.indexOf("."); - if (_at4 <= 0) return undefined; - const provision = _rest.slice(0, _at4); - _rest = _rest.slice(_at4 + 1); - if (_rest === "") return undefined; - const local = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node, consumer, provision, local }; -} +export declare function parseProvisionsByNodeConsumerProvisionLocalKey(_key: string): { node: string; consumer: string; provision: string; local: string } | undefined; /** is what provisioning takes. */ export interface ProvisioningInput { diff --git a/provisioning/ts/seats/meshprovisioner/index.js b/provisioning/ts/seats/meshprovisioner/index.js new file mode 100644 index 0000000..9e51035 --- /dev/null +++ b/provisioning/ts/seats/meshprovisioner/index.js @@ -0,0 +1,84 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-provisioner", defined whole (seats/mesh-provisioner/seat.json): The provisioner (ADR 0349): which domain answers which kind of placeholder, what each module needs, what is applied where. + +export const seat = "mesh-provisioner"; + +export const verbs = { + provisioning: "provisioning", +}; + +export const states = { + plans: "plans", + provisions: "provisions", +}; + +/** The key of one value of the state plans under the form ".". */ +export function plansByNodeModuleKey(node, module) { + return node + "." + module; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parsePlansByNodeModuleKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const module = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node, module }; +} + +/** The key of one value of the state provisions under the form "..". */ +export function provisionsByNodeConsumerProvisionKey(node, consumer, provision) { + return node + "." + consumer + "." + provision; +} + +/** The parts of a key of the form "..", or undefined for a key of another form. */ +export function parseProvisionsByNodeConsumerProvisionKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + const _at2 = _rest.indexOf("."); + if (_at2 <= 0) return undefined; + const consumer = _rest.slice(0, _at2); + _rest = _rest.slice(_at2 + 1); + if (_rest === "") return undefined; + const provision = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node, consumer, provision }; +} + +/** The key of one value of the state provisions under the form "...". */ +export function provisionsByNodeConsumerProvisionLocalKey(node, consumer, provision, local) { + return node + "." + consumer + "." + provision + "." + local; +} + +/** The parts of a key of the form "...", or undefined for a key of another form. */ +export function parseProvisionsByNodeConsumerProvisionLocalKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + const _at2 = _rest.indexOf("."); + if (_at2 <= 0) return undefined; + const consumer = _rest.slice(0, _at2); + _rest = _rest.slice(_at2 + 1); + const _at4 = _rest.indexOf("."); + if (_at4 <= 0) return undefined; + const provision = _rest.slice(0, _at4); + _rest = _rest.slice(_at4 + 1); + if (_rest === "") return undefined; + const local = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node, consumer, provision, local }; +} + diff --git a/provisioning/ts/seats/meshprovisioner/package-lock.json b/provisioning/ts/seats/meshprovisioner/package-lock.json index fe0cee0..090754f 100644 --- a/provisioning/ts/seats/meshprovisioner/package-lock.json +++ b/provisioning/ts/seats/meshprovisioner/package-lock.json @@ -1,9 +1,9 @@ { "lockfileVersion": 3, - "name": "@novox/mesh-provisioning-contracts-mesh-provisioner", + "name": "@novox/mesh-contracts-provisioning-mesh-provisioner", "packages": { "": { - "name": "@novox/mesh-provisioning-contracts-mesh-provisioner", + "name": "@novox/mesh-contracts-provisioning-mesh-provisioner", "version": "0.1.0" } }, diff --git a/provisioning/ts/seats/meshprovisioner/package.json b/provisioning/ts/seats/meshprovisioner/package.json index 022c75d..4d8b9a7 100644 --- a/provisioning/ts/seats/meshprovisioner/package.json +++ b/provisioning/ts/seats/meshprovisioner/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-provisioner, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], - "name": "@novox/mesh-provisioning-contracts-mesh-provisioner", + "name": "@novox/mesh-contracts-provisioning-mesh-provisioner", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/ts/seats/meshbroker/src/index.ts b/ts/seats/meshbroker/index.d.ts similarity index 55% rename from ts/seats/meshbroker/src/index.ts rename to ts/seats/meshbroker/index.d.ts index a2b85a2..f3b0b53 100644 --- a/ts/seats/meshbroker/src/index.ts +++ b/ts/seats/meshbroker/index.d.ts @@ -2,55 +2,77 @@ // The contract of the seat "mesh-broker", defined whole (seats/mesh-broker/seat.json): The mesh's bus, and the bus state modules ask of it in requires (design 25 § 12). create, apply, recreate and drop are granted to the bus module's own credential alone. -export const seat = "mesh-broker"; +export declare const seat: "mesh-broker"; -export const verbs = { - list: "list", - show: "show", - check: "check", - orphans: "orphans", - create: "create", - apply: "apply", - recreate: "recreate", - drop: "drop", -} as const; +export declare const verbs: { + readonly list: "list"; + readonly show: "show"; + readonly check: "check"; + readonly orphans: "orphans"; + readonly create: "create"; + readonly apply: "apply"; + readonly recreate: "recreate"; + readonly drop: "drop"; + readonly snapshotKept: "snapshot-kept"; + readonly restoreKept: "restore-kept"; +}; -export const events = { - created: "created", - refused: "refused", - drifted: "drifted", - driftCleared: "drift-cleared", - full: "full", - fullCleared: "full-cleared", - orphaned: "orphaned", - recreated: "recreated", - dropped: "dropped", -} as const; +export declare const events: { + readonly created: "created"; + readonly refused: "refused"; + readonly drifted: "drifted"; + readonly driftCleared: "drift-cleared"; + readonly full: "full"; + readonly fullCleared: "full-cleared"; + readonly orphaned: "orphaned"; + readonly recreated: "recreated"; + readonly dropped: "dropped"; +}; -export const family = { name: "mesh-broker.events", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "mesh-broker.events"; readonly maxAgeDays: 7 }; -export const createdSubject = "mesh.seat.mesh-broker.event.created"; +export declare const createdSubject: "mesh.seat.mesh-broker.event.created"; -export const refusedSubject = "mesh.seat.mesh-broker.event.refused"; +export declare const refusedSubject: "mesh.seat.mesh-broker.event.refused"; -export const driftedSubject = "mesh.seat.mesh-broker.event.drifted"; +export declare const driftedSubject: "mesh.seat.mesh-broker.event.drifted"; -export const driftClearedSubject = "mesh.seat.mesh-broker.event.drift-cleared"; +export declare const driftClearedSubject: "mesh.seat.mesh-broker.event.drift-cleared"; -export const fullSubject = "mesh.seat.mesh-broker.event.full"; +export declare const fullSubject: "mesh.seat.mesh-broker.event.full"; -export const fullClearedSubject = "mesh.seat.mesh-broker.event.full-cleared"; +export declare const fullClearedSubject: "mesh.seat.mesh-broker.event.full-cleared"; -export const orphanedSubject = "mesh.seat.mesh-broker.event.orphaned"; +export declare const orphanedSubject: "mesh.seat.mesh-broker.event.orphaned"; -export const recreatedSubject = "mesh.seat.mesh-broker.event.recreated"; +export declare const recreatedSubject: "mesh.seat.mesh-broker.event.recreated"; -export const droppedSubject = "mesh.seat.mesh-broker.event.dropped"; +export declare const droppedSubject: "mesh.seat.mesh-broker.event.dropped"; + +/** live kept data a restore set aside, never removed but by discard-aside */ +export interface Aside { + /** when it was set aside */ + "at"?: string; + /** the form it held */ + "form"?: number; + /** its id, for discard-aside */ + "id": string; + /** the kept data */ + "kept": string; + /** the module */ + "module": string; + /** the name it is kept under on the bus */ + "name": string; + /** its size in bytes */ + "size"?: number; +} /** the binding a module receives in its membership for one entry (ADR 0595 §1, §7) */ export interface Binding { /** the entry's name on the bus */ "bus-name": string; + /** the bus name of the state's -objects, where its large values go (design 47 G 58, 399) */ + "objects"?: string; /** how the bus keeps it */ "storage-type": string; /** its subjects, for a stream */ @@ -109,6 +131,43 @@ export interface Held { "why"?: string; } +/** the catch-up tool and its arguments the restore point records (design 47 G 406) */ +export interface KeptPointCatchUp { + "arguments"?: Record; + "tool": string; +} + +export interface KeptPointConsumersItem { + /** the durable consumer */ + "consumer": string; + /** its acknowledged position */ + "sequence": number; + /** the stream */ + "stream": string; +} + +/** a restore point of one module's kept data on the bus, whole, with its consumers' positions */ +export interface KeptPoint { + /** when it was taken */ + "at"?: string; + /** the catch-up tool and its arguments the restore point records (design 47 G 406) */ + "catch-up"?: KeptPointCatchUp; + /** each durable consumer the module reads with, and its position */ + "consumers"?: KeptPointConsumersItem[]; + /** the fingerprint the restore point is taken before */ + "fingerprint": string; + /** its form, the number the holder raises when it changes how it writes it (0 when undeclared) */ + "form": number; + /** the kept data, its local name in the module's manifest */ + "kept": string; + /** the module */ + "module": string; + /** its size in bytes */ + "size"?: number; + /** the restore point's name */ + "snapshot": string; +} + export interface Named { /** the entry's local name */ "local-name": string; @@ -239,6 +298,64 @@ export interface DropAnswer { "snapshot"?: string; } +/** the catch-up tool the newer manifest declares beside the kept data and its arguments whole, recorded in the restore point (design 47 G 299, 406) */ +export interface SnapshotKeptInputCatchUp { + "arguments"?: Record; + "tool": string; +} + +/** is what snapshot-kept takes. */ +export interface SnapshotKeptInput { + /** the catch-up tool the newer manifest declares beside the kept data and its arguments whole, recorded in the restore point (design 47 G 299, 406) */ + "catch-up"?: SnapshotKeptInputCatchUp; + /** the fingerprint the restore point is taken before */ + "fingerprint": string; + /** its form, the number the holder raises when it changes how it writes it (0 when undeclared) */ + "form": number; + /** the kept data, its local name in the module's manifest */ + "kept": string; + /** the module */ + "module": string; + /** why it is taken */ + "why"?: string; +} + +/** is what snapshot-kept answers. */ +export interface SnapshotKeptAnswer { + /** why it failed; set alone */ + "error"?: string; + "point"?: KeptPoint; +} + +/** is what restore-kept takes. */ +export interface RestoreKeptInput { + /** set the live data aside and restore nothing */ + "aside-only"?: boolean; + /** the name of data set aside: remove it and restore nothing */ + "discard-aside"?: string; + /** the fingerprint the restore point is taken before */ + "fingerprint": string; + /** its form, the number the holder raises when it changes how it writes it (0 when undeclared) */ + "form": number; + /** the kept data, its local name in the module's manifest */ + "kept": string; + /** the module */ + "module": string; + /** the restore point's name; not with aside-only or discard-aside */ + "snapshot"?: string; + /** why */ + "why"?: string; +} + +/** is what restore-kept answers. */ +export interface RestoreKeptAnswer { + "aside"?: Aside; + /** why it failed; set alone */ + "error"?: string; + /** the restore point is the live data now */ + "restored"?: boolean; +} + /** is the body of the event created. */ export type CreatedEvent = Said; diff --git a/ts/seats/meshbroker/index.js b/ts/seats/meshbroker/index.js new file mode 100644 index 0000000..b18e8ba --- /dev/null +++ b/ts/seats/meshbroker/index.js @@ -0,0 +1,51 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-broker", defined whole (seats/mesh-broker/seat.json): The mesh's bus, and the bus state modules ask of it in requires (design 25 § 12). create, apply, recreate and drop are granted to the bus module's own credential alone. + +export const seat = "mesh-broker"; + +export const verbs = { + list: "list", + show: "show", + check: "check", + orphans: "orphans", + create: "create", + apply: "apply", + recreate: "recreate", + drop: "drop", + snapshotKept: "snapshot-kept", + restoreKept: "restore-kept", +}; + +export const events = { + created: "created", + refused: "refused", + drifted: "drifted", + driftCleared: "drift-cleared", + full: "full", + fullCleared: "full-cleared", + orphaned: "orphaned", + recreated: "recreated", + dropped: "dropped", +}; + +export const family = { name: "mesh-broker.events", maxAgeDays: 7 }; + +export const createdSubject = "mesh.seat.mesh-broker.event.created"; + +export const refusedSubject = "mesh.seat.mesh-broker.event.refused"; + +export const driftedSubject = "mesh.seat.mesh-broker.event.drifted"; + +export const driftClearedSubject = "mesh.seat.mesh-broker.event.drift-cleared"; + +export const fullSubject = "mesh.seat.mesh-broker.event.full"; + +export const fullClearedSubject = "mesh.seat.mesh-broker.event.full-cleared"; + +export const orphanedSubject = "mesh.seat.mesh-broker.event.orphaned"; + +export const recreatedSubject = "mesh.seat.mesh-broker.event.recreated"; + +export const droppedSubject = "mesh.seat.mesh-broker.event.dropped"; + diff --git a/ts/seats/meshbroker/package.json b/ts/seats/meshbroker/package.json index 0d845e8..03d00ef 100644 --- a/ts/seats/meshbroker/package.json +++ b/ts/seats/meshbroker/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-broker, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], "name": "@novox/mesh-contracts-mesh-broker", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/ts/seats/meshconfig/src/index.ts b/ts/seats/meshconfig/index.d.ts similarity index 58% rename from ts/seats/meshconfig/src/index.ts rename to ts/seats/meshconfig/index.d.ts index 7a6aa32..3188b8f 100644 --- a/ts/seats/meshconfig/src/index.ts +++ b/ts/seats/meshconfig/index.d.ts @@ -2,98 +2,44 @@ // The contract of the seat "mesh-config", defined whole (seats/mesh-config/seat.json): The mesh's config values: read and set one, and the renames still open. mesh-config's own events stay under its own subjects (ADR 0620 §2). -export const seat = "mesh-config"; +export declare const seat: "mesh-config"; -export const verbs = { - config: "config", - renames: "renames", -} as const; +export declare const verbs: { + readonly config: "config"; + readonly renames: "renames"; +}; -export const holderEvents = { - configChanged: "config-changed", - renamed: "renamed", - retiring: "retiring", - retired: "retired", -} as const; +export declare const holderEvents: { + readonly configChanged: "config-changed"; + readonly renamed: "renamed"; + readonly retiring: "retiring"; + readonly retired: "retired"; +}; -export function configChangedHolderSubject(holder: string): string { - return "mesh.mod." + holder + ".event.config-changed"; -} +export declare function configChangedHolderSubject(holder: string): string; -export function renamedHolderSubject(holder: string): string { - return "mesh.stream." + holder + ".event.renamed"; -} +export declare function renamedHolderSubject(holder: string): string; -export function retiringHolderSubject(holder: string): string { - return "mesh.stream." + holder + ".event.retiring"; -} +export declare function retiringHolderSubject(holder: string): string; -export function retiredHolderSubject(holder: string): string { - return "mesh.stream." + holder + ".event.retired"; -} +export declare function retiredHolderSubject(holder: string): string; -export const states = { - resolved: "resolved", - kept: "kept", -} as const; +export declare const states: { + readonly resolved: "resolved"; + readonly kept: "kept"; +}; /** The key of one value of the state resolved under the form "..". */ -export function resolvedByNodeModuleKeyKey(node: string, module: string, key: string): string { - return node + "." + module + "." + key; -} +export declare function resolvedByNodeModuleKeyKey(node: string, module: string, key: string): string; /** The parts of a key of the form "..", or undefined for a key of another form. */ -export function parseResolvedByNodeModuleKeyKey(_key: string): { node: string; module: string; key: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - const _at2 = _rest.indexOf("."); - if (_at2 <= 0) return undefined; - const module = _rest.slice(0, _at2); - _rest = _rest.slice(_at2 + 1); - if (_rest === "") return undefined; - const key = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node, module, key }; -} +export declare function parseResolvedByNodeModuleKeyKey(_key: string): { node: string; module: string; key: string } | undefined; /** The key of one value of the state kept under the form ".....". */ -export function keptByOwnerRepositoryNumberNodeModuleKeyKey(owner: string, repository: string, number: string, node: string, module: string, key: string): string { - return owner + "." + repository + "." + number + "." + node + "." + module + "." + key; -} +export declare function keptByOwnerRepositoryNumberNodeModuleKeyKey(owner: string, repository: string, number: string, node: string, module: string, key: string): string; /** The parts of a key of the form ".....", or undefined for a key of another form. */ -export function parseKeptByOwnerRepositoryNumberNodeModuleKeyKey(_key: string): { owner: string; repository: string; number: string; node: string; module: string; key: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const owner = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - const _at2 = _rest.indexOf("."); - if (_at2 <= 0) return undefined; - const repository = _rest.slice(0, _at2); - _rest = _rest.slice(_at2 + 1); - const _at4 = _rest.indexOf("."); - if (_at4 <= 0) return undefined; - const number = _rest.slice(0, _at4); - _rest = _rest.slice(_at4 + 1); - const _at6 = _rest.indexOf("."); - if (_at6 <= 0) return undefined; - const node = _rest.slice(0, _at6); - _rest = _rest.slice(_at6 + 1); - const _at8 = _rest.indexOf("."); - if (_at8 <= 0) return undefined; - const module = _rest.slice(0, _at8); - _rest = _rest.slice(_at8 + 1); - if (_rest === "") return undefined; - const key = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { owner, repository, number, node, module, key }; -} +export declare function parseKeptByOwnerRepositoryNumberNodeModuleKeyKey(_key: string): { owner: string; repository: string; number: string; node: string; module: string; key: string } | undefined; /** is what config takes. */ export interface ConfigInput { diff --git a/ts/seats/meshconfig/index.js b/ts/seats/meshconfig/index.js new file mode 100644 index 0000000..aeb7b3b --- /dev/null +++ b/ts/seats/meshconfig/index.js @@ -0,0 +1,97 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-config", defined whole (seats/mesh-config/seat.json): The mesh's config values: read and set one, and the renames still open. mesh-config's own events stay under its own subjects (ADR 0620 §2). + +export const seat = "mesh-config"; + +export const verbs = { + config: "config", + renames: "renames", +}; + +export const holderEvents = { + configChanged: "config-changed", + renamed: "renamed", + retiring: "retiring", + retired: "retired", +}; + +export function configChangedHolderSubject(holder) { + return "mesh.mod." + holder + ".event.config-changed"; +} + +export function renamedHolderSubject(holder) { + return "mesh.stream." + holder + ".event.renamed"; +} + +export function retiringHolderSubject(holder) { + return "mesh.stream." + holder + ".event.retiring"; +} + +export function retiredHolderSubject(holder) { + return "mesh.stream." + holder + ".event.retired"; +} + +export const states = { + resolved: "resolved", + kept: "kept", +}; + +/** The key of one value of the state resolved under the form "..". */ +export function resolvedByNodeModuleKeyKey(node, module, key) { + return node + "." + module + "." + key; +} + +/** The parts of a key of the form "..", or undefined for a key of another form. */ +export function parseResolvedByNodeModuleKeyKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + const _at2 = _rest.indexOf("."); + if (_at2 <= 0) return undefined; + const module = _rest.slice(0, _at2); + _rest = _rest.slice(_at2 + 1); + if (_rest === "") return undefined; + const key = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node, module, key }; +} + +/** The key of one value of the state kept under the form ".....". */ +export function keptByOwnerRepositoryNumberNodeModuleKeyKey(owner, repository, number, node, module, key) { + return owner + "." + repository + "." + number + "." + node + "." + module + "." + key; +} + +/** The parts of a key of the form ".....", or undefined for a key of another form. */ +export function parseKeptByOwnerRepositoryNumberNodeModuleKeyKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const owner = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + const _at2 = _rest.indexOf("."); + if (_at2 <= 0) return undefined; + const repository = _rest.slice(0, _at2); + _rest = _rest.slice(_at2 + 1); + const _at4 = _rest.indexOf("."); + if (_at4 <= 0) return undefined; + const number = _rest.slice(0, _at4); + _rest = _rest.slice(_at4 + 1); + const _at6 = _rest.indexOf("."); + if (_at6 <= 0) return undefined; + const node = _rest.slice(0, _at6); + _rest = _rest.slice(_at6 + 1); + const _at8 = _rest.indexOf("."); + if (_at8 <= 0) return undefined; + const module = _rest.slice(0, _at8); + _rest = _rest.slice(_at8 + 1); + if (_rest === "") return undefined; + const key = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { owner, repository, number, node, module, key }; +} + diff --git a/ts/seats/meshconfig/package.json b/ts/seats/meshconfig/package.json index 3c4108c..fb29dd3 100644 --- a/ts/seats/meshconfig/package.json +++ b/ts/seats/meshconfig/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-config, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], "name": "@novox/mesh-contracts-mesh-config", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/ts/seats/meshmoduleassigner/src/index.ts b/ts/seats/meshmoduleassigner/index.d.ts similarity index 71% rename from ts/seats/meshmoduleassigner/src/index.ts rename to ts/seats/meshmoduleassigner/index.d.ts index 5ce1e00..b0f6280 100644 --- a/ts/seats/meshmoduleassigner/src/index.ts +++ b/ts/seats/meshmoduleassigner/index.d.ts @@ -2,181 +2,88 @@ // The contract of the seat "mesh-module-assigner", defined whole (seats/mesh-module-assigner/seat.json): The seat that places modules on nodes (ADR 0567): the state of assignments and the proposals that change it. -export const seat = "mesh-module-assigner"; +export declare const seat: "mesh-module-assigner"; -export const verbs = { - assignments: "assignments", - proposals: "proposals", - propose: "propose", - withdraw: "withdraw", - again: "again", -} as const; +export declare const verbs: { + readonly assignments: "assignments"; + readonly proposals: "proposals"; + readonly propose: "propose"; + readonly withdraw: "withdraw"; + readonly again: "again"; +}; -export const events = { - assignmentsProposed: "assignments-proposed", - assignmentsWithdrawn: "assignments-withdrawn", - assignmentsJudged: "assignments-judged", - assignmentsChanged: "assignments-changed", -} as const; +export declare const events: { + readonly assignmentsProposed: "assignments-proposed"; + readonly assignmentsWithdrawn: "assignments-withdrawn"; + readonly assignmentsJudged: "assignments-judged"; + readonly assignmentsChanged: "assignments-changed"; +}; -export const family = { name: "mesh-module-assigner.events", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "mesh-module-assigner.events"; readonly maxAgeDays: 7 }; -export const assignmentsProposedSubject = "mesh.seat.mesh-module-assigner.event.assignments-proposed"; +export declare const assignmentsProposedSubject: "mesh.seat.mesh-module-assigner.event.assignments-proposed"; -export const assignmentsWithdrawnSubject = "mesh.seat.mesh-module-assigner.event.assignments-withdrawn"; +export declare const assignmentsWithdrawnSubject: "mesh.seat.mesh-module-assigner.event.assignments-withdrawn"; -export const assignmentsJudgedSubject = "mesh.seat.mesh-module-assigner.event.assignments-judged"; +export declare const assignmentsJudgedSubject: "mesh.seat.mesh-module-assigner.event.assignments-judged"; -export const assignmentsChangedSubject = "mesh.seat.mesh-module-assigner.event.assignments-changed"; +export declare const assignmentsChangedSubject: "mesh.seat.mesh-module-assigner.event.assignments-changed"; -export const states = { - assignments: "assignments", - proposals: "proposals", - candidates: "candidates", - pulses: "pulses", - seatHolders: "seat-holders", -} as const; +export declare const states: { + readonly assignments: "assignments"; + readonly proposals: "proposals"; + readonly candidates: "candidates"; + readonly pulses: "pulses"; + readonly seatHolders: "seat-holders"; +}; /** The key of one value of the state assignments under the form ".node". */ -export function assignmentsByNodeNodeKey(node: string): string { - return node + ".node"; -} +export declare function assignmentsByNodeNodeKey(node: string): string; /** The parts of a key of the form ".node", or undefined for a key of another form. */ -export function parseAssignmentsByNodeNodeKey(_key: string): { node: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf(".node"); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 5); - if (_rest !== "") return undefined; - return { node }; -} +export declare function parseAssignmentsByNodeNodeKey(_key: string): { node: string } | undefined; /** The key of one value of the state assignments under the form ".". */ -export function assignmentsByNodeModuleKey(node: string, module: string): string { - return node + "." + module; -} +export declare function assignmentsByNodeModuleKey(node: string, module: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parseAssignmentsByNodeModuleKey(_key: string): { node: string; module: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const module = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node, module }; -} +export declare function parseAssignmentsByNodeModuleKey(_key: string): { node: string; module: string } | undefined; /** The key of one value of the state proposals under the form "". */ -export function proposalsByProposalKey(proposal: string): string { - return proposal; -} +export declare function proposalsByProposalKey(proposal: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseProposalsByProposalKey(_key: string): { proposal: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const proposal = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { proposal }; -} +export declare function parseProposalsByProposalKey(_key: string): { proposal: string } | undefined; /** The key of one value of the state candidates under the form ".". */ -export function candidatesByProposalNodeKey(proposal: string, node: string): string { - return proposal + "." + node; -} +export declare function candidatesByProposalNodeKey(proposal: string, node: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parseCandidatesByProposalNodeKey(_key: string): { proposal: string; node: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const proposal = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const node = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { proposal, node }; -} +export declare function parseCandidatesByProposalNodeKey(_key: string): { proposal: string; node: string } | undefined; /** The key of one value of the state pulses under the form "answer..". */ -export function pulsesByAnswerProposalNodeKey(proposal: string, node: string): string { - return "answer." + proposal + "." + node; -} +export declare function pulsesByAnswerProposalNodeKey(proposal: string, node: string): string; /** The parts of a key of the form "answer..", or undefined for a key of another form. */ -export function parsePulsesByAnswerProposalNodeKey(_key: string): { proposal: string; node: string } | undefined { - let _rest = _key; - if (!_rest.startsWith("answer.")) return undefined; - _rest = _rest.slice(7); - const _at1 = _rest.indexOf("."); - if (_at1 <= 0) return undefined; - const proposal = _rest.slice(0, _at1); - _rest = _rest.slice(_at1 + 1); - if (_rest === "") return undefined; - const node = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { proposal, node }; -} +export declare function parsePulsesByAnswerProposalNodeKey(_key: string): { proposal: string; node: string } | undefined; /** The key of one value of the state pulses under the form "ask.". */ -export function pulsesByAskProposalKey(proposal: string): string { - return "ask." + proposal; -} +export declare function pulsesByAskProposalKey(proposal: string): string; /** The parts of a key of the form "ask.", or undefined for a key of another form. */ -export function parsePulsesByAskProposalKey(_key: string): { proposal: string } | undefined { - let _rest = _key; - if (!_rest.startsWith("ask.")) return undefined; - _rest = _rest.slice(4); - if (_rest === "") return undefined; - const proposal = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { proposal }; -} +export declare function parsePulsesByAskProposalKey(_key: string): { proposal: string } | undefined; /** The key of one value of the state seat-holders under the form "". */ -export function seatHoldersBySeatKey(seat: string): string { - return seat; -} +export declare function seatHoldersBySeatKey(seat: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseSeatHoldersBySeatKey(_key: string): { seat: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const seat = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { seat }; -} +export declare function parseSeatHoldersBySeatKey(_key: string): { seat: string } | undefined; /** The key of one value of the state seat-holders under the form ".". */ -export function seatHoldersBySeatNodeKey(seat: string, node: string): string { - return seat + "." + node; -} +export declare function seatHoldersBySeatNodeKey(seat: string, node: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parseSeatHoldersBySeatNodeKey(_key: string): { seat: string; node: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const seat = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const node = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { seat, node }; -} +export declare function parseSeatHoldersBySeatNodeKey(_key: string): { seat: string; node: string } | undefined; /** one node's assignments assembled */ export interface Assignments { @@ -259,6 +166,10 @@ export interface NodeDecided { export interface PlacedModule { /** by provision, the provider each requirement that keeps data is bound to */ "bindings"?: Record; + /** the watched branch this node runs the module from; absent, the first watched branch of the module's registration (design 47 G 14) */ + "branch"?: string; + /** the fingerprint of the build the node runs; absent, the newest delivered of the branch (design 47 G 78, 402) */ + "build"?: string; "has-layer"?: boolean; "has-mesh-wide"?: boolean; /** this node's settings layer of the module's assignments */ @@ -310,6 +221,10 @@ export interface ProposalChangeKeys { /** one change of a proposal */ export interface ProposalChange { "bindings"?: Record; + /** for place, the watched branch the node runs the module from; absent, the first watched branch of the module's registration (design 47 G 14) */ + "branch"?: string; + /** for place, the build of that branch the node runs, a return to an earlier build being this one value; absent, the newest delivered of the branch (ADR 0666 section 24) */ + "build"?: string; "claim"?: string; "decided"?: NodeDecided; "field"?: string; diff --git a/ts/seats/meshmoduleassigner/index.js b/ts/seats/meshmoduleassigner/index.js new file mode 100644 index 0000000..654af67 --- /dev/null +++ b/ts/seats/meshmoduleassigner/index.js @@ -0,0 +1,180 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "mesh-module-assigner", defined whole (seats/mesh-module-assigner/seat.json): The seat that places modules on nodes (ADR 0567): the state of assignments and the proposals that change it. + +export const seat = "mesh-module-assigner"; + +export const verbs = { + assignments: "assignments", + proposals: "proposals", + propose: "propose", + withdraw: "withdraw", + again: "again", +}; + +export const events = { + assignmentsProposed: "assignments-proposed", + assignmentsWithdrawn: "assignments-withdrawn", + assignmentsJudged: "assignments-judged", + assignmentsChanged: "assignments-changed", +}; + +export const family = { name: "mesh-module-assigner.events", maxAgeDays: 7 }; + +export const assignmentsProposedSubject = "mesh.seat.mesh-module-assigner.event.assignments-proposed"; + +export const assignmentsWithdrawnSubject = "mesh.seat.mesh-module-assigner.event.assignments-withdrawn"; + +export const assignmentsJudgedSubject = "mesh.seat.mesh-module-assigner.event.assignments-judged"; + +export const assignmentsChangedSubject = "mesh.seat.mesh-module-assigner.event.assignments-changed"; + +export const states = { + assignments: "assignments", + proposals: "proposals", + candidates: "candidates", + pulses: "pulses", + seatHolders: "seat-holders", +}; + +/** The key of one value of the state assignments under the form ".node". */ +export function assignmentsByNodeNodeKey(node) { + return node + ".node"; +} + +/** The parts of a key of the form ".node", or undefined for a key of another form. */ +export function parseAssignmentsByNodeNodeKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf(".node"); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 5); + if (_rest !== "") return undefined; + return { node }; +} + +/** The key of one value of the state assignments under the form ".". */ +export function assignmentsByNodeModuleKey(node, module) { + return node + "." + module; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseAssignmentsByNodeModuleKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const module = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node, module }; +} + +/** The key of one value of the state proposals under the form "". */ +export function proposalsByProposalKey(proposal) { + return proposal; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseProposalsByProposalKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const proposal = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { proposal }; +} + +/** The key of one value of the state candidates under the form ".". */ +export function candidatesByProposalNodeKey(proposal, node) { + return proposal + "." + node; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseCandidatesByProposalNodeKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const proposal = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { proposal, node }; +} + +/** The key of one value of the state pulses under the form "answer..". */ +export function pulsesByAnswerProposalNodeKey(proposal, node) { + return "answer." + proposal + "." + node; +} + +/** The parts of a key of the form "answer..", or undefined for a key of another form. */ +export function parsePulsesByAnswerProposalNodeKey(_key) { + let _rest = _key; + if (!_rest.startsWith("answer.")) return undefined; + _rest = _rest.slice(7); + const _at1 = _rest.indexOf("."); + if (_at1 <= 0) return undefined; + const proposal = _rest.slice(0, _at1); + _rest = _rest.slice(_at1 + 1); + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { proposal, node }; +} + +/** The key of one value of the state pulses under the form "ask.". */ +export function pulsesByAskProposalKey(proposal) { + return "ask." + proposal; +} + +/** The parts of a key of the form "ask.", or undefined for a key of another form. */ +export function parsePulsesByAskProposalKey(_key) { + let _rest = _key; + if (!_rest.startsWith("ask.")) return undefined; + _rest = _rest.slice(4); + if (_rest === "") return undefined; + const proposal = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { proposal }; +} + +/** The key of one value of the state seat-holders under the form "". */ +export function seatHoldersBySeatKey(seat) { + return seat; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseSeatHoldersBySeatKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const seat = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { seat }; +} + +/** The key of one value of the state seat-holders under the form ".". */ +export function seatHoldersBySeatNodeKey(seat, node) { + return seat + "." + node; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseSeatHoldersBySeatNodeKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const seat = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { seat, node }; +} + diff --git a/ts/seats/meshmoduleassigner/package.json b/ts/seats/meshmoduleassigner/package.json index e7e83e9..5d8ff33 100644 --- a/ts/seats/meshmoduleassigner/package.json +++ b/ts/seats/meshmoduleassigner/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat mesh-module-assigner, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], "name": "@novox/mesh-contracts-mesh-module-assigner", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" } diff --git a/ts/seats/nodeengine/src/index.ts b/ts/seats/nodeengine/index.d.ts similarity index 81% rename from ts/seats/nodeengine/src/index.ts rename to ts/seats/nodeengine/index.d.ts index d68248e..78d31e4 100644 --- a/ts/seats/nodeengine/src/index.ts +++ b/ts/seats/nodeengine/index.d.ts @@ -1,196 +1,116 @@ // Code generated by seatgen from the seat definitions; DO NOT EDIT. -// The contract of the seat "node-engine", defined whole (seats/node-engine/seat.json): The node seat every node's engine holds (novox/hq ADR 0563, ADR 0618 §3, §4): its hand acts on the operator's warrant, its read-only judgements, its compositions and what it reads of a manifest. Each verb is answered on this node's subject, mesh.seat.node-engine.tool.., and each event is published on mesh.seat.node-engine.event.., the node's name its last token. +// The contract of the seat "node-engine", defined whole (seats/node-engine/seat.json): The node seat every node's engine holds (novox/hq ADR 0563, ADR 0618 §3, §4): its hand acts on the operator's warrant, its read-only judgements, its compositions and what it reads of a manifest. Each verb is answered on this node's subject, mesh.seat.node-engine.tool.., and each event is published on mesh.seat.node-engine.event.., the node's name its last token, or, for an event whose subject names , there (composed., running..): the grants part grants a node's account only its own node's subjects (ADR 0363 §2). -export const seat = "node-engine"; +export declare const seat: "node-engine"; -export const verbs = { - handOver: "hand-over", - accessAct: "access-act", - judgeDirectories: "judge-directories", - setuidSearch: "setuid-search", - rootFree: "root-free", - acts: "acts", - packages: "packages", - composition: "composition", - compose: "compose", - composeCandidate: "compose-candidate", - manifestReads: "manifest-reads", - seatList: "seat-list", - seatListAgain: "seat-list-again", -} as const; +export declare const verbs: { + readonly handOver: "hand-over"; + readonly accessAct: "access-act"; + readonly judgeDirectories: "judge-directories"; + readonly setuidSearch: "setuid-search"; + readonly rootFree: "root-free"; + readonly acts: "acts"; + readonly packages: "packages"; + readonly composition: "composition"; + readonly compose: "compose"; + readonly composeCandidate: "compose-candidate"; + readonly manifestReads: "manifest-reads"; + readonly seatList: "seat-list"; + readonly seatListAgain: "seat-list-again"; + readonly processBuilds: "process-builds"; +}; -export const events = { - asked: "asked", - done: "done", - refused: "refused", - manifestReadsChanged: "manifest-reads-changed", -} as const; +export declare const events: { + readonly asked: "asked"; + readonly done: "done"; + readonly refused: "refused"; + readonly manifestReadsChanged: "manifest-reads-changed"; + readonly composed: "composed"; + readonly running: "running"; + readonly capabilitiesChanged: "capabilities-changed"; +}; -export const family = { name: "node-engine.events", maxAgeDays: 7 } as const; +export declare const family: { readonly name: "node-engine.events"; readonly maxAgeDays: 7 }; -export function askedSubject(caller: string): string { - return "mesh.seat.node-engine.event.asked." + caller; -} +export declare function askedSubject(caller: string): string; -export function doneSubject(caller: string): string { - return "mesh.seat.node-engine.event.done." + caller; -} +export declare function doneSubject(caller: string): string; -export function refusedSubject(caller: string): string { - return "mesh.seat.node-engine.event.refused." + caller; -} +export declare function refusedSubject(caller: string): string; -export function manifestReadsChangedSubject(caller: string): string { - return "mesh.seat.node-engine.event.manifest-reads-changed." + caller; -} +export declare function manifestReadsChangedSubject(caller: string): string; -export const states = { - have: "have", - composed: "composed", - data: "data", - packages: "packages", - health: "health", - findings: "findings", -} as const; +export declare function composedSubject(node: string): string; + +export declare const composedSubjectAll: "mesh.seat.node-engine.event.composed.*"; + +export declare const runningStream: "SEAT_node-engine_running"; + +export declare function runningSubject(node: string, module: string): string; + +export declare const runningSubjectAll: "mesh.seat.node-engine.event.running.*.*"; + +export declare function capabilitiesChangedSubject(node: string): string; + +export declare const capabilitiesChangedSubjectAll: "mesh.seat.node-engine.event.capabilities-changed.*"; + +export declare const states: { + readonly have: "have"; + readonly composed: "composed"; + readonly data: "data"; + readonly packages: "packages"; + readonly health: "health"; + readonly findings: "findings"; +}; /** The key of one value of the state have under the form ".". */ -export function haveByNodeModuleKey(node: string, module: string): string { - return node + "." + module; -} +export declare function haveByNodeModuleKey(node: string, module: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parseHaveByNodeModuleKey(_key: string): { node: string; module: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const module = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node, module }; -} +export declare function parseHaveByNodeModuleKey(_key: string): { node: string; module: string } | undefined; /** The key of one value of the state have under the form ".node". */ -export function haveByNodeNodeKey(node: string): string { - return node + ".node"; -} +export declare function haveByNodeNodeKey(node: string): string; /** The parts of a key of the form ".node", or undefined for a key of another form. */ -export function parseHaveByNodeNodeKey(_key: string): { node: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf(".node"); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 5); - if (_rest !== "") return undefined; - return { node }; -} +export declare function parseHaveByNodeNodeKey(_key: string): { node: string } | undefined; /** The key of one value of the state composed under the form "..". */ -export function composedByNodeModuleFingerprintKey(node: string, module: string, fingerprint: string): string { - return node + "." + module + "." + fingerprint; -} +export declare function composedByNodeModuleFingerprintKey(node: string, module: string, fingerprint: string): string; /** The parts of a key of the form "..", or undefined for a key of another form. */ -export function parseComposedByNodeModuleFingerprintKey(_key: string): { node: string; module: string; fingerprint: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - const _at2 = _rest.indexOf("."); - if (_at2 <= 0) return undefined; - const module = _rest.slice(0, _at2); - _rest = _rest.slice(_at2 + 1); - if (_rest === "") return undefined; - const fingerprint = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node, module, fingerprint }; -} +export declare function parseComposedByNodeModuleFingerprintKey(_key: string): { node: string; module: string; fingerprint: string } | undefined; /** The key of one value of the state composed under the form ".node". */ -export function composedByNodeNodeKey(node: string): string { - return node + ".node"; -} +export declare function composedByNodeNodeKey(node: string): string; /** The parts of a key of the form ".node", or undefined for a key of another form. */ -export function parseComposedByNodeNodeKey(_key: string): { node: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf(".node"); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 5); - if (_rest !== "") return undefined; - return { node }; -} +export declare function parseComposedByNodeNodeKey(_key: string): { node: string } | undefined; /** The key of one value of the state data under the form ".". */ -export function dataByNodeModuleKey(node: string, module: string): string { - return node + "." + module; -} +export declare function dataByNodeModuleKey(node: string, module: string): string; /** The parts of a key of the form ".", or undefined for a key of another form. */ -export function parseDataByNodeModuleKey(_key: string): { node: string; module: string } | undefined { - let _rest = _key; - const _at0 = _rest.indexOf("."); - if (_at0 <= 0) return undefined; - const node = _rest.slice(0, _at0); - _rest = _rest.slice(_at0 + 1); - if (_rest === "") return undefined; - const module = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node, module }; -} +export declare function parseDataByNodeModuleKey(_key: string): { node: string; module: string } | undefined; /** The key of one value of the state packages under the form "". */ -export function packagesByNodeKey(node: string): string { - return node; -} +export declare function packagesByNodeKey(node: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parsePackagesByNodeKey(_key: string): { node: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const node = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node }; -} +export declare function parsePackagesByNodeKey(_key: string): { node: string } | undefined; /** The key of one value of the state health under the form "". */ -export function healthByNodeKey(node: string): string { - return node; -} +export declare function healthByNodeKey(node: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseHealthByNodeKey(_key: string): { node: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const node = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { node }; -} +export declare function parseHealthByNodeKey(_key: string): { node: string } | undefined; /** The key of one value of the state findings under the form "". */ -export function findingsByKeyKey(key: string): string { - return key; -} +export declare function findingsByKeyKey(key: string): string; /** The parts of a key of the form "", or undefined for a key of another form. */ -export function parseFindingsByKeyKey(_key: string): { key: string } | undefined { - let _rest = _key; - if (_rest === "") return undefined; - const key = _rest; - _rest = ""; - if (_rest !== "") return undefined; - return { key }; -} +export declare function parseFindingsByKeyKey(_key: string): { key: string } | undefined; /** the hashes of the users of the list, sealed to the vault */ export interface AccountsHanded { @@ -347,6 +267,34 @@ export interface CandidateRefusal { "why": string; } +/** a node's capabilities changed, which the assigner places by */ +export interface CapabilitiesChanged { + /** when, RFC 3339 */ + "at": string; + /** its capabilities now */ + "capabilities": string[]; + /** the node */ + "node": string; + /** the layout's version */ + "v": number; +} + +/** an entry composed on a node (design 47 *What each step says*) */ +export interface Composed { + /** when, RFC 3339 */ + "at": string; + /** the digest of the composition (design 47 G 404) */ + "digest": string; + /** the fingerprint of the want composed */ + "fingerprint": string; + /** the module */ + "module": string; + /** the node */ + "node": string; + /** the layout's version */ + "v": number; +} + /** a group */ export interface DeclaredGroup { "gid": number; @@ -547,6 +495,32 @@ export interface PlacedDataItem { "protection"?: string; } +/** the build one process of a module was started with */ +export interface ProcessBuild { + /** the fingerprint handed to it in MESH_FINGERPRINT; empty when it was started without one */ + "fingerprint"?: string; + /** service or container */ + "kind": "service" | "container"; + /** the module */ + "module": string; + /** the service's unit or the container's name */ + "process": string; + /** when it was started, RFC 3339 */ + "started"?: string; + /** why its build is unknown: started before the node-engine handed MESH_FINGERPRINT, or the value could not be read */ + "unknown"?: string; +} + +/** what process-builds answers */ +export interface ProcessBuilds { + /** why they could not be read */ + "error"?: string; + /** the node */ + "node": string; + /** every process the node-engine started, by module */ + "processes": ProcessBuild[]; +} + /** the pull from a store a failed apply waits on */ export interface PullWait { /** when the pull began */ @@ -601,6 +575,24 @@ export interface RootVerdict { "why": string; } +/** a module running healthy on a node at a build: what the node-engines of other nodes and the grants part decide a seat's pass from (ADR 0660 §2), kept last per subject with no age limit */ +export interface Running { + /** when it was seen running healthy, RFC 3339 */ + "at": string; + /** the fingerprint of the build it runs; none with stopped */ + "fingerprint"?: string; + /** the digest of that build's manifest, the indexer's manifest of it, read by digest from the catalog half */ + "manifest"?: string; + /** the module */ + "module": string; + /** the node */ + "node": string; + /** true when the module no longer runs on the node: no fingerprint or manifest then (design 47 G 365, 404); mesh-sdk's SeatsToPassOn counts such a module as not running there */ + "stopped"?: boolean; + /** the layout's version */ + "v": number; +} + /** the answer of a read-only judgement */ export interface Said { /** the node */ @@ -999,6 +991,15 @@ export interface SeatListAgainInput { /** is what seat-list-again answers. */ export type SeatListAgainAnswer = SeatList; +/** is what process-builds takes. */ +export interface ProcessBuildsInput { + /** only this module's processes */ + "module"?: string; +} + +/** is what process-builds answers. */ +export type ProcessBuildsAnswer = ProcessBuilds; + /** is the body of the event asked. */ export type AskedEvent = ActSaid; @@ -1011,6 +1012,15 @@ export type RefusedEvent = ActSaid; /** is the body of the event manifest-reads-changed. */ export type ManifestReadsChangedEvent = ManifestReadsChanged; +/** is the body of the event composed. */ +export type ComposedEvent = Composed; + +/** is the body of the event running. */ +export type RunningEvent = Running; + +/** is the body of the event capabilities-changed. */ +export type CapabilitiesChangedEvent = CapabilitiesChanged; + /** is one value of the state have under the key .. */ export interface HaveByNodeModuleValue { "build"?: string; diff --git a/ts/seats/nodeengine/index.js b/ts/seats/nodeengine/index.js new file mode 100644 index 0000000..1cb7831 --- /dev/null +++ b/ts/seats/nodeengine/index.js @@ -0,0 +1,218 @@ +// Code generated by seatgen from the seat definitions; DO NOT EDIT. + +// The contract of the seat "node-engine", defined whole (seats/node-engine/seat.json): The node seat every node's engine holds (novox/hq ADR 0563, ADR 0618 §3, §4): its hand acts on the operator's warrant, its read-only judgements, its compositions and what it reads of a manifest. Each verb is answered on this node's subject, mesh.seat.node-engine.tool.., and each event is published on mesh.seat.node-engine.event.., the node's name its last token, or, for an event whose subject names , there (composed., running..): the grants part grants a node's account only its own node's subjects (ADR 0363 §2). + +export const seat = "node-engine"; + +export const verbs = { + handOver: "hand-over", + accessAct: "access-act", + judgeDirectories: "judge-directories", + setuidSearch: "setuid-search", + rootFree: "root-free", + acts: "acts", + packages: "packages", + composition: "composition", + compose: "compose", + composeCandidate: "compose-candidate", + manifestReads: "manifest-reads", + seatList: "seat-list", + seatListAgain: "seat-list-again", + processBuilds: "process-builds", +}; + +export const events = { + asked: "asked", + done: "done", + refused: "refused", + manifestReadsChanged: "manifest-reads-changed", + composed: "composed", + running: "running", + capabilitiesChanged: "capabilities-changed", +}; + +export const family = { name: "node-engine.events", maxAgeDays: 7 }; + +export function askedSubject(caller) { + return "mesh.seat.node-engine.event.asked." + caller; +} + +export function doneSubject(caller) { + return "mesh.seat.node-engine.event.done." + caller; +} + +export function refusedSubject(caller) { + return "mesh.seat.node-engine.event.refused." + caller; +} + +export function manifestReadsChangedSubject(caller) { + return "mesh.seat.node-engine.event.manifest-reads-changed." + caller; +} + +export function composedSubject(node) { + return "mesh.seat.node-engine.event.composed." + node; +} + +export const composedSubjectAll = "mesh.seat.node-engine.event.composed.*"; + +export const runningStream = "SEAT_node-engine_running"; + +export function runningSubject(node, module) { + return "mesh.seat.node-engine.event.running." + node + "." + module; +} + +export const runningSubjectAll = "mesh.seat.node-engine.event.running.*.*"; + +export function capabilitiesChangedSubject(node) { + return "mesh.seat.node-engine.event.capabilities-changed." + node; +} + +export const capabilitiesChangedSubjectAll = "mesh.seat.node-engine.event.capabilities-changed.*"; + +export const states = { + have: "have", + composed: "composed", + data: "data", + packages: "packages", + health: "health", + findings: "findings", +}; + +/** The key of one value of the state have under the form ".". */ +export function haveByNodeModuleKey(node, module) { + return node + "." + module; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseHaveByNodeModuleKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const module = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node, module }; +} + +/** The key of one value of the state have under the form ".node". */ +export function haveByNodeNodeKey(node) { + return node + ".node"; +} + +/** The parts of a key of the form ".node", or undefined for a key of another form. */ +export function parseHaveByNodeNodeKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf(".node"); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 5); + if (_rest !== "") return undefined; + return { node }; +} + +/** The key of one value of the state composed under the form "..". */ +export function composedByNodeModuleFingerprintKey(node, module, fingerprint) { + return node + "." + module + "." + fingerprint; +} + +/** The parts of a key of the form "..", or undefined for a key of another form. */ +export function parseComposedByNodeModuleFingerprintKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + const _at2 = _rest.indexOf("."); + if (_at2 <= 0) return undefined; + const module = _rest.slice(0, _at2); + _rest = _rest.slice(_at2 + 1); + if (_rest === "") return undefined; + const fingerprint = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node, module, fingerprint }; +} + +/** The key of one value of the state composed under the form ".node". */ +export function composedByNodeNodeKey(node) { + return node + ".node"; +} + +/** The parts of a key of the form ".node", or undefined for a key of another form. */ +export function parseComposedByNodeNodeKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf(".node"); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 5); + if (_rest !== "") return undefined; + return { node }; +} + +/** The key of one value of the state data under the form ".". */ +export function dataByNodeModuleKey(node, module) { + return node + "." + module; +} + +/** The parts of a key of the form ".", or undefined for a key of another form. */ +export function parseDataByNodeModuleKey(_key) { + let _rest = _key; + const _at0 = _rest.indexOf("."); + if (_at0 <= 0) return undefined; + const node = _rest.slice(0, _at0); + _rest = _rest.slice(_at0 + 1); + if (_rest === "") return undefined; + const module = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node, module }; +} + +/** The key of one value of the state packages under the form "". */ +export function packagesByNodeKey(node) { + return node; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parsePackagesByNodeKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node }; +} + +/** The key of one value of the state health under the form "". */ +export function healthByNodeKey(node) { + return node; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseHealthByNodeKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const node = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { node }; +} + +/** The key of one value of the state findings under the form "". */ +export function findingsByKeyKey(key) { + return key; +} + +/** The parts of a key of the form "", or undefined for a key of another form. */ +export function parseFindingsByKeyKey(_key) { + let _rest = _key; + if (_rest === "") return undefined; + const key = _rest; + _rest = ""; + if (_rest !== "") return undefined; + return { key }; +} + diff --git a/ts/seats/nodeengine/package.json b/ts/seats/nodeengine/package.json index b7ac56a..1f2319e 100644 --- a/ts/seats/nodeengine/package.json +++ b/ts/seats/nodeengine/package.json @@ -1,13 +1,18 @@ { "description": "The contract of the seat node-engine, generated from its definition.", "exports": { - ".": "./src/index.ts" + ".": { + "default": "./index.js", + "types": "./index.d.ts" + } }, "files": [ - "src" + "index.js", + "index.d.ts", + "parts" ], "name": "@novox/mesh-contracts-node-engine", "type": "module", - "types": "./src/index.ts", + "types": "./index.d.ts", "version": "0.1.0" }