@knpkv/control-center 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/dist/client/.vite/manifest.json +312 -255
  2. package/dist/client/assets/ActiveWorkPage-C6lIQfjL.js +2 -0
  3. package/dist/client/assets/{ActiveWorkPage-BsaIr8ah.js.map → ActiveWorkPage-C6lIQfjL.js.map} +1 -1
  4. package/dist/client/assets/AgentPage-DqB5BilE.js +6 -0
  5. package/dist/client/assets/{AgentPage-Cybynsnc.js.map → AgentPage-DqB5BilE.js.map} +1 -1
  6. package/dist/client/assets/{AtlassianOAuthCallbackPage-Du3pHuS9.js → AtlassianOAuthCallbackPage-DzTO6SqN.js} +2 -2
  7. package/dist/client/assets/{AtlassianOAuthCallbackPage-Du3pHuS9.js.map → AtlassianOAuthCallbackPage-DzTO6SqN.js.map} +1 -1
  8. package/dist/client/assets/AuthorizedSharePage-V_E5giT7.js +2 -0
  9. package/dist/client/assets/{AuthorizedSharePage-tfTdXNjt.js.map → AuthorizedSharePage-V_E5giT7.js.map} +1 -1
  10. package/dist/client/assets/BrowserCrypto-CoBR2WBd.js +2 -0
  11. package/dist/client/assets/{BrowserCrypto-DVxU0-Oc.js.map → BrowserCrypto-CoBR2WBd.js.map} +1 -1
  12. package/dist/client/assets/BrowserSessionHydrator-CEypgMkR.js +2 -0
  13. package/dist/client/assets/{BrowserSessionHydrator-CvtvZstV.js.map → BrowserSessionHydrator-CEypgMkR.js.map} +1 -1
  14. package/dist/client/assets/CommandSearch-syQMt_rx.js +2 -0
  15. package/dist/client/assets/{CommandSearch-Bf_oW_kD.js.map → CommandSearch-syQMt_rx.js.map} +1 -1
  16. package/dist/client/assets/Dialog-DSwimdwG-BeHnBpPp.js +42 -0
  17. package/dist/client/assets/Dialog-DSwimdwG-BeHnBpPp.js.map +1 -0
  18. package/dist/client/assets/Domain-cJ5aJFpE.js +2 -0
  19. package/dist/client/assets/Domain-cJ5aJFpE.js.map +1 -0
  20. package/dist/client/assets/ItemsPage-Cr3--iJc.js +2 -0
  21. package/dist/client/assets/{ItemsPage-BmWEHinz.js.map → ItemsPage-Cr3--iJc.js.map} +1 -1
  22. package/dist/client/assets/OpenPullRequestPage-BYoRmtui.js +2 -0
  23. package/dist/client/assets/OpenPullRequestPage-BYoRmtui.js.map +1 -0
  24. package/dist/client/assets/{Pages-BmZj4KzS.js → Pages-DrDuXLFH.js} +2 -2
  25. package/dist/client/assets/{Pages-BmZj4KzS.js.map → Pages-DrDuXLFH.js.map} +1 -1
  26. package/dist/client/assets/PairPage-ByOBKuBB.js +2 -0
  27. package/dist/client/assets/{PairPage-CLLUweYZ.js.map → PairPage-ByOBKuBB.js.map} +1 -1
  28. package/dist/client/assets/PortalProvider-CN_81Fy3-D_japesx.js +2 -0
  29. package/dist/client/assets/{PortalProvider-BpgZwSpw-nEH0TqWT.js.map → PortalProvider-CN_81Fy3-D_japesx.js.map} +1 -1
  30. package/dist/client/assets/PortfolioOverview-BacOXO-c.js +2 -0
  31. package/dist/client/assets/{PortfolioOverview-BBKSc-yI.js.map → PortfolioOverview-BacOXO-c.js.map} +1 -1
  32. package/dist/client/assets/{PullRequestReviewPanel-Boi0A6pq.js → PullRequestReviewPanel-DwVYuZ8Q.js} +5 -5
  33. package/dist/client/assets/{PullRequestReviewPanel-Boi0A6pq.js.map → PullRequestReviewPanel-DwVYuZ8Q.js.map} +1 -1
  34. package/dist/client/assets/ReleaseRoute-C-MfQKnL.js +2 -0
  35. package/dist/client/assets/{ReleaseRoute-D4CttCjC.js.map → ReleaseRoute-C-MfQKnL.js.map} +1 -1
  36. package/dist/client/assets/ReleaseWorkset-MV3I0HCi.js +2 -0
  37. package/dist/client/assets/{ReleaseWorkset-Dt-ArwsN.js.map → ReleaseWorkset-MV3I0HCi.js.map} +1 -1
  38. package/dist/client/assets/ReviewSuggestionPublicationSurface-BZIa-Vvc.js +2 -0
  39. package/dist/client/assets/{ReviewSuggestionPublicationSurface-N9Qwdh2n.js.map → ReviewSuggestionPublicationSurface-BZIa-Vvc.js.map} +1 -1
  40. package/dist/client/assets/ServicesPage-BjeCOlsh.js +2 -0
  41. package/dist/client/assets/{ServicesPage-D0ygZTFD.js.map → ServicesPage-BjeCOlsh.js.map} +1 -1
  42. package/dist/client/assets/TimelinePage-Ccnp6Mmg.js +2 -0
  43. package/dist/client/assets/{TimelinePage-Bb2o9DGU.js.map → TimelinePage-Ccnp6Mmg.js.map} +1 -1
  44. package/dist/client/assets/{WorkspaceEntityLink-Cw675wTN.js → WorkspaceEntityLink-D3TXDcD0.js} +2 -2
  45. package/dist/client/assets/{WorkspaceEntityLink-Cw675wTN.js.map → WorkspaceEntityLink-D3TXDcD0.js.map} +1 -1
  46. package/dist/client/assets/WorkspaceEntityRoute-uUK6vwM_.js +14 -0
  47. package/dist/client/assets/WorkspaceEntityRoute-uUK6vwM_.js.map +1 -0
  48. package/dist/client/assets/WorkspaceHomeLink-D5SdEgJJ.js +2 -0
  49. package/dist/client/assets/{WorkspaceHomeLink-FGslxXCu.js.map → WorkspaceHomeLink-D5SdEgJJ.js.map} +1 -1
  50. package/dist/client/assets/WorkspacePullRequestDetails-CKedGIT8.js +3 -0
  51. package/dist/client/assets/{WorkspacePullRequestDetails-Dxg8argO.js.map → WorkspacePullRequestDetails-CKedGIT8.js.map} +1 -1
  52. package/dist/client/assets/{WorkspaceReleaseLayout-BvEiZJEb.js → WorkspaceReleaseLayout-Bdvl0q99.js} +2 -2
  53. package/dist/client/assets/{WorkspaceReleaseLayout-BvEiZJEb.js.map → WorkspaceReleaseLayout-Bdvl0q99.js.map} +1 -1
  54. package/dist/client/assets/{WorkspaceRichText-CocmKQ4T.js → WorkspaceRichText-Beh64wsV.js} +2 -2
  55. package/dist/client/assets/{WorkspaceRichText-CocmKQ4T.js.map → WorkspaceRichText-Beh64wsV.js.map} +1 -1
  56. package/dist/client/assets/WorkspaceSettingsPage-BxFq65Vf.js +2 -0
  57. package/dist/client/assets/{WorkspaceSettingsPage-iZhUs-pg.js.map → WorkspaceSettingsPage-BxFq65Vf.js.map} +1 -1
  58. package/dist/client/assets/{agent-api-CzdQFCcD.js → agent-api-CUWP1qs8.js} +2 -2
  59. package/dist/client/assets/{agent-api-CzdQFCcD.js.map → agent-api-CUWP1qs8.js.map} +1 -1
  60. package/dist/client/assets/{atlassianOAuthSetupIntentStorage-BxsxmjSm.js → atlassianOAuthSetupIntentStorage-Cy1Gw639.js} +2 -2
  61. package/dist/client/assets/{atlassianOAuthSetupIntentStorage-BxsxmjSm.js.map → atlassianOAuthSetupIntentStorage-Cy1Gw639.js.map} +1 -1
  62. package/dist/client/assets/authenticatedMutationClient-Bc_-Jpbo.js +2 -0
  63. package/dist/client/assets/{authenticatedMutationClient-DUqEcJHu.js.map → authenticatedMutationClient-Bc_-Jpbo.js.map} +1 -1
  64. package/dist/client/assets/authorizedShareTransport-kkT3Jf6q.js +2 -0
  65. package/dist/client/assets/{authorizedShareTransport-7YCNH9l3.js.map → authorizedShareTransport-kkT3Jf6q.js.map} +1 -1
  66. package/dist/client/assets/client-D3WRV6yl.js +5 -0
  67. package/dist/client/assets/client-D3WRV6yl.js.map +1 -0
  68. package/dist/client/assets/{confluenceTasks-D9yrB-oV.js → confluenceTasks-By7BV0WN.js} +2 -2
  69. package/dist/client/assets/{confluenceTasks-D9yrB-oV.js.map → confluenceTasks-By7BV0WN.js.map} +1 -1
  70. package/dist/client/assets/connectionTestTransport-CRq7l9X0.js +2 -0
  71. package/dist/client/assets/{connectionTestTransport-D8tiZ4ym.js.map → connectionTestTransport-CRq7l9X0.js.map} +1 -1
  72. package/dist/client/assets/controlCenterRelayDock-D7375HPG.js +3 -0
  73. package/dist/client/assets/controlCenterRelayDock-D7375HPG.js.map +1 -0
  74. package/dist/client/assets/controlCenterRelayDockChrome-B7jSUI3t.js +3 -0
  75. package/dist/client/assets/controlCenterRelayDockChrome-B7jSUI3t.js.map +1 -0
  76. package/dist/client/assets/index-BVikncBH.js +11 -0
  77. package/dist/client/assets/index-BVikncBH.js.map +1 -0
  78. package/dist/client/assets/index-tjRpNCt_.css +1 -0
  79. package/dist/client/assets/openPullRequest-BMlmibLP.js +2 -0
  80. package/dist/client/assets/openPullRequest-BMlmibLP.js.map +1 -0
  81. package/dist/client/assets/patterns-DAeEdyxU.js +2 -0
  82. package/dist/client/assets/patterns-DAeEdyxU.js.map +1 -0
  83. package/dist/client/assets/{presentPortfolio-c8-wbodG.js → presentPortfolio-DVP-zqTg.js} +2 -2
  84. package/dist/client/assets/{presentPortfolio-c8-wbodG.js.map → presentPortfolio-DVP-zqTg.js.map} +1 -1
  85. package/dist/client/assets/{presentWorkspaceItems-DfhyQeSY.js → presentWorkspaceItems-BY8bmqjF.js} +2 -2
  86. package/dist/client/assets/{presentWorkspaceItems-DfhyQeSY.js.map → presentWorkspaceItems-BY8bmqjF.js.map} +1 -1
  87. package/dist/client/assets/primitives-DYGtIZqB-r-Glkv2i.js +2 -0
  88. package/dist/client/assets/primitives-DYGtIZqB-r-Glkv2i.js.map +1 -0
  89. package/dist/client/assets/pullRequestReviewFailures-CCNxSXP6.js +2 -0
  90. package/dist/client/assets/{pullRequestReviewFailures-QvtS729d.js.map → pullRequestReviewFailures-CCNxSXP6.js.map} +1 -1
  91. package/dist/client/assets/pullRequestReviewThreadReplay-eI3Y4i6s.js +2 -0
  92. package/dist/client/assets/{pullRequestReviewThreadReplay-CpPdYxQE.js.map → pullRequestReviewThreadReplay-eI3Y4i6s.js.map} +1 -1
  93. package/dist/client/assets/{releaseAgentTransport-BCQDYqZt.js → releaseAgentTransport-CJjWwE8y.js} +2 -2
  94. package/dist/client/assets/{releaseAgentTransport-BCQDYqZt.js.map → releaseAgentTransport-CJjWwE8y.js.map} +1 -1
  95. package/dist/client/assets/releaseRoutes-h4FVwFvJ.js +2 -0
  96. package/dist/client/assets/{releaseRoutes-CSP_eBj6.js.map → releaseRoutes-h4FVwFvJ.js.map} +1 -1
  97. package/dist/client/assets/{serviceOnboarding-B6v5VXTG.js → serviceOnboarding-F9Lj6a7y.js} +2 -2
  98. package/dist/client/assets/{serviceOnboarding-B6v5VXTG.js.map → serviceOnboarding-F9Lj6a7y.js.map} +1 -1
  99. package/dist/client/assets/useWorkspaceDefaultLanding-DMWfrZfF.js +3 -0
  100. package/dist/client/assets/{useWorkspaceDefaultLanding-C3PRrLgk.js.map → useWorkspaceDefaultLanding-DMWfrZfF.js.map} +1 -1
  101. package/dist/client/assets/useWorkspaceItems-6KWfmFtx.js +2 -0
  102. package/dist/client/assets/{useWorkspaceItems-CHYpfLmL.js.map → useWorkspaceItems-6KWfmFtx.js.map} +1 -1
  103. package/dist/client/assets/{workspaceEntityRoutes-CFPO-iFw.js → workspaceEntityRoutes-BJ-SC0Jd.js} +2 -2
  104. package/dist/client/assets/{workspaceEntityRoutes-CFPO-iFw.js.map → workspaceEntityRoutes-BJ-SC0Jd.js.map} +1 -1
  105. package/dist/client/assets/{workspaceScrollCapture-DUj-_YMd.js → workspaceScrollCapture-CwBIBHg8.js} +2 -2
  106. package/dist/client/assets/{workspaceScrollCapture-DUj-_YMd.js.map → workspaceScrollCapture-CwBIBHg8.js.map} +1 -1
  107. package/dist/client/assets/workspaceSettingsTransport-BwRQteEH.js +2 -0
  108. package/dist/client/assets/{workspaceSettingsTransport-Kq7lfPsC.js.map → workspaceSettingsTransport-BwRQteEH.js.map} +1 -1
  109. package/dist/client/build-graph.json +63 -0
  110. package/dist/client/index.html +3 -3
  111. package/dist/server/api/index.js +1 -1
  112. package/dist/server/assets/{BindConfig-hNWrGfu2.js → BindConfig-D8aIjI_R.js} +2 -2
  113. package/dist/server/assets/{BindConfig-hNWrGfu2.js.map → BindConfig-D8aIjI_R.js.map} +1 -1
  114. package/dist/server/assets/{controlCenterApi-BcVWTP9F.js → controlCenterApi-WaKi6EUb.js} +2 -1
  115. package/dist/server/assets/controlCenterApi-WaKi6EUb.js.map +1 -0
  116. package/dist/server/index.js +1 -1
  117. package/dist/server/server/cli.js +1 -1
  118. package/dist/server/server/index.js +1 -1
  119. package/package.json +7 -6
  120. package/dist/client/assets/ActiveWorkPage-BsaIr8ah.js +0 -2
  121. package/dist/client/assets/AgentPage-Cybynsnc.js +0 -6
  122. package/dist/client/assets/AuthorizedSharePage-tfTdXNjt.js +0 -2
  123. package/dist/client/assets/BrowserCrypto-DVxU0-Oc.js +0 -2
  124. package/dist/client/assets/BrowserSessionHydrator-CvtvZstV.js +0 -2
  125. package/dist/client/assets/CommandSearch-Bf_oW_kD.js +0 -2
  126. package/dist/client/assets/Dialog-1WvU8GjA-C7r26HF0.js +0 -42
  127. package/dist/client/assets/Dialog-1WvU8GjA-C7r26HF0.js.map +0 -1
  128. package/dist/client/assets/ItemsPage-BmWEHinz.js +0 -2
  129. package/dist/client/assets/OpenPullRequestPage-DkCom6mf.js +0 -2
  130. package/dist/client/assets/OpenPullRequestPage-DkCom6mf.js.map +0 -1
  131. package/dist/client/assets/PairPage-CLLUweYZ.js +0 -2
  132. package/dist/client/assets/PortalProvider-BpgZwSpw-nEH0TqWT.js +0 -2
  133. package/dist/client/assets/PortfolioOverview-BBKSc-yI.js +0 -2
  134. package/dist/client/assets/ReleaseRoute-D4CttCjC.js +0 -2
  135. package/dist/client/assets/ReleaseWorkset-Dt-ArwsN.js +0 -2
  136. package/dist/client/assets/ReviewSuggestionPublicationSurface-N9Qwdh2n.js +0 -2
  137. package/dist/client/assets/ServicesPage-D0ygZTFD.js +0 -2
  138. package/dist/client/assets/TimelinePage-Bb2o9DGU.js +0 -2
  139. package/dist/client/assets/WorkspaceEntityRoute-rLRiaF8b.js +0 -14
  140. package/dist/client/assets/WorkspaceEntityRoute-rLRiaF8b.js.map +0 -1
  141. package/dist/client/assets/WorkspaceHomeLink-FGslxXCu.js +0 -2
  142. package/dist/client/assets/WorkspacePullRequestDetails-Dxg8argO.js +0 -3
  143. package/dist/client/assets/WorkspaceSettingsPage-iZhUs-pg.js +0 -2
  144. package/dist/client/assets/authenticatedMutationClient-DUqEcJHu.js +0 -2
  145. package/dist/client/assets/authorizedShareTransport-7YCNH9l3.js +0 -2
  146. package/dist/client/assets/client-D2F6HlDk.js +0 -5
  147. package/dist/client/assets/client-D2F6HlDk.js.map +0 -1
  148. package/dist/client/assets/connectionTestTransport-D8tiZ4ym.js +0 -2
  149. package/dist/client/assets/index-BWx9sNOT.js +0 -11
  150. package/dist/client/assets/index-BWx9sNOT.js.map +0 -1
  151. package/dist/client/assets/index-CIfiz7oF.css +0 -1
  152. package/dist/client/assets/patterns-CxMz8DKX-ByHwV03y.js +0 -2
  153. package/dist/client/assets/patterns-CxMz8DKX-ByHwV03y.js.map +0 -1
  154. package/dist/client/assets/primitives-CW89TsFB-BBLwFFPo.js +0 -2
  155. package/dist/client/assets/primitives-CW89TsFB-BBLwFFPo.js.map +0 -1
  156. package/dist/client/assets/pullRequestReviewFailures-QvtS729d.js +0 -2
  157. package/dist/client/assets/pullRequestReviewThreadReplay-CpPdYxQE.js +0 -2
  158. package/dist/client/assets/releaseRoutes-CSP_eBj6.js +0 -2
  159. package/dist/client/assets/useWorkspaceDefaultLanding-C3PRrLgk.js +0 -3
  160. package/dist/client/assets/useWorkspaceItems-CHYpfLmL.js +0 -2
  161. package/dist/client/assets/workspaceSettingsTransport-Kq7lfPsC.js +0 -2
  162. package/dist/server/assets/controlCenterApi-BcVWTP9F.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PortfolioOverview-BBKSc-yI.js","names":["random.Random","Effect.withFiber","Effect.succeed"],"sources":["../../../../../node_modules/.pnpm/effect@4.0.0-rc.109/node_modules/effect/dist/Random.js","../../../src/client/BrowserSessionStatus.tsx","../../../src/client/portfolio/portfolioFilters.ts","../../../src/client/portfolio/livePortfolioState.ts","../../../src/client/portfolio/usePortfolioSnapshot.ts","../../../src/client/portfolio/PortfolioOverview.module.css","../../../src/client/portfolio/PortfolioOverview.tsx"],"sourcesContent":["import * as Cause from \"./Cause.js\";\nimport * as Effect from \"./Effect.js\";\nimport { dual } from \"./Function.js\";\nimport * as random from \"./internal/random.js\";\nimport * as Predicate from \"./Predicate.js\";\n/**\n * Represents a service for generating pseudo-random numbers.\n *\n * **When to use**\n *\n * Use to access or provide the random-number generator service used by Effect\n * programs.\n *\n * **Gotchas**\n *\n * The default implementation is based on `Math.random` and is not\n * cryptographically secure. Replace the service with a cryptographically secure\n * implementation before using these generators for security-sensitive values.\n *\n * **Example** (Accessing the random service)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * const program = Effect.gen(function*() {\n * const float = yield* Random.next\n * const integer = yield* Random.nextInt\n * const inRange = yield* Random.nextIntBetween(1, 100)\n * return [float, integer, inRange] as const\n * })\n *\n * await Effect.runPromise(program.pipe(Random.withSeed(\"example\"))) // => [0.1633802591287037, 3434461687501127, 1]\n * ```\n *\n * @category services\n * @since 2.0.0\n */\nexport const Random = random.Random;\nconst randomWith = f => Effect.withFiber(fiber => Effect.succeed(f(fiber.getRef(Random))));\n/**\n * Generates a random number between 0 (inclusive) and 1 (exclusive).\n *\n * **When to use**\n *\n * Use to generate a pseudo-random floating-point number in the standard\n * `[0, 1)` range.\n *\n * **Example** (Generating a random number)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.next.pipe(Random.withSeed(\"example\"))) // => 0.1633802591287037\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const next = /*#__PURE__*/randomWith(r => r.nextDoubleUnsafe());\n/**\n * Generates a random boolean value.\n *\n * **When to use**\n *\n * Use to make a pseudo-random true-or-false choice.\n *\n * **Example** (Generating a random boolean)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.nextBoolean.pipe(Random.withSeed(\"example\"))) // => false\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const nextBoolean = /*#__PURE__*/randomWith(r => r.nextDoubleUnsafe() > 0.5);\n/**\n * Generates a random integer between `Number.MIN_SAFE_INTEGER` (inclusive)\n * and `Number.MAX_SAFE_INTEGER` (inclusive).\n *\n * **When to use**\n *\n * Use to generate a pseudo-random safe integer across the full safe-integer\n * range.\n *\n * **Example** (Generating a random integer)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.nextInt.pipe(Random.withSeed(\"example\"))) // => -6064002158214091\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const nextInt = /*#__PURE__*/randomWith(r => r.nextIntUnsafe());\n/**\n * Generates a random number between `min` (inclusive) and `max` (exclusive).\n *\n * **When to use**\n *\n * Use to generate a pseudo-random floating-point number within a numeric range.\n *\n * **Example** (Generating a bounded random number)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.nextBetween(0, 1).pipe(Random.withSeed(\"example\"))) // => 0.1633802591287037\n * ```\n *\n * @category generators\n * @since 4.0.0\n */\nexport const nextBetween = (min, max) => randomWith(r => r.nextDoubleUnsafe() * (max - min) + min);\n/**\n * Generates a random integer between `min` and `max`.\n *\n * **When to use**\n *\n * Use to generate a pseudo-random integer within a rounded numeric range.\n *\n * **Details**\n *\n * The lower bound is rounded up with `Math.ceil` and the upper bound is\n * rounded down with `Math.floor`. By default the range is inclusive; set\n * `options.halfOpen: true` to exclude the upper bound.\n *\n * **Example** (Generating a bounded random integer)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * const program = Effect.gen(function*() {\n * const diceRoll1 = yield* Random.nextIntBetween(1, 6)\n * const diceRoll2 = yield* Random.nextIntBetween(1, 6, {\n * halfOpen: true\n * })\n * const diceRoll3 = yield* Random.nextIntBetween(0, 10)\n * return [diceRoll1, diceRoll2, diceRoll3]\n * })\n *\n * await Effect.runPromise(program.pipe(Random.withSeed(\"example\"))) // => [1, 4, 0]\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const nextIntBetween = (min, max, options) => {\n const extra = options?.halfOpen === true ? 0 : 1;\n return randomWith(r => {\n const minInt = Math.ceil(min);\n const maxInt = Math.floor(max);\n return Math.floor(r.nextDoubleUnsafe() * (maxInt - minInt + extra)) + minInt;\n });\n};\n/**\n * Uses the pseudo-random number generator to shuffle the specified iterable.\n *\n * **When to use**\n *\n * Use to randomly reorder an iterable using the active `Random` service.\n *\n * **Example** (Shuffling values)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.shuffle([1, 2, 3, 4, 5]).pipe(Random.withSeed(\"example\"))) // => [4, 2, 5, 3, 1]\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const shuffle = elements => randomWith(r => {\n const buffer = Array.from(elements);\n for (let i = buffer.length - 1; i >= 1; i = i - 1) {\n const index = Math.min(i, Math.floor(r.nextDoubleUnsafe() * (i + 1)));\n const value = buffer[i];\n buffer[i] = buffer[index];\n buffer[index] = value;\n }\n return buffer;\n});\n/**\n * Gets a random element from an iterable.\n *\n * **When to use**\n *\n * Use to select one value uniformly from a collection using the active `Random`\n * service.\n *\n * **Details**\n *\n * If the input type is known to be non-empty, the returned effect cannot fail.\n * Otherwise, empty iterables fail with `Cause.NoSuchElementError`.\n *\n * **Example** (Choosing a random value)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.choice([\"red\", \"green\", \"blue\"] as const).pipe(Random.withSeed(\"example\"))) // => \"red\"\n * ```\n *\n * @category generators\n * @since 3.6.0\n */\nexport const choice = elements => {\n const buffer = Array.from(elements);\n return buffer.length === 0 ? Effect.fail(new Cause.NoSuchElementError(\"Cannot select a random element from an empty array\")) : randomWith(r => buffer[Math.min(buffer.length - 1, Math.floor(r.nextDoubleUnsafe() * buffer.length))]);\n};\n/**\n * Seeds the pseudo-random number generator with the specified value.\n *\n * **When to use**\n *\n * Use to run an effect with a deterministic pseudo-random sequence.\n *\n * **Details**\n *\n * Using the same seed produces the same random sequence, which is useful for\n * tests and reproducible simulations.\n *\n * **Gotchas**\n *\n * Use an unpredictable seed when uniqueness or unpredictability matters.\n *\n * **Example** (Seeding random generation)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * const program = Effect.gen(function*() {\n * const value1 = yield* Random.next\n * const value2 = yield* Random.next\n * return [value1, value2]\n * })\n *\n * await Effect.runPromise(Effect.all([\n * program.pipe(Random.withSeed(\"my-seed\")),\n * program.pipe(Random.withSeed(\"my-seed\"))\n * ])) // => [[0.018368576514773527, 0.4010840628128671], [0.018368576514773527, 0.4010840628128671]]\n * ```\n *\n * @category providing services\n * @since 4.0.0\n */\nexport const withSeed = /*#__PURE__*/dual(2, (self, seed) => Effect.provideService(self, Random, ISAAC_CSPRNG(seed)));\n/*///////////////////////////////////////////////////////////////////////////////////////////////////\nThis is a derivative work copyright (c) 2025 Effectful Technologies Inc, under MIT license.\nThis is a derivative work copyright (c) 2018, William P. \"Mac\" McMeans, under BSD license.\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n3. Neither the name of isaacCSPRNG nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\nOriginal work copyright (c) 2012 Yves-Marie K. Rinquin, under MIT license.\nhttps://github.com/rubycon/isaac.js\n///////////////////////////////////////////////////////////////////////////////////////////////////*/\nfunction ISAAC_CSPRNG(userSeed) {\n // Internal State\n const memory = new Array(256);\n const result = new Array(256);\n let accumulator = 0;\n let lastResult = 0;\n let generation = 0;\n let counter = 0;\n // Initial Seed\n const internalSeed = Predicate.isUndefined(userSeed) ? getInitialSeed() : userSeed;\n seed(internalSeed);\n function getInitialSeed() {\n const uint32a = new Uint32Array(2);\n crypto.getRandomValues(uint32a);\n return uint32a[0] + uint32a[1];\n }\n function reset() {\n accumulator = 0;\n lastResult = 0;\n counter = 0;\n for (let i = 0; i < 256; ++i) {\n memory[i] = 0;\n result[i] = 0;\n }\n generation = 0;\n }\n function seed(userSeed) {\n // The golden ratio ( 2654435769 )\n // See https://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine\n const magicNumber = 0x9e3779b9;\n let a = magicNumber;\n let b = magicNumber;\n let c = magicNumber;\n let d = magicNumber;\n let e = magicNumber;\n let f = magicNumber;\n let g = magicNumber;\n let h = magicNumber;\n let i = 0;\n let seed;\n if (Predicate.isString(userSeed)) {\n seed = toIntArray(userSeed);\n } else {\n seed = [userSeed];\n }\n reset();\n for (i = 0; i < seed.length; i++) {\n result[i & 0xff] += seed[i];\n }\n function mix() {\n a ^= b << 11;\n d = add32(d, a);\n b = add32(b, c);\n b ^= c >>> 2;\n e = add32(e, b);\n c = add32(c, d);\n c ^= d << 8;\n f = add32(f, c);\n d = add32(d, e);\n d ^= e >>> 16;\n g = add32(g, d);\n e = add32(e, f);\n e ^= f << 10;\n h = add32(h, e);\n f = add32(f, g);\n f ^= g >>> 4;\n a = add32(a, f);\n g = add32(g, h);\n g ^= h << 8;\n b = add32(b, g);\n h = add32(h, a);\n h ^= a >>> 9;\n c = add32(c, h);\n a = add32(a, b);\n }\n // Scramble the seed\n for (i = 0; i < 4; i++) {\n mix();\n }\n for (i = 0; i < 256; i += 8) {\n // Use all the information in the seed\n a = add32(a, result[i]);\n b = add32(b, result[i + 1]);\n c = add32(c, result[i + 2]);\n d = add32(d, result[i + 3]);\n e = add32(e, result[i + 4]);\n f = add32(f, result[i + 5]);\n g = add32(g, result[i + 6]);\n h = add32(h, result[i + 7]);\n mix();\n // Fill in the memory with messy stuff\n memory[i] = a;\n memory[i + 1] = b;\n memory[i + 2] = c;\n memory[i + 3] = d;\n memory[i + 4] = e;\n memory[i + 5] = f;\n memory[i + 6] = g;\n memory[i + 7] = h;\n }\n // Second pass to make sure seed affects memory\n for (i = 0; i < 256; i += 8) {\n a = add32(a, memory[i]);\n b = add32(b, memory[i + 1]);\n c = add32(c, memory[i + 2]);\n d = add32(d, memory[i + 3]);\n e = add32(e, memory[i + 4]);\n f = add32(f, memory[i + 5]);\n g = add32(g, memory[i + 6]);\n h = add32(h, memory[i + 7]);\n mix();\n // Fill in the memory with messy stuff (again)\n memory[i] = a;\n memory[i + 1] = b;\n memory[i + 2] = c;\n memory[i + 3] = d;\n memory[i + 4] = e;\n memory[i + 5] = f;\n memory[i + 6] = g;\n memory[i + 7] = h;\n }\n pnrg();\n generation = 256;\n }\n function pnrg(n) {\n let i = 0;\n let x = 0;\n let y = 0;\n n = Predicate.isUndefined(n) ? 1 : Math.abs(Math.floor(n));\n while (n--) {\n counter = add32(counter, 1);\n lastResult = add32(lastResult, counter);\n for (i = 0; i < 256; i++) {\n switch (i & 3) {\n case 0:\n {\n accumulator ^= accumulator << 13;\n break;\n }\n case 1:\n {\n accumulator ^= accumulator >>> 6;\n break;\n }\n case 2:\n {\n accumulator ^= accumulator << 2;\n break;\n }\n case 3:\n {\n accumulator ^= accumulator >>> 16;\n break;\n }\n }\n accumulator = add32(memory[i + 128 & 0xff], accumulator);\n x = memory[i];\n memory[i] = add32(memory[x >>> 2 & 0xff], add32(accumulator, lastResult));\n y = memory[i];\n result[i] = add32(memory[y >>> 10 & 0xff], x);\n lastResult = result[i];\n }\n }\n }\n /**\n * Returns a signed, random integer in the range [-2^31, 2^31).\n */\n function nextInt32() {\n if (!generation--) {\n pnrg();\n generation = 255;\n }\n return result[generation];\n }\n function nextIntUnsafe() {\n return Math.floor(nextDoubleUnsafe() * (Number.MAX_SAFE_INTEGER - Number.MIN_SAFE_INTEGER + 1)) + Number.MIN_SAFE_INTEGER;\n }\n /**\n * Returns a 53-bit fraction in the range [0, 1).\n */\n function nextDoubleUnsafe() {\n const hi = nextInt32() >>> 0 & 0x1FFFFF; // take top 21 bits\n const lo = nextInt32() >>> 0; // full 32 bits\n // 53-bit integer\n const combined = hi * 4294967296 + lo;\n return combined / 0x20000000000000; // [0, 1)\n }\n return {\n nextIntUnsafe,\n nextDoubleUnsafe\n };\n}\n/**\n * 32-bit addition with overflow handling (JavaScript numbers are 53-bit).\n *\n * Example: add32(0xFFFFFFFF, 0x00000001) = 0x00000000 (wraps around)\n */\nfunction add32(x, y) {\n // Add lower 16 bits separately to handle carry\n // Example: x=0x12345678, y=0xABCDEF01\n // lsb = (0x5678 + 0xEF01) = 0x14579\n const lsb = (x & 0xffff) + (y & 0xffff);\n // Add upper 16 bits + carry from lower addition\n // msb = (0x1234 + 0xABCD + (0x14579 >>> 16)) = (0x1234 + 0xABCD + 0x1) = 0xBE02\n const msb = (x >>> 16) + (y >>> 16) + (lsb >>> 16);\n // Combine: upper 16 bits | lower 16 bits (masked to prevent double carry)\n // return (0xBE02 << 16) | (0x14579 & 0xffff) = 0xBE024579\n return msb << 16 | lsb & 0xffff;\n}\nconst seedEncoder = /*#__PURE__*/new TextEncoder();\n/**\n * Convert a string to UTF-8 encoded 32-bit integers (little-endian).\n */\nfunction toIntArray(seed) {\n const bytes = seedEncoder.encode(seed);\n const result = [];\n for (let index = 0; index < bytes.length; index += 4) {\n result.push((bytes[index] ?? 0) << 0 | (bytes[index + 1] ?? 0) << 8 | (bytes[index + 2] ?? 0) << 16 | (bytes[index + 3] ?? 0) << 24);\n }\n return result;\n}\n//# sourceMappingURL=Random.js.map","import { Text } from \"@knpkv/rly/primitives\"\nimport { type ReactElement, useEffect, useRef } from \"react\"\nimport { Link } from \"react-router\"\n\nimport type { SessionSummary } from \"../api/session.js\"\nimport { useBrowserSession } from \"./BrowserSession.js\"\nimport styles from \"./pages.module.css\"\n\nconst sessionLabel = (permission: SessionSummary[\"permission\"]): string =>\n permission === \"workspace-owner\" ? \"Owner browser paired\" : \"Browser paired\"\n\ninterface BrowserSessionStatusProps {\n readonly anonymousAction?: \"link\" | \"status\"\n}\n\n/** Describe this browser's application-wide private session. */\nexport const BrowserSessionStatus = ({ anonymousAction = \"link\" }: BrowserSessionStatusProps = {}): ReactElement => {\n const { state: browserSession } = useBrowserSession()\n const storageAlert = useRef<HTMLSpanElement>(null)\n\n useEffect(() => {\n if (browserSession._tag === \"storage-unavailable\") storageAlert.current?.focus()\n }, [browserSession._tag])\n\n if (browserSession._tag === \"anonymous\") {\n if (anonymousAction === \"status\") {\n return (\n <Text className={styles.sessionStatus} tone=\"secondary\" variant=\"label\">\n Browser not paired\n </Text>\n )\n }\n return (\n <Link className={styles.linkButton} to=\"/pair\">\n Pair this browser\n </Link>\n )\n }\n if (browserSession._tag === \"authenticated\") {\n return (\n <Text className={styles.sessionBadge} variant=\"label\">\n <span aria-hidden=\"true\">✓</span> {sessionLabel(browserSession.session.permission)}\n </Text>\n )\n }\n if (browserSession._tag === \"storage-unavailable\") {\n return (\n <Text\n aria-atomic=\"true\"\n as=\"span\"\n className={styles.sessionStatus}\n ref={storageAlert}\n role=\"alert\"\n tabIndex={-1}\n tone=\"secondary\"\n variant=\"label\"\n >\n {browserSession.session === null\n ? \"Session storage is unavailable. Check storage permissions or space, then reload.\"\n : \"Browser paired, but session storage is unavailable. Check storage permissions or space, then reload.\"}\n </Text>\n )\n }\n return (\n <Text className={styles.sessionStatus} tone=\"secondary\" variant=\"label\">\n {browserSession._tag === \"checking\"\n ? \"Checking this browser…\"\n : browserSession._tag === \"blocked\"\n ? \"Session access blocked on this connection\"\n : \"Server unavailable\"}\n </Text>\n )\n}\n","import type { PortfolioReleasePresentation } from \"./presentPortfolio.js\"\n\n/** Stable URL and presentation identifiers for the four portfolio views. */\nexport type PortfolioFilter = \"all\" | \"attention\" | \"deploying\" | \"shipped\"\n\nexport interface PortfolioFilterOption {\n readonly count: number\n readonly id: PortfolioFilter\n readonly label: string\n}\n\nconst FILTER_LABELS = {\n all: \"All\",\n attention: \"Need attention\",\n deploying: \"Deploying\",\n shipped: \"Shipped\"\n} satisfies Readonly<Record<PortfolioFilter, string>>\n\nconst FILTER_IDS: ReadonlyArray<PortfolioFilter> = [\"all\", \"attention\", \"deploying\", \"shipped\"]\n\n/** Decode the URL-owned filter, recovering to All for missing or unknown values. */\nexport const portfolioFilterFromSearch = (search: string): PortfolioFilter => {\n const value = new URLSearchParams(search).get(\"status\")\n return value === \"attention\" || value === \"deploying\" || value === \"shipped\" ? value : \"all\"\n}\n\n/** Keep unrelated query state while producing a canonical filter search string. */\nexport const portfolioFilterSearch = (search: string, filter: PortfolioFilter): string => {\n const parameters = new URLSearchParams(search)\n if (filter === \"all\") parameters.delete(\"status\")\n else parameters.set(\"status\", filter)\n const encoded = parameters.toString()\n return encoded.length === 0 ? \"\" : `?${encoded}`\n}\n\nconst releaseMatchesFilter = (release: PortfolioReleasePresentation, filter: PortfolioFilter): boolean => {\n switch (filter) {\n case \"all\":\n return true\n case \"attention\":\n return release.readinessVerdict === \"blocked\" ||\n release.readinessVerdict === \"held\" ||\n release.readinessVerdict === \"unknown\"\n case \"deploying\":\n return release.readinessVerdict === \"deploying\" || release.readinessVerdict === \"building\"\n case \"shipped\":\n return release.readinessVerdict === \"shipped\"\n }\n}\n\n/** Select rows from authoritative verdicts rather than copied display labels. */\nexport const filterPortfolioReleases = (\n releases: ReadonlyArray<PortfolioReleasePresentation>,\n filter: PortfolioFilter\n): ReadonlyArray<PortfolioReleasePresentation> => releases.filter((release) => releaseMatchesFilter(release, filter))\n\n/** Recompute all visible counts from the same live release set used for rows. */\nexport const portfolioFilterOptions = (\n releases: ReadonlyArray<PortfolioReleasePresentation>\n): ReadonlyArray<PortfolioFilterOption> =>\n FILTER_IDS.map((id) => ({\n count: filterPortfolioReleases(releases, id).length,\n id,\n label: FILTER_LABELS[id]\n }))\n\n/** Human-readable label for recoverable filter empty states. */\nexport const portfolioFilterLabel = (filter: PortfolioFilter): string => FILTER_LABELS[filter]\n","import type { PortfolioSnapshot } from \"../../api/portfolio.js\"\nimport type { EventCursor } from \"../../domain/identifiers.js\"\n\nexport type PortfolioLoadFailure = \"blocked\" | \"session-expired\" | \"unavailable\"\n\nexport type PortfolioConnectionState =\n | { readonly _tag: \"connecting\" }\n | { readonly _tag: \"connected\" }\n | { readonly _tag: \"reconnecting\"; readonly attempt: number }\n | { readonly _tag: \"offline\" }\n\nexport type PortfolioSnapshotLoadState =\n | { readonly _tag: \"idle\" }\n | { readonly _tag: \"loading\"; readonly sessionKey: string }\n | {\n readonly _tag: \"loaded\"\n readonly awaitingResetSnapshot: boolean\n readonly connection: PortfolioConnectionState\n readonly isSnapshotStale: boolean\n readonly minimumRefreshCursor: EventCursor | null\n readonly sessionKey: string\n readonly snapshot: PortfolioSnapshot\n }\n | { readonly _tag: \"failed\"; readonly sessionKey: string; readonly failure: PortfolioLoadFailure }\n\nexport type PortfolioLiveStateAction =\n | { readonly _tag: \"begin\"; readonly sessionKey: string }\n | { readonly _tag: \"initial-snapshot\"; readonly sessionKey: string; readonly snapshot: PortfolioSnapshot }\n | { readonly _tag: \"caught-up\" }\n | { readonly _tag: \"stream-snapshot\"; readonly snapshot: PortfolioSnapshot }\n | { readonly _tag: \"invalidated\"; readonly eventCursor: EventCursor }\n | { readonly _tag: \"reset-required\"; readonly headCursor: EventCursor }\n | { readonly _tag: \"reconnecting\"; readonly attempt: number }\n | { readonly _tag: \"offline\" }\n | { readonly _tag: \"failed\"; readonly sessionKey: string; readonly failure: PortfolioLoadFailure }\n | { readonly _tag: \"clear\" }\n\nconst laterCursor = (left: EventCursor | null, right: EventCursor): EventCursor =>\n left === null || right > left ? right : left\n\n/** Reduce portfolio transport facts without ever replacing a snapshot from an invalidation event. */\nexport const reducePortfolioLiveState = (\n state: PortfolioSnapshotLoadState,\n action: PortfolioLiveStateAction\n): PortfolioSnapshotLoadState => {\n switch (action._tag) {\n case \"clear\":\n return { _tag: \"idle\" }\n case \"begin\":\n return { _tag: \"loading\", sessionKey: action.sessionKey }\n case \"failed\":\n return { _tag: \"failed\", sessionKey: action.sessionKey, failure: action.failure }\n case \"initial-snapshot\":\n return {\n _tag: \"loaded\",\n awaitingResetSnapshot: false,\n connection: { _tag: \"connecting\" },\n isSnapshotStale: false,\n minimumRefreshCursor: null,\n sessionKey: action.sessionKey,\n snapshot: action.snapshot\n }\n case \"caught-up\":\n if (state._tag !== \"loaded\") return state\n if (\n state.awaitingResetSnapshot ||\n (state.minimumRefreshCursor !== null && state.minimumRefreshCursor > state.snapshot.eventCursor)\n ) {\n return state\n }\n return {\n ...state,\n awaitingResetSnapshot: false,\n connection: { _tag: \"connected\" },\n isSnapshotStale: false,\n minimumRefreshCursor: null\n }\n case \"stream-snapshot\":\n if (state._tag !== \"loaded\") return state\n if (state.minimumRefreshCursor !== null && action.snapshot.eventCursor < state.minimumRefreshCursor) return state\n if (!state.awaitingResetSnapshot && action.snapshot.eventCursor < state.snapshot.eventCursor) return state\n return {\n ...state,\n awaitingResetSnapshot: false,\n connection: { _tag: \"connected\" },\n isSnapshotStale: false,\n minimumRefreshCursor: null,\n snapshot: action.snapshot\n }\n case \"invalidated\":\n if (\n state._tag !== \"loaded\" ||\n state.awaitingResetSnapshot ||\n action.eventCursor <= state.snapshot.eventCursor\n ) {\n return state\n }\n return {\n ...state,\n isSnapshotStale: true,\n minimumRefreshCursor: laterCursor(state.minimumRefreshCursor, action.eventCursor)\n }\n case \"reset-required\":\n if (state._tag !== \"loaded\") return state\n return {\n ...state,\n awaitingResetSnapshot: true,\n isSnapshotStale: true,\n minimumRefreshCursor: laterCursor(state.minimumRefreshCursor, action.headCursor)\n }\n case \"reconnecting\":\n if (state._tag !== \"loaded\") return state\n return {\n ...state,\n connection: { _tag: \"reconnecting\", attempt: action.attempt },\n isSnapshotStale: true\n }\n case \"offline\":\n if (state._tag !== \"loaded\") return state\n return {\n ...state,\n connection: { _tag: \"offline\" },\n isSnapshotStale: true\n }\n }\n}\n\n/** Read the only cursor safe to acknowledge when reconnecting. */\nexport const appliedPortfolioCursor = (state: PortfolioSnapshotLoadState): EventCursor | null =>\n state._tag === \"loaded\" ? state.snapshot.eventCursor : null\n","import * as Cause from \"effect/Cause\"\nimport * as Data from \"effect/Data\"\nimport * as Effect from \"effect/Effect\"\nimport * as Exit from \"effect/Exit\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Random from \"effect/Random\"\nimport * as Result from \"effect/Result\"\nimport * as Stream from \"effect/Stream\"\nimport * as FetchHttpClient from \"effect/unstable/http/FetchHttpClient\"\nimport { useCallback, useEffect, useState } from \"react\"\n\nimport { makeControlCenterApiClient } from \"../../api/client.js\"\nimport type { ControlCenterLiveEvent, StreamResetRequired } from \"../../api/liveEvents.js\"\nimport type { PortfolioSnapshot } from \"../../api/portfolio.js\"\nimport type { EventCursor } from \"../../domain/identifiers.js\"\nimport {\n appliedPortfolioCursor,\n type PortfolioLoadFailure,\n type PortfolioSnapshotLoadState,\n reducePortfolioLiveState\n} from \"./livePortfolioState.js\"\n\nexport type {\n PortfolioConnectionState,\n PortfolioLoadFailure,\n PortfolioSnapshotLoadState\n} from \"./livePortfolioState.js\"\n\nexport interface PortfolioSnapshotController {\n readonly retry: () => void\n readonly state: PortfolioSnapshotLoadState\n}\n\nexport interface PortfolioFailureResolutionInput {\n readonly failure: unknown\n readonly onSessionExpired: (sessionKey: string) => void\n readonly sessionKey: string\n}\n\nexport interface PortfolioLiveTransport {\n readonly loadSnapshot: Effect.Effect<PortfolioSnapshot, unknown>\n readonly openStream: (after: EventCursor) => Effect.Effect<Stream.Stream<ControlCenterLiveEvent, unknown>, unknown>\n}\n\nexport interface PortfolioBrowserConnectivity {\n readonly isOnline: Effect.Effect<boolean>\n readonly waitUntilOnline: Effect.Effect<void>\n}\n\nexport interface RunPortfolioLiveControllerOptions {\n readonly connectivity: PortfolioBrowserConnectivity\n readonly onSessionExpired: (sessionKey: string) => void\n readonly onState: (state: PortfolioSnapshotLoadState) => void\n readonly sessionKey: string\n readonly transport: PortfolioLiveTransport\n}\n\nexport interface PortfolioSnapshotDependencies {\n readonly connectivity: PortfolioBrowserConnectivity\n readonly transport: PortfolioLiveTransport\n}\n\nconst MAXIMUM_RECONNECT_DELAY_MILLIS = 30_000\nconst INITIAL_RECONNECT_DELAY_MILLIS = 500\nconst MAXIMUM_RECONNECT_EXPONENT = 16\n\nclass PortfolioStreamProtocolError extends Data.TaggedError(\"PortfolioStreamProtocolError\") {}\n\nclass PortfolioStreamClosedError extends Data.TaggedError(\"PortfolioStreamClosedError\") {}\n\nconst classifyFailure = <UnparsedInput>(failure: UnparsedInput): PortfolioLoadFailure => {\n if (!Predicate.hasProperty(failure, \"_tag\") || !Predicate.isString(failure._tag)) return \"unavailable\"\n if (failure._tag === \"UnauthorizedApiError\") return \"session-expired\"\n if (failure._tag === \"ForbiddenApiError\") return \"blocked\"\n return \"unavailable\"\n}\n\n/** Calculate one capped equal-jitter delay from a one-based reconnect attempt. */\nexport const portfolioReconnectDelayMillis = (attempt: number, random: number): number => {\n const exponent = Math.min(Math.max(attempt - 1, 0), MAXIMUM_RECONNECT_EXPONENT)\n const ceiling = Math.min(MAXIMUM_RECONNECT_DELAY_MILLIS, INITIAL_RECONNECT_DELAY_MILLIS * 2 ** exponent)\n const halfCeiling = ceiling / 2\n return Math.max(1, Math.floor(halfCeiling + halfCeiling * Math.min(Math.max(random, 0), 1)))\n}\n\nconst reconnectDelay = (attempt: number): Effect.Effect<void> =>\n Random.next.pipe(\n Effect.map((random) => portfolioReconnectDelayMillis(attempt, random)),\n Effect.flatMap(Effect.sleep)\n )\n\nconst hasValidResetCursorRelation = (reset: StreamResetRequired): boolean => {\n if (reset.prunedThroughCursor > reset.headCursor) return false\n switch (reset.reason) {\n case \"retention\":\n return reset.requestedCursor < reset.prunedThroughCursor\n case \"cursor-ahead\":\n return reset.requestedCursor > reset.headCursor\n case \"gap\":\n return reset.prunedThroughCursor <= reset.requestedCursor && reset.requestedCursor < reset.headCursor\n case \"replay-budget\":\n return reset.requestedCursor <= reset.headCursor\n }\n}\n\nconst browserConnectivity: PortfolioBrowserConnectivity = {\n isOnline: Effect.sync(() => navigator.onLine),\n waitUntilOnline: Effect.suspend(() => {\n if (navigator.onLine) return Effect.void\n return Effect.callback<void>((resume) => {\n const handleOnline = (): void => resume(Effect.void)\n window.addEventListener(\"online\", handleOnline, { once: true })\n return Effect.sync(() => window.removeEventListener(\"online\", handleOnline))\n })\n })\n}\n\nconst generatedTransport = Effect.gen(function*() {\n const client = yield* makeControlCenterApiClient()\n return {\n loadSnapshot: client.portfolio.snapshot(),\n openStream: (after: EventCursor) =>\n client.liveEvents.stream({\n headers: { \"last-event-id\": after },\n query: { after }\n })\n } satisfies PortfolioLiveTransport\n})\n\n/** Classify one request failure and invalidate only the session that issued an unauthorized read. */\nexport const resolvePortfolioFailure = ({\n failure,\n onSessionExpired,\n sessionKey\n}: PortfolioFailureResolutionInput): Extract<PortfolioSnapshotLoadState, { readonly _tag: \"failed\" }> => {\n const classified = classifyFailure(failure)\n if (classified === \"session-expired\") onSessionExpired(sessionKey)\n return { _tag: \"failed\", sessionKey, failure: classified }\n}\n\nconst runController = Effect.fn(\"PortfolioLiveController.run\")(function*({\n connectivity,\n onSessionExpired,\n onState,\n sessionKey,\n transport\n}: RunPortfolioLiveControllerOptions) {\n let currentState: PortfolioSnapshotLoadState = { _tag: \"loading\", sessionKey }\n\n const publish = (action: Parameters<typeof reducePortfolioLiveState>[1]): Effect.Effect<void> =>\n Effect.sync(() => {\n currentState = reducePortfolioLiveState(currentState, action)\n onState(currentState)\n })\n\n const initialResult = yield* Effect.result(transport.loadSnapshot)\n if (Result.isFailure(initialResult)) {\n const failed = resolvePortfolioFailure({\n failure: initialResult.failure,\n onSessionExpired,\n sessionKey\n })\n yield* publish({ _tag: \"failed\", failure: failed.failure, sessionKey })\n return yield* Effect.never\n }\n yield* publish({ _tag: \"initial-snapshot\", sessionKey, snapshot: initialResult.success })\n\n const refreshSnapshot = Effect.fn(\"PortfolioLiveController.refreshSnapshot\")(function*(\n minimumCursor: EventCursor\n ) {\n const snapshot = yield* transport.loadSnapshot\n if (snapshot.eventCursor < minimumCursor) return yield* Effect.fail(new PortfolioStreamProtocolError())\n yield* publish({ _tag: \"stream-snapshot\", snapshot })\n })\n\n const consumeStream = Effect.fn(\"PortfolioLiveController.consumeStream\")(function*(\n stream: Stream.Stream<ControlCenterLiveEvent, unknown>,\n resumeCursor: EventCursor,\n onUsable: Effect.Effect<void>\n ) {\n let isUsable = false\n let resetHeadCursor = currentState._tag === \"loaded\" && currentState.awaitingResetSnapshot\n ? currentState.minimumRefreshCursor\n : null\n let streamCursor = resumeCursor\n\n const advanceStreamCursor = (cursor: EventCursor): void => {\n if (cursor > streamCursor) streamCursor = cursor\n }\n\n const consumeEvent = (event: ControlCenterLiveEvent): Effect.Effect<void, unknown> => {\n switch (event.event) {\n case \"portfolio.snapshot\": {\n if (event.id !== event.data.eventCursor) return Effect.fail(new PortfolioStreamProtocolError())\n const appliedCursor = appliedPortfolioCursor(currentState)\n if (appliedCursor === null) return Effect.fail(new PortfolioStreamProtocolError())\n if (resetHeadCursor !== null && event.id < resetHeadCursor) {\n return Effect.fail(new PortfolioStreamProtocolError())\n }\n if (resetHeadCursor === null) {\n advanceStreamCursor(event.id)\n } else {\n streamCursor = event.id\n }\n if (resetHeadCursor === null && event.id < appliedCursor) return Effect.void\n resetHeadCursor = null\n return publish({ _tag: \"stream-snapshot\", snapshot: event.data })\n }\n case \"portfolio.invalidated\": {\n if (resetHeadCursor !== null || event.id !== event.data.eventCursor) {\n return Effect.fail(new PortfolioStreamProtocolError())\n }\n advanceStreamCursor(event.id)\n const appliedCursor = appliedPortfolioCursor(currentState)\n if (appliedCursor === null || event.id <= appliedCursor) return Effect.void\n return publish({ _tag: \"invalidated\", eventCursor: event.id }).pipe(\n Effect.andThen(refreshSnapshot(event.id))\n )\n }\n case \"stream.reset-required\": {\n if (event.data.requestedCursor !== streamCursor || !hasValidResetCursorRelation(event.data)) {\n return Effect.fail(new PortfolioStreamProtocolError())\n }\n resetHeadCursor = resetHeadCursor === null || event.data.headCursor > resetHeadCursor\n ? event.data.headCursor\n : resetHeadCursor\n return publish({ _tag: \"reset-required\", headCursor: resetHeadCursor })\n }\n case \"stream.heartbeat\":\n if (resetHeadCursor !== null) return Effect.fail(new PortfolioStreamProtocolError())\n {\n const appliedCursor = appliedPortfolioCursor(currentState)\n if (appliedCursor === null) return Effect.fail(new PortfolioStreamProtocolError())\n advanceStreamCursor(event.data.eventCursor)\n if (event.data.eventCursor <= appliedCursor) return publish({ _tag: \"caught-up\" })\n return publish({ _tag: \"invalidated\", eventCursor: event.data.eventCursor }).pipe(\n Effect.andThen(refreshSnapshot(event.data.eventCursor))\n )\n }\n }\n }\n\n yield* Stream.runForEach(stream, (event) =>\n consumeEvent(event).pipe(\n Effect.tap(() => {\n if (isUsable) return Effect.void\n isUsable = true\n return onUsable\n })\n ))\n return yield* Effect.fail(new PortfolioStreamClosedError())\n })\n\n const reconnect = Effect.fn(\"PortfolioLiveController.reconnect\")(function*() {\n let attempt = 0\n while (true) {\n const isOnline = yield* connectivity.isOnline\n if (!isOnline) {\n yield* publish({ _tag: \"offline\" })\n yield* connectivity.waitUntilOnline\n } else if (attempt > 0) {\n yield* publish({ _tag: \"reconnecting\", attempt })\n yield* reconnectDelay(attempt)\n }\n\n const cursor = appliedPortfolioCursor(currentState)\n if (cursor === null) return yield* Effect.never\n const streamResult = yield* Effect.result(\n Effect.gen(function*() {\n const stream = yield* transport.openStream(cursor)\n return yield* consumeStream(\n stream,\n cursor,\n Effect.sync(() => {\n attempt = 0\n })\n )\n })\n )\n if (Result.isSuccess(streamResult)) return yield* Effect.never\n\n const failure = classifyFailure(streamResult.failure)\n if (failure === \"session-expired\" || failure === \"blocked\") {\n const failed = resolvePortfolioFailure({\n failure: streamResult.failure,\n onSessionExpired,\n sessionKey\n })\n yield* publish({ _tag: \"failed\", failure: failed.failure, sessionKey })\n return yield* Effect.never\n }\n attempt += 1\n }\n })\n\n return yield* reconnect()\n})\n\n/** Run one session-isolated authoritative snapshot and live invalidation controller. */\nexport const runPortfolioLiveController = (options: RunPortfolioLiveControllerOptions): Effect.Effect<never> =>\n runController(options)\n\n/** Load an authoritative portfolio and keep it current through the generated SSE client. */\nexport const usePortfolioSnapshot = (\n sessionKey: string | null,\n onSessionExpired: (sessionKey: string) => void,\n dependencies?: PortfolioSnapshotDependencies\n): PortfolioSnapshotController => {\n const [requestRevision, setRequestRevision] = useState(0)\n const [state, setState] = useState<PortfolioSnapshotLoadState>({ _tag: \"idle\" })\n\n useEffect(() => {\n if (sessionKey === null) {\n setState({ _tag: \"idle\" })\n return\n }\n\n const abortController = new AbortController()\n let isCurrent = true\n setState({ _tag: \"loading\", sessionKey })\n const run = (transport: PortfolioLiveTransport, connectivity: PortfolioBrowserConnectivity): Effect.Effect<never> =>\n runPortfolioLiveController({\n connectivity,\n onSessionExpired,\n onState: (nextState) => {\n if (isCurrent) setState(nextState)\n },\n sessionKey,\n transport\n })\n const program = dependencies === undefined\n ? Effect.flatMap(generatedTransport, (transport) => run(transport, browserConnectivity)).pipe(\n Effect.provide(FetchHttpClient.layer)\n )\n : run(dependencies.transport, dependencies.connectivity)\n\n Effect.runPromiseExit(program, { signal: abortController.signal }).then((exit) => {\n if (!isCurrent || Exit.isSuccess(exit) || Cause.hasInterruptsOnly(exit.cause)) return\n setState({ _tag: \"failed\", failure: \"unavailable\", sessionKey })\n })\n return () => {\n isCurrent = false\n abortController.abort()\n }\n }, [dependencies, onSessionExpired, requestRevision, sessionKey])\n\n const retry = useCallback((): void => setRequestRevision((current) => current + 1), [])\n return { retry, state }\n}\n",".root {\n display: grid;\n gap: clamp(4rem, 9vw, 8rem);\n}\n\n.hero {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 2rem;\n align-items: end;\n}\n\n.heroCopy {\n display: grid;\n gap: 1.5rem;\n}\n\n.title {\n max-inline-size: 10ch;\n text-wrap: balance;\n}\n\n.lede {\n max-inline-size: 42rem;\n text-wrap: pretty;\n}\n\n.session {\n display: grid;\n gap: 0.75rem;\n justify-items: end;\n}\n\n.liveStatus {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: 0.5rem;\n}\n\n.content,\n.readyPortfolio,\n.releaseList {\n display: grid;\n gap: 1.25rem;\n}\n\n.readyPortfolio {\n gap: clamp(2.5rem, 6vw, 5rem);\n}\n\n.filters {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n border-block: 1px solid var(--rly-color-border-1);\n}\n\n.filter {\n display: grid;\n min-inline-size: 0;\n min-block-size: clamp(8rem, 14vw, 12rem);\n align-content: space-between;\n gap: 1rem;\n padding: clamp(1rem, 2.5vw, 2rem);\n border-inline-end: 1px solid var(--rly-color-border-1);\n color: var(--rly-color-text-2);\n font-size: clamp(1.35rem, 2.7vw, 3rem);\n font-weight: 650;\n letter-spacing: -0.04em;\n line-height: 0.95;\n text-decoration: none;\n text-wrap: balance;\n transition:\n background-color 160ms ease,\n color 160ms ease;\n}\n\n.filter:last-child {\n border-inline-end: 0;\n}\n\n.filter:hover {\n background: var(--rly-color-surface-2);\n color: var(--rly-color-text-1);\n}\n\n.filter[data-active=\"true\"] {\n background: var(--rly-color-action-background);\n color: var(--rly-color-action-foreground);\n}\n\n.filter:focus-visible {\n position: relative;\n z-index: 1;\n outline: 3px solid var(--rly-color-focus);\n outline-offset: -3px;\n}\n\n.filterCount {\n font-size: clamp(2.75rem, 6vw, 6.5rem);\n font-variant-numeric: tabular-nums;\n font-weight: 720;\n letter-spacing: -0.07em;\n line-height: 0.8;\n}\n\n.releaseList {\n overflow: hidden;\n border-block-start: 1px solid var(--rly-color-border-1);\n border-radius: var(--rly-radius-group);\n background: var(--rly-color-surface-1);\n}\n\n.statePanel {\n max-inline-size: 46rem;\n}\n\n.firstService {\n display: grid;\n gap: clamp(2rem, 5vw, 4rem);\n}\n\n.firstServiceCopy {\n display: grid;\n max-inline-size: 46rem;\n gap: var(--rly-space-12);\n}\n\n.serviceLauncher {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));\n gap: var(--rly-space-12);\n}\n\n.serviceChoice {\n display: flex;\n min-block-size: 8.5rem;\n align-items: flex-start;\n justify-content: space-between;\n flex-direction: column;\n gap: var(--rly-space-24);\n padding: var(--rly-space-20);\n border: 1px solid var(--rly-color-border-1);\n border-block-start-width: 3px;\n border-radius: var(--rly-radius-group);\n background: var(--rly-color-surface-1);\n color: var(--rly-color-text-1);\n text-decoration: none;\n transition:\n border-color 160ms ease,\n background-color 160ms ease,\n transform 160ms ease;\n}\n\n.serviceChoice[data-service=\"codecommit\"] {\n border-block-start-color: var(--rly-color-service-codecommit);\n}\n\n.serviceChoice[data-service=\"codepipeline\"] {\n border-block-start-color: var(--rly-color-service-codepipeline);\n}\n\n.serviceChoice[data-service=\"jira\"] {\n border-block-start-color: var(--rly-color-service-jira);\n}\n\n.serviceChoice[data-service=\"confluence\"] {\n border-block-start-color: var(--rly-color-service-confluence);\n}\n\n.serviceChoice[data-service=\"clockify\"] {\n border-block-start-color: var(--rly-color-service-clockify);\n}\n\n.serviceChoice:hover {\n border-color: var(--rly-color-border-2);\n background: var(--rly-color-surface-2);\n transform: translateY(-2px);\n}\n\n.serviceChoice:focus-visible {\n outline: 3px solid var(--rly-color-focus);\n outline-offset: 3px;\n}\n\n.serviceAction {\n color: var(--rly-color-text-2);\n font: var(--rly-type-label-weight) var(--rly-type-label-size) / var(--rly-type-label-line-height)\n var(--rly-type-label-font);\n}\n\n.pairAction {\n display: inline-flex;\n min-block-size: 3rem;\n align-items: center;\n padding-inline: 1.25rem;\n border: 1px solid var(--rly-color-border-2);\n border-radius: var(--rly-radius-control);\n background: var(--rly-color-action-background);\n color: var(--rly-color-action-foreground);\n font: var(--rly-type-label-weight) var(--rly-type-label-size) / var(--rly-type-label-line-height)\n var(--rly-type-label-font);\n text-decoration: none;\n}\n\n.loading {\n display: grid;\n gap: 1.5rem;\n padding-block: 1rem;\n}\n\n.loadingRail {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 1rem;\n}\n\n.releaseEntry {\n min-inline-size: 0;\n}\n\n.releaseEntry :global([data-rly-release-fact=\"issues\"]) {\n border-color: var(--rly-color-service-jira);\n}\n\n.releaseEntry :global([data-rly-release-fact=\"pull-requests\"]) {\n border-color: var(--rly-color-service-codecommit);\n}\n\n.releaseEntry :global([data-rly-release-fact=\"pipelines\"]) {\n border-color: var(--rly-color-service-codepipeline);\n}\n\n.releaseEntry :global([data-rly-release-fact=\"gaps\"]) {\n border-color: var(--rly-color-held-ink);\n}\n\n.stageRail {\n padding: var(--rly-space-16) var(--rly-space-24) var(--rly-space-20);\n border-block-end: 1px solid var(--rly-color-border-1);\n}\n\n.sourceWarning {\n margin: 0 var(--rly-space-24) var(--rly-space-20);\n}\n\n@media (max-width: 48rem) {\n .root {\n gap: 4rem;\n }\n\n .hero {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .session {\n justify-items: start;\n }\n\n .liveStatus {\n justify-content: flex-start;\n }\n\n .loadingRail {\n grid-template-columns: 1fr;\n }\n\n .filters {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n\n .filter:nth-child(2) {\n border-inline-end: 0;\n }\n\n .filter:nth-child(-n + 2) {\n border-block-end: 1px solid var(--rly-color-border-1);\n }\n}\n\n@media (max-width: 30rem) {\n .filter {\n min-block-size: 7rem;\n }\n\n .stageRail {\n padding-inline: var(--rly-space-16);\n }\n\n .sourceWarning {\n margin-inline: var(--rly-space-16);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .filter,\n .serviceChoice {\n transition: none;\n }\n\n .serviceChoice:hover {\n transform: none;\n }\n}\n","import { ReleaseRow, ServiceMark, StageRail, type RlyReleaseTransitionNames } from \"@knpkv/rly/patterns\"\nimport { Button, type RlyStateTone, Skeleton, StateLabel, StatePanel, Text } from \"@knpkv/rly/primitives\"\nimport type { ReactElement } from \"react\"\nimport { Link, Navigate, useLocation, useViewTransitionState } from \"react-router\"\n\nimport { firstPartyServiceIdentities } from \"../../domain/firstPartyServices.js\"\nimport { BrowserSessionStatus } from \"../BrowserSessionStatus.js\"\nimport { useBrowserSession } from \"../BrowserSession.js\"\nimport { releaseParentPath, releaseTransitionNames } from \"../releases/releaseRoutes.js\"\nimport { serviceSetupPath } from \"../services/serviceOnboarding.js\"\nimport { useWorkspaceDefaultLandingPath } from \"../settings/useWorkspaceDefaultLanding.js\"\nimport { presentPortfolio, type PortfolioPresentation, type PortfolioReleasePresentation } from \"./presentPortfolio.js\"\nimport {\n filterPortfolioReleases,\n type PortfolioFilter,\n portfolioFilterFromSearch,\n portfolioFilterLabel,\n portfolioFilterOptions,\n portfolioFilterSearch\n} from \"./portfolioFilters.js\"\nimport {\n type PortfolioConnectionState,\n type PortfolioLoadFailure,\n type PortfolioSnapshotLoadState,\n usePortfolioSnapshot\n} from \"./usePortfolioSnapshot.js\"\nimport styles from \"./PortfolioOverview.module.css\"\n\nexport type PortfolioOverviewState =\n | {\n readonly _tag: \"session\"\n readonly reason: \"anonymous\" | \"blocked\" | \"checking\" | \"storage-unavailable\" | \"unavailable\"\n }\n | { readonly _tag: \"loading\" }\n | {\n readonly _tag: \"ready\"\n readonly connection: PortfolioConnectionState\n readonly isSnapshotStale: boolean\n readonly portfolio: PortfolioPresentation\n }\n | { readonly _tag: \"failed\"; readonly failure: PortfolioLoadFailure }\n\nexport interface PortfolioOverviewViewProps {\n readonly onPreviewRelease: (releaseId: PortfolioReleasePresentation[\"id\"]) => void\n readonly onRetry: () => void\n readonly previewPathForRelease?: (releaseId: PortfolioReleasePresentation[\"id\"]) => string\n readonly state: PortfolioOverviewState\n}\n\nexport interface PortfolioOverviewController {\n readonly onRetry: () => void\n readonly state: PortfolioOverviewState\n}\n\ninterface ReleaseDossierProps {\n readonly onPreview: () => void\n readonly release: PortfolioReleasePresentation\n readonly transitionNames?: RlyReleaseTransitionNames\n}\n\ninterface ConnectionPresentation {\n readonly detail: string\n readonly label: string\n readonly tone: RlyStateTone\n}\n\nconst connectionPresentation = (\n connection: PortfolioConnectionState,\n isSnapshotStale: boolean\n): ConnectionPresentation => {\n switch (connection._tag) {\n case \"connecting\":\n return { detail: \"Connecting to live updates.\", label: \"Connecting\", tone: \"progress\" }\n case \"reconnecting\":\n return {\n detail: \"Showing the last snapshot; it may be stale.\",\n label: \"Reconnecting\",\n tone: \"caution\"\n }\n case \"offline\":\n return { detail: \"Showing the last snapshot; it may be stale.\", label: \"Offline\", tone: \"caution\" }\n case \"connected\":\n return isSnapshotStale\n ? { detail: \"Refreshing the authoritative snapshot.\", label: \"Updating\", tone: \"progress\" }\n : { detail: \"Snapshot up to date.\", label: \"Live\", tone: \"positive\" }\n }\n}\n\nconst PortfolioLiveStatus = ({\n connection,\n isSnapshotStale\n}: {\n readonly connection: PortfolioConnectionState\n readonly isSnapshotStale: boolean\n}): ReactElement => {\n const presentation = connectionPresentation(connection, isSnapshotStale)\n return (\n <div aria-atomic=\"true\" aria-live=\"polite\" className={styles.liveStatus} role=\"status\">\n <StateLabel label={presentation.label} size=\"compact\" tone={presentation.tone} />\n <Text tone=\"tertiary\" variant=\"meta\">\n {presentation.detail}\n </Text>\n </div>\n )\n}\n\nconst EmptyPortfolio = (): ReactElement => (\n <section aria-labelledby=\"first-service-title\" className={styles.firstService}>\n <div className={styles.firstServiceCopy}>\n <Text as=\"h2\" id=\"first-service-title\" variant=\"page-title\">\n Choose your first service\n </Text>\n <Text tone=\"secondary\" variant=\"body-large\">\n Enable and verify one source. Its releases, people, and delivery evidence will appear here automatically.\n </Text>\n </div>\n <nav aria-label=\"Services available to enable\" className={styles.serviceLauncher}>\n {firstPartyServiceIdentities.map((service) => (\n <Link\n className={styles.serviceChoice}\n data-service={service.providerId}\n key={service.providerId}\n to={serviceSetupPath(service.providerId)}\n >\n <ServiceMark service={service.providerId} />\n <span className={styles.serviceAction}>Enable</span>\n </Link>\n ))}\n </nav>\n </section>\n)\n\nconst LoadingPortfolio = (): ReactElement => (\n <div className={styles.loading}>\n <Skeleton decorative={false} height=\"1.25rem\" label=\"Loading releases\" width=\"10rem\" />\n <Skeleton decorative height=\"8rem\" variant=\"block\" />\n <div className={styles.loadingRail}>\n <Skeleton decorative height=\"3rem\" variant=\"block\" />\n <Skeleton decorative height=\"3rem\" variant=\"block\" />\n <Skeleton decorative height=\"3rem\" variant=\"block\" />\n </div>\n </div>\n)\n\ntype PortfolioSessionReason = Extract<PortfolioOverviewState, { readonly _tag: \"session\" }>[\"reason\"]\n\ninterface PortfolioSessionBoundaryPresentation {\n readonly announce?: \"assertive\"\n readonly description: string\n readonly title: string\n readonly tone?: \"caution\" | \"critical\"\n}\n\nexport const portfolioSessionBoundaryPresentation = (\n reason: PortfolioSessionReason\n): PortfolioSessionBoundaryPresentation => {\n switch (reason) {\n case \"anonymous\":\n return {\n description:\n \"Pair this browser to read the workspace portfolio. Release facts never load before authentication.\",\n title: \"Release facts stay private\"\n }\n case \"checking\":\n return {\n description: \"Control Center is confirming whether this browser can read the workspace portfolio.\",\n title: \"Checking this browser\"\n }\n case \"blocked\":\n return {\n announce: \"assertive\",\n description: \"This connection cannot read private release facts. Use an allowed Control Center address.\",\n title: \"Portfolio access blocked\",\n tone: \"critical\"\n }\n case \"storage-unavailable\":\n return {\n announce: \"assertive\",\n description:\n \"This browser cannot retain the private session proof. Check storage permissions or space, then reload.\",\n title: \"Session storage unavailable\",\n tone: \"caution\"\n }\n case \"unavailable\":\n return {\n announce: \"assertive\",\n description: \"Control Center could not check this browser session. Check the server, then reload this page.\",\n title: \"Control Center unavailable\",\n tone: \"critical\"\n }\n }\n}\n\nconst SessionBoundary = ({ reason }: Extract<PortfolioOverviewState, { readonly _tag: \"session\" }>): ReactElement => {\n const presentation = portfolioSessionBoundaryPresentation(reason)\n return (\n <StatePanel\n {...presentation}\n action={\n reason === \"anonymous\" ? (\n <Link className={styles.pairAction} to=\"/pair\">\n Pair this browser\n </Link>\n ) : undefined\n }\n className={styles.statePanel}\n />\n )\n}\n\nconst FailedPortfolio = ({\n failure,\n onRetry\n}: {\n readonly failure: PortfolioLoadFailure\n readonly onRetry: () => void\n}): ReactElement => {\n if (failure === \"session-expired\") {\n return (\n <StatePanel\n action={\n <Link className={styles.pairAction} to=\"/pair\">\n Pair this browser\n </Link>\n }\n announce=\"assertive\"\n className={styles.statePanel}\n description=\"Pair this browser again to read the workspace portfolio.\"\n title=\"Pairing expired\"\n tone=\"caution\"\n />\n )\n }\n if (failure === \"blocked\") {\n return (\n <StatePanel\n announce=\"assertive\"\n className={styles.statePanel}\n description=\"This connection cannot read private release facts. Use an allowed Control Center address.\"\n title=\"Portfolio access blocked\"\n tone=\"critical\"\n />\n )\n }\n return (\n <StatePanel\n action={<Button onClick={onRetry}>Try again</Button>}\n announce=\"assertive\"\n className={styles.statePanel}\n description=\"Control Center could not read the saved portfolio. Check the server, then try again.\"\n title=\"Overview unavailable\"\n tone=\"critical\"\n />\n )\n}\n\nconst ReleaseDossier = ({ onPreview, release, transitionNames }: ReleaseDossierProps): ReactElement => (\n <div className={styles.releaseEntry} data-portfolio-release-id={release.id}>\n <ReleaseRow\n onPreview={onPreview}\n previewLabel={`Preview ${release.relay.codename}`}\n release={release.release}\n {...(transitionNames === undefined ? {} : { transitionNames })}\n />\n <StageRail className={styles.stageRail} heading=\"Delivery\" size=\"compact\" stages={release.stages} />\n {release.source.warning === null ? null : (\n <StatePanel\n announce=\"polite\"\n className={styles.sourceWarning}\n description={release.source.warning}\n title=\"Showing preserved source facts\"\n tone=\"caution\"\n />\n )}\n </div>\n)\n\nconst PortfolioFilters = ({\n activeFilter,\n portfolio\n}: {\n readonly activeFilter: PortfolioFilter\n readonly portfolio: PortfolioPresentation\n}): ReactElement => {\n const location = useLocation()\n return (\n <nav aria-label=\"Release filters\" className={styles.filters}>\n {portfolioFilterOptions(portfolio.releases).map((option) => (\n <Link\n aria-current={option.id === activeFilter ? \"page\" : undefined}\n className={styles.filter}\n data-active={option.id === activeFilter ? \"true\" : \"false\"}\n key={option.id}\n to={{ pathname: location.pathname, search: portfolioFilterSearch(location.search, option.id) }}\n >\n <span>{option.label}</span>\n <span\n aria-label={`${String(option.count)} ${option.count === 1 ? \"release\" : \"releases\"}`}\n className={styles.filterCount}\n >\n {option.count}\n </span>\n </Link>\n ))}\n </nav>\n )\n}\n\nconst EmptyFilter = ({ filter }: { readonly filter: PortfolioFilter }): ReactElement => {\n const location = useLocation()\n return (\n <StatePanel\n action={\n <Link\n className={styles.pairAction}\n to={{ pathname: location.pathname, search: portfolioFilterSearch(location.search, \"all\") }}\n >\n Show all releases\n </Link>\n }\n className={styles.statePanel}\n description={`No releases currently match ${portfolioFilterLabel(filter)}. Live updates may change this view.`}\n title=\"Nothing here right now\"\n />\n )\n}\n\nconst TransitioningReleaseDossier = ({\n onPreview,\n originPath,\n previewPath,\n release\n}: ReleaseDossierProps & { readonly originPath: string; readonly previewPath: string }): ReactElement => {\n const location = useLocation()\n const isTransitioning = useViewTransitionState(previewPath)\n return (\n <ReleaseDossier\n onPreview={onPreview}\n release={release}\n {...(isTransitioning && location.pathname === originPath\n ? { transitionNames: releaseTransitionNames(release.id) }\n : {})}\n />\n )\n}\n\nconst ReadyPortfolio = ({\n onPreviewRelease,\n portfolio,\n previewPathForRelease\n}: {\n readonly onPreviewRelease: (releaseId: PortfolioReleasePresentation[\"id\"]) => void\n readonly portfolio: PortfolioPresentation\n readonly previewPathForRelease?: (releaseId: PortfolioReleasePresentation[\"id\"]) => string\n}): ReactElement => {\n if (portfolio.releases.length === 0) return <EmptyPortfolio />\n const location = useLocation()\n const activeFilter = portfolioFilterFromSearch(location.search)\n const releases = filterPortfolioReleases(portfolio.releases, activeFilter)\n return (\n <div className={styles.readyPortfolio}>\n <PortfolioFilters activeFilter={activeFilter} portfolio={portfolio} />\n {releases.length === 0 ? (\n <EmptyFilter filter={activeFilter} />\n ) : (\n <div className={styles.releaseList}>\n {releases.map((release) =>\n previewPathForRelease === undefined ? (\n <ReleaseDossier key={release.id} onPreview={() => onPreviewRelease(release.id)} release={release} />\n ) : (\n <TransitioningReleaseDossier\n key={release.id}\n onPreview={() => onPreviewRelease(release.id)}\n originPath={releaseParentPath(portfolio.workspaceId)}\n previewPath={previewPathForRelease(release.id)}\n release={release}\n />\n )\n )}\n </div>\n )}\n </div>\n )\n}\n\n/** Render every Overview outcome from an explicit controlled state. */\nexport const PortfolioOverviewView = ({\n onPreviewRelease,\n onRetry,\n previewPathForRelease,\n state\n}: PortfolioOverviewViewProps): ReactElement => (\n <section aria-labelledby=\"portfolio-title\" className={styles.root}>\n <header className={styles.hero}>\n <div className={styles.heroCopy}>\n <Text as=\"h1\" className={styles.title} id=\"portfolio-title\" tabIndex={-1} variant=\"verdict\">\n Every release. One view.\n </Text>\n <Text className={styles.lede} tone=\"secondary\" variant=\"body-large\">\n One factual view of releases, people, source health, and every handoff still to prove.\n </Text>\n </div>\n <div className={styles.session}>\n {state._tag === \"session\" && state.reason === \"storage-unavailable\" ? null : (\n <BrowserSessionStatus anonymousAction=\"status\" />\n )}\n {state._tag === \"ready\" ? (\n <>\n <PortfolioLiveStatus connection={state.connection} isSnapshotStale={state.isSnapshotStale} />\n <Text as=\"time\" dateTime={state.portfolio.generatedAt} tone=\"tertiary\" variant=\"meta\">\n Snapshot {state.portfolio.generatedTime}\n </Text>\n </>\n ) : null}\n </div>\n </header>\n\n <div className={styles.content}>\n {state._tag === \"session\" ? <SessionBoundary {...state} /> : null}\n {state._tag === \"loading\" ? <LoadingPortfolio /> : null}\n {state._tag === \"failed\" ? <FailedPortfolio failure={state.failure} onRetry={onRetry} /> : null}\n {state._tag === \"ready\" ? (\n <ReadyPortfolio\n onPreviewRelease={onPreviewRelease}\n portfolio={state.portfolio}\n {...(previewPathForRelease === undefined ? {} : { previewPathForRelease })}\n />\n ) : null}\n </div>\n </section>\n)\n\nconst overviewState = (loadState: PortfolioSnapshotLoadState): PortfolioOverviewState => {\n switch (loadState._tag) {\n case \"idle\":\n return { _tag: \"session\", reason: \"anonymous\" }\n case \"loading\":\n return { _tag: \"loading\" }\n case \"failed\":\n return { _tag: \"failed\", failure: loadState.failure }\n case \"loaded\":\n return {\n _tag: \"ready\",\n connection: loadState.connection,\n isSnapshotStale: loadState.isSnapshotStale,\n portfolio: presentPortfolio(loadState.snapshot)\n }\n }\n}\n\n/** Prevent a prior browser session's snapshot from crossing an authentication transition. */\nexport const selectPortfolioOverviewState = (\n loadState: PortfolioSnapshotLoadState,\n sessionKey: string | null,\n sessionReason: Extract<PortfolioOverviewState, { readonly _tag: \"session\" }>[\"reason\"] = \"anonymous\"\n): PortfolioOverviewState => {\n if (sessionKey === null) return { _tag: \"session\", reason: sessionReason }\n if (loadState._tag === \"idle\" || loadState.sessionKey !== sessionKey) return { _tag: \"loading\" }\n return overviewState(loadState)\n}\n\n/** Read the authenticated live portfolio through one shared route-level controller. */\nexport const usePortfolioOverviewController = (): PortfolioOverviewController => {\n const { invalidateSession, state: browserSession } = useBrowserSession()\n const readableSession =\n browserSession._tag === \"authenticated\"\n ? browserSession.session\n : browserSession._tag === \"storage-unavailable\"\n ? browserSession.session\n : null\n const controller = usePortfolioSnapshot(readableSession?.sessionId ?? null, invalidateSession)\n return {\n onRetry: controller.retry,\n state: selectPortfolioOverviewState(\n controller.state,\n readableSession?.sessionId ?? null,\n browserSession._tag === \"authenticated\" ? \"checking\" : browserSession._tag\n )\n }\n}\n\n/** Load and present the authenticated server portfolio at the root application route. */\nexport const PortfolioOverview = (): ReactElement => {\n const controller = usePortfolioOverviewController()\n const { state } = controller\n const workspaceId = state._tag === \"ready\" ? state.portfolio.workspaceId : null\n const defaultLandingPath = useWorkspaceDefaultLandingPath(workspaceId)\n if (state._tag === \"ready\" && defaultLandingPath !== null) {\n return <Navigate replace to={defaultLandingPath} />\n }\n return <PortfolioOverviewView onPreviewRelease={() => undefined} onRetry={controller.onRetry} state={state} />\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
