@aeolus-fleet/gateway 0.0.0 → 0.28.1

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 (179) hide show
  1. package/README.md +11 -10
  2. package/dist/adapters/crypto/page-sessions.d.ts +15 -0
  3. package/dist/adapters/crypto/page-sessions.js +40 -0
  4. package/dist/adapters/crypto/page-sessions.js.map +1 -0
  5. package/dist/adapters/crypto/request-ids.d.ts +1 -1
  6. package/dist/adapters/crypto/request-ids.js +2 -9
  7. package/dist/adapters/crypto/request-ids.js.map +1 -1
  8. package/dist/adapters/crypto/sign-in-seals.d.ts +1 -1
  9. package/dist/adapters/crypto/sign-in-seals.js +7 -9
  10. package/dist/adapters/crypto/sign-in-seals.js.map +1 -1
  11. package/dist/adapters/fleet/actor-door.d.ts +20 -0
  12. package/dist/adapters/fleet/actor-door.js +75 -0
  13. package/dist/adapters/fleet/actor-door.js.map +1 -0
  14. package/dist/adapters/fleet/core-version.d.ts +8 -8
  15. package/dist/adapters/fleet/core-version.js +6 -47
  16. package/dist/adapters/fleet/core-version.js.map +1 -1
  17. package/dist/adapters/fleet/fleet-network.js +7 -17
  18. package/dist/adapters/fleet/fleet-network.js.map +1 -1
  19. package/dist/adapters/fleet/logged-verified-facts.d.ts +13 -0
  20. package/dist/adapters/fleet/logged-verified-facts.js +18 -0
  21. package/dist/adapters/fleet/logged-verified-facts.js.map +1 -0
  22. package/dist/adapters/fleet/proxy-ship-reads.d.ts +7 -0
  23. package/dist/adapters/fleet/proxy-ship-reads.js +24 -0
  24. package/dist/adapters/fleet/proxy-ship-reads.js.map +1 -0
  25. package/dist/adapters/fleet/proxy-ships-as-actor.d.ts +3 -0
  26. package/dist/adapters/fleet/proxy-ships-as-actor.js +25 -0
  27. package/dist/adapters/fleet/proxy-ships-as-actor.js.map +1 -0
  28. package/dist/adapters/fleet/rest-fleet-door.d.ts +2 -2
  29. package/dist/adapters/fleet/rest-fleet-door.js +23 -7
  30. package/dist/adapters/fleet/rest-fleet-door.js.map +1 -1
  31. package/dist/adapters/http/add-server-page.d.ts +7 -0
  32. package/dist/adapters/http/add-server-page.js +175 -0
  33. package/dist/adapters/http/add-server-page.js.map +1 -0
  34. package/dist/adapters/http/delivery-page.d.ts +24 -0
  35. package/dist/adapters/http/delivery-page.js +115 -0
  36. package/dist/adapters/http/delivery-page.js.map +1 -0
  37. package/dist/adapters/http/front-door.d.ts +8 -0
  38. package/dist/adapters/http/front-door.js +19 -0
  39. package/dist/adapters/http/front-door.js.map +1 -0
  40. package/dist/adapters/http/oauth-routes.d.ts +15 -3
  41. package/dist/adapters/http/oauth-routes.js +33 -1
  42. package/dist/adapters/http/oauth-routes.js.map +1 -1
  43. package/dist/adapters/http/outside-parties-page.d.ts +29 -2
  44. package/dist/adapters/http/outside-parties-page.js +15 -11
  45. package/dist/adapters/http/outside-parties-page.js.map +1 -1
  46. package/dist/adapters/http/outside-party-page.d.ts +7 -0
  47. package/dist/adapters/http/outside-party-page.js +212 -0
  48. package/dist/adapters/http/outside-party-page.js.map +1 -0
  49. package/dist/adapters/http/overview-page.d.ts +2 -1
  50. package/dist/adapters/http/overview-page.js +79 -36
  51. package/dist/adapters/http/overview-page.js.map +1 -1
  52. package/dist/adapters/http/parties-page.d.ts +2 -1
  53. package/dist/adapters/http/parties-page.js +8 -10
  54. package/dist/adapters/http/parties-page.js.map +1 -1
  55. package/dist/adapters/http/scope-rows.d.ts +10 -0
  56. package/dist/adapters/http/scope-rows.js +30 -0
  57. package/dist/adapters/http/scope-rows.js.map +1 -0
  58. package/dist/adapters/http/signal.d.ts +10 -1
  59. package/dist/adapters/http/signal.js +50 -7
  60. package/dist/adapters/http/signal.js.map +1 -1
  61. package/dist/adapters/pagasae/pagasae-client.js +7 -9
  62. package/dist/adapters/pagasae/pagasae-client.js.map +1 -1
  63. package/dist/adapters/prisma/account-grants.js +2 -2
  64. package/dist/adapters/prisma/account-grants.js.map +1 -1
  65. package/dist/adapters/prisma/client-calls.js +9 -0
  66. package/dist/adapters/prisma/client-calls.js.map +1 -1
  67. package/dist/adapters/prisma/generated/internal/class.js +4 -4
  68. package/dist/adapters/prisma/generated/internal/class.js.map +1 -1
  69. package/dist/adapters/prisma/generated/internal/prismaNamespace.d.ts +1 -1
  70. package/dist/adapters/prisma/generated/internal/prismaNamespace.js +1 -1
  71. package/dist/adapters/prisma/generated/internal/prismaNamespace.js.map +1 -1
  72. package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.d.ts +1 -1
  73. package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.js +1 -1
  74. package/dist/adapters/prisma/generated/internal/prismaNamespaceBrowser.js.map +1 -1
  75. package/dist/adapters/prisma/generated/models/AccountGrant.d.ts +33 -1
  76. package/dist/adapters/prisma/generated/models/ClientCall.d.ts +14 -14
  77. package/dist/adapters/prisma/generated/models/Party.d.ts +1 -29
  78. package/dist/adapters/prisma/oauth-stores.js +3 -0
  79. package/dist/adapters/prisma/oauth-stores.js.map +1 -1
  80. package/dist/adapters/prisma/party-store.js +0 -2
  81. package/dist/adapters/prisma/party-store.js.map +1 -1
  82. package/dist/adapters/prisma/pending-requests.js +7 -1
  83. package/dist/adapters/prisma/pending-requests.js.map +1 -1
  84. package/dist/adapters/trpc/router.d.ts +210 -12
  85. package/dist/adapters/trpc/router.js +159 -7
  86. package/dist/adapters/trpc/router.js.map +1 -1
  87. package/dist/app.js +67 -19
  88. package/dist/app.js.map +1 -1
  89. package/dist/core/actors/authenticate-actor.d.ts +21 -5
  90. package/dist/core/actors/authenticate-actor.js +14 -2
  91. package/dist/core/actors/authenticate-actor.js.map +1 -1
  92. package/dist/core/actors/credential-of.d.ts +27 -0
  93. package/dist/core/actors/credential-of.js +25 -0
  94. package/dist/core/actors/credential-of.js.map +1 -0
  95. package/dist/core/connection/connect.js +5 -4
  96. package/dist/core/connection/connect.js.map +1 -1
  97. package/dist/core/connection/ports.d.ts +6 -1
  98. package/dist/core/mcp-in/call-tool.d.ts +6 -6
  99. package/dist/core/mcp-in/call-tool.js +3 -3
  100. package/dist/core/mcp-in/call-tool.js.map +1 -1
  101. package/dist/core/mcp-in/client-call.d.ts +2 -2
  102. package/dist/core/mcp-in/client-call.js +2 -2
  103. package/dist/core/mcp-in/client-call.js.map +1 -1
  104. package/dist/core/mcp-in/collect-replies.d.ts +4 -11
  105. package/dist/core/mcp-in/collect-replies.js +52 -30
  106. package/dist/core/mcp-in/collect-replies.js.map +1 -1
  107. package/dist/core/mcp-in/list-tools.d.ts +4 -0
  108. package/dist/core/mcp-in/list-tools.js +1 -1
  109. package/dist/core/mcp-in/list-tools.js.map +1 -1
  110. package/dist/core/mcp-in/ports.d.ts +24 -1
  111. package/dist/core/mcp-out/hand-call.d.ts +2 -0
  112. package/dist/core/mcp-out/hand-call.js +4 -2
  113. package/dist/core/mcp-out/hand-call.js.map +1 -1
  114. package/dist/core/mcp-out/state-party.d.ts +2 -1
  115. package/dist/core/mcp-out/state-party.js +1 -1
  116. package/dist/core/mcp-out/state-party.js.map +1 -1
  117. package/dist/core/mcp-out/statement.d.ts +10 -0
  118. package/dist/core/mcp-out/statement.js +7 -5
  119. package/dist/core/mcp-out/statement.js.map +1 -1
  120. package/dist/core/oauth/ports.d.ts +2 -0
  121. package/dist/core/oauth/read-authorization.js +2 -2
  122. package/dist/core/oauth/read-authorization.js.map +1 -1
  123. package/dist/core/oauth/redirect-uri.d.ts +7 -0
  124. package/dist/core/oauth/redirect-uri.js +23 -0
  125. package/dist/core/oauth/redirect-uri.js.map +1 -1
  126. package/dist/core/outside-parties/ports.d.ts +1 -5
  127. package/dist/core/outside-parties/set-outside-parties.d.ts +5 -3
  128. package/dist/core/outside-parties/set-outside-parties.js +6 -2
  129. package/dist/core/outside-parties/set-outside-parties.js.map +1 -1
  130. package/dist/core/parties/approve-party.js +24 -8
  131. package/dist/core/parties/approve-party.js.map +1 -1
  132. package/dist/core/parties/change-party.d.ts +42 -0
  133. package/dist/core/parties/change-party.js +49 -0
  134. package/dist/core/parties/change-party.js.map +1 -0
  135. package/dist/core/parties/check-server.d.ts +24 -0
  136. package/dist/core/parties/check-server.js +21 -0
  137. package/dist/core/parties/check-server.js.map +1 -0
  138. package/dist/core/parties/list-parties.d.ts +28 -7
  139. package/dist/core/parties/list-parties.js +35 -4
  140. package/dist/core/parties/list-parties.js.map +1 -1
  141. package/dist/core/parties/party.d.ts +12 -6
  142. package/dist/core/parties/party.js +23 -1
  143. package/dist/core/parties/party.js.map +1 -1
  144. package/dist/core/parties/ports.d.ts +36 -1
  145. package/dist/core/parties/read-party-tools.d.ts +22 -0
  146. package/dist/core/parties/read-party-tools.js +22 -0
  147. package/dist/core/parties/read-party-tools.js.map +1 -0
  148. package/dist/core/parties/retire-party.d.ts +29 -0
  149. package/dist/core/parties/retire-party.js +43 -0
  150. package/dist/core/parties/retire-party.js.map +1 -0
  151. package/dist/core/parties/shown-party.d.ts +8 -2
  152. package/dist/core/parties/shown-party.js +3 -3
  153. package/dist/core/parties/shown-party.js.map +1 -1
  154. package/dist/core/requests/decide-request.js +9 -1
  155. package/dist/core/requests/decide-request.js.map +1 -1
  156. package/dist/core/requests/list-mine.d.ts +16 -0
  157. package/dist/core/requests/list-mine.js +20 -0
  158. package/dist/core/requests/list-mine.js.map +1 -0
  159. package/dist/core/requests/ports.d.ts +5 -0
  160. package/dist/core/shared/errors.d.ts +1 -1
  161. package/dist/core/shared/errors.js.map +1 -1
  162. package/dist/core/sign-in/account-token.d.ts +8 -4
  163. package/dist/core/sign-in/account-token.js +4 -4
  164. package/dist/core/sign-in/account-token.js.map +1 -1
  165. package/dist/core/sign-in/complete-sign-in.d.ts +15 -4
  166. package/dist/core/sign-in/complete-sign-in.js +27 -4
  167. package/dist/core/sign-in/complete-sign-in.js.map +1 -1
  168. package/dist/core/sign-in/ports.d.ts +37 -7
  169. package/dist/core/sign-in/sign-out.d.ts +10 -0
  170. package/dist/core/sign-in/sign-out.js +9 -0
  171. package/dist/core/sign-in/sign-out.js.map +1 -0
  172. package/dist/core/sign-in/start-page-sign-in.d.ts +25 -0
  173. package/dist/core/sign-in/start-page-sign-in.js +30 -0
  174. package/dist/core/sign-in/start-page-sign-in.js.map +1 -0
  175. package/package.json +3 -3
  176. package/src/adapters/prisma/migrations/20261020200000_account_grant_scopes/migration.sql +2 -0
  177. package/src/adapters/prisma/migrations/20261020210000_party_owner_from_fleet/migration.sql +2 -0
  178. package/src/adapters/prisma/migrations/20261020220000_client_call_deadline_optional/migration.sql +2 -0
  179. package/src/adapters/prisma/schema.prisma +3 -2
