@aeolus-fleet/core 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/LICENSE +201 -0
  2. package/dist/adapters/prisma/generated/browser.d.ts +25 -0
  3. package/dist/adapters/prisma/generated/client.d.ts +25 -0
  4. package/dist/adapters/prisma/generated/internal/class.d.ts +44 -0
  5. package/dist/adapters/prisma/generated/internal/class.js +4 -4
  6. package/dist/adapters/prisma/generated/internal/class.js.map +1 -1
  7. package/dist/adapters/prisma/generated/internal/prismaNamespace.d.ts +338 -1
  8. package/dist/adapters/prisma/generated/internal/prismaNamespace.js +34 -1
  9. package/dist/adapters/prisma/generated/internal/prismaNamespace.js.map +1 -1
  10. package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.d.ts +37 -0
  11. package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.js +34 -1
  12. package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.js.map +1 -1
  13. package/dist/adapters/prisma/generated/models/CrewRequest.d.ts +103 -1
  14. package/dist/adapters/prisma/generated/models/Fleet.d.ts +860 -0
  15. package/dist/adapters/prisma/generated/models/Label.d.ts +1475 -0
  16. package/dist/adapters/prisma/generated/models/Label.js +2 -0
  17. package/dist/adapters/prisma/generated/models/Label.js.map +1 -0
  18. package/dist/adapters/prisma/generated/models/LabelValue.d.ts +1454 -0
  19. package/dist/adapters/prisma/generated/models/LabelValue.js +2 -0
  20. package/dist/adapters/prisma/generated/models/LabelValue.js.map +1 -0
  21. package/dist/adapters/prisma/generated/models/Ship.d.ts +1225 -70
  22. package/dist/adapters/prisma/generated/models/ShipLabel.d.ts +1431 -0
  23. package/dist/adapters/prisma/generated/models/ShipLabel.js +2 -0
  24. package/dist/adapters/prisma/generated/models/ShipLabel.js.map +1 -0
  25. package/dist/adapters/prisma/generated/models/WorktreeClearRequest.d.ts +1539 -0
  26. package/dist/adapters/prisma/generated/models/WorktreeClearRequest.js +2 -0
  27. package/dist/adapters/prisma/generated/models/WorktreeClearRequest.js.map +1 -0
  28. package/dist/adapters/prisma/generated/models.d.ts +4 -0
  29. package/dist/adapters/prisma/registry.d.ts +3 -1
  30. package/dist/adapters/prisma/registry.js +129 -9
  31. package/dist/adapters/prisma/registry.js.map +1 -1
  32. package/dist/adapters/prisma/rows.d.ts +10 -0
  33. package/dist/adapters/prisma/rows.js +41 -2
  34. package/dist/adapters/prisma/rows.js.map +1 -1
  35. package/dist/adapters/prisma/unit-of-work.d.ts +3 -1
  36. package/dist/adapters/prisma/unit-of-work.js +3 -1
  37. package/dist/adapters/prisma/unit-of-work.js.map +1 -1
  38. package/dist/adapters/trpc/console.d.ts +1 -1
  39. package/dist/adapters/trpc/context.d.ts +20 -0
  40. package/dist/adapters/trpc/fleet.d.ts +144 -8
  41. package/dist/adapters/trpc/fleet.js +149 -12
  42. package/dist/adapters/trpc/fleet.js.map +1 -1
  43. package/dist/adapters/trpc/router.d.ts +134 -8
  44. package/dist/adapters/trpc/ship-contract.js +10 -0
  45. package/dist/adapters/trpc/ship-contract.js.map +1 -1
  46. package/dist/adapters/trpc/trpc.d.ts +2 -2
  47. package/dist/adapters/trpc/trpc.js +16 -2
  48. package/dist/adapters/trpc/trpc.js.map +1 -1
  49. package/dist/domain/registry/assign-label.d.ts +32 -0
  50. package/dist/domain/registry/assign-label.js +39 -0
  51. package/dist/domain/registry/assign-label.js.map +1 -0
  52. package/dist/domain/registry/change-label-values.d.ts +33 -0
  53. package/dist/domain/registry/change-label-values.js +34 -0
  54. package/dist/domain/registry/change-label-values.js.map +1 -0
  55. package/dist/domain/registry/clear-request.d.ts +69 -0
  56. package/dist/domain/registry/clear-request.js +51 -0
  57. package/dist/domain/registry/clear-request.js.map +1 -0
  58. package/dist/domain/registry/confirm-worktree-cleared.d.ts +31 -0
  59. package/dist/domain/registry/confirm-worktree-cleared.js +30 -0
  60. package/dist/domain/registry/confirm-worktree-cleared.js.map +1 -0
  61. package/dist/domain/registry/crew-request.d.ts +9 -3
  62. package/dist/domain/registry/crew-request.js +9 -6
  63. package/dist/domain/registry/crew-request.js.map +1 -1
  64. package/dist/domain/registry/define-label.d.ts +33 -0
  65. package/dist/domain/registry/define-label.js +33 -0
  66. package/dist/domain/registry/define-label.js.map +1 -0
  67. package/dist/domain/registry/delete-label.d.ts +30 -0
  68. package/dist/domain/registry/delete-label.js +32 -0
  69. package/dist/domain/registry/delete-label.js.map +1 -0
  70. package/dist/domain/registry/find-label-value.d.ts +22 -0
  71. package/dist/domain/registry/find-label-value.js +19 -0
  72. package/dist/domain/registry/find-label-value.js.map +1 -0
  73. package/dist/domain/registry/get-ship.d.ts +1 -1
  74. package/dist/domain/registry/get-ship.js +2 -2
  75. package/dist/domain/registry/get-ship.js.map +1 -1
  76. package/dist/domain/registry/get-starting-prompt.js +3 -3
  77. package/dist/domain/registry/get-starting-prompt.js.map +1 -1
  78. package/dist/domain/registry/label.d.ts +197 -0
  79. package/dist/domain/registry/label.js +263 -0
  80. package/dist/domain/registry/label.js.map +1 -0
  81. package/dist/domain/registry/list-fleet.d.ts +13 -7
  82. package/dist/domain/registry/list-fleet.js +10 -5
  83. package/dist/domain/registry/list-fleet.js.map +1 -1
  84. package/dist/domain/registry/list-labels.d.ts +12 -0
  85. package/dist/domain/registry/list-labels.js +9 -0
  86. package/dist/domain/registry/list-labels.js.map +1 -0
  87. package/dist/domain/registry/ports.d.ts +59 -1
  88. package/dist/domain/registry/read-clear-requests.d.ts +15 -0
  89. package/dist/domain/registry/read-clear-requests.js +16 -0
  90. package/dist/domain/registry/read-clear-requests.js.map +1 -0
  91. package/dist/domain/registry/release-ship.d.ts +1 -1
  92. package/dist/domain/registry/release-ship.js +2 -2
  93. package/dist/domain/registry/release-ship.js.map +1 -1
  94. package/dist/domain/registry/report-crew-status.d.ts +6 -3
  95. package/dist/domain/registry/report-crew-status.js +11 -4
  96. package/dist/domain/registry/report-crew-status.js.map +1 -1
  97. package/dist/domain/registry/request-worktree-clear.d.ts +31 -0
  98. package/dist/domain/registry/request-worktree-clear.js +35 -0
  99. package/dist/domain/registry/request-worktree-clear.js.map +1 -0
  100. package/dist/domain/registry/retire-ship.d.ts +9 -3
  101. package/dist/domain/registry/retire-ship.js +27 -2
  102. package/dist/domain/registry/retire-ship.js.map +1 -1
  103. package/dist/domain/registry/ship.d.ts +1 -1
  104. package/dist/domain/registry/unassign-label.d.ts +30 -0
  105. package/dist/domain/registry/unassign-label.js +37 -0
  106. package/dist/domain/registry/unassign-label.js.map +1 -0
  107. package/dist/domain/shared/errors.d.ts +1 -1
  108. package/dist/domain/shared/errors.js.map +1 -1
  109. package/dist/wiring.d.ts +20 -0
  110. package/dist/wiring.js +21 -1
  111. package/dist/wiring.js.map +1 -1
  112. package/package.json +7 -5
  113. package/src/adapters/prisma/migrations/20261007020000_broad_crewing_scope_retired/migration.sql +8 -0
  114. package/src/adapters/prisma/migrations/20261007100000_labels/migration.sql +87 -0
  115. package/src/adapters/prisma/migrations/20261007110000_foreign_key_indexes/migration.sql +42 -0
  116. package/src/adapters/prisma/migrations/20261007120000_crew_status_attempt/migration.sql +4 -0
  117. package/src/adapters/prisma/migrations/20261007140000_worktree_clear_requests/migration.sql +32 -0
  118. package/src/adapters/prisma/schema.prisma +120 -0