1
+ {"version":3,"file":"PortfolioOverview-BacOXO-c.js","names":["random.Random","Effect.withFiber","Effect.succeed"],"sources":["../../../../../node_modules/.pnpm/effect@4.0.0-rc.109/node_modules/effect/dist/Random.js","../../../src/client/BrowserSessionStatus.tsx","../../../src/client/portfolio/portfolioFilters.ts","../../../src/client/portfolio/livePortfolioState.ts","../../../src/client/portfolio/usePortfolioSnapshot.ts","../../../src/client/portfolio/PortfolioOverview.module.css","../../../src/client/portfolio/PortfolioOverview.tsx"],"sourcesContent":["import * as Cause from \"./Cause.js\";\nimport * as Effect from \"./Effect.js\";\nimport { dual } from \"./Function.js\";\nimport * as random from \"./internal/random.js\";\nimport * as Predicate from \"./Predicate.js\";\n/**\n * Represents a service for generating pseudo-random numbers.\n *\n * **When to use**\n *\n * Use to access or provide the random-number generator service used by Effect\n * programs.\n *\n * **Gotchas**\n *\n * The default implementation is based on `Math.random` and is not\n * cryptographically secure. Replace the service with a cryptographically secure\n * implementation before using these generators for security-sensitive values.\n *\n * **Example** (Accessing the random service)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * const program = Effect.gen(function*() {\n * const float = yield* Random.next\n * const integer = yield* Random.nextInt\n * const inRange = yield* Random.nextIntBetween(1, 100)\n * return [float, integer, inRange] as const\n * })\n *\n * await Effect.runPromise(program.pipe(Random.withSeed(\"example\"))) // => [0.1633802591287037, 3434461687501127, 1]\n * ```\n *\n * @category services\n * @since 2.0.0\n */\nexport const Random = random.Random;\nconst randomWith = f => Effect.withFiber(fiber => Effect.succeed(f(fiber.getRef(Random))));\n/**\n * Generates a random number between 0 (inclusive) and 1 (exclusive).\n *\n * **When to use**\n *\n * Use to generate a pseudo-random floating-point number in the standard\n * `[0, 1)` range.\n *\n * **Example** (Generating a random number)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.next.pipe(Random.withSeed(\"example\"))) // => 0.1633802591287037\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const next = /*#__PURE__*/randomWith(r => r.nextDoubleUnsafe());\n/**\n * Generates a random boolean value.\n *\n * **When to use**\n *\n * Use to make a pseudo-random true-or-false choice.\n *\n * **Example** (Generating a random boolean)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.nextBoolean.pipe(Random.withSeed(\"example\"))) // => false\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const nextBoolean = /*#__PURE__*/randomWith(r => r.nextDoubleUnsafe() > 0.5);\n/**\n * Generates a random integer between `Number.MIN_SAFE_INTEGER` (inclusive)\n * and `Number.MAX_SAFE_INTEGER` (inclusive).\n *\n * **When to use**\n *\n * Use to generate a pseudo-random safe integer across the full safe-integer\n * range.\n *\n * **Example** (Generating a random integer)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.nextInt.pipe(Random.withSeed(\"example\"))) // => -6064002158214091\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const nextInt = /*#__PURE__*/randomWith(r => r.nextIntUnsafe());\n/**\n * Generates a random number between `min` (inclusive) and `max` (exclusive).\n *\n * **When to use**\n *\n * Use to generate a pseudo-random floating-point number within a numeric range.\n *\n * **Example** (Generating a bounded random number)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.nextBetween(0, 1).pipe(Random.withSeed(\"example\"))) // => 0.1633802591287037\n * ```\n *\n * @category generators\n * @since 4.0.0\n */\nexport const nextBetween = (min, max) => randomWith(r => r.nextDoubleUnsafe() * (max - min) + min);\n/**\n * Generates a random integer between `min` and `max`.\n *\n * **When to use**\n *\n * Use to generate a pseudo-random integer within a rounded numeric range.\n *\n * **Details**\n *\n * The lower bound is rounded up with `Math.ceil` and the upper bound is\n * rounded down with `Math.floor`. By default the range is inclusive; set\n * `options.halfOpen: true` to exclude the upper bound.\n *\n * **Example** (Generating a bounded random integer)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * const program = Effect.gen(function*() {\n * const diceRoll1 = yield* Random.nextIntBetween(1, 6)\n * const diceRoll2 = yield* Random.nextIntBetween(1, 6, {\n * halfOpen: true\n * })\n * const diceRoll3 = yield* Random.nextIntBetween(0, 10)\n * return [diceRoll1, diceRoll2, diceRoll3]\n * })\n *\n * await Effect.runPromise(program.pipe(Random.withSeed(\"example\"))) // => [1, 4, 0]\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const nextIntBetween = (min, max, options) => {\n const extra = options?.halfOpen === true ? 0 : 1;\n return randomWith(r => {\n const minInt = Math.ceil(min);\n const maxInt = Math.floor(max);\n return Math.floor(r.nextDoubleUnsafe() * (maxInt - minInt + extra)) + minInt;\n });\n};\n/**\n * Uses the pseudo-random number generator to shuffle the specified iterable.\n *\n * **When to use**\n *\n * Use to randomly reorder an iterable using the active `Random` service.\n *\n * **Example** (Shuffling values)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.shuffle([1, 2, 3, 4, 5]).pipe(Random.withSeed(\"example\"))) // => [4, 2, 5, 3, 1]\n * ```\n *\n * @category generators\n * @since 2.0.0\n */\nexport const shuffle = elements => randomWith(r => {\n const buffer = Array.from(elements);\n for (let i = buffer.length - 1; i >= 1; i = i - 1) {\n const index = Math.min(i, Math.floor(r.nextDoubleUnsafe() * (i + 1)));\n const value = buffer[i];\n buffer[i] = buffer[index];\n buffer[index] = value;\n }\n return buffer;\n});\n/**\n * Gets a random element from an iterable.\n *\n * **When to use**\n *\n * Use to select one value uniformly from a collection using the active `Random`\n * service.\n *\n * **Details**\n *\n * If the input type is known to be non-empty, the returned effect cannot fail.\n * Otherwise, empty iterables fail with `Cause.NoSuchElementError`.\n *\n * **Example** (Choosing a random value)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * await Effect.runPromise(Random.choice([\"red\", \"green\", \"blue\"] as const).pipe(Random.withSeed(\"example\"))) // => \"red\"\n * ```\n *\n * @category generators\n * @since 3.6.0\n */\nexport const choice = elements => {\n const buffer = Array.from(elements);\n return buffer.length === 0 ? Effect.fail(new Cause.NoSuchElementError(\"Cannot select a random element from an empty array\")) : randomWith(r => buffer[Math.min(buffer.length - 1, Math.floor(r.nextDoubleUnsafe() * buffer.length))]);\n};\n/**\n * Seeds the pseudo-random number generator with the specified value.\n *\n * **When to use**\n *\n * Use to run an effect with a deterministic pseudo-random sequence.\n *\n * **Details**\n *\n * Using the same seed produces the same random sequence, which is useful for\n * tests and reproducible simulations.\n *\n * **Gotchas**\n *\n * Use an unpredictable seed when uniqueness or unpredictability matters.\n *\n * **Example** (Seeding random generation)\n *\n * ```ts import.meta.vitest\n * import { Effect, Random } from \"effect\"\n *\n * const program = Effect.gen(function*() {\n * const value1 = yield* Random.next\n * const value2 = yield* Random.next\n * return [value1, value2]\n * })\n *\n * await Effect.runPromise(Effect.all([\n * program.pipe(Random.withSeed(\"my-seed\")),\n * program.pipe(Random.withSeed(\"my-seed\"))\n * ])) // => [[0.018368576514773527, 0.4010840628128671], [0.018368576514773527, 0.4010840628128671]]\n * ```\n *\n * @category providing services\n * @since 4.0.0\n */\nexport const withSeed = /*#__PURE__*/dual(2, (self, seed) => Effect.provideService(self, Random, ISAAC_CSPRNG(seed)));\n/*///////////////////////////////////////////////////////////////////////////////////////////////////\nThis is a derivative work copyright (c) 2025 Effectful Technologies Inc, under MIT license.\nThis is a derivative work copyright (c) 2018, William P. \"Mac\" McMeans, under BSD license.\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n3. Neither the name of isaacCSPRNG nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\nOriginal work copyright (c) 2012 Yves-Marie K. Rinquin, under MIT license.\nhttps://github.com/rubycon/isaac.js\n///////////////////////////////////////////////////////////////////////////////////////////////////*/\nfunction ISAAC_CSPRNG(userSeed) {\n // Internal State\n const memory = new Array(256);\n const result = new Array(256);\n let accumulator = 0;\n let lastResult = 0;\n let generation = 0;\n let counter = 0;\n // Initial Seed\n const internalSeed = Predicate.isUndefined(userSeed) ? getInitialSeed() : userSeed;\n seed(internalSeed);\n function getInitialSeed() {\n const uint32a = new Uint32Array(2);\n crypto.getRandomValues(uint32a);\n return uint32a[0] + uint32a[1];\n }\n function reset() {\n accumulator = 0;\n lastResult = 0;\n counter = 0;\n for (let i = 0; i < 256; ++i) {\n memory[i] = 0;\n result[i] = 0;\n }\n generation = 0;\n }\n function seed(userSeed) {\n // The golden ratio ( 2654435769 )\n // See https://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine\n const magicNumber = 0x9e3779b9;\n let a = magicNumber;\n let b = magicNumber;\n let c = magicNumber;\n let d = magicNumber;\n let e = magicNumber;\n let f = magicNumber;\n let g = magicNumber;\n let h = magicNumber;\n let i = 0;\n let seed;\n if (Predicate.isString(userSeed)) {\n seed = toIntArray(userSeed);\n } else {\n seed = [userSeed];\n }\n reset();\n for (i = 0; i < seed.length; i++) {\n result[i & 0xff] += seed[i];\n }\n function mix() {\n a ^= b << 11;\n d = add32(d, a);\n b = add32(b, c);\n b ^= c >>> 2;\n e = add32(e, b);\n c = add32(c, d);\n c ^= d << 8;\n f = add32(f, c);\n d = add32(d, e);\n d ^= e >>> 16;\n g = add32(g, d);\n e = add32(e, f);\n e ^= f << 10;\n h = add32(h, e);\n f = add32(f, g);\n f ^= g >>> 4;\n a = add32(a, f);\n g = add32(g, h);\n g ^= h << 8;\n b = add32(b, g);\n h = add32(h, a);\n h ^= a >>> 9;\n c = add32(c, h);\n a = add32(a, b);\n }\n // Scramble the seed\n for (i = 0; i < 4; i++) {\n mix();\n }\n for (i = 0; i < 256; i += 8) {\n // Use all the information in the seed\n a = add32(a, result[i]);\n b = add32(b, result[i + 1]);\n c = add32(c, result[i + 2]);\n d = add32(d, result[i + 3]);\n e = add32(e, result[i + 4]);\n f = add32(f, result[i + 5]);\n g = add32(g, result[i + 6]);\n h = add32(h, result[i + 7]);\n mix();\n // Fill in the memory with messy stuff\n memory[i] = a;\n memory[i + 1] = b;\n memory[i + 2] = c;\n memory[i + 3] = d;\n memory[i + 4] = e;\n memory[i + 5] = f;\n memory[i + 6] = g;\n memory[i + 7] = h;\n }\n // Second pass to make sure seed affects memory\n for (i = 0; i < 256; i += 8) {\n a = add32(a, memory[i]);\n b = add32(b, memory[i + 1]);\n c = add32(c, memory[i + 2]);\n d = add32(d, memory[i + 3]);\n e = add32(e, memory[i + 4]);\n f = add32(f, memory[i + 5]);\n g = add32(g, memory[i + 6]);\n h = add32(h, memory[i + 7]);\n mix();\n // Fill in the memory with messy stuff (again)\n memory[i] = a;\n memory[i + 1] = b;\n memory[i + 2] = c;\n memory[i + 3] = d;\n memory[i + 4] = e;\n memory[i + 5] = f;\n memory[i + 6] = g;\n memory[i + 7] = h;\n }\n pnrg();\n generation = 256;\n }\n function pnrg(n) {\n let i = 0;\n let x = 0;\n let y = 0;\n n = Predicate.isUndefined(n) ? 1 : Math.abs(Math.floor(n));\n while (n--) {\n counter = add32(counter, 1);\n lastResult = add32(lastResult, counter);\n for (i = 0; i < 256; i++) {\n switch (i & 3) {\n case 0:\n {\n accumulator ^= accumulator << 13;\n break;\n }\n case 1:\n {\n accumulator ^= accumulator >>> 6;\n break;\n }\n case 2:\n {\n accumulator ^= accumulator << 2;\n break;\n }\n case 3:\n {\n accumulator ^= accumulator >>> 16;\n break;\n }\n }\n accumulator = add32(memory[i + 128 & 0xff], accumulator);\n x = memory[i];\n memory[i] = add32(memory[x >>> 2 & 0xff], add32(accumulator, lastResult));\n y = memory[i];\n result[i] = add32(memory[y >>> 10 & 0xff], x);\n lastResult = result[i];\n }\n }\n }\n /**\n * Returns a signed, random integer in the range [-2^31, 2^31).\n */\n function nextInt32() {\n if (!generation--) {\n pnrg();\n generation = 255;\n }\n return result[generation];\n }\n function nextIntUnsafe() {\n return Math.floor(nextDoubleUnsafe() * (Number.MAX_SAFE_INTEGER - Number.MIN_SAFE_INTEGER + 1)) + Number.MIN_SAFE_INTEGER;\n }\n /**\n * Returns a 53-bit fraction in the range [0, 1).\n */\n function nextDoubleUnsafe() {\n const hi = nextInt32() >>> 0 & 0x1FFFFF; // take top 21 bits\n const lo = nextInt32() >>> 0; // full 32 bits\n // 53-bit integer\n const combined = hi * 4294967296 + lo;\n return combined / 0x20000000000000; // [0, 1)\n }\n return {\n nextIntUnsafe,\n nextDoubleUnsafe\n };\n}\n/**\n * 32-bit addition with overflow handling (JavaScript numbers are 53-bit).\n *\n * Example: add32(0xFFFFFFFF, 0x00000001) = 0x00000000 (wraps around)\n */\nfunction add32(x, y) {\n // Add lower 16 bits separately to handle carry\n // Example: x=0x12345678, y=0xABCDEF01\n // lsb = (0x5678 + 0xEF01) = 0x14579\n const lsb = (x & 0xffff) + (y & 0xffff);\n // Add upper 16 bits + carry from lower addition\n // msb = (0x1234 + 0xABCD + (0x14579 >>> 16)) = (0x1234 + 0xABCD + 0x1) = 0xBE02\n const msb = (x >>> 16) + (y >>> 16) + (lsb >>> 16);\n // Combine: upper 16 bits | lower 16 bits (masked to prevent double carry)\n // return (0xBE02 << 16) | (0x14579 & 0xffff) = 0xBE024579\n return msb << 16 | lsb & 0xffff;\n}\nconst seedEncoder = /*#__PURE__*/new TextEncoder();\n/**\n * Convert a string to UTF-8 encoded 32-bit integers (little-endian).\n */\nfunction toIntArray(seed) {\n const bytes = seedEncoder.encode(seed);\n const result = [];\n for (let index = 0; index < bytes.length; index += 4) {\n result.push((bytes[index] ?? 0) << 0 | (bytes[index + 1] ?? 0) << 8 | (bytes[index + 2] ?? 0) << 16 | (bytes[index + 3] ?? 0) << 24);\n }\n return result;\n}\n//# sourceMappingURL=Random.js.map","import { Text } from \"@knpkv/rly/primitives\"\nimport { type ReactElement, useEffect, useRef } from \"react\"\nimport { Link } from \"react-router\"\n\nimport type { SessionSummary } from \"../api/session.js\"\nimport { useBrowserSession } from \"./BrowserSession.js\"\nimport styles from \"./pages.module.css\"\n\nconst sessionLabel = (permission: SessionSummary[\"permission\"]): string =>\n permission === \"workspace-owner\" ? \"Owner browser paired\" : \"Browser paired\"\n\ninterface BrowserSessionStatusProps {\n readonly anonymousAction?: \"link\" | \"status\"\n}\n\n/** Describe this browser's application-wide private session. */\nexport const BrowserSessionStatus = ({ anonymousAction = \"link\" }: BrowserSessionStatusProps = {}): ReactElement => {\n const { state: browserSession } = useBrowserSession()\n const storageAlert = useRef<HTMLSpanElement>(null)\n\n useEffect(() => {\n if (browserSession._tag === \"storage-unavailable\") storageAlert.current?.focus()\n }, [browserSession._tag])\n\n if (browserSession._tag === \"anonymous\") {\n if (anonymousAction === \"status\") {\n return (\n <Text className={styles.sessionStatus} tone=\"secondary\" variant=\"label\">\n Browser not paired\n </Text>\n )\n }\n return (\n <Link className={styles.linkButton} to=\"/pair\">\n Pair this browser\n </Link>\n )\n }\n if (browserSession._tag === \"authenticated\") {\n return (\n <Text className={styles.sessionBadge} variant=\"label\">\n <span aria-hidden=\"true\">✓</span> {sessionLabel(browserSession.session.permission)}\n </Text>\n )\n }\n if (browserSession._tag === \"storage-unavailable\") {\n return (\n <Text\n aria-atomic=\"true\"\n as=\"span\"\n className={styles.sessionStatus}\n ref={storageAlert}\n role=\"alert\"\n tabIndex={-1}\n tone=\"secondary\"\n variant=\"label\"\n >\n {browserSession.session === null\n ? \"Session storage is unavailable. Check storage permissions or space, then reload.\"\n : \"Browser paired, but session storage is unavailable. Check storage permissions or space, then reload.\"}\n </Text>\n )\n }\n return (\n <Text className={styles.sessionStatus} tone=\"secondary\" variant=\"label\">\n {browserSession._tag === \"checking\"\n ? \"Checking this browser…\"\n : browserSession._tag === \"blocked\"\n ? \"Session access blocked on this connection\"\n : \"Server unavailable\"}\n </Text>\n )\n}\n","import type { PortfolioReleasePresentation } from \"./presentPortfolio.js\"\n\n/** Stable URL and presentation identifiers for the four portfolio views. */\nexport type PortfolioFilter = \"all\" | \"attention\" | \"deploying\" | \"shipped\"\n\nexport interface PortfolioFilterOption {\n readonly count: number\n readonly id: PortfolioFilter\n readonly label: string\n}\n\nconst FILTER_LABELS = {\n all: \"All\",\n attention: \"Need attention\",\n deploying: \"Deploying\",\n shipped: \"Shipped\"\n} satisfies Readonly<Record<PortfolioFilter, string>>\n\nconst FILTER_IDS: ReadonlyArray<PortfolioFilter> = [\"all\", \"attention\", \"deploying\", \"shipped\"]\n\n/** Decode the URL-owned filter, recovering to All for missing or unknown values. */\nexport const portfolioFilterFromSearch = (search: string): PortfolioFilter => {\n const value = new URLSearchParams(search).get(\"status\")\n return value === \"attention\" || value === \"deploying\" || value === \"shipped\" ? value : \"all\"\n}\n\n/** Keep unrelated query state while producing a canonical filter search string. */\nexport const portfolioFilterSearch = (search: string, filter: PortfolioFilter): string => {\n const parameters = new URLSearchParams(search)\n if (filter === \"all\") parameters.delete(\"status\")\n else parameters.set(\"status\", filter)\n const encoded = parameters.toString()\n return encoded.length === 0 ? \"\" : `?${encoded}`\n}\n\nconst releaseMatchesFilter = (release: PortfolioReleasePresentation, filter: PortfolioFilter): boolean => {\n switch (filter) {\n case \"all\":\n return true\n case \"attention\":\n return release.readinessVerdict === \"blocked\" ||\n release.readinessVerdict === \"held\" ||\n release.readinessVerdict === \"unknown\"\n case \"deploying\":\n return release.readinessVerdict === \"deploying\" || release.readinessVerdict === \"building\"\n case \"shipped\":\n return release.readinessVerdict === \"shipped\"\n }\n}\n\n/** Select rows from authoritative verdicts rather than copied display labels. */\nexport const filterPortfolioReleases = (\n releases: ReadonlyArray<PortfolioReleasePresentation>,\n filter: PortfolioFilter\n): ReadonlyArray<PortfolioReleasePresentation> => releases.filter((release) => releaseMatchesFilter(release, filter))\n\n/** Recompute all visible counts from the same live release set used for rows. */\nexport const portfolioFilterOptions = (\n releases: ReadonlyArray<PortfolioReleasePresentation>\n): ReadonlyArray<PortfolioFilterOption> =>\n FILTER_IDS.map((id) => ({\n count: filterPortfolioReleases(releases, id).length,\n id,\n label: FILTER_LABELS[id]\n }))\n\n/** Human-readable label for recoverable filter empty states. */\nexport const portfolioFilterLabel = (filter: PortfolioFilter): string => FILTER_LABELS[filter]\n","import type { PortfolioSnapshot } from \"../../api/portfolio.js\"\nimport type { EventCursor } from \"../../domain/identifiers.js\"\n\nexport type PortfolioLoadFailure = \"blocked\" | \"session-expired\" | \"unavailable\"\n\nexport type PortfolioConnectionState =\n | { readonly _tag: \"connecting\" }\n | { readonly _tag: \"connected\" }\n | { readonly _tag: \"reconnecting\"; readonly attempt: number }\n | { readonly _tag: \"offline\" }\n\nexport type PortfolioSnapshotLoadState =\n | { readonly _tag: \"idle\" }\n | { readonly _tag: \"loading\"; readonly sessionKey: string }\n | {\n readonly _tag: \"loaded\"\n readonly awaitingResetSnapshot: boolean\n readonly connection: PortfolioConnectionState\n readonly isSnapshotStale: boolean\n readonly minimumRefreshCursor: EventCursor | null\n readonly sessionKey: string\n readonly snapshot: PortfolioSnapshot\n }\n | { readonly _tag: \"failed\"; readonly sessionKey: string; readonly failure: PortfolioLoadFailure }\n\nexport type PortfolioLiveStateAction =\n | { readonly _tag: \"begin\"; readonly sessionKey: string }\n | { readonly _tag: \"initial-snapshot\"; readonly sessionKey: string; readonly snapshot: PortfolioSnapshot }\n | { readonly _tag: \"caught-up\" }\n | { readonly _tag: \"stream-snapshot\"; readonly snapshot: PortfolioSnapshot }\n | { readonly _tag: \"invalidated\"; readonly eventCursor: EventCursor }\n | { readonly _tag: \"reset-required\"; readonly headCursor: EventCursor }\n | { readonly _tag: \"reconnecting\"; readonly attempt: number }\n | { readonly _tag: \"offline\" }\n | { readonly _tag: \"failed\"; readonly sessionKey: string; readonly failure: PortfolioLoadFailure }\n | { readonly _tag: \"clear\" }\n\nconst laterCursor = (left: EventCursor | null, right: EventCursor): EventCursor =>\n left === null || right > left ? right : left\n\n/** Reduce portfolio transport facts without ever replacing a snapshot from an invalidation event. */\nexport const reducePortfolioLiveState = (\n state: PortfolioSnapshotLoadState,\n action: PortfolioLiveStateAction\n): PortfolioSnapshotLoadState => {\n switch (action._tag) {\n case \"clear\":\n return { _tag: \"idle\" }\n case \"begin\":\n return { _tag: \"loading\", sessionKey: action.sessionKey }\n case \"failed\":\n return { _tag: \"failed\", sessionKey: action.sessionKey, failure: action.failure }\n case \"initial-snapshot\":\n return {\n _tag: \"loaded\",\n awaitingResetSnapshot: false,\n connection: { _tag: \"connecting\" },\n isSnapshotStale: false,\n minimumRefreshCursor: null,\n sessionKey: action.sessionKey,\n snapshot: action.snapshot\n }\n case \"caught-up\":\n if (state._tag !== \"loaded\") return state\n if (\n state.awaitingResetSnapshot ||\n (state.minimumRefreshCursor !== null && state.minimumRefreshCursor > state.snapshot.eventCursor)\n ) {\n return state\n }\n return {\n ...state,\n awaitingResetSnapshot: false,\n connection: { _tag: \"connected\" },\n isSnapshotStale: false,\n minimumRefreshCursor: null\n }\n case \"stream-snapshot\":\n if (state._tag !== \"loaded\") return state\n if (state.minimumRefreshCursor !== null && action.snapshot.eventCursor < state.minimumRefreshCursor) return state\n if (!state.awaitingResetSnapshot && action.snapshot.eventCursor < state.snapshot.eventCursor) return state\n return {\n ...state,\n awaitingResetSnapshot: false,\n connection: { _tag: \"connected\" },\n isSnapshotStale: false,\n minimumRefreshCursor: null,\n snapshot: action.snapshot\n }\n case \"invalidated\":\n if (\n state._tag !== \"loaded\" ||\n state.awaitingResetSnapshot ||\n action.eventCursor <= state.snapshot.eventCursor\n ) {\n return state\n }\n return {\n ...state,\n isSnapshotStale: true,\n minimumRefreshCursor: laterCursor(state.minimumRefreshCursor, action.eventCursor)\n }\n case \"reset-required\":\n if (state._tag !== \"loaded\") return state\n return {\n ...state,\n awaitingResetSnapshot: true,\n isSnapshotStale: true,\n minimumRefreshCursor: laterCursor(state.minimumRefreshCursor, action.headCursor)\n }\n case \"reconnecting\":\n if (state._tag !== \"loaded\") return state\n return {\n ...state,\n connection: { _tag: \"reconnecting\", attempt: action.attempt },\n isSnapshotStale: true\n }\n case \"offline\":\n if (state._tag !== \"loaded\") return state\n return {\n ...state,\n connection: { _tag: \"offline\" },\n isSnapshotStale: true\n }\n }\n}\n\n/** Read the only cursor safe to acknowledge when reconnecting. */\nexport const appliedPortfolioCursor = (state: PortfolioSnapshotLoadState): EventCursor | null =>\n state._tag === \"loaded\" ? state.snapshot.eventCursor : null\n","import * as Cause from \"effect/Cause\"\nimport * as Data from \"effect/Data\"\nimport * as Effect from \"effect/Effect\"\nimport * as Exit from \"effect/Exit\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Random from \"effect/Random\"\nimport * as Result from \"effect/Result\"\nimport * as Stream from \"effect/Stream\"\nimport * as FetchHttpClient from \"effect/unstable/http/FetchHttpClient\"\nimport { useCallback, useEffect, useState } from \"react\"\n\nimport { makeControlCenterApiClient } from \"../../api/client.js\"\nimport type { ControlCenterLiveEvent, StreamResetRequired } from \"../../api/liveEvents.js\"\nimport type { PortfolioSnapshot } from \"../../api/portfolio.js\"\nimport type { EventCursor } from \"../../domain/identifiers.js\"\nimport {\n appliedPortfolioCursor,\n type PortfolioLoadFailure,\n type PortfolioSnapshotLoadState,\n reducePortfolioLiveState\n} from \"./livePortfolioState.js\"\n\nexport type {\n PortfolioConnectionState,\n PortfolioLoadFailure,\n PortfolioSnapshotLoadState\n} from \"./livePortfolioState.js\"\n\nexport interface PortfolioSnapshotController {\n readonly retry: () => void\n readonly state: PortfolioSnapshotLoadState\n}\n\nexport interface PortfolioFailureResolutionInput {\n readonly failure: unknown\n readonly onSessionExpired: (sessionKey: string) => void\n readonly sessionKey: string\n}\n\nexport interface PortfolioLiveTransport {\n readonly loadSnapshot: Effect.Effect<PortfolioSnapshot, unknown>\n readonly openStream: (after: EventCursor) => Effect.Effect<Stream.Stream<ControlCenterLiveEvent, unknown>, unknown>\n}\n\nexport interface PortfolioBrowserConnectivity {\n readonly isOnline: Effect.Effect<boolean>\n readonly waitUntilOnline: Effect.Effect<void>\n}\n\nexport interface RunPortfolioLiveControllerOptions {\n readonly connectivity: PortfolioBrowserConnectivity\n readonly onSessionExpired: (sessionKey: string) => void\n readonly onState: (state: PortfolioSnapshotLoadState) => void\n readonly sessionKey: string\n readonly transport: PortfolioLiveTransport\n}\n\nexport interface PortfolioSnapshotDependencies {\n readonly connectivity: PortfolioBrowserConnectivity\n readonly transport: PortfolioLiveTransport\n}\n\nconst MAXIMUM_RECONNECT_DELAY_MILLIS = 30_000\nconst INITIAL_RECONNECT_DELAY_MILLIS = 500\nconst MAXIMUM_RECONNECT_EXPONENT = 16\n\nclass PortfolioStreamProtocolError extends Data.TaggedError(\"PortfolioStreamProtocolError\") {}\n\nclass PortfolioStreamClosedError extends Data.TaggedError(\"PortfolioStreamClosedError\") {}\n\nconst classifyFailure = <UnparsedInput>(failure: UnparsedInput): PortfolioLoadFailure => {\n if (!Predicate.hasProperty(failure, \"_tag\") || !Predicate.isString(failure._tag)) return \"unavailable\"\n if (failure._tag === \"UnauthorizedApiError\") return \"session-expired\"\n if (failure._tag === \"ForbiddenApiError\") return \"blocked\"\n return \"unavailable\"\n}\n\n/** Calculate one capped equal-jitter delay from a one-based reconnect attempt. */\nexport const portfolioReconnectDelayMillis = (attempt: number, random: number): number => {\n const exponent = Math.min(Math.max(attempt - 1, 0), MAXIMUM_RECONNECT_EXPONENT)\n const ceiling = Math.min(MAXIMUM_RECONNECT_DELAY_MILLIS, INITIAL_RECONNECT_DELAY_MILLIS * 2 ** exponent)\n const halfCeiling = ceiling / 2\n return Math.max(1, Math.floor(halfCeiling + halfCeiling * Math.min(Math.max(random, 0), 1)))\n}\n\nconst reconnectDelay = (attempt: number): Effect.Effect<void> =>\n Random.next.pipe(\n Effect.map((random) => portfolioReconnectDelayMillis(attempt, random)),\n Effect.flatMap(Effect.sleep)\n )\n\nconst hasValidResetCursorRelation = (reset: StreamResetRequired): boolean => {\n if (reset.prunedThroughCursor > reset.headCursor) return false\n switch (reset.reason) {\n case \"retention\":\n return reset.requestedCursor < reset.prunedThroughCursor\n case \"cursor-ahead\":\n return reset.requestedCursor > reset.headCursor\n case \"gap\":\n return reset.prunedThroughCursor <= reset.requestedCursor && reset.requestedCursor < reset.headCursor\n case \"replay-budget\":\n return reset.requestedCursor <= reset.headCursor\n }\n}\n\nconst browserConnectivity: PortfolioBrowserConnectivity = {\n isOnline: Effect.sync(() => navigator.onLine),\n waitUntilOnline: Effect.suspend(() => {\n if (navigator.onLine) return Effect.void\n return Effect.callback<void>((resume) => {\n const handleOnline = (): void => resume(Effect.void)\n window.addEventListener(\"online\", handleOnline, { once: true })\n return Effect.sync(() => window.removeEventListener(\"online\", handleOnline))\n })\n })\n}\n\nconst generatedTransport = Effect.gen(function*() {\n const client = yield* makeControlCenterApiClient()\n return {\n loadSnapshot: client.portfolio.snapshot(),\n openStream: (after: EventCursor) =>\n client.liveEvents.stream({\n headers: { \"last-event-id\": after },\n query: { after }\n })\n } satisfies PortfolioLiveTransport\n})\n\n/** Classify one request failure and invalidate only the session that issued an unauthorized read. */\nexport const resolvePortfolioFailure = ({\n failure,\n onSessionExpired,\n sessionKey\n}: PortfolioFailureResolutionInput): Extract<PortfolioSnapshotLoadState, { readonly _tag: \"failed\" }> => {\n const classified = classifyFailure(failure)\n if (classified === \"session-expired\") onSessionExpired(sessionKey)\n return { _tag: \"failed\", sessionKey, failure: classified }\n}\n\nconst runController = Effect.fn(\"PortfolioLiveController.run\")(function*({\n connectivity,\n onSessionExpired,\n onState,\n sessionKey,\n transport\n}: RunPortfolioLiveControllerOptions) {\n let currentState: PortfolioSnapshotLoadState = { _tag: \"loading\", sessionKey }\n\n const publish = (action: Parameters<typeof reducePortfolioLiveState>[1]): Effect.Effect<void> =>\n Effect.sync(() => {\n currentState = reducePortfolioLiveState(currentState, action)\n onState(currentState)\n })\n\n const initialResult = yield* Effect.result(transport.loadSnapshot)\n if (Result.isFailure(initialResult)) {\n const failed = resolvePortfolioFailure({\n failure: initialResult.failure,\n onSessionExpired,\n sessionKey\n })\n yield* publish({ _tag: \"failed\", failure: failed.failure, sessionKey })\n return yield* Effect.never\n }\n yield* publish({ _tag: \"initial-snapshot\", sessionKey, snapshot: initialResult.success })\n\n const refreshSnapshot = Effect.fn(\"PortfolioLiveController.refreshSnapshot\")(function*(\n minimumCursor: EventCursor\n ) {\n const snapshot = yield* transport.loadSnapshot\n if (snapshot.eventCursor < minimumCursor) return yield* Effect.fail(new PortfolioStreamProtocolError())\n yield* publish({ _tag: \"stream-snapshot\", snapshot })\n })\n\n const consumeStream = Effect.fn(\"PortfolioLiveController.consumeStream\")(function*(\n stream: Stream.Stream<ControlCenterLiveEvent, unknown>,\n resumeCursor: EventCursor,\n onUsable: Effect.Effect<void>\n ) {\n let isUsable = false\n let resetHeadCursor = currentState._tag === \"loaded\" && currentState.awaitingResetSnapshot\n ? currentState.minimumRefreshCursor\n : null\n let streamCursor = resumeCursor\n\n const advanceStreamCursor = (cursor: EventCursor): void => {\n if (cursor > streamCursor) streamCursor = cursor\n }\n\n const consumeEvent = (event: ControlCenterLiveEvent): Effect.Effect<void, unknown> => {\n switch (event.event) {\n case \"portfolio.snapshot\": {\n if (event.id !== event.data.eventCursor) return Effect.fail(new PortfolioStreamProtocolError())\n const appliedCursor = appliedPortfolioCursor(currentState)\n if (appliedCursor === null) return Effect.fail(new PortfolioStreamProtocolError())\n if (resetHeadCursor !== null && event.id < resetHeadCursor) {\n return Effect.fail(new PortfolioStreamProtocolError())\n }\n if (resetHeadCursor === null) {\n advanceStreamCursor(event.id)\n } else {\n streamCursor = event.id\n }\n if (resetHeadCursor === null && event.id < appliedCursor) return Effect.void\n resetHeadCursor = null\n return publish({ _tag: \"stream-snapshot\", snapshot: event.data })\n }\n case \"portfolio.invalidated\": {\n if (resetHeadCursor !== null || event.id !== event.data.eventCursor) {\n return Effect.fail(new PortfolioStreamProtocolError())\n }\n advanceStreamCursor(event.id)\n const appliedCursor = appliedPortfolioCursor(currentState)\n if (appliedCursor === null || event.id <= appliedCursor) return Effect.void\n return publish({ _tag: \"invalidated\", eventCursor: event.id }).pipe(\n Effect.andThen(refreshSnapshot(event.id))\n )\n }\n case \"stream.reset-required\": {\n if (event.data.requestedCursor !== streamCursor || !hasValidResetCursorRelation(event.data)) {\n return Effect.fail(new PortfolioStreamProtocolError())\n }\n resetHeadCursor = resetHeadCursor === null || event.data.headCursor > resetHeadCursor\n ? event.data.headCursor\n : resetHeadCursor\n return publish({ _tag: \"reset-required\", headCursor: resetHeadCursor })\n }\n case \"stream.heartbeat\":\n if (resetHeadCursor !== null) return Effect.fail(new PortfolioStreamProtocolError())\n {\n const appliedCursor = appliedPortfolioCursor(currentState)\n if (appliedCursor === null) return Effect.fail(new PortfolioStreamProtocolError())\n advanceStreamCursor(event.data.eventCursor)\n if (event.data.eventCursor <= appliedCursor) return publish({ _tag: \"caught-up\" })\n return publish({ _tag: \"invalidated\", eventCursor: event.data.eventCursor }).pipe(\n Effect.andThen(refreshSnapshot(event.data.eventCursor))\n )\n }\n }\n }\n\n yield* Stream.runForEach(stream, (event) =>\n consumeEvent(event).pipe(\n Effect.tap(() => {\n if (isUsable) return Effect.void\n isUsable = true\n return onUsable\n })\n ))\n return yield* Effect.fail(new PortfolioStreamClosedError())\n })\n\n const reconnect = Effect.fn(\"PortfolioLiveController.reconnect\")(function*() {\n let attempt = 0\n while (true) {\n const isOnline = yield* connectivity.isOnline\n if (!isOnline) {\n yield* publish({ _tag: \"offline\" })\n yield* connectivity.waitUntilOnline\n } else if (attempt > 0) {\n yield* publish({ _tag: \"reconnecting\", attempt })\n yield* reconnectDelay(attempt)\n }\n\n const cursor = appliedPortfolioCursor(currentState)\n if (cursor === null) return yield* Effect.never\n const streamResult = yield* Effect.result(\n Effect.gen(function*() {\n const stream = yield* transport.openStream(cursor)\n return yield* consumeStream(\n stream,\n cursor,\n Effect.sync(() => {\n attempt = 0\n })\n )\n })\n )\n if (Result.isSuccess(streamResult)) return yield* Effect.never\n\n const failure = classifyFailure(streamResult.failure)\n if (failure === \"session-expired\" || failure === \"blocked\") {\n const failed = resolvePortfolioFailure({\n failure: streamResult.failure,\n onSessionExpired,\n sessionKey\n })\n yield* publish({ _tag: \"failed\", failure: failed.failure, sessionKey })\n return yield* Effect.never\n }\n attempt += 1\n }\n })\n\n return yield* reconnect()\n})\n\n/** Run one session-isolated authoritative snapshot and live invalidation controller. */\nexport const runPortfolioLiveController = (options: RunPortfolioLiveControllerOptions): Effect.Effect<never> =>\n runController(options)\n\n/** Load an authoritative portfolio and keep it current through the generated SSE client. */\nexport const usePortfolioSnapshot = (\n sessionKey: string | null,\n onSessionExpired: (sessionKey: string) => void,\n dependencies?: PortfolioSnapshotDependencies\n): PortfolioSnapshotController => {\n const [requestRevision, setRequestRevision] = useState(0)\n const [state, setState] = useState<PortfolioSnapshotLoadState>({ _tag: \"idle\" })\n\n useEffect(() => {\n if (sessionKey === null) {\n setState({ _tag: \"idle\" })\n return\n }\n\n const abortController = new AbortController()\n let isCurrent = true\n setState({ _tag: \"loading\", sessionKey })\n const run = (transport: PortfolioLiveTransport, connectivity: PortfolioBrowserConnectivity): Effect.Effect<never> =>\n runPortfolioLiveController({\n connectivity,\n onSessionExpired,\n onState: (nextState) => {\n if (isCurrent) setState(nextState)\n },\n sessionKey,\n transport\n })\n const program = dependencies === undefined\n ? Effect.flatMap(generatedTransport, (transport) => run(transport, browserConnectivity)).pipe(\n Effect.provide(FetchHttpClient.layer)\n )\n : run(dependencies.transport, dependencies.connectivity)\n\n Effect.runPromiseExit(program, { signal: abortController.signal }).then((exit) => {\n if (!isCurrent || Exit.isSuccess(exit) || Cause.hasInterruptsOnly(exit.cause)) return\n setState({ _tag: \"failed\", failure: \"unavailable\", sessionKey })\n })\n return () => {\n isCurrent = false\n abortController.abort()\n }\n }, [dependencies, onSessionExpired, requestRevision, sessionKey])\n\n const retry = useCallback((): void => setRequestRevision((current) => current + 1), [])\n return { retry, state }\n}\n",".root {\n display: grid;\n gap: clamp(4rem, 9vw, 8rem);\n}\n\n.hero {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 2rem;\n align-items: end;\n}\n\n.heroCopy {\n display: grid;\n gap: 1.5rem;\n}\n\n.title {\n max-inline-size: 10ch;\n text-wrap: balance;\n}\n\n.lede {\n max-inline-size: 42rem;\n text-wrap: pretty;\n}\n\n.session {\n display: grid;\n gap: 0.75rem;\n justify-items: end;\n}\n\n.liveStatus {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: 0.5rem;\n}\n\n.content,\n.readyPortfolio,\n.releaseList {\n display: grid;\n gap: 1.25rem;\n}\n\n.readyPortfolio {\n gap: clamp(2.5rem, 6vw, 5rem);\n}\n\n.filters {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n border-block: 1px solid var(--rly-color-border-1);\n}\n\n.filter {\n display: grid;\n min-inline-size: 0;\n min-block-size: clamp(8rem, 14vw, 12rem);\n align-content: space-between;\n gap: 1rem;\n padding: clamp(1rem, 2.5vw, 2rem);\n border-inline-end: 1px solid var(--rly-color-border-1);\n color: var(--rly-color-text-2);\n font-size: clamp(1.35rem, 2.7vw, 3rem);\n font-weight: 650;\n letter-spacing: -0.04em;\n line-height: 0.95;\n text-decoration: none;\n text-wrap: balance;\n transition:\n background-color 160ms ease,\n color 160ms ease;\n}\n\n.filter:last-child {\n border-inline-end: 0;\n}\n\n.filter:hover {\n background: var(--rly-color-surface-2);\n color: var(--rly-color-text-1);\n}\n\n.filter[data-active=\"true\"] {\n background: var(--rly-color-action-background);\n color: var(--rly-color-action-foreground);\n}\n\n.filter:focus-visible {\n position: relative;\n z-index: 1;\n outline: 3px solid var(--rly-color-focus);\n outline-offset: -3px;\n}\n\n.filterCount {\n font-size: clamp(2.75rem, 6vw, 6.5rem);\n font-variant-numeric: tabular-nums;\n font-weight: 720;\n letter-spacing: -0.07em;\n line-height: 0.8;\n}\n\n.releaseList {\n overflow: hidden;\n border-block-start: 1px solid var(--rly-color-border-1);\n border-radius: var(--rly-radius-group);\n background: var(--rly-color-surface-1);\n}\n\n.statePanel {\n max-inline-size: 46rem;\n}\n\n.firstService {\n display: grid;\n gap: clamp(2rem, 5vw, 4rem);\n}\n\n.firstServiceCopy {\n display: grid;\n max-inline-size: 46rem;\n gap: var(--rly-space-12);\n}\n\n.serviceLauncher {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));\n gap: var(--rly-space-12);\n}\n\n.serviceChoice {\n display: flex;\n min-block-size: 8.5rem;\n align-items: flex-start;\n justify-content: space-between;\n flex-direction: column;\n gap: var(--rly-space-24);\n padding: var(--rly-space-20);\n border: 1px solid var(--rly-color-border-1);\n border-block-start-width: 3px;\n border-radius: var(--rly-radius-group);\n background: var(--rly-color-surface-1);\n color: var(--rly-color-text-1);\n text-decoration: none;\n transition:\n border-color 160ms ease,\n background-color 160ms ease,\n transform 160ms ease;\n}\n\n.serviceChoice[data-service=\"codecommit\"] {\n border-block-start-color: var(--rly-color-service-codecommit);\n}\n\n.serviceChoice[data-service=\"codepipeline\"] {\n border-block-start-color: var(--rly-color-service-codepipeline);\n}\n\n.serviceChoice[data-service=\"jira\"] {\n border-block-start-color: var(--rly-color-service-jira);\n}\n\n.serviceChoice[data-service=\"confluence\"] {\n border-block-start-color: var(--rly-color-service-confluence);\n}\n\n.serviceChoice[data-service=\"clockify\"] {\n border-block-start-color: var(--rly-color-service-clockify);\n}\n\n.serviceChoice:hover {\n border-color: var(--rly-color-border-2);\n background: var(--rly-color-surface-2);\n transform: translateY(-2px);\n}\n\n.serviceChoice:focus-visible {\n outline: 3px solid var(--rly-color-focus);\n outline-offset: 3px;\n}\n\n.serviceAction {\n color: var(--rly-color-text-2);\n font: var(--rly-type-label-weight) var(--rly-type-label-size) / var(--rly-type-label-line-height)\n var(--rly-type-label-font);\n}\n\n.pairAction {\n display: inline-flex;\n min-block-size: 3rem;\n align-items: center;\n padding-inline: 1.25rem;\n border: 1px solid var(--rly-color-border-2);\n border-radius: var(--rly-radius-control);\n background: var(--rly-color-action-background);\n color: var(--rly-color-action-foreground);\n font: var(--rly-type-label-weight) var(--rly-type-label-size) / var(--rly-type-label-line-height)\n var(--rly-type-label-font);\n text-decoration: none;\n}\n\n.loading {\n display: grid;\n gap: 1.5rem;\n padding-block: 1rem;\n}\n\n.loadingRail {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 1rem;\n}\n\n.releaseEntry {\n min-inline-size: 0;\n}\n\n.releaseEntry :global([data-rly-release-fact=\"issues\"]) {\n border-color: var(--rly-color-service-jira);\n}\n\n.releaseEntry :global([data-rly-release-fact=\"pull-requests\"]) {\n border-color: var(--rly-color-service-codecommit);\n}\n\n.releaseEntry :global([data-rly-release-fact=\"pipelines\"]) {\n border-color: var(--rly-color-service-codepipeline);\n}\n\n.releaseEntry :global([data-rly-release-fact=\"gaps\"]) {\n border-color: var(--rly-color-held-ink);\n}\n\n.stageRail {\n padding: var(--rly-space-16) var(--rly-space-24) var(--rly-space-20);\n border-block-end: 1px solid var(--rly-color-border-1);\n}\n\n.sourceWarning {\n margin: 0 var(--rly-space-24) var(--rly-space-20);\n}\n\n@media (max-width: 48rem) {\n .root {\n gap: 4rem;\n }\n\n .hero {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .session {\n justify-items: start;\n }\n\n .liveStatus {\n justify-content: flex-start;\n }\n\n .loadingRail {\n grid-template-columns: 1fr;\n }\n\n .filters {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n\n .filter:nth-child(2) {\n border-inline-end: 0;\n }\n\n .filter:nth-child(-n + 2) {\n border-block-end: 1px solid var(--rly-color-border-1);\n }\n}\n\n@media (max-width: 30rem) {\n .filter {\n min-block-size: 7rem;\n }\n\n .stageRail {\n padding-inline: var(--rly-space-16);\n }\n\n .sourceWarning {\n margin-inline: var(--rly-space-16);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .filter,\n .serviceChoice {\n transition: none;\n }\n\n .serviceChoice:hover {\n transform: none;\n }\n}\n","import { ReleaseRow, ServiceMark, StageRail, type RlyReleaseTransitionNames } from \"@knpkv/rly/patterns\"\nimport { Button, type RlyStateTone, Skeleton, StateLabel, StatePanel, Text } from \"@knpkv/rly/primitives\"\nimport type { ReactElement } from \"react\"\nimport { Link, Navigate, useLocation, useViewTransitionState } from \"react-router\"\n\nimport { firstPartyServiceIdentities } from \"../../domain/firstPartyServices.js\"\nimport { BrowserSessionStatus } from \"../BrowserSessionStatus.js\"\nimport { useBrowserSession } from \"../BrowserSession.js\"\nimport { releaseParentPath, releaseTransitionNames } from \"../releases/releaseRoutes.js\"\nimport { serviceSetupPath } from \"../services/serviceOnboarding.js\"\nimport { useWorkspaceDefaultLandingPath } from \"../settings/useWorkspaceDefaultLanding.js\"\nimport { presentPortfolio, type PortfolioPresentation, type PortfolioReleasePresentation } from \"./presentPortfolio.js\"\nimport {\n filterPortfolioReleases,\n type PortfolioFilter,\n portfolioFilterFromSearch,\n portfolioFilterLabel,\n portfolioFilterOptions,\n portfolioFilterSearch\n} from \"./portfolioFilters.js\"\nimport {\n type PortfolioConnectionState,\n type PortfolioLoadFailure,\n type PortfolioSnapshotLoadState,\n usePortfolioSnapshot\n} from \"./usePortfolioSnapshot.js\"\nimport styles from \"./PortfolioOverview.module.css\"\n\nexport type PortfolioOverviewState =\n | {\n readonly _tag: \"session\"\n readonly reason: \"anonymous\" | \"blocked\" | \"checking\" | \"storage-unavailable\" | \"unavailable\"\n }\n | { readonly _tag: \"loading\" }\n | {\n readonly _tag: \"ready\"\n readonly connection: PortfolioConnectionState\n readonly isSnapshotStale: boolean\n readonly portfolio: PortfolioPresentation\n }\n | { readonly _tag: \"failed\"; readonly failure: PortfolioLoadFailure }\n\nexport interface PortfolioOverviewViewProps {\n readonly onPreviewRelease: (releaseId: PortfolioReleasePresentation[\"id\"]) => void\n readonly onRetry: () => void\n readonly previewPathForRelease?: (releaseId: PortfolioReleasePresentation[\"id\"]) => string\n readonly state: PortfolioOverviewState\n}\n\nexport interface PortfolioOverviewController {\n readonly onRetry: () => void\n readonly state: PortfolioOverviewState\n}\n\ninterface ReleaseDossierProps {\n readonly onPreview: () => void\n readonly release: PortfolioReleasePresentation\n readonly transitionNames?: RlyReleaseTransitionNames\n}\n\ninterface ConnectionPresentation {\n readonly detail: string\n readonly label: string\n readonly tone: RlyStateTone\n}\n\nconst connectionPresentation = (\n connection: PortfolioConnectionState,\n isSnapshotStale: boolean\n): ConnectionPresentation => {\n switch (connection._tag) {\n case \"connecting\":\n return { detail: \"Connecting to live updates.\", label: \"Connecting\", tone: \"progress\" }\n case \"reconnecting\":\n return {\n detail: \"Showing the last snapshot; it may be stale.\",\n label: \"Reconnecting\",\n tone: \"caution\"\n }\n case \"offline\":\n return { detail: \"Showing the last snapshot; it may be stale.\", label: \"Offline\", tone: \"caution\" }\n case \"connected\":\n return isSnapshotStale\n ? { detail: \"Refreshing the authoritative snapshot.\", label: \"Updating\", tone: \"progress\" }\n : { detail: \"Snapshot up to date.\", label: \"Live\", tone: \"positive\" }\n }\n}\n\nconst PortfolioLiveStatus = ({\n connection,\n isSnapshotStale\n}: {\n readonly connection: PortfolioConnectionState\n readonly isSnapshotStale: boolean\n}): ReactElement => {\n const presentation = connectionPresentation(connection, isSnapshotStale)\n return (\n <div aria-atomic=\"true\" aria-live=\"polite\" className={styles.liveStatus} role=\"status\">\n <StateLabel label={presentation.label} size=\"compact\" tone={presentation.tone} />\n <Text tone=\"tertiary\" variant=\"meta\">\n {presentation.detail}\n </Text>\n </div>\n )\n}\n\nconst EmptyPortfolio = (): ReactElement => (\n <section aria-labelledby=\"first-service-title\" className={styles.firstService}>\n <div className={styles.firstServiceCopy}>\n <Text as=\"h2\" id=\"first-service-title\" variant=\"page-title\">\n Choose your first service\n </Text>\n <Text tone=\"secondary\" variant=\"body-large\">\n Enable and verify one source. Its releases, people, and delivery evidence will appear here automatically.\n </Text>\n </div>\n <nav aria-label=\"Services available to enable\" className={styles.serviceLauncher}>\n {firstPartyServiceIdentities.map((service) => (\n <Link\n className={styles.serviceChoice}\n data-service={service.providerId}\n key={service.providerId}\n to={serviceSetupPath(service.providerId)}\n >\n <ServiceMark service={service.providerId} />\n <span className={styles.serviceAction}>Enable</span>\n </Link>\n ))}\n </nav>\n </section>\n)\n\nconst LoadingPortfolio = (): ReactElement => (\n <div className={styles.loading}>\n <Skeleton decorative={false} height=\"1.25rem\" label=\"Loading releases\" width=\"10rem\" />\n <Skeleton decorative height=\"8rem\" variant=\"block\" />\n <div className={styles.loadingRail}>\n <Skeleton decorative height=\"3rem\" variant=\"block\" />\n <Skeleton decorative height=\"3rem\" variant=\"block\" />\n <Skeleton decorative height=\"3rem\" variant=\"block\" />\n </div>\n </div>\n)\n\ntype PortfolioSessionReason = Extract<PortfolioOverviewState, { readonly _tag: \"session\" }>[\"reason\"]\n\ninterface PortfolioSessionBoundaryPresentation {\n readonly announce?: \"assertive\"\n readonly description: string\n readonly title: string\n readonly tone?: \"caution\" | \"critical\"\n}\n\nexport const portfolioSessionBoundaryPresentation = (\n reason: PortfolioSessionReason\n): PortfolioSessionBoundaryPresentation => {\n switch (reason) {\n case \"anonymous\":\n return {\n description:\n \"Pair this browser to read the workspace portfolio. Release facts never load before authentication.\",\n title: \"Release facts stay private\"\n }\n case \"checking\":\n return {\n description: \"Control Center is confirming whether this browser can read the workspace portfolio.\",\n title: \"Checking this browser\"\n }\n case \"blocked\":\n return {\n announce: \"assertive\",\n description: \"This connection cannot read private release facts. Use an allowed Control Center address.\",\n title: \"Portfolio access blocked\",\n tone: \"critical\"\n }\n case \"storage-unavailable\":\n return {\n announce: \"assertive\",\n description:\n \"This browser cannot retain the private session proof. Check storage permissions or space, then reload.\",\n title: \"Session storage unavailable\",\n tone: \"caution\"\n }\n case \"unavailable\":\n return {\n announce: \"assertive\",\n description: \"Control Center could not check this browser session. Check the server, then reload this page.\",\n title: \"Control Center unavailable\",\n tone: \"critical\"\n }\n }\n}\n\nconst SessionBoundary = ({ reason }: Extract<PortfolioOverviewState, { readonly _tag: \"session\" }>): ReactElement => {\n const presentation = portfolioSessionBoundaryPresentation(reason)\n return (\n <StatePanel\n {...presentation}\n action={\n reason === \"anonymous\" ? (\n <Link className={styles.pairAction} to=\"/pair\">\n Pair this browser\n </Link>\n ) : undefined\n }\n className={styles.statePanel}\n />\n )\n}\n\nconst FailedPortfolio = ({\n failure,\n onRetry\n}: {\n readonly failure: PortfolioLoadFailure\n readonly onRetry: () => void\n}): ReactElement => {\n if (failure === \"session-expired\") {\n return (\n <StatePanel\n action={\n <Link className={styles.pairAction} to=\"/pair\">\n Pair this browser\n </Link>\n }\n announce=\"assertive\"\n className={styles.statePanel}\n description=\"Pair this browser again to read the workspace portfolio.\"\n title=\"Pairing expired\"\n tone=\"caution\"\n />\n )\n }\n if (failure === \"blocked\") {\n return (\n <StatePanel\n announce=\"assertive\"\n className={styles.statePanel}\n description=\"This connection cannot read private release facts. Use an allowed Control Center address.\"\n title=\"Portfolio access blocked\"\n tone=\"critical\"\n />\n )\n }\n return (\n <StatePanel\n action={<Button onClick={onRetry}>Try again</Button>}\n announce=\"assertive\"\n className={styles.statePanel}\n description=\"Control Center could not read the saved portfolio. Check the server, then try again.\"\n title=\"Overview unavailable\"\n tone=\"critical\"\n />\n )\n}\n\nconst ReleaseDossier = ({ onPreview, release, transitionNames }: ReleaseDossierProps): ReactElement => (\n <div className={styles.releaseEntry} data-portfolio-release-id={release.id}>\n <ReleaseRow\n onPreview={onPreview}\n previewLabel={`Preview ${release.relay.codename}`}\n release={release.release}\n {...(transitionNames === undefined ? {} : { transitionNames })}\n />\n <StageRail className={styles.stageRail} heading=\"Delivery\" size=\"compact\" stages={release.stages} />\n {release.source.warning === null ? null : (\n <StatePanel\n announce=\"polite\"\n className={styles.sourceWarning}\n description={release.source.warning}\n title=\"Showing preserved source facts\"\n tone=\"caution\"\n />\n )}\n </div>\n)\n\nconst PortfolioFilters = ({\n activeFilter,\n portfolio\n}: {\n readonly activeFilter: PortfolioFilter\n readonly portfolio: PortfolioPresentation\n}): ReactElement => {\n const location = useLocation()\n return (\n <nav aria-label=\"Release filters\" className={styles.filters}>\n {portfolioFilterOptions(portfolio.releases).map((option) => (\n <Link\n aria-current={option.id === activeFilter ? \"page\" : undefined}\n className={styles.filter}\n data-active={option.id === activeFilter ? \"true\" : \"false\"}\n key={option.id}\n to={{ pathname: location.pathname, search: portfolioFilterSearch(location.search, option.id) }}\n >\n <span>{option.label}</span>\n <span\n aria-label={`${String(option.count)} ${option.count === 1 ? \"release\" : \"releases\"}`}\n className={styles.filterCount}\n >\n {option.count}\n </span>\n </Link>\n ))}\n </nav>\n )\n}\n\nconst EmptyFilter = ({ filter }: { readonly filter: PortfolioFilter }): ReactElement => {\n const location = useLocation()\n return (\n <StatePanel\n action={\n <Link\n className={styles.pairAction}\n to={{ pathname: location.pathname, search: portfolioFilterSearch(location.search, \"all\") }}\n >\n Show all releases\n </Link>\n }\n className={styles.statePanel}\n description={`No releases currently match ${portfolioFilterLabel(filter)}. Live updates may change this view.`}\n title=\"Nothing here right now\"\n />\n )\n}\n\nconst TransitioningReleaseDossier = ({\n onPreview,\n originPath,\n previewPath,\n release\n}: ReleaseDossierProps & { readonly originPath: string; readonly previewPath: string }): ReactElement => {\n const location = useLocation()\n const isTransitioning = useViewTransitionState(previewPath)\n return (\n <ReleaseDossier\n onPreview={onPreview}\n release={release}\n {...(isTransitioning && location.pathname === originPath\n ? { transitionNames: releaseTransitionNames(release.id) }\n : {})}\n />\n )\n}\n\nconst ReadyPortfolio = ({\n onPreviewRelease,\n portfolio,\n previewPathForRelease\n}: {\n readonly onPreviewRelease: (releaseId: PortfolioReleasePresentation[\"id\"]) => void\n readonly portfolio: PortfolioPresentation\n readonly previewPathForRelease?: (releaseId: PortfolioReleasePresentation[\"id\"]) => string\n}): ReactElement => {\n if (portfolio.releases.length === 0) return <EmptyPortfolio />\n const location = useLocation()\n const activeFilter = portfolioFilterFromSearch(location.search)\n const releases = filterPortfolioReleases(portfolio.releases, activeFilter)\n return (\n <div className={styles.readyPortfolio}>\n <PortfolioFilters activeFilter={activeFilter} portfolio={portfolio} />\n {releases.length === 0 ? (\n <EmptyFilter filter={activeFilter} />\n ) : (\n <div className={styles.releaseList}>\n {releases.map((release) =>\n previewPathForRelease === undefined ? (\n <ReleaseDossier key={release.id} onPreview={() => onPreviewRelease(release.id)} release={release} />\n ) : (\n <TransitioningReleaseDossier\n key={release.id}\n onPreview={() => onPreviewRelease(release.id)}\n originPath={releaseParentPath(portfolio.workspaceId)}\n previewPath={previewPathForRelease(release.id)}\n release={release}\n />\n )\n )}\n </div>\n )}\n </div>\n )\n}\n\n/** Render every Overview outcome from an explicit controlled state. */\nexport const PortfolioOverviewView = ({\n onPreviewRelease,\n onRetry,\n previewPathForRelease,\n state\n}: PortfolioOverviewViewProps): ReactElement => (\n <section aria-labelledby=\"portfolio-title\" className={styles.root}>\n <header className={styles.hero}>\n <div className={styles.heroCopy}>\n <Text as=\"h1\" className={styles.title} id=\"portfolio-title\" tabIndex={-1} variant=\"verdict\">\n Every release. One view.\n </Text>\n <Text className={styles.lede} tone=\"secondary\" variant=\"body-large\">\n One factual view of releases, people, source health, and every handoff still to prove.\n </Text>\n </div>\n <div className={styles.session}>\n {state._tag === \"session\" && state.reason === \"storage-unavailable\" ? null : (\n <BrowserSessionStatus anonymousAction=\"status\" />\n )}\n {state._tag === \"ready\" ? (\n <>\n <PortfolioLiveStatus connection={state.connection} isSnapshotStale={state.isSnapshotStale} />\n <Text as=\"time\" dateTime={state.portfolio.generatedAt} tone=\"tertiary\" variant=\"meta\">\n Snapshot {state.portfolio.generatedTime}\n </Text>\n </>\n ) : null}\n </div>\n </header>\n\n <div className={styles.content}>\n {state._tag === \"session\" ? <SessionBoundary {...state} /> : null}\n {state._tag === \"loading\" ? <LoadingPortfolio /> : null}\n {state._tag === \"failed\" ? <FailedPortfolio failure={state.failure} onRetry={onRetry} /> : null}\n {state._tag === \"ready\" ? (\n <ReadyPortfolio\n onPreviewRelease={onPreviewRelease}\n portfolio={state.portfolio}\n {...(previewPathForRelease === undefined ? {} : { previewPathForRelease })}\n />\n ) : null}\n </div>\n </section>\n)\n\nconst overviewState = (loadState: PortfolioSnapshotLoadState): PortfolioOverviewState => {\n switch (loadState._tag) {\n case \"idle\":\n return { _tag: \"session\", reason: \"anonymous\" }\n case \"loading\":\n return { _tag: \"loading\" }\n case \"failed\":\n return { _tag: \"failed\", failure: loadState.failure }\n case \"loaded\":\n return {\n _tag: \"ready\",\n connection: loadState.connection,\n isSnapshotStale: loadState.isSnapshotStale,\n portfolio: presentPortfolio(loadState.snapshot)\n }\n }\n}\n\n/** Prevent a prior browser session's snapshot from crossing an authentication transition. */\nexport const selectPortfolioOverviewState = (\n loadState: PortfolioSnapshotLoadState,\n sessionKey: string | null,\n sessionReason: Extract<PortfolioOverviewState, { readonly _tag: \"session\" }>[\"reason\"] = \"anonymous\"\n): PortfolioOverviewState => {\n if (sessionKey === null) return { _tag: \"session\", reason: sessionReason }\n if (loadState._tag === \"idle\" || loadState.sessionKey !== sessionKey) return { _tag: \"loading\" }\n return overviewState(loadState)\n}\n\n/** Read the authenticated live portfolio through one shared route-level controller. */\nexport const usePortfolioOverviewController = (): PortfolioOverviewController => {\n const { invalidateSession, state: browserSession } = useBrowserSession()\n const readableSession =\n browserSession._tag === \"authenticated\"\n ? browserSession.session\n : browserSession._tag === \"storage-unavailable\"\n ? browserSession.session\n : null\n const controller = usePortfolioSnapshot(readableSession?.sessionId ?? null, invalidateSession)\n return {\n onRetry: controller.retry,\n state: selectPortfolioOverviewState(\n controller.state,\n readableSession?.sessionId ?? null,\n browserSession._tag === \"authenticated\" ? \"checking\" : browserSession._tag\n )\n }\n}\n\n/** Load and present the authenticated server portfolio at the root application route. */\nexport const PortfolioOverview = (): ReactElement => {\n const controller = usePortfolioOverviewController()\n const { state } = controller\n const workspaceId = state._tag === \"ready\" ? state.portfolio.workspaceId : null\n const defaultLandingPath = useWorkspaceDefaultLandingPath(workspaceId)\n if (state._tag === \"ready\" && defaultLandingPath !== null) {\n return <Navigate replace to={defaultLandingPath} />\n }\n return <PortfolioOverviewView onPreviewRelease={() => undefined} onRetry={controller.onRetry} state={state} />\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}