package/README.md CHANGED
@@ -24,7 +24,7 @@ DATABASE_URL=postgresql://... FLEET_URL=https://fleet.example.com npm start
24
24
 
25
25
  | Command | Does |
26
26
  | --- | --- |
27
- | `aeolus-gateway start` | Reads core's version and exits 1 when core is older than it needs (core 0.27.0 or later), saying both versions; migrates its database; serves |
27
+ | `aeolus-gateway start` | Reads core's version and exits 1 when core is older than it needs (core 0.28.0 or later), saying both versions; migrates its database; serves |
28
28
  | `aeolus-gateway migrate` | Migrates its database, and nothing else. Needs `DATABASE_URL` alone |
29
29
 
30
30
  `GET /api/version` answers the version it runs, and `GET /api/health` answers `{ "status": "ok" }` while its database answers, else 503.
@@ -33,17 +33,17 @@ DATABASE_URL=postgresql://... FLEET_URL=https://fleet.example.com npm start
33
33
 
34
34
  argo commissions the gateway's ship in the console as an app ship (decision 0044: it is software, so its messages state no model), with `fleet:read`, `fleet:commission`, `fleet:on-behalf` and `scopes:declare`, and connects the gateway with it; the gateway registers with the ship's secret, keeps only the crew token, and declares its own scope, `gateway:approve` (decision 0056): any actor the fleet grants it approves outside parties. A fleet that does not take the declaration, as when another ship holds the `gateway` namespace, is refused (CONFLICT). The gateway connects and is switched on whatever network the fleet has (interop I-3): the fleet decides its network. A fleet's outside parties (its outside MCP servers and clients) are a switch, off by default: while off, the gateway approves no party, takes no party's calls and refuses a client party's token at `/mcp` (403). `outsideParties.status` reads it; `outsideParties.set` needs `fleet:network`. Turning it on while the fleet applies no network rules (`fleet.networkRules`, read as the actor) answers PRECONDITION_FAILED with a warning until the call confirms it with `isOpenNetworkConfirmed`.