@@ -0,0 +1,197 @@
1
+ import { type FleetId, type LabelId, type LabelValueId, type ShipId } from '@aeolus-fleet/common';
2
+ import { type DomainError } from '../shared/errors.js';
3
+ import type { Actor, NewEvent } from '../shared/events.js';
4
+ import { type Result } from '../shared/result.js';
5
+ import type { Ship } from './ship.js';
6
+ /** One value of a label: its own id, and its text for people. */
7
+ export interface LabelValue {
8
+ id: LabelValueId;
9
+ value: string;
10
+ }
11
+ /**
12
+ * A label (docs/blueprint.md, "Label"; decision 0031): a key with a defined
13
+ * set of values, each with its own id, owned by the ship that defined it.
14
+ * Ids are for machines, key and value texts for people. Only its owner
15
+ * changes its values and assigns them, never to itself. It retires with its
16
+ * owner.
17
+ */
18
+ export interface Label {
19
+ fleetId: FleetId;
20
+ id: LabelId;
21
+ /** Unique among the fleet's labels. */
22
+ key: string;
23
+ /** In the order the owner gave them, each once. */
24
+ values: readonly LabelValue[];
25
+ ownerShipId: ShipId;
26
+ }
27
+ /** A label as the fleet lists it: its id, key and values, and its owner by id and name. */
28
+ export interface ListedLabel {
29
+ id: LabelId;
30
+ key: string;
31
+ values: readonly LabelValue[];
32
+ owner: {
33
+ id: ShipId;
34
+ name: string;
35
+ };
36
+ }
37
+ /** One value a ship carries, with its label: ids and texts. */
38
+ export interface CarriedLabel {
39
+ labelId: LabelId;
40
+ key: string;
41
+ valueId: LabelValueId;
42
+ value: string;
43
+ }
44
+ /** One value a ship carries. A ship holds a set of values, of one label or several. */
45
+ export interface ShipLabel {
46
+ fleetId: FleetId;
47
+ shipId: ShipId;
48
+ labelId: LabelId;
49
+ valueId: LabelValueId;
50
+ }
51
+ /** A value text as a definition or a change gives it, with the id it gets if the label does not have it yet. */
52
+ export interface NewLabelValue {
53
+ value: string;
54
+ newId: LabelValueId;
55
+ }
56
+ /**
57
+ * Whether a ship carries every value of the selector: exact matches by id,
58
+ * combined with AND (decision 0031). No selector, or an empty one, selects
59
+ * every ship.
60
+ */
61
+ export declare function carriesEvery(carried: readonly CarriedLabel[], valueIds: readonly LabelValueId[] | undefined): boolean;
62
+ type InvalidKey = DomainError<'INVALID_LABEL_KEY'>;
63
+ type InvalidValue = DomainError<'INVALID_LABEL_VALUE'>;
64
+ type InvalidValues = DomainError<'INVALID_LABEL_VALUES'>;
65
+ /** A label's key, checked against the limits. */
66
+ export declare function labelKey(key: string): Result<string, InvalidKey>;
67
+ export type DefineLabelRefusal = InvalidKey | InvalidValue | InvalidValues | DomainError<'LABEL_KEY_TAKEN'>;
68
+ /**
69
+ * A ship defines a label, owning it: a key unique in the fleet and its values,
70
+ * the label and each value with its new id. A key the fleet has is refused,
71
+ * naming its owner. LabelDefined names the owner, with the label and its
72
+ * values.
73
+ */
74
+ export declare function defineLabel({ owner, existing, }: {
75
+ owner: Pick<Ship, 'fleetId' | 'id'>;
76
+ existing: {
77
+ label: Label;
78
+ ownerName: string;
79
+ } | undefined;
80
+ }, input: {
81
+ id: LabelId;
82
+ key: string;
83
+ values: readonly NewLabelValue[];
84
+ at: Date;
85
+ actor: Actor;
86
+ }): Result<{
87
+ label: Label;
88
+ events: NewEvent[];
89
+ }, DefineLabelRefusal>;
90
+ type NotTheOwner = DomainError<'NOT_THE_LABEL_OWNER'>;
91
+ export type ChangeLabelValuesRefusal = NotTheOwner | InvalidValue | InvalidValues | DomainError<'LABEL_VALUE_CARRIED'>;
92
+ /**
93
+ * The owner gives its label the values it has from now on, adding and
94
+ * removing at once: a value it has keeps its id, a new one gets its new id.
95
+ * A value ships carry is never removed: the refusal names them. The values
96
+ * it has already, in any order, change nothing.
97
+ */
98
+ export declare function changeLabelValues({ label, ownerName, carriers, }: {
99
+ label: Label;
100
+ ownerName: string;
101
+ carriers: readonly {
102
+ valueId: LabelValueId;
103
+ shipName: string;
104
+ }[];
105
+ }, input: {
106
+ callerShipId: ShipId;
107
+ values: readonly NewLabelValue[];
108
+ at: Date;
109
+ actor: Actor;
110
+ }): Result<{
111
+ label: Label;
112
+ events: NewEvent[];
113
+ }, ChangeLabelValuesRefusal>;
114
+ export type DeleteLabelRefusal = NotTheOwner | DomainError<'LABEL_CARRIED'>;
115
+ /**
116
+ * The owner deletes its label with its values, freeing its key. A label any
117
+ * ship carries a value of is never deleted: the refusal names the ships.
118
+ * LabelDeleted names the owner, with the label.
119
+ */
120
+ export declare function deleteLabel({ label, ownerName, carrierNames }: {
121
+ label: Label;
122
+ ownerName: string;
123
+ carrierNames: readonly string[];
124
+ }, input: {
125
+ callerShipId: ShipId;
126
+ at: Date;
127
+ actor: Actor;
128
+ }): Result<{
129
+ events: NewEvent[];
130
+ }, DeleteLabelRefusal>;
131
+ type OwnShip = DomainError<'LABEL_ON_OWN_SHIP'>;
132
+ export type AssignLabelRefusal = NotTheOwner | OwnShip | DomainError<'SHIP_ALREADY_RETIRED' | 'SHIP_LABEL_LIMIT_REACHED'>;
133
+ /**
134
+ * The owner gives a ship one of its label's values, by its id: the ship
135
+ * holds a set of values, so it may carry several of one label. A value it
136
+ * carries changes nothing. Never the owner's own ship or a retired ship;
137
+ * argo and the viewer ship as any other (decision 0016). A ship carries at
138
+ * most 20 values. LabelAssigned names the ship, with the label and the value.
139
+ */
140
+ export declare function assignLabel({ label, ownerName, ship, carried, }: {
141
+ label: Label;
142
+ ownerName: string;
143
+ ship: Ship;
144
+ carried: readonly ShipLabel[];
145
+ }, input: {
146
+ callerShipId: ShipId;
147
+ valueId: LabelValueId;
148
+ at: Date;
149
+ actor: Actor;
150
+ }): Result<{
151
+ assignment: ShipLabel | undefined;
152
+ events: NewEvent[];
153
+ }, AssignLabelRefusal>;
154
+ export type UnassignLabelRefusal = NotTheOwner | OwnShip;
155
+ /**
156
+ * The owner takes one value of its label off a ship. A ship that does not
157
+ * carry it changes nothing. LabelUnassigned names the ship, with the label
158
+ * and the value it carried.
159
+ */
160
+ export declare function unassignLabel({ label, ownerName, ship, carried, }: {
161
+ label: Label;
162
+ ownerName: string;
163
+ ship: Ship;
164
+ carried: readonly ShipLabel[];
165
+ }, input: {
166
+ callerShipId: ShipId;
167
+ valueId: LabelValueId;
168
+ at: Date;
169
+ actor: Actor;
170
+ }): Result<{
171
+ unassigned: ShipLabel | undefined;
172
+ events: NewEvent[];
173
+ }, UnassignLabelRefusal>;
174
+ /**
175
+ * A ship is retired: the labels it owns retire with it (their meaning
176
+ * retires with their owner), each after every assignment of it goes, and
177
+ * the values it carries go. LabelUnassigned for every assignment that goes,
178
+ * LabelRetired for every label.
179
+ */
180
+ export declare function retireLabelsWith({ owned, carried, }: {
181
+ owned: readonly {
182
+ label: Label;
183
+ carriers: readonly ShipLabel[];
184
+ }[];
185
+ carried: readonly {
186
+ label: Label;
187
+ assignment: ShipLabel;
188
+ }[];
189
+ }, input: {
190
+ at: Date;
191
+ actor: Actor;
192
+ }): {
193
+ unassigned: ShipLabel[];
194
+ retired: Label[];
195
+ events: NewEvent[];
196
+ };
197
+ export {};
@@ -0,0 +1,263 @@
1
+ import { LABEL_HANDLE_MAX_LENGTH, LABEL_HANDLE_PATTERN, LABEL_VALUES_MAX, SHIP_LABELS_MAX, } from '@aeolus-fleet/common';
2
+ import { refuse } from '../shared/errors.js';
3
+ import { ok } from '../shared/result.js';
4
+ /**
5
+ * Whether a ship carries every value of the selector: exact matches by id,
6
+ * combined with AND (decision 0031). No selector, or an empty one, selects
7
+ * every ship.
8
+ */
9
+ export function carriesEvery(carried, valueIds) {
10
+ return (valueIds ?? []).every((valueId) => carried.some((label) => label.valueId === valueId));
11
+ }
12
+ const LIMITS = `lowercase a-z, 0-9 and -, at most ${String(LABEL_HANDLE_MAX_LENGTH)} characters (decision 0031)`;
13
+ function isLabelHandle(text) {
14
+ return text.length <= LABEL_HANDLE_MAX_LENGTH && LABEL_HANDLE_PATTERN.test(text);
15
+ }
16
+ /** A label's key, checked against the limits. */
17
+ export function labelKey(key) {
18
+ return isLabelHandle(key) ? ok(key) : refuse('INVALID_LABEL_KEY', `A label key is ${LIMITS}`);
19
+ }
20
+ /** A label's value texts: one to the most a label may define, each once, each within the limits. */
21
+ function checkValueTexts(values) {
22
+ if (values.length === 0 || values.length > LABEL_VALUES_MAX) {
23
+ return refuse('INVALID_LABEL_VALUES', `A label has 1 to ${String(LABEL_VALUES_MAX)} values (decision 0031)`);
24
+ }
25
+ if (values.some((value) => !isLabelHandle(value))) {
26
+ return refuse('INVALID_LABEL_VALUE', `A label value is ${LIMITS}`);
27
+ }
28
+ if (new Set(values).size !== values.length) {
29
+ return refuse('INVALID_LABEL_VALUES', 'A label names each of its values once');
30
+ }
31
+ return ok(undefined);
32
+ }
33
+ /** Each value with the id the label has for its text, or its new id. */
34
+ function withIds(values, kept) {
35
+ return values.map(({ value, newId }) => ({
36
+ id: kept.find((held) => held.value === value)?.id ?? newId,
37
+ value,
38
+ }));
39
+ }
40
+ function labelEvent(label, change) {
41
+ return {
42
+ fleetId: label.fleetId,
43
+ occurredAt: change.at,
44
+ actor: change.actor,
45
+ shipId: label.ownerShipId,
46
+ type: change.type,
47
+ details: { labelId: label.id, key: label.key, ...change.details },
48
+ };
49
+ }
50
+ /** The values as an event's details carry them: flat texts, comma separated, since neither a value nor an id holds a comma. */
51
+ function valuesDetails(values) {
52
+ return {
53
+ values: values.map((value) => value.value).join(','),
54
+ valueIds: values.map((value) => value.id).join(','),
55
+ };
56
+ }
57
+ /**
58
+ * A ship defines a label, owning it: a key unique in the fleet and its values,
59
+ * the label and each value with its new id. A key the fleet has is refused,
60
+ * naming its owner. LabelDefined names the owner, with the label and its
61
+ * values.
62
+ */
63
+ export function defineLabel({ owner, existing, }, input) {
64
+ const key = labelKey(input.key);
65
+ if (!key.isOk) {
66
+ return key;
67
+ }
68
+ const texts = checkValueTexts(input.values.map(({ value }) => value));
69
+ if (!texts.isOk) {
70
+ return texts;
71
+ }
72
+ if (existing) {
73
+ return refuse('LABEL_KEY_TAKEN', `The fleet has the label ${key.value} already, owned by ${existing.ownerName}`);
74
+ }
75
+ const label = {
76
+ fleetId: owner.fleetId,
77
+ id: input.id,
78
+ key: key.value,
79
+ values: withIds(input.values, []),
80
+ ownerShipId: owner.id,
81
+ };
82
+ return ok({
83
+ label,
84
+ events: [
85
+ labelEvent(label, {
86
+ at: input.at,
87
+ actor: input.actor,
88
+ type: 'LabelDefined',
89
+ details: valuesDetails(label.values),
90
+ }),
91
+ ],
92
+ });
93
+ }
94
+ /** Only a label's owner changes it or assigns it. */
95
+ function checkOwner({ label, ownerName }, caller) {
96
+ return label.ownerShipId === caller.shipId
97
+ ? ok(undefined)
98
+ : refuse('NOT_THE_LABEL_OWNER', `The label ${label.key} is owned by ${ownerName}: only its owner ${caller.act} it`);
99
+ }
100
+ /**
101
+ * The owner gives its label the values it has from now on, adding and
102
+ * removing at once: a value it has keeps its id, a new one gets its new id.
103
+ * A value ships carry is never removed: the refusal names them. The values
104
+ * it has already, in any order, change nothing.
105
+ */
106
+ export function changeLabelValues({ label, ownerName, carriers, }, input) {
107
+ const owned = checkOwner({ label, ownerName }, { shipId: input.callerShipId, act: 'changes' });
108
+ if (!owned.isOk) {
109
+ return owned;
110
+ }
111
+ const texts = input.values.map(({ value }) => value);
112
+ const checked = checkValueTexts(texts);
113
+ if (!checked.isOk) {
114
+ return checked;
115
+ }
116
+ const removed = label.values.filter((value) => !texts.includes(value.value));
117
+ const carried = removed
118
+ .map((value) => ({
119
+ value,
120
+ ships: carriers.filter((carrier) => carrier.valueId === value.id).map((carrier) => carrier.shipName),
121
+ }))
122
+ .filter(({ ships }) => ships.length > 0);
123
+ if (carried.length > 0) {
124
+ const named = carried.map(({ value, ships }) => `${label.key}=${value.value}: ${ships.join(', ')}`).join('; ');
125
+ return refuse('LABEL_VALUE_CARRIED', `Ships carry ${named}`);
126
+ }
127
+ if (removed.length === 0 && texts.length === label.values.length) {
128
+ return ok({ label, events: [] });
129
+ }
130
+ const changed = {
131
+ ...label,
132
+ values: withIds(input.values, label.values),
133
+ };
134
+ return ok({
135
+ label: changed,
136
+ events: [
137
+ labelEvent(changed, {
138
+ at: input.at,
139
+ actor: input.actor,
140
+ type: 'LabelValuesChanged',
141
+ details: valuesDetails(changed.values),
142
+ }),
143
+ ],
144
+ });
145
+ }
146
+ /**
147
+ * The owner deletes its label with its values, freeing its key. A label any
148
+ * ship carries a value of is never deleted: the refusal names the ships.
149
+ * LabelDeleted names the owner, with the label.
150
+ */
151
+ export function deleteLabel({ label, ownerName, carrierNames }, input) {
152
+ const owned = checkOwner({ label, ownerName }, { shipId: input.callerShipId, act: 'deletes' });
153
+ if (!owned.isOk) {
154
+ return owned;
155
+ }
156
+ if (carrierNames.length > 0) {
157
+ return refuse('LABEL_CARRIED', `Ships carry the label ${label.key}: ${[...new Set(carrierNames)].join(', ')}`);
158
+ }
159
+ return ok({ events: [labelEvent(label, { at: input.at, actor: input.actor, type: 'LabelDeleted' })] });
160
+ }
161
+ function assignmentEvent({ label, assignment }, change) {
162
+ return {
163
+ fleetId: assignment.fleetId,
164
+ occurredAt: change.at,
165
+ actor: change.actor,
166
+ shipId: assignment.shipId,
167
+ type: change.type,
168
+ details: {
169
+ labelId: label.id,
170
+ key: label.key,
171
+ valueId: assignment.valueId,
172
+ value: label.values.find((value) => value.id === assignment.valueId)?.value ?? '',
173
+ },
174
+ };
175
+ }
176
+ /** No ship labels itself: that would let it enforce a plugin's policy on its own (decision 0031). */
177
+ function checkNotOwnShip(label, ship) {
178
+ return ship.id === label.ownerShipId ? refuse('LABEL_ON_OWN_SHIP', `No ship labels itself: ${label.key} is your own ship's label`) : ok(undefined);
179
+ }
180
+ /**
181
+ * The owner gives a ship one of its label's values, by its id: the ship
182
+ * holds a set of values, so it may carry several of one label. A value it
183
+ * carries changes nothing. Never the owner's own ship or a retired ship;
184
+ * argo and the viewer ship as any other (decision 0016). A ship carries at
185
+ * most 20 values. LabelAssigned names the ship, with the label and the value.
186
+ */
187
+ export function assignLabel({ label, ownerName, ship, carried, }, input) {
188
+ const owned = checkOwner({ label, ownerName }, { shipId: input.callerShipId, act: 'assigns' });
189
+ if (!owned.isOk) {
190
+ return owned;
191
+ }
192
+ const notOwn = checkNotOwnShip(label, ship);
193
+ if (!notOwn.isOk) {
194
+ return notOwn;
195
+ }
196
+ if (ship.retiredAt !== null) {
197
+ return refuse('SHIP_ALREADY_RETIRED', `${ship.name} is retired`);
198
+ }
199
+ if (carried.some((each) => each.valueId === input.valueId)) {
200
+ return ok({ assignment: undefined, events: [] });
201
+ }
202
+ if (carried.length >= SHIP_LABELS_MAX) {
203
+ return refuse('SHIP_LABEL_LIMIT_REACHED', `${ship.name} carries ${String(SHIP_LABELS_MAX)} labels, the most a ship carries (decision 0031)`);
204
+ }
205
+ const assignment = {
206
+ fleetId: ship.fleetId,
207
+ shipId: ship.id,
208
+ labelId: label.id,
209
+ valueId: input.valueId,
210
+ };
211
+ return ok({
212
+ assignment,
213
+ events: [assignmentEvent({ label, assignment }, { type: 'LabelAssigned', at: input.at, actor: input.actor })],
214
+ });
215
+ }
216
+ /**
217
+ * The owner takes one value of its label off a ship. A ship that does not
218
+ * carry it changes nothing. LabelUnassigned names the ship, with the label
219
+ * and the value it carried.
220
+ */
221
+ export function unassignLabel({ label, ownerName, ship, carried, }, input) {
222
+ const owned = checkOwner({ label, ownerName }, { shipId: input.callerShipId, act: 'unassigns' });
223
+ if (!owned.isOk) {
224
+ return owned;
225
+ }
226
+ const notOwn = checkNotOwnShip(label, ship);
227
+ if (!notOwn.isOk) {
228
+ return notOwn;
229
+ }
230
+ const current = carried.find((each) => each.valueId === input.valueId);
231
+ if (!current) {
232
+ return ok({ unassigned: undefined, events: [] });
233
+ }
234
+ return ok({
235
+ unassigned: current,
236
+ events: [assignmentEvent({ label: label, assignment: current }, { type: 'LabelUnassigned', at: input.at, actor: input.actor })],
237
+ });
238
+ }
239
+ /**
240
+ * A ship is retired: the labels it owns retire with it (their meaning
241
+ * retires with their owner), each after every assignment of it goes, and
242
+ * the values it carries go. LabelUnassigned for every assignment that goes,
243
+ * LabelRetired for every label.
244
+ */
245
+ export function retireLabelsWith({ owned, carried, }, input) {
246
+ const unassigned = [];
247
+ const events = [];
248
+ const unassign = (label, assignment) => {
249
+ unassigned.push(assignment);
250
+ events.push(assignmentEvent({ label, assignment }, { type: 'LabelUnassigned', ...input }));
251
+ };
252
+ for (const { label, carriers } of owned) {
253
+ for (const assignment of carriers) {
254
+ unassign(label, assignment);
255
+ }
256
+ events.push(labelEvent(label, { ...input, type: 'LabelRetired' }));
257
+ }
258
+ for (const { label, assignment } of carried) {
259
+ unassign(label, assignment);
260
+ }
261
+ return { unassigned, retired: owned.map(({ label }) => label), events };
262
+ }
263
+ //# sourceMappingURL=label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.js","sourceRoot":"","sources":["../../../src/domain/registry/label.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import type { Scope, ShipId, ShipKind, ShipStatus } from '@aeolus-fleet/common';
1
+ import type { LabelValueId, Scope, ShipId, ShipKind, ShipStatus } from '@aeolus-fleet/common';
2
2
  import type { Caller } from '../shared/caller.js';
