@aeolus-fleet/core 0.26.0 → 0.27.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.
- package/README.md +1 -1
- package/dist/adapters/http/request-credentials.d.ts +2 -9
- package/dist/adapters/http/request-credentials.js +8 -1
- package/dist/adapters/http/request-credentials.js.map +1 -1
- package/dist/adapters/http/server.js +2 -1
- package/dist/adapters/http/server.js.map +1 -1
- package/dist/adapters/mcp/mcp-endpoint.js +11 -1
- package/dist/adapters/mcp/mcp-endpoint.js.map +1 -1
- package/dist/adapters/prisma/generated/browser.d.ts +8 -0
- package/dist/adapters/prisma/generated/client.d.ts +8 -0
- package/dist/adapters/prisma/generated/enums.d.ts +2 -0
- package/dist/adapters/prisma/generated/enums.js +3 -1
- package/dist/adapters/prisma/generated/enums.js.map +1 -1
- package/dist/adapters/prisma/generated/internal/class.d.ts +11 -0
- package/dist/adapters/prisma/generated/internal/class.js +4 -4
- package/dist/adapters/prisma/generated/internal/class.js.map +1 -1
- package/dist/adapters/prisma/generated/internal/prismaNamespace.d.ts +94 -1
- package/dist/adapters/prisma/generated/internal/prismaNamespace.js +18 -1
- package/dist/adapters/prisma/generated/internal/prismaNamespace.js.map +1 -1
- package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.d.ts +18 -0
- package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.js +18 -1
- package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.js.map +1 -1
- package/dist/adapters/prisma/generated/models/Delivery.d.ts +71 -1
- package/dist/adapters/prisma/generated/models/Fleet.d.ts +275 -0
- package/dist/adapters/prisma/generated/models/Lease.d.ts +113 -1
- package/dist/adapters/prisma/generated/models/NetworkSettings.d.ts +151 -19
- package/dist/adapters/prisma/generated/models/ReachRefusal.d.ts +71 -1
- package/dist/adapters/prisma/generated/models/ScopeNamespace.d.ts +1220 -0
- package/dist/adapters/prisma/generated/models/ScopeNamespace.js +2 -0
- package/dist/adapters/prisma/generated/models/ScopeNamespace.js.map +1 -0
- package/dist/adapters/prisma/generated/models/Ship.d.ts +983 -55
- package/dist/adapters/prisma/generated/models.d.ts +1 -0
- package/dist/adapters/prisma/health.js +27 -7
- package/dist/adapters/prisma/health.js.map +1 -1
- package/dist/adapters/prisma/history.js +14 -70
- package/dist/adapters/prisma/history.js.map +1 -1
- package/dist/adapters/prisma/messaging.js +27 -34
- package/dist/adapters/prisma/messaging.js.map +1 -1
- package/dist/adapters/prisma/network.js +39 -12
- package/dist/adapters/prisma/network.js.map +1 -1
- package/dist/adapters/prisma/registry.js +65 -11
- package/dist/adapters/prisma/registry.js.map +1 -1
- package/dist/adapters/prisma/rows.d.ts +3 -0
- package/dist/adapters/prisma/rows.js +20 -7
- package/dist/adapters/prisma/rows.js.map +1 -1
- package/dist/adapters/prisma/scope-namespaces.d.ts +4 -0
- package/dist/adapters/prisma/scope-namespaces.js +39 -0
- package/dist/adapters/prisma/scope-namespaces.js.map +1 -0
- package/dist/adapters/prisma/unit-of-work.d.ts +2 -1
- package/dist/adapters/prisma/unit-of-work.js +2 -0
- package/dist/adapters/prisma/unit-of-work.js.map +1 -1
- package/dist/adapters/rest/rest-api.js +2 -2
- package/dist/adapters/rest/rest-api.js.map +1 -1
- package/dist/adapters/trpc/console.d.ts +1 -1
- package/dist/adapters/trpc/console.js +6 -4
- package/dist/adapters/trpc/console.js.map +1 -1
- package/dist/adapters/trpc/context.d.ts +20 -4
- package/dist/adapters/trpc/fleet.d.ts +179 -82
- package/dist/adapters/trpc/fleet.js +117 -53
- package/dist/adapters/trpc/fleet.js.map +1 -1
- package/dist/adapters/trpc/router.d.ts +231 -80
- package/dist/adapters/trpc/ship-contract.js +4 -0
- package/dist/adapters/trpc/ship-contract.js.map +1 -1
- package/dist/adapters/trpc/ship-protocol.js +7 -5
- package/dist/adapters/trpc/ship-protocol.js.map +1 -1
- package/dist/adapters/trpc/ship.d.ts +71 -3
- package/dist/adapters/trpc/ship.js +42 -5
- package/dist/adapters/trpc/ship.js.map +1 -1
- package/dist/adapters/trpc/trpc.d.ts +6 -5
- package/dist/adapters/trpc/trpc.js +76 -21
- package/dist/adapters/trpc/trpc.js.map +1 -1
- package/dist/domain/messaging/check-inbox.d.ts +5 -5
- package/dist/domain/messaging/check-inbox.js +9 -7
- package/dist/domain/messaging/check-inbox.js.map +1 -1
- package/dist/domain/messaging/dismiss-delivery.d.ts +9 -4
- package/dist/domain/messaging/dismiss-delivery.js +26 -19
- package/dist/domain/messaging/dismiss-delivery.js.map +1 -1
- package/dist/domain/messaging/message.d.ts +11 -5
- package/dist/domain/messaging/message.js +11 -4
- package/dist/domain/messaging/message.js.map +1 -1
- package/dist/domain/messaging/ping-ship.d.ts +3 -3
- package/dist/domain/messaging/ping-ship.js +6 -2
- package/dist/domain/messaging/ping-ship.js.map +1 -1
- package/dist/domain/messaging/ports.d.ts +9 -3
- package/dist/domain/messaging/receive-deliveries.d.ts +2 -0
- package/dist/domain/messaging/receive-deliveries.js +1 -0
- package/dist/domain/messaging/receive-deliveries.js.map +1 -1
- package/dist/domain/messaging/resend-delivery.d.ts +5 -2
- package/dist/domain/messaging/resend-delivery.js +8 -4
- package/dist/domain/messaging/resend-delivery.js.map +1 -1
- package/dist/domain/messaging/send-message.d.ts +9 -2
- package/dist/domain/messaging/send-message.js +12 -2
- package/dist/domain/messaging/send-message.js.map +1 -1
- package/dist/domain/messaging/send-request.d.ts +3 -1
- package/dist/domain/messaging/send-request.js +4 -2
- package/dist/domain/messaging/send-request.js.map +1 -1
- package/dist/domain/registry/assign-label.d.ts +2 -1
- package/dist/domain/registry/assign-label.js +3 -2
- package/dist/domain/registry/assign-label.js.map +1 -1
- package/dist/domain/registry/check-reach.d.ts +63 -4
- package/dist/domain/registry/check-reach.js +107 -11
- package/dist/domain/registry/check-reach.js.map +1 -1
- package/dist/domain/registry/commission-ship.d.ts +17 -8
- package/dist/domain/registry/commission-ship.js +24 -10
- package/dist/domain/registry/commission-ship.js.map +1 -1
- package/dist/domain/registry/crew-request.d.ts +1 -1
- package/dist/domain/registry/declare-scopes.d.ts +38 -0
- package/dist/domain/registry/declare-scopes.js +34 -0
- package/dist/domain/registry/declare-scopes.js.map +1 -0
- package/dist/domain/registry/declared-network-rules.d.ts +2 -1
- package/dist/domain/registry/declared-network-rules.js +11 -5
- package/dist/domain/registry/declared-network-rules.js.map +1 -1
- package/dist/domain/registry/discover.d.ts +28 -0
- package/dist/domain/registry/discover.js +54 -0
- package/dist/domain/registry/discover.js.map +1 -0
- package/dist/domain/registry/explain-reach.d.ts +12 -12
- package/dist/domain/registry/explain-reach.js +35 -12
- package/dist/domain/registry/explain-reach.js.map +1 -1
- package/dist/domain/registry/get-ship.d.ts +11 -3
- package/dist/domain/registry/get-ship.js +8 -2
- package/dist/domain/registry/get-ship.js.map +1 -1
- package/dist/domain/registry/get-starting-prompt.d.ts +18 -2
- package/dist/domain/registry/get-starting-prompt.js +7 -7
- package/dist/domain/registry/get-starting-prompt.js.map +1 -1
- package/dist/domain/registry/grant-scopes.d.ts +34 -0
- package/dist/domain/registry/grant-scopes.js +35 -0
- package/dist/domain/registry/grant-scopes.js.map +1 -0
- package/dist/domain/registry/label.d.ts +12 -7
- package/dist/domain/registry/label.js +21 -4
- package/dist/domain/registry/label.js.map +1 -1
- package/dist/domain/registry/list-fleet.d.ts +19 -6
- package/dist/domain/registry/list-fleet.js +18 -3
- package/dist/domain/registry/list-fleet.js.map +1 -1
- package/dist/domain/registry/list-scopes.d.ts +24 -0
- package/dist/domain/registry/list-scopes.js +22 -0
- package/dist/domain/registry/list-scopes.js.map +1 -0
- package/dist/domain/registry/managed-or-assigned.d.ts +25 -0
- package/dist/domain/registry/managed-or-assigned.js +23 -0
- package/dist/domain/registry/managed-or-assigned.js.map +1 -0
- package/dist/domain/registry/named-namespaces.d.ts +19 -0
- package/dist/domain/registry/named-namespaces.js +19 -0
- package/dist/domain/registry/named-namespaces.js.map +1 -0
- package/dist/domain/registry/network-settings.d.ts +84 -24
- package/dist/domain/registry/network-settings.js +134 -45
- package/dist/domain/registry/network-settings.js.map +1 -1
- package/dist/domain/registry/ports.d.ts +63 -1
- package/dist/domain/registry/public.d.ts +3 -2
- package/dist/domain/registry/public.js +3 -2
- package/dist/domain/registry/public.js.map +1 -1
- package/dist/domain/registry/reach-refusal.d.ts +12 -4
- package/dist/domain/registry/read-assigned-crew-requests.d.ts +12 -3
- package/dist/domain/registry/read-assigned-crew-requests.js +8 -8
- package/dist/domain/registry/read-assigned-crew-requests.js.map +1 -1
- package/dist/domain/registry/read-built-in-rules.d.ts +20 -0
- package/dist/domain/registry/read-built-in-rules.js +23 -0
- package/dist/domain/registry/read-built-in-rules.js.map +1 -0
- package/dist/domain/registry/read-clear-requests.d.ts +5 -3
- package/dist/domain/registry/read-clear-requests.js +7 -5
- package/dist/domain/registry/read-clear-requests.js.map +1 -1
- package/dist/domain/registry/read-on-behalf.d.ts +20 -0
- package/dist/domain/registry/read-on-behalf.js +31 -0
- package/dist/domain/registry/read-on-behalf.js.map +1 -0
- package/dist/domain/registry/read-reach.d.ts +62 -0
- package/dist/domain/registry/read-reach.js +78 -0
- package/dist/domain/registry/read-reach.js.map +1 -0
- package/dist/domain/registry/recrew-ship.d.ts +3 -2
- package/dist/domain/registry/recrew-ship.js +6 -1
- package/dist/domain/registry/recrew-ship.js.map +1 -1
- package/dist/domain/registry/release-ship.d.ts +6 -3
- package/dist/domain/registry/release-ship.js +7 -7
- package/dist/domain/registry/release-ship.js.map +1 -1
- package/dist/domain/registry/remove-crew-request.d.ts +4 -3
- package/dist/domain/registry/remove-crew-request.js +6 -1
- package/dist/domain/registry/remove-crew-request.js.map +1 -1
- package/dist/domain/registry/rename-ship.d.ts +7 -5
- package/dist/domain/registry/rename-ship.js +9 -3
- package/dist/domain/registry/rename-ship.js.map +1 -1
- package/dist/domain/registry/request-crew.d.ts +5 -4
- package/dist/domain/registry/request-crew.js +6 -1
- package/dist/domain/registry/request-crew.js.map +1 -1
- package/dist/domain/registry/request-worktree-clear.d.ts +3 -2
- package/dist/domain/registry/request-worktree-clear.js +6 -1
- package/dist/domain/registry/request-worktree-clear.js.map +1 -1
- package/dist/domain/registry/retire-ship.d.ts +16 -7
- package/dist/domain/registry/retire-ship.js +46 -5
- package/dist/domain/registry/retire-ship.js.map +1 -1
- package/dist/domain/registry/scope-grant.d.ts +53 -0
- package/dist/domain/registry/scope-grant.js +74 -0
- package/dist/domain/registry/scope-grant.js.map +1 -0
- package/dist/domain/registry/scope-namespace.d.ts +68 -0
- package/dist/domain/registry/scope-namespace.js +82 -0
- package/dist/domain/registry/scope-namespace.js.map +1 -0
- package/dist/domain/registry/set-built-in-rule.d.ts +28 -0
- package/dist/domain/registry/set-built-in-rule.js +33 -0
- package/dist/domain/registry/set-built-in-rule.js.map +1 -0
- package/dist/domain/registry/set-network-rules.d.ts +3 -3
- package/dist/domain/registry/set-network-rules.js +2 -2
- package/dist/domain/registry/set-owner.d.ts +30 -0
- package/dist/domain/registry/set-owner.js +37 -0
- package/dist/domain/registry/set-owner.js.map +1 -0
- package/dist/domain/registry/set-statement.d.ts +27 -0
- package/dist/domain/registry/set-statement.js +28 -0
- package/dist/domain/registry/set-statement.js.map +1 -0
- package/dist/domain/registry/ship.d.ts +70 -10
- package/dist/domain/registry/ship.js +95 -10
- package/dist/domain/registry/ship.js.map +1 -1
- package/dist/domain/registry/statement.d.ts +32 -0
- package/dist/domain/registry/statement.js +39 -0
- package/dist/domain/registry/statement.js.map +1 -0
- package/dist/domain/registry/unassign-label.js +1 -1
- package/dist/domain/registry/unassign-label.js.map +1 -1
- package/dist/domain/registry/whoami.d.ts +5 -1
- package/dist/domain/registry/whoami.js +7 -4
- package/dist/domain/registry/whoami.js.map +1 -1
- package/dist/domain/shared/caller.d.ts +5 -2
- package/dist/domain/shared/caller.js.map +1 -1
- package/dist/domain/shared/errors.d.ts +1 -1
- package/dist/domain/shared/errors.js.map +1 -1
- package/dist/domain/shared/events-read.d.ts +16 -0
- package/dist/domain/shared/events-read.js +15 -0
- package/dist/domain/shared/events-read.js.map +1 -0
- package/dist/domain/shared/follow-fleet.d.ts +8 -2
- package/dist/domain/shared/follow-fleet.js +14 -4
- package/dist/domain/shared/follow-fleet.js.map +1 -1
- package/dist/domain/shared/health.d.ts +9 -2
- package/dist/domain/shared/health.js +9 -3
- package/dist/domain/shared/health.js.map +1 -1
- package/dist/domain/shared/history.d.ts +9 -42
- package/dist/domain/shared/history.js +9 -0
- package/dist/domain/shared/history.js.map +1 -1
- package/dist/domain/shared/read-fleet-events.d.ts +8 -2
- package/dist/domain/shared/read-fleet-events.js +10 -4
- package/dist/domain/shared/read-fleet-events.js.map +1 -1
- package/dist/domain/shared/read-health.d.ts +4 -1
- package/dist/domain/shared/read-health.js +7 -2
- package/dist/domain/shared/read-health.js.map +1 -1
- package/dist/domain/shared/read-inbox.d.ts +6 -3
- package/dist/domain/shared/read-inbox.js +14 -4
- package/dist/domain/shared/read-inbox.js.map +1 -1
- package/dist/domain/shared/read-message.d.ts +6 -2
- package/dist/domain/shared/read-message.js +6 -2
- package/dist/domain/shared/read-message.js.map +1 -1
- package/dist/domain/shared/read-needs-attention.d.ts +4 -1
- package/dist/domain/shared/read-needs-attention.js +8 -3
- package/dist/domain/shared/read-needs-attention.js.map +1 -1
- package/dist/domain/shared/read-ship-messages.d.ts +6 -2
- package/dist/domain/shared/read-ship-messages.js +7 -2
- package/dist/domain/shared/read-ship-messages.js.map +1 -1
- package/dist/domain/shared/read-ship-timeline.d.ts +5 -2
- package/dist/domain/shared/read-ship-timeline.js +11 -6
- package/dist/domain/shared/read-ship-timeline.js.map +1 -1
- package/dist/domain/shared/read-ship-way.d.ts +11 -4
- package/dist/domain/shared/read-ship-way.js +9 -2
- package/dist/domain/shared/read-ship-way.js.map +1 -1
- package/dist/domain/shared/stuck.d.ts +10 -1
- package/dist/domain/shared/stuck.js +1 -1
- package/dist/domain/shared/stuck.js.map +1 -1
- package/dist/wiring.d.ts +18 -4
- package/dist/wiring.js +37 -18
- package/dist/wiring.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/prisma/migrations/20261018100000_force_scope/migration.sql +8 -0
- package/src/adapters/prisma/migrations/20261018110000_forced_delivery/migration.sql +4 -0
- package/src/adapters/prisma/migrations/20261018120000_person_and_app_ships/migration.sql +3 -0
- package/src/adapters/prisma/migrations/20261018130000_owners/migration.sql +14 -0
- package/src/adapters/prisma/migrations/20261018140000_owners_on_reach_refusals/migration.sql +14 -0
- package/src/adapters/prisma/migrations/20261018150000_network_verbs/migration.sql +9 -0
- package/src/adapters/prisma/migrations/20261018160000_built_in_rules/migration.sql +13 -0
- package/src/adapters/prisma/migrations/20261018170000_network_rules_a_list/migration.sql +5 -0
- package/src/adapters/prisma/migrations/20261018180000_verb_on_reach_refusals/migration.sql +4 -0
- package/src/adapters/prisma/migrations/20261018200000_lease_statements/migration.sql +3 -0
- package/src/adapters/prisma/migrations/20261018210000_declare_and_grant_scopes/migration.sql +8 -0
- package/src/adapters/prisma/migrations/20261018220000_plugin_scopes/migration.sql +14 -0
- package/src/adapters/prisma/migrations/20261018230000_scope_namespaces/migration.sql +20 -0
- package/src/adapters/prisma/migrations/20261018240000_trierarch_plugin_crew_run/migration.sql +44 -0
- package/src/adapters/prisma/migrations/20261018250000_scope_catalogue/migration.sql +66 -0
- package/src/adapters/prisma/migrations/20261019090000_reach_refusal_asked_by/migration.sql +2 -0
- package/src/adapters/prisma/migrations/20261019100000_on_behalf_scope/migration.sql +59 -0
- package/src/adapters/prisma/migrations/20261019110000_events_fleet_id_occurred_at/migration.sql +2 -0
- package/src/adapters/prisma/schema.prisma +47 -2
- package/dist/domain/shared/read-no-ship-can-take.d.ts +0 -13
- package/dist/domain/shared/read-no-ship-can-take.js +0 -12
- package/dist/domain/shared/read-no-ship-can-take.js.map +0 -1
- package/dist/domain/shared/read-overdue.d.ts +0 -13
- package/dist/domain/shared/read-overdue.js +0 -12
- package/dist/domain/shared/read-overdue.js.map +0 -1
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { hasScope } from '../shared/caller.js';
|
|
2
|
+
import { readsShip } from './read-reach.js';
|
|
2
3
|
/**
|
|
3
4
|
* Use case: the pending clear requests (decision 0032). A caller with
|
|
4
|
-
* fleet:read reads every trierarch's
|
|
5
|
-
* clearing; a trierarch with crew:run reads
|
|
6
|
-
* checked before this runs.
|
|
5
|
+
* fleet:read reads every trierarch's for the ships it reads (decision 0034),
|
|
6
|
+
* so the console shows a worktree clearing; a trierarch with crew:run reads
|
|
7
|
+
* its own. One of the two scopes is checked before this runs.
|
|
7
8
|
*/
|
|
8
9
|
export function createReadClearRequests(deps) {
|
|
9
10
|
return async (caller) => {
|
|
10
|
-
const
|
|
11
|
-
|
|
11
|
+
const reach = hasScope(caller, 'fleet:read') ? await deps.readReach(caller) : undefined;
|
|
12
|
+
const requests = reach
|
|
13
|
+
? (await deps.clearRequests.list(caller.fleetId)).filter((request) => readsShip(reach, request.shipId))
|
|
12
14
|
: await deps.clearRequests.listFor(caller.fleetId, caller.shipId);
|
|
13
15
|
return requests.map(({ trierarchShipId, shipId, repository, requestedBy, requestedAt }) => ({ trierarchShipId, shipId, repository, requestedBy, requestedAt }));
|
|
14
16
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-clear-requests.js","sourceRoot":"","sources":["../../../src/domain/registry/read-clear-requests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAe,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"read-clear-requests.js","sourceRoot":"","sources":["../../../src/domain/registry/read-clear-requests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAe,MAAM,qBAAqB,CAAC;AAG5D,OAAO,EAAE,SAAS,EAAoB,MAAM,iBAAiB,CAAC;AAO9D;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAiG;IACvI,OAAO,KAAK,EAAE,MAAM,EAAE,EAAE;QACtB,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxF,MAAM,QAAQ,GAAG,KAAK;YACpB,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACvG,CAAC,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACpE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IAClK,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ShipId } from '@aeolus-fleet/common';
|
|
2
|
+
import { type Caller } from '../shared/caller.js';
|
|
3
|
+
import { type DomainError } from '../shared/errors.js';
|
|
4
|
+
import { type Result } from '../shared/result.js';
|
|
5
|
+
import type { ShipRepository } from './ports.js';
|
|
6
|
+
export type ReadOnBehalf = (caller: Caller, input: {
|
|
7
|
+
shipId: ShipId;
|
|
8
|
+
}) => Promise<Result<Caller, DomainError<'SCOPE_NOT_HELD' | 'SHIP_NOT_FOUND' | 'SHIP_NOT_READ_ON_BEHALF'>>>;
|
|
9
|
+
/**
|
|
10
|
+
* Use case: the reader a plugin ship reads as on behalf of a named ship
|
|
11
|
+
* (decision 0034): the named ship with fleet:read only, so every fleet:read
|
|
12
|
+
* read filters by that ship's read reach whatever its own scopes, with the
|
|
13
|
+
* plugin kept as the one that asked. The plugin needs fleet:read and
|
|
14
|
+
* fleet:on-behalf itself: fleet:read alone reads only as its own ship. argo
|
|
15
|
+
* and the viewer are never named: their read is the whole fleet, which a
|
|
16
|
+
* plugin would gain by naming them.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createReadOnBehalf(deps: {
|
|
19
|
+
ships: Pick<ShipRepository, 'find'>;
|
|
20
|
+
}): ReadOnBehalf;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { hasScope } from '../shared/caller.js';
|
|
2
|
+
import { refuse } from '../shared/errors.js';
|
|
3
|
+
import { ok } from '../shared/result.js';
|
|
4
|
+
/**
|
|
5
|
+
* Use case: the reader a plugin ship reads as on behalf of a named ship
|
|
6
|
+
* (decision 0034): the named ship with fleet:read only, so every fleet:read
|
|
7
|
+
* read filters by that ship's read reach whatever its own scopes, with the
|
|
8
|
+
* plugin kept as the one that asked. The plugin needs fleet:read and
|
|
9
|
+
* fleet:on-behalf itself: fleet:read alone reads only as its own ship. argo
|
|
10
|
+
* and the viewer are never named: their read is the whole fleet, which a
|
|
11
|
+
* plugin would gain by naming them.
|
|
12
|
+
*/
|
|
13
|
+
export function createReadOnBehalf(deps) {
|
|
14
|
+
return async (caller, { shipId }) => {
|
|
15
|
+
if (!hasScope(caller, 'fleet:read')) {
|
|
16
|
+
return refuse('SCOPE_NOT_HELD', 'Reading on behalf of a ship needs the fleet:read scope');
|
|
17
|
+
}
|
|
18
|
+
if (!hasScope(caller, 'fleet:on-behalf')) {
|
|
19
|
+
return refuse('SCOPE_NOT_HELD', 'Reading on behalf of a ship needs the fleet:on-behalf scope');
|
|
20
|
+
}
|
|
21
|
+
const ship = await deps.ships.find(caller.fleetId, shipId);
|
|
22
|
+
if (ship?.retiredAt !== null) {
|
|
23
|
+
return refuse('SHIP_NOT_FOUND', `No ship ${shipId} in this fleet`);
|
|
24
|
+
}
|
|
25
|
+
if (ship.kind === 'operator' || ship.kind === 'viewer') {
|
|
26
|
+
return refuse('SHIP_NOT_READ_ON_BEHALF', `A plugin reads on behalf of no ${ship.kind === 'operator' ? 'argo' : 'viewer'}: its read is the whole fleet`);
|
|
27
|
+
}
|
|
28
|
+
return ok({ fleetId: caller.fleetId, shipId: ship.id, kind: ship.kind, scopes: ['fleet:read'], askedBy: caller.shipId });
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=read-on-behalf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-on-behalf.js","sourceRoot":"","sources":["../../../src/domain/registry/read-on-behalf.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAe,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAQtD;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAA6C;IAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC;YACpC,OAAO,MAAM,CAAC,gBAAgB,EAAE,wDAAwD,CAAC,CAAC;QAC5F,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACzC,OAAO,MAAM,CAAC,gBAAgB,EAAE,6DAA6D,CAAC,CAAC;QACjG,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3D,IAAI,IAAI,EAAE,SAAS,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO,MAAM,CAAC,gBAAgB,EAAE,WAAW,MAAM,gBAAgB,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO,MAAM,CAAC,yBAAyB,EAAE,kCAAkC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,+BAA+B,CAAC,CAAC;QAC1J,CAAC;QACD,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3H,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { EventType, ShipId } from '@aeolus-fleet/common';
|
|
2
|
+
import type { Caller } from '../shared/caller.js';
|
|
3
|
+
import type { Clock } from '../shared/clock.js';
|
|
4
|
+
import type { Recipient } from '../shared/selector.js';
|
|
5
|
+
import type { UnitOfWork } from '../shared/unit-of-work.js';
|
|
6
|
+
import { type CheckReachTx } from './check-reach.js';
|
|
7
|
+
import type { ShipRepository } from './ports.js';
|
|
8
|
+
/**
|
|
9
|
+
* The ships a caller reads (decision 0034): every ship, or some by id, with
|
|
10
|
+
* the types of the active ones among them, by which an unclaimed message to a
|
|
11
|
+
* type is read.
|
|
12
|
+
*/
|
|
13
|
+
export type ReadReach = {
|
|
14
|
+
kind: 'every';
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'some';
|
|
17
|
+
shipIds: ReadonlySet<ShipId>;
|
|
18
|
+
types: ReadonlySet<string>;
|
|
19
|
+
};
|
|
20
|
+
/** The ports read reach is worked out from, in one unit of work so it reads one version of the rules. */
|
|
21
|
+
export interface ReadReachTx {
|
|
22
|
+
networkSettings: CheckReachTx['networkSettings'];
|
|
23
|
+
ships: Pick<ShipRepository, 'find' | 'list'>;
|
|
24
|
+
labels: Pick<CheckReachTx['labels'], 'carriedBy'>;
|
|
25
|
+
leases: CheckReachTx['leases'];
|
|
26
|
+
}
|
|
27
|
+
/** A message as read reach sees it: its sender, its recipient, and for a type the ship that claimed it, if one has. */
|
|
28
|
+
export interface MessageParties {
|
|
29
|
+
senderId: ShipId;
|
|
30
|
+
recipient: Recipient;
|
|
31
|
+
claimedBy: ShipId | null;
|
|
32
|
+
}
|
|
33
|
+
export type ReadReachOf = (caller: Caller) => Promise<ReadReach>;
|
|
34
|
+
/**
|
|
35
|
+
* Works out what a caller reads now, as a send is checked: the rules in
|
|
36
|
+
* force, what the networking plugin declared while it does not respond, the
|
|
37
|
+
* built-in rules, read rules only. A ship always reads itself. argo reads
|
|
38
|
+
* every ship, as does every ship while open is on for read and the viewer
|
|
39
|
+
* while its reading is on; otherwise each ship of the fleet, retired ones
|
|
40
|
+
* too, is read when a rule lets the caller read it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createReadReachOf(deps: {
|
|
43
|
+
uow: UnitOfWork<ReadReachTx>;
|
|
44
|
+
clock: Clock;
|
|
45
|
+
}): ReadReachOf;
|
|
46
|
+
export declare function readsShip(reach: ReadReach, shipId: ShipId): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the reach reads the message: through its sender or its recipient.
|
|
49
|
+
* A message to a type is read through the ship that claimed it, or while none
|
|
50
|
+
* has, through any active ship of the type the reach reads.
|
|
51
|
+
*/
|
|
52
|
+
export declare function readsMessage(reach: ReadReach, message: MessageParties): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Whether the reach reads an event: through the message it concerns, else
|
|
55
|
+
* through the ship it concerns. One that concerns neither, such as a label's,
|
|
56
|
+
* or a rules event, every reader reads. Who caused it does not count.
|
|
57
|
+
*/
|
|
58
|
+
export declare function readsEvent(reach: ReadReach, event: {
|
|
59
|
+
type: EventType;
|
|
60
|
+
shipId: ShipId | null;
|
|
61
|
+
message: MessageParties | null;
|
|
62
|
+
}): boolean;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ok } from '../shared/result.js';
|
|
2
|
+
import { rulesInForceAt } from './check-reach.js';
|
|
3
|
+
import { allowsReach } from './network-settings.js';
|
|
4
|
+
const EVERY = { kind: 'every' };
|
|
5
|
+
/**
|
|
6
|
+
* Works out what a caller reads now, as a send is checked: the rules in
|
|
7
|
+
* force, what the networking plugin declared while it does not respond, the
|
|
8
|
+
* built-in rules, read rules only. A ship always reads itself. argo reads
|
|
9
|
+
* every ship, as does every ship while open is on for read and the viewer
|
|
10
|
+
* while its reading is on; otherwise each ship of the fleet, retired ones
|
|
11
|
+
* too, is read when a rule lets the caller read it.
|
|
12
|
+
*/
|
|
13
|
+
export function createReadReachOf(deps) {
|
|
14
|
+
return async (caller) => {
|
|
15
|
+
const worked = await deps.uow.run(async (tx) => {
|
|
16
|
+
if (caller.kind === 'operator') {
|
|
17
|
+
return ok(EVERY);
|
|
18
|
+
}
|
|
19
|
+
const { fleetId } = caller;
|
|
20
|
+
const settings = await tx.networkSettings.findForShare(fleetId);
|
|
21
|
+
const inForce = await rulesInForceAt(tx, { settings, now: deps.clock.now() });
|
|
22
|
+
if (inForce.builtIns.open.read || (caller.kind === 'viewer' && inForce.builtIns.isViewerReadOn)) {
|
|
23
|
+
return ok(EVERY);
|
|
24
|
+
}
|
|
25
|
+
const readerShip = await tx.ships.find(fleetId, caller.shipId);
|
|
26
|
+
const reader = readerShip && (await reachingOf(tx, readerShip));
|
|
27
|
+
const read = [];
|
|
28
|
+
for (const ship of await tx.ships.list(fleetId)) {
|
|
29
|
+
if (ship.id === caller.shipId || (reader && allowsReach(inForce, { verb: 'read', sender: reader, recipient: await reachingOf(tx, ship), isAnswerToSender: false }))) {
|
|
30
|
+
read.push(ship);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return ok({
|
|
34
|
+
kind: 'some',
|
|
35
|
+
shipIds: new Set(read.map((ship) => ship.id)),
|
|
36
|
+
types: new Set(read.filter((ship) => ship.retiredAt === null && ship.kind !== 'viewer').map((ship) => ship.type)),
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
// The work refuses nothing; were it to, the caller reads only itself.
|
|
40
|
+
return worked.isOk ? worked.value : { kind: 'some', shipIds: new Set([caller.shipId]), types: new Set() };
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async function reachingOf(tx, ship) {
|
|
44
|
+
const labels = (await tx.labels.carriedBy(ship.fleetId, ship.id)).map(({ labelId, valueId }) => ({ labelId, valueId }));
|
|
45
|
+
return { id: ship.id, owner: ship.owner, kind: ship.kind, labels };
|
|
46
|
+
}
|
|
47
|
+
export function readsShip(reach, shipId) {
|
|
48
|
+
return reach.kind === 'every' || reach.shipIds.has(shipId);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Whether the reach reads the message: through its sender or its recipient.
|
|
52
|
+
* A message to a type is read through the ship that claimed it, or while none
|
|
53
|
+
* has, through any active ship of the type the reach reads.
|
|
54
|
+
*/
|
|
55
|
+
export function readsMessage(reach, message) {
|
|
56
|
+
if (reach.kind === 'every' || readsShip(reach, message.senderId)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
const { recipient, claimedBy } = message;
|
|
60
|
+
if (recipient.kind === 'ship') {
|
|
61
|
+
return readsShip(reach, recipient.shipId);
|
|
62
|
+
}
|
|
63
|
+
return claimedBy === null ? reach.types.has(recipient.type) : readsShip(reach, claimedBy);
|
|
64
|
+
}
|
|
65
|
+
/** The events about the rules: they concern no ship, whichever ship set or declared them, so every reader reads them. */
|
|
66
|
+
const RULES_EVENTS = new Set(['NetworkRulesDeclared', 'NetworkRulesSet', 'BuiltInRuleChanged']);
|
|
67
|
+
/**
|
|
68
|
+
* Whether the reach reads an event: through the message it concerns, else
|
|
69
|
+
* through the ship it concerns. One that concerns neither, such as a label's,
|
|
70
|
+
* or a rules event, every reader reads. Who caused it does not count.
|
|
71
|
+
*/
|
|
72
|
+
export function readsEvent(reach, event) {
|
|
73
|
+
if (event.message !== null) {
|
|
74
|
+
return readsMessage(reach, event.message);
|
|
75
|
+
}
|
|
76
|
+
return event.shipId === null || RULES_EVENTS.has(event.type) || readsShip(reach, event.shipId);
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=read-reach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-reach.js","sourceRoot":"","sources":["../../../src/domain/registry/read-reach.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAGtD,OAAO,EAAE,cAAc,EAAqB,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAqB,MAAM,uBAAuB,CAAC;AA4BvE,MAAM,KAAK,GAAc,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAoD;IACpF,OAAO,KAAK,EAAE,MAAM,EAAE,EAAE;QACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAqC,EAAE;YAChF,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC/B,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;YACD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;YAC3B,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAChE,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC9E,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBAChG,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;YACD,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC/D,MAAM,MAAM,GAAG,UAAU,IAAI,CAAC,MAAM,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;YAChE,MAAM,IAAI,GAAW,EAAE,CAAC;YACxB,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChD,IAAI,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;oBACpK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClB,CAAC;YACH,CAAC;YACD,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC7C,KAAK,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aAClH,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,sEAAsE;QACtE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IAC5G,CAAC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,EAA+B,EAAE,IAAU;IACnE,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACxH,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAgB,EAAE,MAAc;IACxD,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAgB,EAAE,OAAuB;IACpE,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IACzC,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC5F,CAAC;AAED,yHAAyH;AACzH,MAAM,YAAY,GAA2B,IAAI,GAAG,CAAC,CAAC,sBAAsB,EAAE,iBAAiB,EAAE,oBAAoB,CAAC,CAAC,CAAC;AAExH;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAgB,EAAE,KAAiF;IAC5H,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC3B,OAAO,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AACjG,CAAC"}
|
|
@@ -6,14 +6,15 @@ import { type DomainError } from '../shared/errors.js';
|
|
|
6
6
|
import { type Result } from '../shared/result.js';
|
|
7
7
|
import type { UnitOfWork } from '../shared/unit-of-work.js';
|
|
8
8
|
import { type LeaseTx } from './leases.js';
|
|
9
|
+
import { type CheckManageTx, type NotReachable } from './check-reach.js';
|
|
9
10
|
import type { ShipRepository } from './ports.js';
|
|
10
11
|
import type { ReleaseShipTx } from './release-ship.js';
|
|
11
12
|
import { type ReleaseRefusal } from './ship.js';
|
|
12
13
|
import { type IssuedStartingPrompt, type StartingPromptTx } from './starting-prompt.js';
|
|
13
|
-
export type RecrewShipTx = ReleaseShipTx & StartingPromptTx & LeaseTx & {
|
|
14
|
+
export type RecrewShipTx = ReleaseShipTx & StartingPromptTx & LeaseTx & CheckManageTx & {
|
|
14
15
|
ships: ShipRepository;
|
|
15
16
|
};
|
|
16
|
-
export type RecrewShipRefusal = DomainError<'SHIP_NOT_FOUND'> | ReleaseRefusal;
|
|
17
|
+
export type RecrewShipRefusal = DomainError<'SHIP_NOT_FOUND'> | NotReachable | ReleaseRefusal;
|
|
17
18
|
export type RecrewShip = (caller: Caller, input: {
|
|
18
19
|
shipId: ShipId;
|
|
19
20
|
}) => Promise<Result<IssuedStartingPrompt, RecrewShipRefusal>>;
|
|
@@ -3,6 +3,7 @@ import { refuse } from '../shared/errors.js';
|
|
|
3
3
|
import { shipActor } from '../shared/events.js';
|
|
4
4
|
import { ok } from '../shared/result.js';
|
|
5
5
|
import { endLease } from './leases.js';
|
|
6
|
+
import { checkManage, keepingReachRefusal } from './check-reach.js';
|
|
6
7
|
import { checkCanRelease } from './ship.js';
|
|
7
8
|
import { issueStartingPrompt } from './starting-prompt.js';
|
|
8
9
|
/**
|
|
@@ -14,12 +15,16 @@ import { issueStartingPrompt } from './starting-prompt.js';
|
|
|
14
15
|
* (fleet:manage) is checked before this runs.
|
|
15
16
|
*/
|
|
16
17
|
export function createRecrewShip(deps) {
|
|
17
|
-
return (caller, { shipId }) => deps.uow
|
|
18
|
+
return (caller, { shipId }) => keepingReachRefusal(deps.uow, async (tx) => {
|
|
18
19
|
const { fleetId } = caller;
|
|
19
20
|
const ship = await tx.ships.findForUpdate(fleetId, shipId);
|
|
20
21
|
if (!ship) {
|
|
21
22
|
return refuse('SHIP_NOT_FOUND', `Ship ${shipId} does not exist`);
|
|
22
23
|
}
|
|
24
|
+
const managed = await checkManage({ tx, ids: deps.ids }, { fleetId: fleetId, managerShipId: caller.shipId, shipId: ship.id, at: deps.clock.now() });
|
|
25
|
+
if (!managed.isOk) {
|
|
26
|
+
return managed;
|
|
27
|
+
}
|
|
23
28
|
const actor = shipActor(caller.shipId);
|
|
24
29
|
const at = deps.clock.now();
|
|
25
30
|
await revokeShipSecret({ tx, ids: deps.ids }, { fleetId, shipId, actor, at });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recrew-ship.js","sourceRoot":"","sources":["../../../src/domain/registry/recrew-ship.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAG3E,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAgB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"recrew-ship.js","sourceRoot":"","sources":["../../../src/domain/registry/recrew-ship.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAG3E,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAgB,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAyC,MAAM,kBAAkB,CAAC;AAG3G,OAAO,EAAE,eAAe,EAAuB,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAoD,MAAM,sBAAsB,CAAC;AAW7G;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAKhC;IACC,OAAO,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAC5B,mBAAmB,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAA4D,EAAE;QACnG,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,MAAM,CAAC,gBAAgB,EAAE,QAAQ,MAAM,iBAAiB,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpJ,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAE5B,MAAM,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9E,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACxF,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,QAAQ,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3G,OAAO,EAAE,CACP,MAAM,mBAAmB,CACvB,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EACnD,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAC/B,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -6,13 +6,15 @@ import { type DomainError } from '../shared/errors.js';
|
|
|
6
6
|
import { type Result } from '../shared/result.js';
|
|
7
7
|
import type { UnitOfWork } from '../shared/unit-of-work.js';
|
|
8
8
|
import { type LeaseTx } from './leases.js';
|
|
9
|
+
import { type NotReachable } from './check-reach.js';
|
|
10
|
+
import { type ManagedOrAssignedTx } from './managed-or-assigned.js';
|
|
9
11
|
import type { CrewRequestRepository, ShipRepository } from './ports.js';
|
|
10
12
|
import { type ReleaseRefusal } from './ship.js';
|
|
11
|
-
export interface ReleaseShipTx extends LeaseTx, CredentialTx {
|
|
13
|
+
export interface ReleaseShipTx extends LeaseTx, CredentialTx, Omit<ManagedOrAssignedTx, 'ships' | 'leases' | 'crewRequests'> {
|
|
12
14
|
ships: ShipRepository;
|
|
13
15
|
crewRequests: Pick<CrewRequestRepository, 'find'>;
|
|
14
16
|
}
|
|
15
|
-
export type ReleaseShipRefusal = DomainError<'SHIP_NOT_FOUND' | 'CREW_REQUEST_NOT_ASSIGNED_TO_CALLER'> | ReleaseRefusal;
|
|
17
|
+
export type ReleaseShipRefusal = DomainError<'SHIP_NOT_FOUND' | 'CREW_REQUEST_NOT_ASSIGNED_TO_CALLER'> | NotReachable | ReleaseRefusal;
|
|
16
18
|
export type ReleaseShip = (caller: Caller, input: {
|
|
17
19
|
shipId: ShipId;
|
|
18
20
|
}) => Promise<Result<undefined, ReleaseShipRefusal>>;
|
|
@@ -24,7 +26,8 @@ export type ReleaseShip = (caller: Caller, input: {
|
|
|
24
26
|
* their attempts kept. The next crew needs a new starting prompt. The caller's
|
|
25
27
|
* scope (fleet:manage or crew:run) is checked before this runs;
|
|
26
28
|
* crew:run reaches only the ships whose crew requests are assigned to the
|
|
27
|
-
* caller's ship
|
|
29
|
+
* caller's ship, and fleet:manage the ships in its manage reach (decision
|
|
30
|
+
* 0034).
|
|
28
31
|
*
|
|
29
32
|
* Locks in the fleet's order: the ship, then its secret, then its lease. A
|
|
30
33
|
* receive holding the lease makes the release wait, then the release returns
|
|
@@ -3,10 +3,9 @@ import { refuse } from '../shared/errors.js';
|
|
|
3
3
|
import { shipActor } from '../shared/events.js';
|
|
4
4
|
import { ok } from '../shared/result.js';
|
|
5
5
|
import { endLease } from './leases.js';
|
|
6
|
-
import {
|
|
6
|
+
import { keepingReachRefusal } from './check-reach.js';
|
|
7
|
+
import { checkManagedOrAssigned } from './managed-or-assigned.js';
|
|
7
8
|
import { checkCanRelease } from './ship.js';
|
|
8
|
-
/** The scopes that release every ship; crew:run releases only the ships assigned to the caller's ship. */
|
|
9
|
-
const RELEASE_SCOPES = ['fleet:manage'];
|
|
10
9
|
/**
|
|
11
10
|
* Use case: the caller releases a crewed ship of its fleet (Release): the
|
|
12
11
|
* session crewing it loses it, and the ship awaits a new crew (ADR 0010). In
|
|
@@ -15,7 +14,8 @@ const RELEASE_SCOPES = ['fleet:manage'];
|
|
|
15
14
|
* their attempts kept. The next crew needs a new starting prompt. The caller's
|
|
16
15
|
* scope (fleet:manage or crew:run) is checked before this runs;
|
|
17
16
|
* crew:run reaches only the ships whose crew requests are assigned to the
|
|
18
|
-
* caller's ship
|
|
17
|
+
* caller's ship, and fleet:manage the ships in its manage reach (decision
|
|
18
|
+
* 0034).
|
|
19
19
|
*
|
|
20
20
|
* Locks in the fleet's order: the ship, then its secret, then its lease. A
|
|
21
21
|
* receive holding the lease makes the release wait, then the release returns
|
|
@@ -23,18 +23,18 @@ const RELEASE_SCOPES = ['fleet:manage'];
|
|
|
23
23
|
* prompt reads it, and a refusal rolls the revoked secret back.
|
|
24
24
|
*/
|
|
25
25
|
export function createReleaseShip(deps) {
|
|
26
|
-
return (caller, { shipId }) => deps.uow
|
|
26
|
+
return (caller, { shipId }) => keepingReachRefusal(deps.uow, async (tx) => {
|
|
27
27
|
const { fleetId } = caller;
|
|
28
28
|
const ship = await tx.ships.findForUpdate(fleetId, shipId);
|
|
29
29
|
if (!ship) {
|
|
30
30
|
return refuse('SHIP_NOT_FOUND', `Ship ${shipId} does not exist`);
|
|
31
31
|
}
|
|
32
|
-
const
|
|
32
|
+
const at = deps.clock.now();
|
|
33
|
+
const reaches = await checkManagedOrAssigned({ tx, ids: deps.ids }, { caller, ship, at });
|
|
33
34
|
if (!reaches.isOk) {
|
|
34
35
|
return reaches;
|
|
35
36
|
}
|
|
36
37
|
const actor = shipActor(caller.shipId);
|
|
37
|
-
const at = deps.clock.now();
|
|
38
38
|
await revokeShipSecret({ tx, ids: deps.ids }, { fleetId, shipId, actor, at });
|
|
39
39
|
const lease = checkCanRelease(ship, await tx.leases.findOpenForUpdate(fleetId, shipId));
|
|
40
40
|
if (!lease.isOk) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-ship.js","sourceRoot":"","sources":["../../../src/domain/registry/release-ship.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,uBAAuB,CAAC;AAG5E,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAgB,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"release-ship.js","sourceRoot":"","sources":["../../../src/domain/registry/release-ship.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,uBAAuB,CAAC;AAG5E,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAgB,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAqB,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAA4B,MAAM,0BAA0B,CAAC;AAE5F,OAAO,EAAE,eAAe,EAAuB,MAAM,WAAW,CAAC;AAcjE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAIjC;IACC,OAAO,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAC5B,mBAAmB,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAkD,EAAE;QACzF,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,MAAM,CAAC,gBAAgB,EAAE,QAAQ,MAAM,iBAAiB,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1F,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAEvC,MAAM,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9E,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACxF,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,QAAQ,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3G,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -5,15 +5,16 @@ import { type DomainError } from '../shared/errors.js';
|
|
|
5
5
|
import { type EventLog } from '../shared/events.js';
|
|
6
6
|
import { type Result } from '../shared/result.js';
|
|
7
7
|
import type { UnitOfWork } from '../shared/unit-of-work.js';
|
|
8
|
+
import { type CheckManageTx, type NotReachable } from './check-reach.js';
|
|
8
9
|
import type { CrewRequestRepository, ShipRepository } from './ports.js';
|
|
9
|
-
export interface RemoveCrewRequestTx {
|
|
10
|
-
ships: Pick<ShipRepository, 'findForUpdate'>;
|
|
10
|
+
export interface RemoveCrewRequestTx extends Omit<CheckManageTx, 'ships'> {
|
|
11
|
+
ships: Pick<ShipRepository, 'find' | 'findForUpdate'>;
|
|
11
12
|
crewRequests: CrewRequestRepository;
|
|
12
13
|
events: EventLog;
|
|
13
14
|
}
|
|
14
15
|
export type RemoveCrewRequest = (caller: Caller, input: {
|
|
15
16
|
shipId: ShipId;
|
|
16
|
-
}) => Promise<Result<undefined, DomainError<'SHIP_NOT_FOUND' | 'CREW_REQUEST_NOT_FOUND'
|
|
17
|
+
}) => Promise<Result<undefined, DomainError<'SHIP_NOT_FOUND' | 'CREW_REQUEST_NOT_FOUND'> | NotReachable>>;
|
|
17
18
|
/**
|
|
18
19
|
* Use case: a requester removes a ship's crew request. Its scope
|
|
19
20
|
* (fleet:manage) is checked before this runs. In one unit of work, locking the
|
|
@@ -2,6 +2,7 @@ import { refuse } from '../shared/errors.js';
|
|
|
2
2
|
import { recordEvent, shipActor } from '../shared/events.js';
|
|
3
3
|
import { ok } from '../shared/result.js';
|
|
4
4
|
import { removeCrewRequest } from './crew-request.js';
|
|
5
|
+
import { checkManage, keepingReachRefusal } from './check-reach.js';
|
|
5
6
|
/**
|
|
6
7
|
* Use case: a requester removes a ship's crew request. Its scope
|
|
7
8
|
* (fleet:manage) is checked before this runs. In one unit of work, locking the
|
|
@@ -10,11 +11,15 @@ import { removeCrewRequest } from './crew-request.js';
|
|
|
10
11
|
* confirm. A crew aboard without a trierarch stays aboard.
|
|
11
12
|
*/
|
|
12
13
|
export function createRemoveCrewRequest(deps) {
|
|
13
|
-
return (caller, input) => deps.uow
|
|
14
|
+
return (caller, input) => keepingReachRefusal(deps.uow, async (tx) => {
|
|
14
15
|
const ship = await tx.ships.findForUpdate(caller.fleetId, input.shipId);
|
|
15
16
|
if (!ship) {
|
|
16
17
|
return refuse('SHIP_NOT_FOUND', `Ship ${input.shipId} does not exist`);
|
|
17
18
|
}
|
|
19
|
+
const managed = await checkManage({ tx, ids: deps.ids }, { fleetId: caller.fleetId, managerShipId: caller.shipId, shipId: ship.id, at: deps.clock.now() });
|
|
20
|
+
if (!managed.isOk) {
|
|
21
|
+
return managed;
|
|
22
|
+
}
|
|
18
23
|
const current = await tx.crewRequests.find(caller.fleetId, ship.id);
|
|
19
24
|
const removed = removeCrewRequest({ ship, current }, { at: deps.clock.now(), actor: shipActor(caller.shipId) });
|
|
20
25
|
if (!removed.isOk) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-crew-request.js","sourceRoot":"","sources":["../../../src/domain/registry/remove-crew-request.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAiB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"remove-crew-request.js","sourceRoot":"","sources":["../../../src/domain/registry/remove-crew-request.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAiB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAyC,MAAM,kBAAkB,CAAC;AAc3G;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAA8E;IACpH,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CACvB,mBAAmB,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAuG,EAAE;QAC9I,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACxE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,MAAM,CAAC,gBAAgB,EAAE,QAAQ,KAAK,CAAC,MAAM,iBAAiB,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC3J,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,iBAAiB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChH,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAClC,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACzC,MAAM,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -5,20 +5,22 @@ import { type DomainError } from '../shared/errors.js';
|
|
|
5
5
|
import { type EventLog } from '../shared/events.js';
|
|
6
6
|
import { type Result } from '../shared/result.js';
|
|
7
7
|
import type { UnitOfWork } from '../shared/unit-of-work.js';
|
|
8
|
+
import { type CheckManageTx, type NotReachable } from './check-reach.js';
|
|
8
9
|
import type { ShipRepository } from './ports.js';
|
|
9
10
|
import { type RenameRefusal } from './ship.js';
|
|
10
|
-
export interface RenameShipTx {
|
|
11
|
-
ships: Pick<ShipRepository, 'findForUpdate' | 'lockName' | 'findActiveByName' | 'rename'>;
|
|
11
|
+
export interface RenameShipTx extends Omit<CheckManageTx, 'ships'> {
|
|
12
|
+
ships: Pick<ShipRepository, 'find' | 'findForUpdate' | 'lockName' | 'findActiveByName' | 'rename'>;
|
|
12
13
|
events: EventLog;
|
|
13
14
|
}
|
|
14
|
-
export type RenameShipRefusal = DomainError<'SHIP_NOT_FOUND'> | RenameRefusal;
|
|
15
|
+
export type RenameShipRefusal = DomainError<'SHIP_NOT_FOUND'> | NotReachable | RenameRefusal;
|
|
15
16
|
export type RenameShip = (caller: Caller, input: {
|
|
16
17
|
shipId: ShipId;
|
|
17
18
|
name: string;
|
|
18
19
|
}) => Promise<Result<undefined, RenameShipRefusal>>;
|
|
19
20
|
/**
|
|
20
|
-
* Use case: the
|
|
21
|
-
* before this runs
|
|
21
|
+
* Use case: the caller renames a ship it manages: its scope (fleet:manage)
|
|
22
|
+
* is checked before this runs, and manage reach on the ship here (decision
|
|
23
|
+
* 0034), a refusal storing only its record. In one unit of work, locking the ship, then the new name
|
|
22
24
|
* (as a commission does), so two renames or a commission to one name never
|
|
23
25
|
* both find it free: the new name and ShipRenamed. Its id, history and
|
|
24
26
|
* session stay; a sender addressing the old name no longer reaches it.
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import { refuse } from '../shared/errors.js';
|
|
2
2
|
import { recordEvent, shipActor } from '../shared/events.js';
|
|
3
3
|
import { ok } from '../shared/result.js';
|
|
4
|
+
import { checkManage, keepingReachRefusal } from './check-reach.js';
|
|
4
5
|
import { renameShip } from './ship.js';
|
|
5
6
|
/**
|
|
6
|
-
* Use case: the
|
|
7
|
-
* before this runs
|
|
7
|
+
* Use case: the caller renames a ship it manages: its scope (fleet:manage)
|
|
8
|
+
* is checked before this runs, and manage reach on the ship here (decision
|
|
9
|
+
* 0034), a refusal storing only its record. In one unit of work, locking the ship, then the new name
|
|
8
10
|
* (as a commission does), so two renames or a commission to one name never
|
|
9
11
|
* both find it free: the new name and ShipRenamed. Its id, history and
|
|
10
12
|
* session stay; a sender addressing the old name no longer reaches it.
|
|
11
13
|
*/
|
|
12
14
|
export function createRenameShip(deps) {
|
|
13
|
-
return (caller, input) => deps.uow
|
|
15
|
+
return (caller, input) => keepingReachRefusal(deps.uow, async (tx) => {
|
|
14
16
|
const { fleetId } = caller;
|
|
15
17
|
const ship = await tx.ships.findForUpdate(fleetId, input.shipId);
|
|
16
18
|
if (!ship) {
|
|
17
19
|
return refuse('SHIP_NOT_FOUND', `Ship ${input.shipId} does not exist`);
|
|
18
20
|
}
|
|
21
|
+
const managed = await checkManage({ tx, ids: deps.ids }, { fleetId, managerShipId: caller.shipId, shipId: ship.id, at: deps.clock.now() });
|
|
22
|
+
if (!managed.isOk) {
|
|
23
|
+
return managed;
|
|
24
|
+
}
|
|
19
25
|
await tx.ships.lockName(fleetId, input.name);
|
|
20
26
|
const renamed = renameShip(ship, {
|
|
21
27
|
name: input.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rename-ship.js","sourceRoot":"","sources":["../../../src/domain/registry/rename-ship.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAiB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"rename-ship.js","sourceRoot":"","sources":["../../../src/domain/registry/rename-ship.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAiB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAyC,MAAM,kBAAkB,CAAC;AAE3G,OAAO,EAAE,UAAU,EAAsB,MAAM,WAAW,CAAC;AAc3D;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAuE;IACtG,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CACvB,mBAAmB,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAiD,EAAE;QACxF,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,MAAM,CAAC,gBAAgB,EAAE,QAAQ,KAAK,CAAC,MAAM,iBAAiB,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC3I,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE;YAC/B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;YACpB,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;YAC/B,eAAe,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC;SACtE,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAChD,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1E,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -6,12 +6,13 @@ import { type EventLog } from '../shared/events.js';
|
|
|
6
6
|
import { type Result } from '../shared/result.js';
|
|
7
7
|
import type { UnitOfWork } from '../shared/unit-of-work.js';
|
|
8
8
|
import { type RequestCrewRefusal } from './crew-request.js';
|
|
9
|
+
import { type CheckManageTx, type NotReachable } from './check-reach.js';
|
|
9
10
|
import type { CrewRequestRepository, LabelRepository, ShipRepository } from './ports.js';
|
|
10
11
|
import type { JsonObject } from './report-details.js';
|
|
11
|
-
export interface RequestCrewTx {
|
|
12
|
-
ships: Pick<ShipRepository, 'findForUpdate'>;
|
|
12
|
+
export interface RequestCrewTx extends Omit<CheckManageTx, 'ships' | 'labels'> {
|
|
13
|
+
ships: Pick<ShipRepository, 'find' | 'findForUpdate'>;
|
|
13
14
|
crewRequests: CrewRequestRepository;
|
|
14
|
-
labels: Pick<LabelRepository, 'findByValueForShare'>;
|
|
15
|
+
labels: Pick<LabelRepository, 'findByValueForShare' | 'carriedBy' | 'find'>;
|
|
15
16
|
events: EventLog;
|
|
16
17
|
}
|
|
17
18
|
export type RequestCrew = (caller: Caller, input: {
|
|
@@ -19,7 +20,7 @@ export type RequestCrew = (caller: Caller, input: {
|
|
|
19
20
|
settings: JsonObject;
|
|
20
21
|
}) => Promise<Result<{
|
|
21
22
|
settingsVersion: number;
|
|
22
|
-
}, DomainError<'SHIP_NOT_FOUND'> | RequestCrewRefusal>>;
|
|
23
|
+
}, DomainError<'SHIP_NOT_FOUND'> | NotReachable | RequestCrewRefusal>>;
|
|
23
24
|
/**
|
|
24
25
|
* Use case: a requester asks that a ship be kept crewed, with these settings,
|
|
25
26
|
* replacing any request the ship holds. Its scope (fleet:manage) is checked
|
|
@@ -2,6 +2,7 @@ import { refuse } from '../shared/errors.js';
|
|
|
2
2
|
import { recordEvent, shipActor } from '../shared/events.js';
|
|
3
3
|
import { ok } from '../shared/result.js';
|
|
4
4
|
import { machineLabelsOf, requestCrew } from './crew-request.js';
|
|
5
|
+
import { checkManage, keepingReachRefusal } from './check-reach.js';
|
|
5
6
|
/**
|
|
6
7
|
* Use case: a requester asks that a ship be kept crewed, with these settings,
|
|
7
8
|
* replacing any request the ship holds. Its scope (fleet:manage) is checked
|
|
@@ -12,11 +13,15 @@ import { machineLabelsOf, requestCrew } from './crew-request.js';
|
|
|
12
13
|
* CrewRequested.
|
|
13
14
|
*/
|
|
14
15
|
export function createRequestCrew(deps) {
|
|
15
|
-
return (caller, input) => deps.uow
|
|
16
|
+
return (caller, input) => keepingReachRefusal(deps.uow, async (tx) => {
|
|
16
17
|
const ship = await tx.ships.findForUpdate(caller.fleetId, input.shipId);
|
|
17
18
|
if (!ship) {
|
|
18
19
|
return refuse('SHIP_NOT_FOUND', `Ship ${input.shipId} does not exist`);
|
|
19
20
|
}
|
|
21
|
+
const managed = await checkManage({ tx, ids: deps.ids }, { fleetId: caller.fleetId, managerShipId: caller.shipId, shipId: ship.id, at: deps.clock.now() });
|
|
22
|
+
if (!managed.isOk) {
|
|
23
|
+
return managed;
|
|
24
|
+
}
|
|
20
25
|
const current = await tx.crewRequests.find(caller.fleetId, ship.id);
|
|
21
26
|
const labelValues = new Set();
|
|
22
27
|
for (const valueId of machineLabelsOf(input.settings)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-crew.js","sourceRoot":"","sources":["../../../src/domain/registry/request-crew.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAoB,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAiB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"request-crew.js","sourceRoot":"","sources":["../../../src/domain/registry/request-crew.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,13 +6,14 @@ import { type EventLog } from '../shared/events.js';
|
|
|
6
6
|
import { type Result } from '../shared/result.js';
|
|
7
7
|
import type { UnitOfWork } from '../shared/unit-of-work.js';
|
|
8
8
|
import { type RequestWorktreeClearRefusal } from './clear-request.js';
|
|
9
|
+
import { type CheckManageTx, type NotReachable } from './check-reach.js';
|
|
9
10
|
import type { ClearRequestRepository, ShipRepository } from './ports.js';
|
|
10
|
-
export interface RequestWorktreeClearTx {
|
|
11
|
+
export interface RequestWorktreeClearTx extends Omit<CheckManageTx, 'ships'> {
|
|
11
12
|
ships: Pick<ShipRepository, 'find' | 'findForUpdate'>;
|
|
12
13
|
clearRequests: ClearRequestRepository;
|
|
13
14
|
events: EventLog;
|
|
14
15
|
}
|
|
15
|
-
export type RequestWorktreeClearUseCaseRefusal = DomainError<'SHIP_NOT_FOUND'> | RequestWorktreeClearRefusal;
|
|
16
|
+
export type RequestWorktreeClearUseCaseRefusal = DomainError<'SHIP_NOT_FOUND'> | NotReachable | RequestWorktreeClearRefusal;
|
|
16
17
|
export type RequestWorktreeClear = (caller: Caller, input: {
|
|
17
18
|
trierarchShipId: ShipId;
|
|
18
19
|
shipId: ShipId;
|