35
35
 
36
- The API is tRPC at `/trpc`. Its procedures take an actor (decision 0057): argo's or a viewer's console session cookie, checked with the fleet's `console.session`, or any ship's own crew token as a bearer token, for a fleet the gateway is connected to. What an actor may call is the scopes the fleet holds for it, read by the gateway's ship; a change needs `fleet:manage`. `requests.toDecide` and `requests.decide` need `gateway:approve` (decision 0056): every open pending request of the fleet, and a decision on one. Approving names the proxy ship's name, its owner (a person ship) and its scopes, only scopes the approver holds beside `messages:send` and `messages:receive`, and for an outside MCP server its credential and concurrency; the gateway commissions and crews the proxy ship as its own ship, and the fleet refuses a scope the gateway's ship does not hold. The first decision counts. A request is kept 7 days, then expires; a refused proxy ship leaves it pending. The outcome of a request for an outside MCP server is told to each requester with a person ship, as a text message from the gateway's ship: written with the decision or the expiry in one transaction, sent at once, and sent again every minute under the same idempotency key until the fleet stores it. One the fleet refuses is left for the gateway's page. Due requests expire in the same round. When a request opens, the gateway's ship asks its owner (read from the fleet; argo when argo owns it) a question (decision 0038) pointing to the gateway's `/overview`, where any holder of `gateway:approve` decides; it withdraws the question once the request is decided or expired. Both are kept and sent again under the same key until the fleet stores them. `installation.setEnabled`, `installation.get` and `installation.delete` take the installation token in `x-aeolus-installation-token`.
36
+ The API is tRPC at `/trpc`. Its procedures take an actor (decision 0057): an account by the page session it signed in to the gateway's pages with, argo's or a viewer's console session cookie, checked with the fleet's `console.session`, or any ship's own crew token as a bearer token, for a fleet the gateway is connected to. What an actor may call is the scopes the fleet holds for it, read by the gateway's ship on the ship's own behalf (so its own read reach holds it), or for an account the scopes its account token carries; a change needs `fleet:manage`. `requests.toDecide` and `requests.decide` need `gateway:approve` (decision 0056): every open pending request of the fleet, and a decision on one. Approving names the proxy ship's name, its owner (a person ship) and its scopes, only scopes the approver holds beside `messages:send` and `messages:receive`, and for an outside MCP server its credential and concurrency; the gateway commissions and crews the proxy ship as its own ship, and the fleet refuses a scope the gateway's ship does not hold. The first decision counts. A request is kept 7 days, then expires; a refused proxy ship leaves it pending. The outcome of a request for an outside MCP server is told to each requester with a person ship, as a text message from the gateway's ship: written with the decision or the expiry in one transaction, sent at once, and sent again every minute under the same idempotency key until the fleet stores it. One the fleet refuses is left for the gateway's page. Due requests expire in the same round. When a request opens, the gateway's ship asks its owner (read from the fleet; argo when argo owns it) a question (decision 0038) pointing to the gateway's `/overview`, where any holder of `gateway:approve` decides; it withdraws the question once the request is decided or expired. Both are kept and sent again under the same key until the fleet stores them. `installation.setEnabled`, `installation.get` and `installation.delete` take the installation token in `x-aeolus-installation-token`.
37
37
 
38
38
  ## Parties
39
39
 