3
3
  import type { Location } from './lease.js';
4
4
  import { type PingStatus } from './ping-status.js';
5
5
  import type { CrewRequest } from './crew-request.js';
6
+ import { type CarriedLabel } from './label.js';
6
7
  import type { FleetListing, ShipFacts } from './ports.js';
7
8
  import type { ShipReport } from './ship-report.js';
8
9
  /** A ship as the fleet snapshot shows it. */
@@ -33,7 +34,7 @@ export interface ListedShip {
33
34
  /** The crew's last report with the version of its details, never the details; null until it reports, and while no session crews the ship. */
34
35
  report: Omit<ShipReport, 'details'> | null;
35
36
  /** The ship's crew request by its settings version and when it was requested, never its settings; null when it holds none. */
36
- crewRequest: (Pick<CrewRequest, 'settingsVersion' | 'requestedAt' | 'status' | 'reason'> & {
37
+ crewRequest: (Pick<CrewRequest, 'settingsVersion' | 'requestedAt' | 'status' | 'reason' | 'attempt' | 'sessionStartedAt'> & {
37
38
  /** The trierarch ship it is assigned to, by id and name; null while unassigned. */
38
39
  assignedTo: {
39
40
  id: ShipId;
@@ -45,6 +46,8 @@ export interface ListedShip {
45
46
  name: string;
46
47
  } | null;
47
48
  }) | null;
49
+ /** The label values the ship carries, with their labels, by key then value (decision 0031); none for a ship without. */
50
+ labels: readonly CarriedLabel[];
48
51
  /** The harness the crewing session stated, read together with its location; null while no session crews the ship. */
49
52
  harness: string | null;
50
53
  /** The ship's current model: the last its sessions stated on a send, and when; null before any. */
@@ -57,14 +60,17 @@ export interface ListedShip {
57
60
  /** When the operator retired the ship; null while it is active. */
58
61
  retiredAt: Date | null;
59
62
  }
60
- export type ListFleet = (caller: Caller) => Promise<ListedShip[]>;
63
+ export type ListFleet = (caller: Caller, input?: {
64
+ valueIds?: readonly LabelValueId[];
65
+ }) => Promise<ListedShip[]>;
61
66
  /**
62
- * Use case: every ship of the caller's fleet, `argo` included, oldest first.
63
- * Never a secret, a crew token or their hashes. The caller's scope
64
- * (fleet:read) is checked before this runs.
67
+ * Use case: every ship of the caller's fleet, `argo` included, oldest first,
68
+ * or with label value ids only the ships that carry every one of them
69
+ * (decision 0031). Never a secret, a crew token or their hashes. The
70
+ * caller's scope (fleet:read) is checked before this runs.
65
71
  */
66
72
  export declare function createListFleet(deps: {
67
73
  listing: FleetListing;
68
74
  }): ListFleet;
69
75
  /** A ship as the fleet snapshot shows it, from what the listing read about it. */
70
- export declare function listedShipOf({ ship, openLease, validSecret, crewRequest, crewRequestAssignee, crewedBy, lastPing, lastModel, lastViewedAt, lastLeaseEndedAt, }: ShipFacts): ListedShip;
76
+ export declare function listedShipOf({ ship, openLease, validSecret, crewRequest, crewRequestAssignee, labels, crewedBy, lastPing, lastModel, lastViewedAt, lastLeaseEndedAt, }: ShipFacts): ListedShip;
@@ -1,15 +1,17 @@
1
1
  import { pingStatusOf } from './ping-status.js';
2
+ import { carriesEvery } from './label.js';
2
3
  import { shipStatus } from './ship.js';
3
4
  /**
4
- * Use case: every ship of the caller's fleet, `argo` included, oldest first.
5
- * Never a secret, a crew token or their hashes. The caller's scope
6
- * (fleet:read) is checked before this runs.
5
+ * Use case: every ship of the caller's fleet, `argo` included, oldest first,
6
+ * or with label value ids only the ships that carry every one of them
7
+ * (decision 0031). Never a secret, a crew token or their hashes. The
8
+ * caller's scope (fleet:read) is checked before this runs.
7
9
  */
8
10
  export function createListFleet(deps) {
9
- return async (caller) => (await deps.listing.ships(caller.fleetId)).map(listedShipOf);
11
+ return async (caller, input) => (await deps.listing.ships(caller.fleetId)).filter((facts) => carriesEvery(facts.labels, input?.valueIds)).map(listedShipOf);
10
12
  }
11
13
  /** A ship as the fleet snapshot shows it, from what the listing read about it. */
12
- export function listedShipOf({ ship, openLease, validSecret, crewRequest, crewRequestAssignee, crewedBy, lastPing, lastModel, lastViewedAt, lastLeaseEndedAt, }) {
14
+ export function listedShipOf({ ship, openLease, validSecret, crewRequest, crewRequestAssignee, labels, crewedBy, lastPing, lastModel, lastViewedAt, lastLeaseEndedAt, }) {
13
15
  const status = shipStatus(ship, { isCrewed: openLease !== null });
14
16
  return {
15
17
  id: ship.id,
@@ -31,7 +33,10 @@ export function listedShipOf({ ship, openLease, validSecret, crewRequest, crewRe
31
33
  status: crewRequest.status,
32
34
  reason: crewRequest.reason,
33
35
  crewedBy,
36
+ attempt: crewRequest.attempt,
37
+ sessionStartedAt: crewRequest.sessionStartedAt,
34
38
  },
39
+ labels,
35
40
  harness: openLease?.harness ?? null,
36
41
  model: lastModel,
37
42
  awaitingCrewSince: status === 'awaitingCrew' ? latestOf(ship.createdAt, lastLeaseEndedAt) : null,
@@ -1 +1 @@
1
- {"version":3,"file":"list-fleet.js","sourceRoot":"","sources":["../../../src/domain/registry/list-fleet.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAmB,MAAM,kBAAkB,CAAC;AAIjE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AA+CvC;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAA+B;IAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AACxF,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,EAC3B,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,gBAAgB,GACN;IACV,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,SAAS,KAAK,IAAI,EAAE,CAAC,CAAC;IAClE,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM;QACN,cAAc,EAAE,WAAW,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,SAAS,KAAK,IAAI,EAAE;QAC5G,QAAQ,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI;QACrC,iGAAiG;QACjG,UAAU,EAAE,SAAS,EAAE,UAAU,IAAI,YAAY;QACjD,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC;QAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;QACnE,WAAW,EAAE,WAAW,IAAI;YAC1B,eAAe,EAAE,WAAW,CAAC,eAAe;YAC5C,WAAW,EAAE,WAAW,CAAC,WAAW;YACpC,UAAU,EAAE,mBAAmB;YAC/B,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,QAAQ;SACT;QACD,OAAO,EAAE,SAAS,EAAE,OAAO,IAAI,IAAI;QACnC,KAAK,EAAE,SAAS;QAChB,iBAAiB,EAAE,MAAM,KAAK,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI;QAChG,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAc;IAC7E,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAW,EAAE,MAAmB;IAChD,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5D,CAAC"}
1
+ {"version":3,"file":"list-fleet.js","sourceRoot":"","sources":["../../../src/domain/registry/list-fleet.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAmB,MAAM,kBAAkB,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAqB,MAAM,YAAY,CAAC;AAG7D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAiDvC;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,IAA+B;IAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAC7B,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAChI,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,EAC3B,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,gBAAgB,GACN;IACV,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,SAAS,KAAK,IAAI,EAAE,CAAC,CAAC;IAClE,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM;QACN,cAAc,EAAE,WAAW,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,SAAS,KAAK,IAAI,EAAE;QAC5G,QAAQ,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI;QACrC,iGAAiG;QACjG,UAAU,EAAE,SAAS,EAAE,UAAU,IAAI,YAAY;QACjD,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC;QAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;QACnE,WAAW,EAAE,WAAW,IAAI;YAC1B,eAAe,EAAE,WAAW,CAAC,eAAe;YAC5C,WAAW,EAAE,WAAW,CAAC,WAAW;YACpC,UAAU,EAAE,mBAAmB;YAC/B,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,QAAQ;YACR,OAAO,EAAE,WAAW,CAAC,OAAO;YAC5B,gBAAgB,EAAE,WAAW,CAAC,gBAAgB;SAC/C;QACD,MAAM;QACN,OAAO,EAAE,SAAS,EAAE,OAAO,IAAI,IAAI;QACnC,KAAK,EAAE,SAAS;QAChB,iBAAiB,EAAE,MAAM,KAAK,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI;QAChG,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAc;IAC7E,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAW,EAAE,MAAmB;IAChD,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { Caller } from '../shared/caller.js';
2
+ import type { ListedLabel } from './label.js';
3
+ import type { FleetListing } from './ports.js';
4
+ export type ListLabels = (caller: Caller) => Promise<ListedLabel[]>;
5
+ /**
6
+ * Use case: the labels of the caller's fleet by key, each with its values and
7
+ * its owner (decision 0031). The caller's scope (fleet:read) is checked
8
+ * before this runs.
9
+ */
10
+ export declare function createListLabels(deps: {
11
+ listing: Pick<FleetListing, 'labels'>;
12
+ }): ListLabels;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Use case: the labels of the caller's fleet by key, each with its values and
3
+ * its owner (decision 0031). The caller's scope (fleet:read) is checked
4
+ * before this runs.
5
+ */
6
+ export function createListLabels(deps) {
7
+ return (caller) => deps.listing.labels(caller.fleetId);
8
+ }
9
+ //# sourceMappingURL=list-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-labels.js","sourceRoot":"","sources":["../../../src/domain/registry/list-labels.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAA+C;IAC9E,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACzD,CAAC"}