40
- argo approves an outside MCP server as a party with `parties.approve` (argo's console session): its name, its Streamable HTTP URL, the credential the gateway calls it with (a static bearer, or OAuth client credentials with their issuer), the owner argo picks for it (a person's ship or argo) and how many calls it takes at once (1 to 10, the most core's pushReceive hands at once; 4 by default). The gateway, as its own ship, commissions the party's app proxy ship of type `mcp-server` with that owner, crews it, and keeps its crew token. argo labels the proxy ship in the console, as any ship, for the network rules to select it. `parties.list` shows each party without its credential or crew token. A proxy ship left awaiting crew (the commission's answer was lost, and its secret with it) takes a new secret from a new starting prompt with `parties.crew`.
40
+ argo approves an outside MCP server as a party with `parties.approve` (argo's console session): its name, its Streamable HTTP URL, the credential the gateway calls it with (a static bearer, or OAuth client credentials with their issuer), the owner argo picks for it (a person's ship or argo) and how many calls it takes at once (1 to 10, the most core's pushReceive hands at once; 4 by default). The gateway, as its own ship, commissions the party's app proxy ship of type `mcp-server` with that owner, crews it, and keeps its crew token. argo labels the proxy ship in the console, as any ship, for the network rules to select it. `parties.list` shows each party without its credential or crew token, with its proxy ship's owner and scopes as the fleet holds them, read as the actor who asked (decision 0056: the owner is core's, and the gateway keeps none of its own; null outside the actor's read reach, while there is no proxy ship, or while the fleet does not answer). `parties.get {name}` shows one. `parties.changeOwner {name, ownerShipId}` (needs `fleet:owner`) and `parties.changeScopes {name, grant, revoke}` (needs `scopes:grant`, only scopes the actor holds) change the proxy ship in the fleet as the actor, so the fleet checks its manage reach (decision 0056); the gateway keeps neither. `parties.retire` retires a party (decision 0056): it needs `fleet:manage`, and the gateway retires the proxy ship in the fleet as the actor who asked, so the fleet checks its manage reach; only then does the gateway forget the party and revoke its client's tokens. A proxy ship retired already counts as retired. Adding it again is a new request. A proxy ship left awaiting crew (the commission's answer was lost, and its secret with it) takes a new secret from a new starting prompt with `parties.crew`.
41
41
 
42
- The gateway keeps outside credentials and crew tokens as they are in its own database, as squadrons keeps crew tokens: a key on the same server would protect only backups. Guard the database and its backups accordingly.
42
+ Once a proxy ship is crewed, the gateway's ship writes what the gateway checked about it as verified facts (`fleet:verify`, decision 0059), which discovery shows beside its statement: `tlsHost` for an MCP server reached over https, `clientIdDocumentDomain` for an MCP client known by an https metadata document. A write the fleet refuses is logged and leaves the approval as it is; in a fleet that applies its own network rules the gateway's ship has no manage reach over its proxy ships, so the fleet refuses them there. The gateway's ship needs `fleet:verify` to connect.
43
43
 
44
- `parties.state` states the proxy ship anew from the server's `tools/list`: each tool is one capability with its MCP fields and annotations, called with `application/vnd.aeolus.mcp-tool+json; name=<tool>` (the tool arguments as a JSON object) and answered with `application/vnd.aeolus.mcp-result+json; name=<tool>` (the tool result). The summary names the party only, never its URL or credential. `parties.markTool` marks a tool repeatable, or takes the mark off, and states it at once: only argo's mark lets the gateway hand a call that died unanswered again; the server's hints never do.
44
+ The gateway keeps outside credentials and crew tokens as they are in its own database, as squadrons keeps crew tokens: a key on the same server would protect only backups. Guard the database and its backups accordingly.
45
45
 
46
- Commissioning an app ship with a named owner needs core 0.28 (aeolus-fleet#959), and so do the statement's `annotations` and `repeatable` fields (aeolus-fleet#956): core 0.27 refuses a statement that holds them.
46
+ `parties.state` states the proxy ship anew from the server's `tools/list`: each tool is one capability with its MCP fields and annotations, called with `application/vnd.aeolus.mcp-tool+json; name=<tool>` (the tool arguments as a JSON object) and answered with `application/vnd.aeolus.mcp-result+json; name=<tool>` (the tool result). The summary names the party only, never its URL or credential. Each capability states the gateway's own timing: `waitMs`, how long an outside client waits for the answer (`MCP_WAIT_MAX_MS`), and `deadlineMs`, when the gateway gives up on the server's `tools/call` (`TOOL_CALL_TIMEOUT_MS`). `parties.markTool` marks a tool repeatable, or takes the mark off, and states it at once: only argo's mark lets the gateway hand a call that died unanswered again; the server's hints never do.
47
47
 
48
48
  ## The page of parties
49
49
 
@@ -57,7 +57,7 @@ From its start, and as soon as a party is crewed, the gateway takes the calls of
57
57
  - A call sent with no answer (a broken stream, no answer within 5 minutes) is handed again only when argo marked its tool repeatable. Otherwise the gateway reports it not handled: it may have run, and a human who can check the outside system resends or dismisses it.
58
58
  - A party takes at most its concurrency limit of calls at once.
59
59
 
60
- With core 0.27 the not handled report is refused (aeolus-fleet#955): the call is never made again, and its delivery stays handed until argo resends or dismisses it.
60
+ Each hand-over names its channel, `mcp` (interop 5.1). A call reported not handled shows in the console's Needs attention with why, for argo to resend or dismiss; it is never called again.
61
61
 
62
62
  ## MCP clients sign in
63
63
 
@@ -67,6 +67,7 @@ The gateway is an OAuth 2.1 authorization server for outside MCP clients, such a
67
67
  - A client is pre-registered by argo with `oauth.registerClient` (its name, its redirect URIs, and whether it keeps a secret, answered once), or known by its client metadata document (CIMD): its client id is the https URL of that document. There is no dynamic registration.
68
68
  - `/authorize` shows the client and two picks (decision 0056, Q1 a): sign in as yourself, or ask for access for this client. Either sends the person to pagasae to sign in. Only the authorization code flow with PKCE S256 is served, and the `resource` must be the gateway's MCP endpoint (RFC 8707).
69
69
  - A person signs in through pagasae (decision 0054). pagasae answers their only fleet, or asks which, and sends them back to `/pagasae/callback`; signed in as themselves, the gateway keeps their account's grant (the account, its fleet, its person ship and pagasae's tokens) and sends their client back with its code, with no approval. The sign-in under way travels sealed in pagasae's `state`, so nothing is stored before the fleet is known. The browser that starts it holds a secret sealed with it, in an HttpOnly cookie sent only to `/pagasae/callback` for its 10 minutes, so no other browser finishes it (login CSRF). A fleet the gateway does not serve is refused. A person's client is served their person ship's tools: `aeolus_inbox` (what waits, by titles only, at most 10), `aeolus_open` (one delivery whole; opening it acknowledges it), `aeolus_answer` (a reply to its sender, then it is handled) and `aeolus_done` (handled with no answer). The gateway makes these calls as the crew of the account's own person ship, with the account's token (decision 0057): it crews the ship once, shared by every client of the person, and crews it again when its lease ended. An account with no person ship is told so, and the fleet is asked nothing. `aeolus_ask_for_server` asks for an outside MCP server by its http or https address, as the account (decision 0056): it opens a pending request, or joins the one pending for the same server, and an approver adds the server with its credential. A server that is a party already is said so. While the fleet's outside parties are off, nobody asks.
70
+ - A person signs in to the gateway's own pages at `/sign-in?return_to=<a path of the gateway's>` through pagasae as well (decision 0054): back at `/pagasae/callback`, the gateway keeps the account's grant with the scopes its account token carries, and the browser holds a page session naming it in the HttpOnly cookie `aeolus_gateway_session` (path `/`, SameSite Lax, for the browser's session), not the console's `aeolus_session`, which reaches only the fleet's own domain. The pages then act as the account, its account token refreshed through pagasae when about to end; what the gateway asks the fleet for the account, such as the network rules when outside parties are turned on, it asks with that token, presented by the gateway's ship. A path that is not the gateway's own goes to `/overview`. A form posting to `/sign-out` from the gateway's own pages ends the session's grant and its cookie; the account's MCP clients stay signed in.
70
71
  - A person who asks for access for the client asks as their account. A client that is a party already is sent back with its party's code at once. Otherwise the account opens a pending request for the client, or joins the one pending, and its browser waits at `/authorize/waiting`, which reloads itself: approved and its proxy ship crewed, the client gets its party's code; denied or expired, `access_denied`. Closed meanwhile, the next try after a deny or expiry ends with `access_denied` once, and a later try asks anew. The waiting travels sealed in the page's address, and the browser holds the sign-in's secret in an HttpOnly cookie sent only to the waiting page, for the request's 7 days. While the fleet's outside parties are off, nobody asks. Each client party has its own app proxy ship, of type `mcp-client`; every token of a client party names its party, so every fleet call the client makes is its proxy ship's, within its reach; a person's token names their account's grant. `parties.list` shows client parties beside server parties.
71
72
  - `/token` takes a code once, within its minute, for an access token (one hour) and a refresh token (30 days). Refreshing rotates the pair; a code or a refresh token used twice revokes what it gave.
72
73
 
@@ -83,13 +84,13 @@ Serve the gateway at its own origin, such as `https://gateway.example.com`, with
83
84
  - Its description is the capability's, then the ship's summary. A capability that takes plain text first gets one `text` argument. Every tool takes an optional `aeolus_idempotency_key`.
84
85
  - Left out: argo, ships with no statement by their crew, capabilities whose first input type is neither JSON nor plain text or whose input schema is not an object, and tool names over 128 characters.
85
86
  - No tool states an output schema: a call may answer a handle, and MCP clients check every answer against it.
86
- - `tools/call` sends the arguments, without `aeolus_idempotency_key`, as a message from the client's proxy ship to the tool's ship, under the capability's first input type. The client is answered only once the fleet answered the send. The call then waits up to `MCP_WAIT_MAX_MS` for its answer: answered within it, the client gets the answer itself; else `{"handle": "...", "state": "submitted"}` (or `working`). A fleet that refuses the send gets a tool error, and one that cannot be reached gives no reason why.
87
+ - `tools/call` sends the arguments, without `aeolus_idempotency_key`, as a message from the client's proxy ship to the tool's ship, under the capability's first input type. The client is answered only once the fleet answered the send. The call then waits for its answer as long as the capability's `waitMs` states, at most `MCP_WAIT_MAX_MS` (interop 5.3), and not at all when it states none: answered within it, the client gets the answer itself; else `{"handle": "...", "state": "submitted"}` (or `working`). A fleet that refuses the send gets a tool error, and one that cannot be reached gives no reason why.
87
88
  - The same `aeolus_idempotency_key` again sends no second message. The send's key is derived from it under `GATEWAY_SECRET`, and the handle from the message, so the client never sees a `msg_` id.
88
89
  - `aeolus_result({ handle })` reads the client's own call: `submitted`, `working` once a reply of another type came, its answer once completed, or a tool error once it failed (interop 3.4).
89
90
  - MCP Tasks (`io.modelcontextprotocol/tasks`, stated at `server/discover`): a client that declares the extension on its `tools/call` is answered a task in place of the handle, its `taskId` the handle. `tasks/get` reads it: `working` while submitted or working, `completed` with the answer as its `result`, or `failed` once its deadline passed. A task never expires (`ttlMs` null), as the gateway keeps every call. `tasks/cancel` and `tasks/update` are acknowledged and change nothing: a sent call cannot be unsent, and no call asks for input yet.
90
91
  - The first reply of the capability's first output type completes it; plain text completes a call to a ship that states no output type. An outside tool's result, as MCP out replies one, is answered as that result.
91
- - A call fails 10 minutes after it was sent without its answer: the gateway's default while statements state no deadline. A reply after that is kept and changes nothing.
92
- - Each client party's worker takes the replies of its proxy ship, keeps each on its call, then acknowledges and handles its delivery. With core 0.27 a message to the proxy ship that replies to no call stays unacknowledged, for a later slice's inbox. Ten of them would take every pushReceive answer and keep replies out, until core 0.28's `receiveReply` (aeolus-fleet#953) takes replies by message.
92
+ - A call fails at its capability's `deadlineMs` after it was sent without its answer, and never by time when the capability states none (interop 3.4). A reply after the deadline is kept and changes nothing.
93
+ - Each client party's worker takes the replies to its calls with `receiveReply` (aeolus-fleet#953) for each call neither completed nor past its deadline, at most 10 calls at once, each in its turn: it keeps each reply on its call, then acknowledges and handles its delivery. It never takes a delivery with `pushReceive`, so the proxy ship's lease stays plain, as `receiveReply` needs. A message to the proxy ship that replies to no call waits in the fleet and keeps no reply out.
93
94
 
94
95
  ## Develop
95
96
 
@@ -0,0 +1,15 @@
1
+ import type { PageSessions } from '../../core/sign-in/ports.js';
2
+ /** The cookie a browser signed in to the gateway's pages holds; not the console's aeolus_session, which the fleet reads. */
3
+ export declare const PAGE_SESSION_COOKIE = "aeolus_gateway_session";
4
+ /**
5
+ * The page session's own pair in a Cookie header, and nothing else: the
6
+ * pages are accounts only (Thomas, 20 Oct), so no other cookie the browser
7
+ * sends, such as the console's, reaches them.
8
+ */
9
+ export declare function pageCookieOf(header: string | undefined): string | undefined;
10
+ /**
11
+ * Seals a page session into the gateway's own cookie under a key derived
12
+ * from the gateway's secret, and finds it in a Cookie header. A value
13
+ * changed on the way, or sealed under another secret or label, is none.
14
+ */
15
+ export declare function createPageSessions(secret: string): PageSessions;
@@ -0,0 +1,40 @@
1
+ import { idSchema } from '@aeolus-fleet/common';
2
+ import { z } from 'zod';
3
+ import { createSealer } from './sealer.js';
4
+ /** The cookie a browser signed in to the gateway's pages holds; not the console's aeolus_session, which the fleet reads. */
5
+ export const PAGE_SESSION_COOKIE = 'aeolus_gateway_session';
6
+ const PREFIX = `${PAGE_SESSION_COOKIE}=`;
7
+ /**
8
+ * The page session's own pair in a Cookie header, and nothing else: the
9
+ * pages are accounts only (Thomas, 20 Oct), so no other cookie the browser
10
+ * sends, such as the console's, reaches them.
11
+ */
12
+ export function pageCookieOf(header) {
13
+ return header
14
+ ?.split(';')
15
+ .map((pair) => pair.trim())
16
+ .find((pair) => pair.startsWith(PREFIX) && pair.length > PREFIX.length);
17
+ }
18
+ /** Its own label, so the sealing key is never also a key the gateway derives elsewhere. */
19
+ const SEAL_LABEL = 'page-session';
20
+ const sealedSchema = z.object({ fleetId: idSchema('fleet'), grantId: z.string().min(1) });
21
+ /**
22
+ * Seals a page session into the gateway's own cookie under a key derived
23
+ * from the gateway's secret, and finds it in a Cookie header. A value
24
+ * changed on the way, or sealed under another secret or label, is none.
25
+ */
26
+ export function createPageSessions(secret) {
27
+ const sealer = createSealer(secret, SEAL_LABEL);
28
+ return {
29
+ seal: ({ fleetId, grantId }) => sealer.seal({ fleetId, grantId }),
30
+ inCookie: (cookie) => {
31
+ const sealed = pageCookieOf(cookie)?.slice(PREFIX.length);
32
+ if (sealed === undefined) {
33
+ return undefined;
34
+ }
35
+ const session = sealedSchema.safeParse(sealer.open(sealed));
36
+ return session.success ? session.data : undefined;
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=page-sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-sessions.js","sourceRoot":"","sources":["../../../src/adapters/crypto/page-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,4HAA4H;AAC5H,MAAM,CAAC,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AAE5D,MAAM,MAAM,GAAG,GAAG,mBAAmB,GAAG,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAA0B;IACrD,OAAO,MAAM;QACX,EAAE,KAAK,CAAC,GAAG,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;AAC5E,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAE1F;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,OAAO;QACL,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QACjE,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YACnB,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC1D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAC5D,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACpD,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import { createIdGenerator } from '@aeolus-fleet/common';
2
2
  import type { RequestIds } from '../../core/requests/ports.js';
3
- /** New request ids: a common id's time-ordered body under the request prefix. */
3
+ /** New request ids: common's time-ordered ids of kind request (`req_`). */
4
4
  export declare function createRequestIds(options?: Parameters<typeof createIdGenerator>[0]): RequestIds;
@@ -1,14 +1,7 @@
1
1
  import { createIdGenerator } from '@aeolus-fleet/common';
2
- /** The prefix common gives a pending request from 0.28.0 (`ID_PREFIXES.request`); until then its time-ordered body is drawn here (aeolus-fleet#991). */
3
- const REQUEST_PREFIX = 'req_';
4
- /** New request ids: a common id's time-ordered body under the request prefix. */
2
+ /** New request ids: common's time-ordered ids of kind request (`req_`). */
5
3
  export function createRequestIds(options = {}) {
6
4
  const generate = createIdGenerator(options);
7
- return {
8
- newRequestId: () => {
9
- const id = generate('event');
10
- return `${REQUEST_PREFIX}${id.slice(id.indexOf('_') + 1)}`;
11
- },
12
- };
5
+ return { newRequestId: () => generate('request') };
13
6
  }
14
7
  //# sourceMappingURL=request-ids.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-ids.js","sourceRoot":"","sources":["../../../src/adapters/crypto/request-ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIzD,wJAAwJ;AACxJ,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,UAAmD,EAAE;IACpF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO;QACL,YAAY,EAAE,GAAG,EAAE;YACjB,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC7B,OAAO,GAAG,cAAc,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"request-ids.js","sourceRoot":"","sources":["../../../src/adapters/crypto/request-ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIzD,2EAA2E;AAC3E,MAAM,UAAU,gBAAgB,CAAC,UAAmD,EAAE;IACpF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;AACrD,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import type { SignInSeals } from '../../core/sign-in/ports.js';
2
2
  /**
3
- * Seals a sign-in under way into the state pagasae carries back, under a key
3
+ * Seals a sign-in under way, a client's or the pages', into the state pagasae carries back, under a key
4
4
  * derived from the gateway's secret. A state changed on the way, or sealed
5
5
  * under another secret, opens to nothing.
6
6
  */
@@ -2,22 +2,20 @@ import { z } from 'zod';
2
2
  import { createSealer, setParameters } from './sealer.js';
3
3
  /** Its own label, so the sealing key is never also a key the gateway derives elsewhere. */
4
4
  const SEAL_LABEL = 'sign-in-seal';
5
- const sealedSchema = z.object({
6
- verifier: z.string(),
7
- browserSecret: z.string(),
8
- request: z.record(z.string(), z.string()),
9
- holder: z.enum(['account', 'party']),
10
- expiresAt: z.iso.datetime(),
11
- });
5
+ const underWay = { verifier: z.string(), browserSecret: z.string(), expiresAt: z.iso.datetime() };
6
+ const sealedSchema = z.discriminatedUnion('holder', [
7
+ z.object({ ...underWay, holder: z.enum(['account', 'party']), request: z.record(z.string(), z.string()) }),
8
+ z.object({ ...underWay, holder: z.literal('page'), returnTo: z.string() }),
9
+ ]);
12
10
  /**
13
- * Seals a sign-in under way into the state pagasae carries back, under a key
11
+ * Seals a sign-in under way, a client's or the pages', into the state pagasae carries back, under a key
14
12
  * derived from the gateway's secret. A state changed on the way, or sealed
15
13
  * under another secret, opens to nothing.
16
14
  */
17
15
  export function createSignInSeals(secret) {
18
16
  const sealer = createSealer(secret, SEAL_LABEL);
19
17
  return {
20
- seal: ({ verifier, browserSecret, request, holder, expiresAt }) => sealer.seal({ verifier, browserSecret, request: setParameters(request), holder, expiresAt: expiresAt.toISOString() }),
18
+ seal: (signIn) => sealer.seal(signIn.holder === 'page' ? { ...signIn, expiresAt: signIn.expiresAt.toISOString() } : { ...signIn, request: setParameters(signIn.request), expiresAt: signIn.expiresAt.toISOString() }),
21
19
  open: (state) => {
22
20
  const signIn = sealedSchema.safeParse(sealer.open(state));
23
21
  return signIn.success ? { ...signIn.data, expiresAt: new Date(signIn.data.expiresAt) } : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"sign-in-seals.js","sourceRoot":"","sources":["../../../src/adapters/crypto/sign-in-seals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1D,2FAA2F;AAC3F,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IACzC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACpC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,OAAO;QACL,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QACxL,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;YACd,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1D,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACrG,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"sign-in-seals.js","sourceRoot":"","sources":["../../../src/adapters/crypto/sign-in-seals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1D,2FAA2F;AAC3F,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,MAAM,QAAQ,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;AAClG,MAAM,YAAY,GAAG,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE;IAClD,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;IAC1G,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;CAC3E,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,OAAO;QACL,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CACf,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QACrM,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;YACd,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1D,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACrG,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { ActorCredential } from '../../core/actors/credential-of.js';
2
+ import type { FleetRefusal } from '../../core/connection/ports.js';
3
+ import { type Result } from '../../core/shared/result.js';
4
+ /** The fleet's refusal as its code and message, whichever door answered it. */
5
+ export declare function refusalOf(status: number, body: unknown): FleetRefusal;
6
+ /** The headers a REST call carries as the actor: its crew token, and the account's token it presents. */
7
+ export declare function restHeaders(as: ActorCredential): Record<string, string>;
8
+ /** One fleet mutation as the actor, by the door its credential goes through: what the fleet answered, unparsed. */
9
+ export declare function mutateAs(fleetUrl: string, call: {
10
+ as: ActorCredential;
11
+ procedure: string;
12
+ input: unknown;
13
+ isTrpcOnly?: boolean;
14
+ }): Promise<Result<unknown, FleetRefusal>>;
15
+ /** One fleet read as the actor: a ship or an account over REST, argo or a viewer over tRPC as a query; what the fleet answered, unparsed. */
16
+ export declare function readAs(fleetUrl: string, call: {
17
+ as: ActorCredential;
18
+ procedure: string;
19
+ input: unknown;
20
+ }): Promise<Result<unknown, FleetRefusal>>;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The fleet's two doors for a call made as the actor (decision 0057): a crew
3
+ * token, alone or presenting an account's token, over REST; argo's or a
4
+ * viewer's console session over tRPC, as the console calls it. Each answers
5
+ * the fleet's refusal as its code and message.
6
+ */
7
+ import { ACCOUNT_TOKEN_HEADER } from '@aeolus-fleet/common';
8
+ import { z } from 'zod';
9
+ import { err, ok } from '../../core/shared/result.js';
10
+ const refusalSchema = z.object({ code: z.string(), message: z.string() });
11
+ const trpcRefusalSchema = z.object({ error: z.object({ message: z.string(), data: z.object({ code: z.string() }) }) });
12
+ const trpcAnswerSchema = z.object({ result: z.object({ data: z.unknown() }) });
13
+ /** The fleet's refusal as its code and message, whichever door answered it. */
14
+ export function refusalOf(status, body) {
15
+ const rest = refusalSchema.safeParse(body);
16
+ if (rest.success) {
17
+ return rest.data;
18
+ }
19
+ const trpc = trpcRefusalSchema.safeParse(body);
20
+ return trpc.success ? { code: trpc.data.error.data.code, message: trpc.data.error.message } : { code: 'UNAVAILABLE', message: `The fleet answered ${String(status)}` };
21
+ }
22
+ /** The headers a REST call carries as the actor: its crew token, and the account's token it presents. */
23
+ export function restHeaders(as) {
24
+ return { authorization: `Bearer ${as.crewToken ?? ''}`, ...(as.accountToken === undefined ? {} : { [ACCOUNT_TOKEN_HEADER]: as.accountToken }) };
25
+ }
26
+ /** One fleet mutation as the actor, by the door its credential goes through: what the fleet answered, unparsed. */
27
+ export async function mutateAs(fleetUrl, call) {
28
+ const { as, procedure, input } = call;
29
+ const isConsole = as.crewToken === undefined;
30
+ // A call with no REST door goes over tRPC with the same headers a REST call carries.
31
+ const isTrpc = isConsole || call.isTrpcOnly === true;
32
+ const request = isConsole
33
+ ? { url: `${fleetUrl}/trpc/fleet.${procedure}`, headers: { cookie: as.cookie ?? '' } }
34
+ : { url: isTrpc ? `${fleetUrl}/trpc/fleet.${procedure}` : `${fleetUrl}/api/v1/fleet/${procedure}`, headers: restHeaders(as) };
35
+ let response;
36
+ try {
37
+ response = await fetch(request.url, { method: 'POST', headers: { 'content-type': 'application/json', ...request.headers }, body: JSON.stringify(input) });
38
+ }
39
+ catch (error) {
40
+ return err({ code: 'UNAVAILABLE', message: error instanceof Error ? error.message : 'The fleet did not answer' });
41
+ }
42
+ const body = await response.json().catch(() => null);
43
+ if (!response.ok) {
44
+ return err(refusalOf(response.status, body));
45
+ }
46
+ if (!isTrpc) {
47
+ return ok(body);
48
+ }
49
+ const answer = trpcAnswerSchema.safeParse(body);
50
+ return answer.success ? ok(answer.data.result.data) : err({ code: 'UNAVAILABLE', message: 'The fleet answered no result' });
51
+ }
52
+ /** One fleet read as the actor: a ship or an account over REST, argo or a viewer over tRPC as a query; what the fleet answered, unparsed. */
53
+ export async function readAs(fleetUrl, call) {
54
+ const { as, procedure, input } = call;
55
+ const isConsole = as.crewToken === undefined;
56
+ let response;
57
+ try {
58
+ response = isConsole
59
+ ? await fetch(`${fleetUrl}/trpc/fleet.${procedure}?input=${encodeURIComponent(JSON.stringify(input))}`, { headers: { cookie: as.cookie ?? '' } })
60
+ : await fetch(`${fleetUrl}/api/v1/fleet/${procedure}`, { method: 'POST', headers: { 'content-type': 'application/json', ...restHeaders(as) }, body: JSON.stringify(input) });
61
+ }
62
+ catch (error) {
63
+ return err({ code: 'UNAVAILABLE', message: error instanceof Error ? error.message : 'The fleet did not answer' });
64
+ }
65
+ const body = await response.json().catch(() => null);
66
+ if (!response.ok) {
67
+ return err(refusalOf(response.status, body));
68
+ }
69
+ if (!isConsole) {
70
+ return ok(body);
71
+ }
72
+ const answer = trpcAnswerSchema.safeParse(body);
73
+ return answer.success ? ok(answer.data.result.data) : err({ code: 'UNAVAILABLE', message: 'The fleet answered no result' });
74
+ }
75
+ //# sourceMappingURL=actor-door.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actor-door.js","sourceRoot":"","sources":["../../../src/adapters/fleet/actor-door.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,11 @@
1
+ /**
2
+ * The minimum core version check (decision 0049, docs/compatibility.md): the
3
+ * gateway reads core's version at start and refuses to run against an older
4
+ * core, saying both versions, as common's coreVersionRefusal words it.
5
+ */
6
+ import { type VersionFetch } from '@aeolus-fleet/common';
7
+ export type { VersionFetch };
1
8
  /** The oldest core the gateway runs against: the ship contract it calls (docs/compatibility.md). */
2
- export declare const MINIMUM_CORE_VERSION = "0.27.0";
3
- /** The part of `fetch` the check uses, so a test hands in its own core. */
4
- export type VersionFetch = (url: string, init: {
5
- signal: AbortSignal;
6
- }) => Promise<{
7
- status: number;
8
- json(): Promise<unknown>;
9
- }>;
9
+ export declare const MINIMUM_CORE_VERSION = "0.28.0";
10
10
  /** Stops the start when the fleet's core is older than the gateway needs, or does not say its version. */
11
11
  export declare function requireCoreVersion(fleetUrl: string, fetch?: VersionFetch): Promise<void>;
@@ -1,59 +1,18 @@
1
1
  /**
2
2
  * The minimum core version check (decision 0049, docs/compatibility.md): the
3
3
  * gateway reads core's version at start and refuses to run against an older
4
- * core, saying both versions. It follows @aeolus-fleet/common's
5
- * coreVersionRefusal, which no released common carries yet; the gateway
6
- * takes common's once it is on npm.
4
+ * core, saying both versions, as common's coreVersionRefusal words it.
7
5
  */
8
- import { z } from 'zod';
6
+ import { coreVersionRefusal } from '@aeolus-fleet/common';
9
7
  import { ConfigError } from '../../config.js';
10
8
  import { runningVersion } from '../http/version.js';
11
9
  /** The oldest core the gateway runs against: the ship contract it calls (docs/compatibility.md). */
12
- export const MINIMUM_CORE_VERSION = '0.27.0';
13
- /** Where core says its version, without authentication. */
14
- const CORE_VERSION_PATH = '/api/version';
15
- /** How long the gateway waits for core's version before it counts the fleet as not answering. */
16
- const CORE_VERSION_TIMEOUT_MS = 10_000;
17
- /** The HTTP statuses that answer a version. */
18
- const HTTP_OK_FIRST = 200;
19
- const HTTP_OK_LAST = 299;
20
- /** A plain release version; core `0.0.0` is a build from main. */
21
- const VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
22
- const coreVersionAnswerSchema = z.object({ server: z.string() });
23
- function versionOf(text) {
24
- const match = VERSION_PATTERN.exec(text);
25
- return match === null ? undefined : [Number(match[1]), Number(match[2]), Number(match[3])];
26
- }
27
- function isOlder(version, than) {
28
- const differing = version.findIndex((part, index) => part !== than[index]);
29
- return differing !== -1 && (version[differing] ?? 0) < (than[differing] ?? 0);
30
- }
31
- /** Core's version, or why it could not be read. */
32
- async function readCoreVersion(fleetUrl, fetch) {
33
- try {
34
- const response = await fetch(`${fleetUrl.replace(/\/+$/, '')}${CORE_VERSION_PATH}`, { signal: AbortSignal.timeout(CORE_VERSION_TIMEOUT_MS) });
35
- if (response.status < HTTP_OK_FIRST || response.status > HTTP_OK_LAST) {
36
- return { unread: `HTTP ${String(response.status)}` };
37
- }
38
- const answer = coreVersionAnswerSchema.safeParse(await response.json());
39
- const parsed = answer.success ? versionOf(answer.data.server) : undefined;
40
- return answer.success && parsed !== undefined ? { core: answer.data.server, parsed } : { unread: `its ${CORE_VERSION_PATH} answered no core version` };
41
- }
42
- catch (error) {
43
- return { unread: error instanceof Error ? error.message : String(error) };
44
- }
45
- }
10
+ export const MINIMUM_CORE_VERSION = '0.28.0';
46
11
  /** Stops the start when the fleet's core is older than the gateway needs, or does not say its version. */
47
12
  export async function requireCoreVersion(fleetUrl, fetch = globalThis.fetch) {
48
- const needs = `gateway ${runningVersion()} needs core ${MINIMUM_CORE_VERSION} or later`;
49
- const minimum = versionOf(MINIMUM_CORE_VERSION) ?? [0, 0, 0];
50
- const read = await readCoreVersion(fleetUrl, fetch);
51
- if ('unread' in read) {
52
- throw new ConfigError(`${needs}, and could not read the version of the fleet at ${fleetUrl}: ${read.unread}`);
53
- }
54
- const isMainBuild = read.parsed.every((part) => part === 0);
55
- if (!isMainBuild && isOlder(read.parsed, minimum)) {
56
- throw new ConfigError(`${needs}; the fleet at ${fleetUrl} runs core ${read.core}: upgrade core first`);
13
+ const refusal = await coreVersionRefusal({ packageName: 'gateway', version: runningVersion(), minimum: MINIMUM_CORE_VERSION, fleetUrl, fetch });
14
+ if (refusal !== undefined) {
15
+ throw new ConfigError(refusal);
57
16
  }
58
17
  }
59
18
  //# sourceMappingURL=core-version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"core-version.js","sourceRoot":"","sources":["../../../src/adapters/fleet/core-version.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"core-version.js","sourceRoot":"","sources":["../../../src/adapters/fleet/core-version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,kBAAkB,EAAqB,MAAM,sBAAsB,CAAC;AAE7E,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,oGAAoG;AACpG,MAAM,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AAE7C,0GAA0G;AAC1G,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAgB,EAAE,QAAsB,UAAU,CAAC,KAAK;IAC/F,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAChJ,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;AACH,CAAC"}
@@ -1,30 +1,20 @@
1
1
  /**
2
2
  * Reads whether the fleet applies network rules with `fleet.networkRules`
3
3
  * (aeolus-fleet #997), as the actor who asked (decision 0057): a ship with its
4
- * crew token over REST, argo with the console session over tRPC. The answer's
5
- * schema stands in for common's until core 0.28 publishes it (aeolus-fleet#991).
4
+ * crew token over REST, an account with its account token presented by the
5
+ * gateway's ship over REST, argo with the console session over tRPC.
6
6
  */
7
+ import { networkRulesOutputSchema } from '@aeolus-fleet/common';
7
8
  import { z } from 'zod';
8
9
  import { err, ok } from '../../core/shared/result.js';
9
- const networkRulesSchema = z.object({ applied: z.object({ rules: z.array(z.unknown()).nullable() }) });
10
- const trpcAnswerSchema = z.object({ result: z.object({ data: networkRulesSchema }) }).transform(({ result }) => result.data);
11
- const refusalSchema = z.object({ code: z.string(), message: z.string() });
12
- const trpcRefusalSchema = z.object({ error: z.object({ message: z.string(), data: z.object({ code: z.string() }) }) });
13
- /** The fleet's refusal as its code and message, whichever door answered it. */
14
- function refusalOf(status, body) {
15
- const rest = refusalSchema.safeParse(body);
16
- if (rest.success) {
17
- return rest.data;
18
- }
19
- const trpc = trpcRefusalSchema.safeParse(body);
20
- return trpc.success ? { code: trpc.data.error.data.code, message: trpc.data.error.message } : { code: 'UNAVAILABLE', message: `The fleet answered ${String(status)}` };
21
- }
10
+ import { refusalOf, restHeaders } from './actor-door.js';
11
+ const trpcAnswerSchema = z.object({ result: z.object({ data: networkRulesOutputSchema }) }).transform(({ result }) => result.data);
22
12
  export function createFleetNetwork(fleetUrl) {
23
13
  return {
24
14
  isOpen: async (as) => {
25
15
  const request = as.crewToken === undefined
26
16
  ? { url: `${fleetUrl}/trpc/fleet.networkRules`, headers: { cookie: as.cookie ?? '' } }
27
- : { url: `${fleetUrl}/api/v1/fleet/networkRules`, headers: { authorization: `Bearer ${as.crewToken}` } };
17
+ : { url: `${fleetUrl}/api/v1/fleet/networkRules`, headers: restHeaders(as) };
28
18
  let response;
29
19
  try {
30
20
  response = await fetch(request.url, { headers: request.headers });
@@ -36,7 +26,7 @@ export function createFleetNetwork(fleetUrl) {
36
26
  if (!response.ok) {
37
27
  return err(refusalOf(response.status, body));
38
28
  }
39
- const rules = (as.crewToken === undefined ? trpcAnswerSchema : networkRulesSchema).safeParse(body);
29
+ const rules = (as.crewToken === undefined ? trpcAnswerSchema : networkRulesOutputSchema).safeParse(body);
40
30
  return rules.success ? ok(rules.data.applied.rules === null) : err({ code: 'UNAVAILABLE', message: 'The fleet answered no network rules' });
41
31
  },
42
32
  };
@@ -1 +1 @@
1
- {"version":3,"file":"fleet-network.js","sourceRoot":"","sources":["../../../src/adapters/fleet/fleet-network.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fleet-network.js","sourceRoot":"","sources":["../../../src/adapters/fleet/fleet-network.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAEnI,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO;QACL,MAAM,EAAE,KAAK,EAAE,EAAmB,EAA0C,EAAE;YAC5E,MAAM,OAAO,GACX,EAAE,CAAC,SAAS,KAAK,SAAS;gBACxB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,QAAQ,0BAA0B,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,IAAI,EAAE,EAAE,EAAE;gBACtF,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,QAAQ,4BAA4B,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;YACjF,IAAI,QAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;YACpE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,EAAE,CAAC,CAAC;YACpH,CAAC;YACD,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YAC9D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,OAAO,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;YAC/C,CAAC;YACD,MAAM,KAAK,GAAG,CAAC,EAAE,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACzG,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,qCAAqC,EAAE,CAAC,CAAC;QAC9I,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { ProxyShipDoor } from '../../core/parties/ports.js';
2
+ /** The part of a logger this needs: a warning with its fields. */
3
+ interface WarningLog {
4
+ warn(fields: Record<string, unknown>, message: string): void;
5
+ }
6
+ /**
7
+ * The fleet's verified facts write, with a refusal logged as a warning: the
8
+ * approval goes on without it (decision 0059), so the log is where a refused
9
+ * write shows, as in a fleet whose own network rules give the gateway's ship
10
+ * no manage reach over its proxy ships.
11
+ */
12
+ export declare function logRefusedFacts(door: Pick<ProxyShipDoor, 'setVerifiedFacts'>, log: WarningLog): Pick<ProxyShipDoor, 'setVerifiedFacts'>;
13
+ export {};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The fleet's verified facts write, with a refusal logged as a warning: the
3
+ * approval goes on without it (decision 0059), so the log is where a refused
4
+ * write shows, as in a fleet whose own network rules give the gateway's ship
5
+ * no manage reach over its proxy ships.
6
+ */
7
+ export function logRefusedFacts(door, log) {
8
+ return {
9
+ setVerifiedFacts: async (crewToken, written) => {
10
+ const set = await door.setVerifiedFacts(crewToken, written);
11
+ if (!set.isOk) {
12
+ log.warn({ shipId: written.shipId, code: set.error.code, reason: set.error.message }, 'the fleet refused the verified facts about a proxy ship');
13
+ }
14
+ return set;
15
+ },
16
+ };
17
+ }
18
+ //# sourceMappingURL=logged-verified-facts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logged-verified-facts.js","sourceRoot":"","sources":["../../../src/adapters/fleet/logged-verified-facts.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,IAA6C,EAAE,GAAe;IAC5F,OAAO;QACL,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;YAC7C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC5D,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBACd,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,yDAAyD,CAAC,CAAC;YACnJ,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ProxyShipReads } from '../../core/parties/ports.js';
2
+ /**
3
+ * A party's proxy ship as the actor reads it (fleet.ship, decision 0057): its
4
+ * owner and scopes within the actor's read reach, and neither outside it,
5
+ * where the fleet answers only the ship's name, type and status.
6
+ */
7
+ export declare function createProxyShipReads(fleetUrl: string): ProxyShipReads;
@@ -0,0 +1,24 @@
1
+ import { shipOutputSchema } from '@aeolus-fleet/common';
2
+ import { err, ok } from '../../core/shared/result.js';
3
+ import { readAs } from './actor-door.js';
4
+ /**
5
+ * A party's proxy ship as the actor reads it (fleet.ship, decision 0057): its
6
+ * owner and scopes within the actor's read reach, and neither outside it,
7
+ * where the fleet answers only the ship's name, type and status.
8
+ */
9
+ export function createProxyShipReads(fleetUrl) {
10
+ return {
11
+ read: async (as, { shipId }) => {
12
+ const read = await readAs(fleetUrl, { as, procedure: 'ship', input: { shipId } });
13
+ if (!read.isOk) {
14
+ return read;
15
+ }
16
+ const ship = shipOutputSchema.safeParse(read.value);
17
+ if (!ship.success) {
18
+ return err({ code: 'UNAVAILABLE', message: 'The fleet answered no ship' });
19
+ }
20
+ return 'isInReadReach' in ship.data ? ok({ ownerShipId: null, scopes: null }) : ok({ ownerShipId: ship.data.owner?.id ?? null, scopes: [...ship.data.scopes] });
21
+ },
22
+ };
23
+ }
24
+ //# sourceMappingURL=proxy-ship-reads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-ship-reads.js","sourceRoot":"","sources":["../../../src/adapters/fleet/proxy-ship-reads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACnD,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YAC7B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YAClF,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,IAAI,GAAG,gBAAgB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC,CAAC;YAC7E,CAAC;YACD,OAAO,eAAe,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClK,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ProxyShipsAsActor } from '../../core/parties/ports.js';
2
+ /** A party's proxy ship, as the actor calls the fleet on it (decision 0057). */
3
+ export declare function createProxyShipsAsActor(fleetUrl: string): ProxyShipsAsActor;