@dxos/plugin-client 0.10.0 → 0.11.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 (358) hide show
  1. package/dist/lib/ClientPlugin.mjs +65 -0
  2. package/dist/lib/ClientPlugin.mjs.map +1 -0
  3. package/dist/lib/ClientPlugin.node.mjs +904 -0
  4. package/dist/lib/ClientPlugin.node.mjs.map +1 -0
  5. package/dist/lib/ClientPlugin.workerd.mjs +10 -0
  6. package/dist/lib/ClientPlugin.workerd.mjs.map +1 -0
  7. package/dist/lib/capabilities/node.mjs +13 -0
  8. package/dist/lib/capabilities/node.mjs.map +1 -0
  9. package/dist/lib/capabilities.mjs +23 -0
  10. package/dist/lib/capabilities.mjs.map +1 -0
  11. package/dist/lib/chunk-AccountContainer.mjs +190 -0
  12. package/dist/lib/chunk-AccountContainer.mjs.map +1 -0
  13. package/dist/lib/chunk-DevicesContainer.mjs +275 -0
  14. package/dist/lib/chunk-DevicesContainer.mjs.map +1 -0
  15. package/dist/lib/chunk-InvitationsContainer.mjs +149 -0
  16. package/dist/lib/chunk-InvitationsContainer.mjs.map +1 -0
  17. package/dist/lib/chunk-JoinDialog.mjs +35 -0
  18. package/dist/lib/chunk-JoinDialog.mjs.map +1 -0
  19. package/dist/lib/chunk-ProfileContainer.mjs +145 -0
  20. package/dist/lib/chunk-ProfileContainer.mjs.map +1 -0
  21. package/dist/lib/chunk-RecoveryCodeDialog.mjs +72 -0
  22. package/dist/lib/chunk-RecoveryCodeDialog.mjs.map +1 -0
  23. package/dist/lib/chunk-RecoveryCredentialsContainer.mjs +65 -0
  24. package/dist/lib/chunk-RecoveryCredentialsContainer.mjs.map +1 -0
  25. package/dist/lib/chunk-ResetDialog.mjs +47 -0
  26. package/dist/lib/chunk-ResetDialog.mjs.map +1 -0
  27. package/dist/lib/chunk-UsageContainer.mjs +217 -0
  28. package/dist/lib/chunk-UsageContainer.mjs.map +1 -0
  29. package/dist/lib/{neutral/account-cache-YVQKLNV2.mjs → chunk-account-cache.mjs} +10 -12
  30. package/dist/lib/chunk-account-cache.mjs.map +1 -0
  31. package/dist/lib/chunk-app-graph-builder.mjs +111 -0
  32. package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
  33. package/dist/lib/chunk-client.mjs +90 -0
  34. package/dist/lib/chunk-client.mjs.map +1 -0
  35. package/dist/lib/{neutral/chunk-GSKMAS3S.mjs → chunk-constants.mjs} +5 -8
  36. package/dist/lib/chunk-constants.mjs.map +1 -0
  37. package/dist/lib/chunk-create-agent.mjs +23 -0
  38. package/dist/lib/chunk-create-agent.mjs.map +1 -0
  39. package/dist/lib/chunk-create-identity.mjs +28 -0
  40. package/dist/lib/chunk-create-identity.mjs.map +1 -0
  41. package/dist/lib/chunk-create-passkey.mjs +85 -0
  42. package/dist/lib/chunk-create-passkey.mjs.map +1 -0
  43. package/dist/lib/chunk-create-recovery-code.mjs +31 -0
  44. package/dist/lib/chunk-create-recovery-code.mjs.map +1 -0
  45. package/dist/lib/chunk-hooks.mjs +29 -0
  46. package/dist/lib/chunk-hooks.mjs.map +1 -0
  47. package/dist/lib/chunk-hub-http-client.mjs +14 -0
  48. package/dist/lib/chunk-hub-http-client.mjs.map +1 -0
  49. package/dist/lib/chunk-join-identity.mjs +20 -0
  50. package/dist/lib/chunk-join-identity.mjs.map +1 -0
  51. package/dist/lib/chunk-layer-specs.mjs +107 -0
  52. package/dist/lib/chunk-layer-specs.mjs.map +1 -0
  53. package/dist/lib/{neutral/chunk-6G4KZLBG.mjs → chunk-meta.mjs} +13 -20
  54. package/dist/lib/chunk-meta.mjs.map +1 -0
  55. package/dist/lib/chunk-migrations.mjs +29 -0
  56. package/dist/lib/chunk-migrations.mjs.map +1 -0
  57. package/dist/lib/chunk-navigation-handler.mjs +71 -0
  58. package/dist/lib/chunk-navigation-handler.mjs.map +1 -0
  59. package/dist/lib/chunk-navigation-target-loader.mjs +46 -0
  60. package/dist/lib/chunk-navigation-target-loader.mjs.map +1 -0
  61. package/dist/lib/chunk-open-usage.mjs +14 -0
  62. package/dist/lib/chunk-open-usage.mjs.map +1 -0
  63. package/dist/lib/chunk-operation-handler.mjs +11 -0
  64. package/dist/lib/chunk-operation-handler.mjs.map +1 -0
  65. package/dist/lib/chunk-operations.mjs +212 -0
  66. package/dist/lib/chunk-operations.mjs.map +1 -0
  67. package/dist/lib/chunk-progress.mjs +10 -0
  68. package/dist/lib/chunk-progress.mjs.map +1 -0
  69. package/dist/lib/chunk-react-context.mjs +30 -0
  70. package/dist/lib/chunk-react-context.mjs.map +1 -0
  71. package/dist/lib/chunk-react-surface.mjs +70 -0
  72. package/dist/lib/chunk-react-surface.mjs.map +1 -0
  73. package/dist/lib/chunk-recover-identity.mjs +17 -0
  74. package/dist/lib/chunk-recover-identity.mjs.map +1 -0
  75. package/dist/lib/chunk-redeem-passkey.mjs +72 -0
  76. package/dist/lib/chunk-redeem-passkey.mjs.map +1 -0
  77. package/dist/lib/chunk-redeem-token.mjs +24 -0
  78. package/dist/lib/chunk-redeem-token.mjs.map +1 -0
  79. package/dist/lib/chunk-remote-trace-monitor.mjs +37 -0
  80. package/dist/lib/chunk-remote-trace-monitor.mjs.map +1 -0
  81. package/dist/lib/chunk-reset-storage.mjs +17 -0
  82. package/dist/lib/chunk-reset-storage.mjs.map +1 -0
  83. package/dist/lib/chunk-resolve-navigation-targets.mjs +32 -0
  84. package/dist/lib/chunk-resolve-navigation-targets.mjs.map +1 -0
  85. package/dist/lib/chunk-schema-defs.mjs +53 -0
  86. package/dist/lib/chunk-schema-defs.mjs.map +1 -0
  87. package/dist/lib/chunk-share-identity.mjs +16 -0
  88. package/dist/lib/chunk-share-identity.mjs.map +1 -0
  89. package/dist/lib/chunk-space-replication-progress.mjs +94 -0
  90. package/dist/lib/chunk-space-replication-progress.mjs.map +1 -0
  91. package/dist/lib/chunk-trace-progress.mjs +69 -0
  92. package/dist/lib/chunk-trace-progress.mjs.map +1 -0
  93. package/dist/lib/chunk-update-profile.mjs +15 -0
  94. package/dist/lib/chunk-update-profile.mjs.map +1 -0
  95. package/dist/lib/components.mjs +0 -0
  96. package/dist/lib/containers.mjs +15 -0
  97. package/dist/lib/containers.mjs.map +1 -0
  98. package/dist/lib/index.mjs +27 -0
  99. package/dist/lib/index.mjs.map +1 -0
  100. package/dist/lib/meta.mjs +2 -0
  101. package/dist/lib/operations.mjs +2 -0
  102. package/dist/lib/plugin.mjs +9 -0
  103. package/dist/lib/plugin.mjs.map +1 -0
  104. package/dist/lib/testing.mjs +21 -0
  105. package/dist/lib/testing.mjs.map +1 -0
  106. package/dist/lib/translations.mjs +111 -0
  107. package/dist/lib/translations.mjs.map +1 -0
  108. package/dist/lib/types.mjs +139 -0
  109. package/dist/lib/types.mjs.map +1 -0
  110. package/dist/types/src/ClientPlugin.d.ts.map +1 -1
  111. package/dist/types/src/capabilities/account-cache.d.ts +1 -1
  112. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  113. package/dist/types/src/capabilities/client.d.ts +1 -1
  114. package/dist/types/src/capabilities/client.d.ts.map +1 -1
  115. package/dist/types/src/capabilities/hub-http-client.d.ts +1 -1
  116. package/dist/types/src/capabilities/index.d.ts +6 -1
  117. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  118. package/dist/types/src/capabilities/layer-specs.d.ts +1 -1
  119. package/dist/types/src/capabilities/migrations.d.ts +1 -1
  120. package/dist/types/src/capabilities/navigation-handler/navigation-handler.d.ts +3 -1
  121. package/dist/types/src/capabilities/navigation-handler/navigation-handler.d.ts.map +1 -1
  122. package/dist/types/src/capabilities/navigation-target-loader.d.ts +11 -0
  123. package/dist/types/src/capabilities/navigation-target-loader.d.ts.map +1 -0
  124. package/dist/types/src/capabilities/node.d.ts +2 -1
  125. package/dist/types/src/capabilities/node.d.ts.map +1 -1
  126. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  127. package/dist/types/src/capabilities/react-context.d.ts +1 -1
  128. package/dist/types/src/capabilities/react-context.d.ts.map +1 -1
  129. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  130. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  131. package/dist/types/src/capabilities/remote-trace-monitor.d.ts +15 -0
  132. package/dist/types/src/capabilities/remote-trace-monitor.d.ts.map +1 -0
  133. package/dist/types/src/capabilities/schema-defs.d.ts +1 -1
  134. package/dist/types/src/capabilities/space-replication-progress.d.ts +11 -0
  135. package/dist/types/src/capabilities/space-replication-progress.d.ts.map +1 -0
  136. package/dist/types/src/capabilities/trace-progress.d.ts +17 -0
  137. package/dist/types/src/capabilities/trace-progress.d.ts.map +1 -0
  138. package/dist/types/src/commands/account/login/login.d.ts +2 -1
  139. package/dist/types/src/commands/account/login/login.d.ts.map +1 -1
  140. package/dist/types/src/commands/account/logout/logout.d.ts +1 -1
  141. package/dist/types/src/commands/account/logout/logout.d.ts.map +1 -1
  142. package/dist/types/src/commands/halo/index.d.ts.map +1 -1
  143. package/dist/types/src/commands/halo/share/share.d.ts.map +1 -1
  144. package/dist/types/src/commands/profile/create.d.ts.map +1 -1
  145. package/dist/types/src/containers/AccountContainer/AccountContainer.d.ts +4 -1
  146. package/dist/types/src/containers/AccountContainer/AccountContainer.d.ts.map +1 -1
  147. package/dist/types/src/containers/AccountContainer/AccountContainer.stories.d.ts +4 -1
  148. package/dist/types/src/containers/AccountContainer/AccountContainer.stories.d.ts.map +1 -1
  149. package/dist/types/src/containers/DevicesContainer/DevicesContainer.d.ts +4 -1
  150. package/dist/types/src/containers/DevicesContainer/DevicesContainer.d.ts.map +1 -1
  151. package/dist/types/src/containers/DevicesContainer/DevicesContainer.stories.d.ts +4 -1
  152. package/dist/types/src/containers/DevicesContainer/DevicesContainer.stories.d.ts.map +1 -1
  153. package/dist/types/src/containers/InvitationsContainer/InvitationsContainer.d.ts +4 -1
  154. package/dist/types/src/containers/InvitationsContainer/InvitationsContainer.d.ts.map +1 -1
  155. package/dist/types/src/containers/InvitationsContainer/InvitationsContainer.stories.d.ts +4 -1
  156. package/dist/types/src/containers/InvitationsContainer/InvitationsContainer.stories.d.ts.map +1 -1
  157. package/dist/types/src/containers/JoinDialog/JoinDialog.d.ts +4 -1
  158. package/dist/types/src/containers/JoinDialog/JoinDialog.d.ts.map +1 -1
  159. package/dist/types/src/containers/JoinDialog/JoinDialog.stories.d.ts +4 -1
  160. package/dist/types/src/containers/JoinDialog/JoinDialog.stories.d.ts.map +1 -1
  161. package/dist/types/src/containers/ProfileContainer/ProfileContainer.d.ts +4 -1
  162. package/dist/types/src/containers/ProfileContainer/ProfileContainer.d.ts.map +1 -1
  163. package/dist/types/src/containers/ProfileContainer/ProfileContainer.stories.d.ts +4 -1
  164. package/dist/types/src/containers/ProfileContainer/ProfileContainer.stories.d.ts.map +1 -1
  165. package/dist/types/src/containers/RecoveryCodeDialog/RecoveryCodeDialog.d.ts +4 -1
  166. package/dist/types/src/containers/RecoveryCodeDialog/RecoveryCodeDialog.d.ts.map +1 -1
  167. package/dist/types/src/containers/RecoveryCredentialsContainer/RecoveryCredentialsContainer.d.ts +4 -1
  168. package/dist/types/src/containers/RecoveryCredentialsContainer/RecoveryCredentialsContainer.d.ts.map +1 -1
  169. package/dist/types/src/containers/RecoveryCredentialsContainer/RecoveryCredentialsContainer.stories.d.ts +4 -1
  170. package/dist/types/src/containers/RecoveryCredentialsContainer/RecoveryCredentialsContainer.stories.d.ts.map +1 -1
  171. package/dist/types/src/containers/ResetDialog/ResetDialog.d.ts +4 -1
  172. package/dist/types/src/containers/ResetDialog/ResetDialog.d.ts.map +1 -1
  173. package/dist/types/src/containers/ResetDialog/ResetDialog.stories.d.ts +4 -1
  174. package/dist/types/src/containers/ResetDialog/ResetDialog.stories.d.ts.map +1 -1
  175. package/dist/types/src/containers/UsageContainer/UsageContainer.d.ts +4 -5
  176. package/dist/types/src/containers/UsageContainer/UsageContainer.d.ts.map +1 -1
  177. package/dist/types/src/containers/UsageContainer/UsageView.d.ts +4 -7
  178. package/dist/types/src/containers/UsageContainer/UsageView.d.ts.map +1 -1
  179. package/dist/types/src/containers/UsageContainer/UsageView.stories.d.ts +4 -2
  180. package/dist/types/src/containers/UsageContainer/UsageView.stories.d.ts.map +1 -1
  181. package/dist/types/src/halo-services-layer.d.ts +19 -0
  182. package/dist/types/src/halo-services-layer.d.ts.map +1 -0
  183. package/dist/types/src/index.d.ts +3 -0
  184. package/dist/types/src/index.d.ts.map +1 -1
  185. package/dist/types/src/operations/definitions.d.ts +9 -1
  186. package/dist/types/src/operations/definitions.d.ts.map +1 -1
  187. package/dist/types/src/operations/errors.d.ts +109 -0
  188. package/dist/types/src/operations/errors.d.ts.map +1 -0
  189. package/dist/types/src/operations/errors.test.d.ts +2 -0
  190. package/dist/types/src/operations/errors.test.d.ts.map +1 -0
  191. package/dist/types/src/operations/index.d.ts +1 -0
  192. package/dist/types/src/operations/index.d.ts.map +1 -1
  193. package/dist/types/src/operations/redeem-passkey.d.ts.map +1 -1
  194. package/dist/types/src/operations/resolve-navigation-targets.d.ts +5 -0
  195. package/dist/types/src/operations/resolve-navigation-targets.d.ts.map +1 -0
  196. package/dist/types/src/operations/update-profile.d.ts +5 -0
  197. package/dist/types/src/operations/update-profile.d.ts.map +1 -0
  198. package/dist/types/src/progress/index.d.ts +2 -0
  199. package/dist/types/src/progress/index.d.ts.map +1 -0
  200. package/dist/types/src/progress/progress-keys.d.ts +6 -0
  201. package/dist/types/src/progress/progress-keys.d.ts.map +1 -0
  202. package/dist/types/src/testing/initializeIdentity.d.ts +5 -1
  203. package/dist/types/src/testing/initializeIdentity.d.ts.map +1 -1
  204. package/dist/types/src/translations.d.ts.map +1 -1
  205. package/dist/types/src/types/capabilities.d.ts +10 -1
  206. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  207. package/dist/types/src/types/schema.d.ts +6 -0
  208. package/dist/types/src/types/schema.d.ts.map +1 -1
  209. package/dist/types/tsconfig.tsbuildinfo +1 -1
  210. package/package.json +60 -55
  211. package/src/ClientPlugin.ts +25 -2
  212. package/src/capabilities/app-graph-builder.ts +1 -1
  213. package/src/capabilities/client.ts +26 -0
  214. package/src/capabilities/index.ts +10 -0
  215. package/src/capabilities/layer-specs.ts +64 -2
  216. package/src/capabilities/migrations.ts +9 -1
  217. package/src/capabilities/navigation-handler/navigation-handler.ts +20 -3
  218. package/src/capabilities/navigation-target-loader.ts +70 -0
  219. package/src/capabilities/react-context.tsx +20 -2
  220. package/src/capabilities/{react-surface.tsx → react-surface.ts} +14 -12
  221. package/src/capabilities/remote-trace-monitor.ts +62 -0
  222. package/src/capabilities/space-replication-progress.ts +143 -0
  223. package/src/capabilities/trace-progress.ts +84 -0
  224. package/src/commands/account/login/login.ts +48 -6
  225. package/src/commands/account/logout/logout.ts +4 -0
  226. package/src/commands/halo/index.ts +6 -2
  227. package/src/commands/halo/share/share.ts +16 -5
  228. package/src/commands/profile/create.ts +23 -40
  229. package/src/containers/AccountContainer/AccountContainer.tsx +6 -5
  230. package/src/containers/DevicesContainer/DevicesContainer.tsx +2 -0
  231. package/src/containers/InvitationsContainer/InvitationsContainer.tsx +2 -0
  232. package/src/containers/JoinDialog/JoinDialog.tsx +2 -0
  233. package/src/containers/ProfileContainer/ProfileContainer.tsx +19 -13
  234. package/src/containers/RecoveryCodeDialog/RecoveryCodeDialog.tsx +2 -0
  235. package/src/containers/RecoveryCredentialsContainer/RecoveryCredentialsContainer.tsx +7 -9
  236. package/src/containers/ResetDialog/ResetDialog.tsx +2 -0
  237. package/src/containers/UsageContainer/UsageContainer.tsx +10 -1
  238. package/src/containers/UsageContainer/UsageView.stories.tsx +0 -12
  239. package/src/containers/UsageContainer/UsageView.tsx +9 -10
  240. package/src/halo-services-layer.ts +29 -0
  241. package/src/index.ts +9 -0
  242. package/src/operations/definitions.ts +9 -1
  243. package/src/operations/errors.test.ts +27 -0
  244. package/src/operations/errors.ts +47 -0
  245. package/src/operations/index.ts +3 -0
  246. package/src/operations/open-usage.ts +3 -3
  247. package/src/operations/redeem-passkey.ts +85 -55
  248. package/src/operations/resolve-navigation-targets.ts +71 -0
  249. package/src/operations/share-identity.ts +3 -3
  250. package/src/operations/update-profile.ts +20 -0
  251. package/src/progress/index.ts +5 -0
  252. package/src/progress/progress-keys.ts +15 -0
  253. package/src/testing/initializeIdentity.ts +10 -2
  254. package/src/translations.ts +2 -0
  255. package/src/types/capabilities.ts +15 -1
  256. package/src/types/schema.ts +7 -0
  257. package/dist/lib/neutral/AccountContainer-7SF53UON.mjs +0 -186
  258. package/dist/lib/neutral/AccountContainer-7SF53UON.mjs.map +0 -7
  259. package/dist/lib/neutral/ClientPlugin.mjs +0 -72
  260. package/dist/lib/neutral/ClientPlugin.mjs.map +0 -7
  261. package/dist/lib/neutral/ClientPlugin.node.mjs +0 -1156
  262. package/dist/lib/neutral/ClientPlugin.node.mjs.map +0 -7
  263. package/dist/lib/neutral/ClientPlugin.workerd.mjs +0 -16
  264. package/dist/lib/neutral/ClientPlugin.workerd.mjs.map +0 -7
  265. package/dist/lib/neutral/DevicesContainer-PRWIN36N.mjs +0 -271
  266. package/dist/lib/neutral/DevicesContainer-PRWIN36N.mjs.map +0 -7
  267. package/dist/lib/neutral/InvitationsContainer-BI5RAWET.mjs +0 -143
  268. package/dist/lib/neutral/InvitationsContainer-BI5RAWET.mjs.map +0 -7
  269. package/dist/lib/neutral/JoinDialog-4BWV4CYB.mjs +0 -53
  270. package/dist/lib/neutral/JoinDialog-4BWV4CYB.mjs.map +0 -7
  271. package/dist/lib/neutral/ProfileContainer-YEAYOTX5.mjs +0 -169
  272. package/dist/lib/neutral/ProfileContainer-YEAYOTX5.mjs.map +0 -7
  273. package/dist/lib/neutral/RecoveryCodeDialog-7EPNKCLB.mjs +0 -59
  274. package/dist/lib/neutral/RecoveryCodeDialog-7EPNKCLB.mjs.map +0 -7
  275. package/dist/lib/neutral/RecoveryCredentialsContainer-6BZ2IWX7.mjs +0 -60
  276. package/dist/lib/neutral/RecoveryCredentialsContainer-6BZ2IWX7.mjs.map +0 -7
  277. package/dist/lib/neutral/ResetDialog-KUWX45JY.mjs +0 -57
  278. package/dist/lib/neutral/ResetDialog-KUWX45JY.mjs.map +0 -7
  279. package/dist/lib/neutral/UsageContainer-2DWCVVE4.mjs +0 -241
  280. package/dist/lib/neutral/UsageContainer-2DWCVVE4.mjs.map +0 -7
  281. package/dist/lib/neutral/account-cache-YVQKLNV2.mjs.map +0 -7
  282. package/dist/lib/neutral/app-graph-builder-RVXTD6OE.mjs +0 -159
  283. package/dist/lib/neutral/app-graph-builder-RVXTD6OE.mjs.map +0 -7
  284. package/dist/lib/neutral/capabilities/index.mjs +0 -34
  285. package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
  286. package/dist/lib/neutral/capabilities/node.mjs +0 -21
  287. package/dist/lib/neutral/capabilities/node.mjs.map +0 -7
  288. package/dist/lib/neutral/chunk-6G4KZLBG.mjs.map +0 -7
  289. package/dist/lib/neutral/chunk-7DEIKHB7.mjs +0 -199
  290. package/dist/lib/neutral/chunk-7DEIKHB7.mjs.map +0 -7
  291. package/dist/lib/neutral/chunk-A7WDDIWY.mjs +0 -162
  292. package/dist/lib/neutral/chunk-A7WDDIWY.mjs.map +0 -7
  293. package/dist/lib/neutral/chunk-GSKMAS3S.mjs.map +0 -7
  294. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  295. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  296. package/dist/lib/neutral/chunk-JY35S2CN.mjs +0 -27
  297. package/dist/lib/neutral/chunk-JY35S2CN.mjs.map +0 -7
  298. package/dist/lib/neutral/chunk-ZFABGG2E.mjs +0 -8
  299. package/dist/lib/neutral/chunk-ZFABGG2E.mjs.map +0 -7
  300. package/dist/lib/neutral/client-7I5Y5SOA.mjs +0 -62
  301. package/dist/lib/neutral/client-7I5Y5SOA.mjs.map +0 -7
  302. package/dist/lib/neutral/components/index.mjs +0 -1
  303. package/dist/lib/neutral/components/index.mjs.map +0 -7
  304. package/dist/lib/neutral/containers/index.mjs +0 -25
  305. package/dist/lib/neutral/containers/index.mjs.map +0 -7
  306. package/dist/lib/neutral/create-agent-6UKJMZS5.mjs +0 -26
  307. package/dist/lib/neutral/create-agent-6UKJMZS5.mjs.map +0 -7
  308. package/dist/lib/neutral/create-identity-ULCRB3YH.mjs +0 -42
  309. package/dist/lib/neutral/create-identity-ULCRB3YH.mjs.map +0 -7
  310. package/dist/lib/neutral/create-passkey-I7VDS3AC.mjs +0 -81
  311. package/dist/lib/neutral/create-passkey-I7VDS3AC.mjs.map +0 -7
  312. package/dist/lib/neutral/create-recovery-code-DH2B6EGP.mjs +0 -36
  313. package/dist/lib/neutral/create-recovery-code-DH2B6EGP.mjs.map +0 -7
  314. package/dist/lib/neutral/hub-http-client-WOJUCDKV.mjs +0 -19
  315. package/dist/lib/neutral/hub-http-client-WOJUCDKV.mjs.map +0 -7
  316. package/dist/lib/neutral/index.mjs +0 -25
  317. package/dist/lib/neutral/index.mjs.map +0 -7
  318. package/dist/lib/neutral/join-identity-PJCHDNLH.mjs +0 -27
  319. package/dist/lib/neutral/join-identity-PJCHDNLH.mjs.map +0 -7
  320. package/dist/lib/neutral/layer-specs-YI7BVWKZ.mjs +0 -59
  321. package/dist/lib/neutral/layer-specs-YI7BVWKZ.mjs.map +0 -7
  322. package/dist/lib/neutral/meta.json +0 -1
  323. package/dist/lib/neutral/meta.mjs +0 -8
  324. package/dist/lib/neutral/meta.mjs.map +0 -7
  325. package/dist/lib/neutral/migrations-7FTW55ER.mjs +0 -23
  326. package/dist/lib/neutral/migrations-7FTW55ER.mjs.map +0 -7
  327. package/dist/lib/neutral/navigation-handler-MQ6MZXLX.mjs +0 -46
  328. package/dist/lib/neutral/navigation-handler-MQ6MZXLX.mjs.map +0 -7
  329. package/dist/lib/neutral/open-usage-OJVTPGOY.mjs +0 -27
  330. package/dist/lib/neutral/open-usage-OJVTPGOY.mjs.map +0 -7
  331. package/dist/lib/neutral/operation-handler-E3HB7E2T.mjs +0 -13
  332. package/dist/lib/neutral/operation-handler-E3HB7E2T.mjs.map +0 -7
  333. package/dist/lib/neutral/operations/index.mjs +0 -12
  334. package/dist/lib/neutral/operations/index.mjs.map +0 -7
  335. package/dist/lib/neutral/plugin.mjs +0 -17
  336. package/dist/lib/neutral/plugin.mjs.map +0 -7
  337. package/dist/lib/neutral/react-context-V74T6JOJ.mjs +0 -23
  338. package/dist/lib/neutral/react-context-V74T6JOJ.mjs.map +0 -7
  339. package/dist/lib/neutral/react-surface-HPXRA65U.mjs +0 -75
  340. package/dist/lib/neutral/react-surface-HPXRA65U.mjs.map +0 -7
  341. package/dist/lib/neutral/recover-identity-B7YM2BR4.mjs +0 -26
  342. package/dist/lib/neutral/recover-identity-B7YM2BR4.mjs.map +0 -7
  343. package/dist/lib/neutral/redeem-passkey-TYP4XLHO.mjs +0 -66
  344. package/dist/lib/neutral/redeem-passkey-TYP4XLHO.mjs.map +0 -7
  345. package/dist/lib/neutral/redeem-token-2J33R3PV.mjs +0 -29
  346. package/dist/lib/neutral/redeem-token-2J33R3PV.mjs.map +0 -7
  347. package/dist/lib/neutral/reset-storage-K47HZTGP.mjs +0 -26
  348. package/dist/lib/neutral/reset-storage-K47HZTGP.mjs.map +0 -7
  349. package/dist/lib/neutral/schema-defs-IHBCKTMM.mjs +0 -51
  350. package/dist/lib/neutral/schema-defs-IHBCKTMM.mjs.map +0 -7
  351. package/dist/lib/neutral/share-identity-TOROBLWL.mjs +0 -31
  352. package/dist/lib/neutral/share-identity-TOROBLWL.mjs.map +0 -7
  353. package/dist/lib/neutral/testing/index.mjs +0 -25
  354. package/dist/lib/neutral/testing/index.mjs.map +0 -7
  355. package/dist/lib/neutral/translations.mjs +0 -124
  356. package/dist/lib/neutral/translations.mjs.map +0 -7
  357. package/dist/lib/neutral/types/index.mjs +0 -16
  358. package/dist/lib/neutral/types/index.mjs.map +0 -7
@@ -0,0 +1,145 @@
1
+ import { hexToEmoji, hexToHue } from "@dxos/util";
2
+ import * as Schema from "effect/Schema";
3
+ import { meta } from "#meta";
4
+ import { ClientOperation } from "#operations";
5
+ import { useCallback, useMemo, useState } from "react";
6
+ import { useOperationInvoker } from "@dxos/app-framework/ui";
7
+ import { useIdentity } from "@dxos/halo-react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { ButtonGroup, Clipboard, Input, useTranslation } from "@dxos/react-ui";
10
+ import { Form } from "@dxos/react-ui-form";
11
+ import { debounce } from "@dxos/async";
12
+ import { EmojiPickerBlock, HuePicker } from "@dxos/react-ui-pickers";
13
+ //#region src/containers/ProfileContainer/ProfileContainer.tsx
14
+ var UserProfile = Schema.Struct({
15
+ did: Schema.String.annotations({ title: "DID" }),
16
+ displayName: Schema.String.annotations({ title: "Display name" }),
17
+ emoji: Schema.String.annotations({ title: "Avatar" }),
18
+ hue: Schema.String.annotations({ title: "Color" })
19
+ });
20
+ var getDefaultHueValue = (identity) => hexToHue(identity?.identityKey ?? "0");
21
+ var getHueValue = (identity) => identity?.data?.hue || getDefaultHueValue(identity);
22
+ var getDefaultEmojiValue = (identity) => hexToEmoji(identity?.identityKey ?? "0");
23
+ var getEmojiValue = (identity) => identity?.data?.emoji || getDefaultEmojiValue(identity);
24
+ var ProfileContainer = () => {
25
+ const { t } = useTranslation(meta.profile.key);
26
+ const { invokePromise } = useOperationInvoker();
27
+ const identity = useIdentity();
28
+ const [displayName, setDisplayNameDirectly] = useState(identity?.displayName ?? "");
29
+ const [emoji, setEmojiDirectly] = useState(getEmojiValue(identity));
30
+ const [hue, setHueDirectly] = useState(getHueValue(identity));
31
+ const updateProfile = useMemo(() => debounce((profile, currentData) => invokePromise(ClientOperation.UpdateProfile, {
32
+ displayName: profile.displayName,
33
+ data: {
34
+ ...currentData,
35
+ emoji: profile.emoji,
36
+ hue: profile.hue
37
+ }
38
+ }), 2e3), [invokePromise]);
39
+ const handleChange = useCallback((profile, meta) => {
40
+ for (const [path, changed] of Object.entries(meta.changed)) if (changed) switch (path) {
41
+ case "displayName":
42
+ setDisplayNameDirectly(profile.displayName ?? "");
43
+ break;
44
+ case "emoji":
45
+ setEmojiDirectly(profile.emoji ?? getDefaultEmojiValue(identity));
46
+ break;
47
+ case "hue":
48
+ setHueDirectly(profile.hue ?? getDefaultHueValue(identity));
49
+ break;
50
+ default: break;
51
+ }
52
+ updateProfile(profile, identity?.data);
53
+ }, [identity, updateProfile]);
54
+ const values = useMemo(() => ({
55
+ did: identity?.did,
56
+ displayName,
57
+ emoji,
58
+ hue
59
+ }), [
60
+ identity,
61
+ displayName,
62
+ emoji,
63
+ hue
64
+ ]);
65
+ const fieldMap = useMemo(() => ({
66
+ displayName: ({ type, label, getValue, onValueChange }) => {
67
+ const handleChange = useCallback(({ target: { value } }) => onValueChange(type, value), [onValueChange, type]);
68
+ return /* @__PURE__ */ jsx(Form.Row, {
69
+ label,
70
+ description: t("display-name.description"),
71
+ children: /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsx(Input.TextInput, {
72
+ value: getValue(),
73
+ onChange: handleChange,
74
+ placeholder: t("display-name-input.placeholder"),
75
+ classNames: "min-w-64"
76
+ }) })
77
+ });
78
+ },
79
+ emoji: ({ type, label, getValue, onValueChange }) => {
80
+ const handleChange = useCallback((nextEmoji) => onValueChange(type, nextEmoji), [onValueChange, type]);
81
+ const handleEmojiReset = useCallback(() => onValueChange(type, getDefaultEmojiValue(identity)), [onValueChange, type]);
82
+ return /* @__PURE__ */ jsx(Form.Row, {
83
+ label,
84
+ description: t("icon.description"),
85
+ children: /* @__PURE__ */ jsx(EmojiPickerBlock, {
86
+ triggerVariant: "default",
87
+ emoji: getValue(),
88
+ onChangeEmoji: handleChange,
89
+ onClickClear: handleEmojiReset,
90
+ classNames: "justify-self-end"
91
+ })
92
+ });
93
+ },
94
+ hue: ({ type, label, getValue, onValueChange }) => {
95
+ const handleChange = useCallback((nextHue) => onValueChange(type, nextHue), [onValueChange, type]);
96
+ const handleHueReset = useCallback(() => onValueChange(type, getDefaultHueValue(identity)), [onValueChange, type]);
97
+ return /* @__PURE__ */ jsx(Form.Row, {
98
+ label,
99
+ description: t("hue.description"),
100
+ children: /* @__PURE__ */ jsx("div", {
101
+ className: "flex justify-self-end",
102
+ children: /* @__PURE__ */ jsx(HuePicker, {
103
+ value: getValue(),
104
+ onChange: handleChange,
105
+ onReset: handleHueReset
106
+ })
107
+ })
108
+ });
109
+ },
110
+ did: ({ label, getValue }) => {
111
+ return /* @__PURE__ */ jsx(Form.Row, {
112
+ label,
113
+ description: t("did.description"),
114
+ children: /* @__PURE__ */ jsx(Input.Root, { children: /* @__PURE__ */ jsxs(ButtonGroup, {
115
+ classNames: "w-full",
116
+ children: [/* @__PURE__ */ jsx(Input.TextInput, {
117
+ value: getValue(),
118
+ disabled: true,
119
+ classNames: "min-w-64"
120
+ }), /* @__PURE__ */ jsx(Clipboard.IconButton, { value: getValue() ?? "" })]
121
+ }) })
122
+ });
123
+ }
124
+ }), [t]);
125
+ return /* @__PURE__ */ jsx(Clipboard.Provider, { children: /* @__PURE__ */ jsx(Form.Root, {
126
+ variant: "settings",
127
+ schema: UserProfile,
128
+ values,
129
+ fieldMap,
130
+ onValuesChanged: handleChange,
131
+ children: /* @__PURE__ */ jsx(Form.Viewport, {
132
+ scroll: true,
133
+ children: /* @__PURE__ */ jsx(Form.Content, { children: /* @__PURE__ */ jsx(Form.Section, {
134
+ title: t("profile.label"),
135
+ description: t("profile.description"),
136
+ children: /* @__PURE__ */ jsx(Form.FieldSet, {})
137
+ }) })
138
+ })
139
+ }) });
140
+ };
141
+ ProfileContainer.displayName = "ProfileContainer";
142
+ //#endregion
143
+ export { ProfileContainer as default };
144
+
145
+ //# sourceMappingURL=chunk-ProfileContainer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-ProfileContainer.mjs","names":[],"sources":["../../src/containers/ProfileContainer/ProfileContainer.tsx"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\nimport React, { type ChangeEvent, useCallback, useMemo, useState } from 'react';\n\nimport { useOperationInvoker } from '@dxos/app-framework/ui';\nimport { debounce } from '@dxos/async';\nimport { type Identity } from '@dxos/halo';\nimport { useIdentity } from '@dxos/halo-react';\nimport { ButtonGroup, Clipboard, Input, useTranslation } from '@dxos/react-ui';\nimport { Form, type FormFieldMap, type FormUpdateMeta } from '@dxos/react-ui-form';\nimport { EmojiPickerBlock, HuePicker } from '@dxos/react-ui-pickers';\nimport { hexToEmoji, hexToHue } from '@dxos/util';\n\nimport { meta } from '#meta';\nimport { ClientOperation } from '#operations';\n\n// TOOD(burdon): Factor out?\n// TODO(wittjosiah): Integrate annotations with translations.\nconst UserProfile = Schema.Struct({\n did: Schema.String.annotations({ title: 'DID' }),\n displayName: Schema.String.annotations({ title: 'Display name' }),\n emoji: Schema.String.annotations({ title: 'Avatar' }),\n hue: Schema.String.annotations({ title: 'Color' }),\n});\n\ntype UserProfile = Schema.Schema.Type<typeof UserProfile>;\n\n// TODO(thure): Factor out?\nconst getDefaultHueValue = (identity?: Identity.Info): string => hexToHue(identity?.identityKey ?? '0');\nconst getHueValue = (identity?: Identity.Info): string => identity?.data?.hue || getDefaultHueValue(identity);\nconst getDefaultEmojiValue = (identity?: Identity.Info): string => hexToEmoji(identity?.identityKey ?? '0');\nconst getEmojiValue = (identity?: Identity.Info): string => identity?.data?.emoji || getDefaultEmojiValue(identity);\n\nexport const ProfileContainer = () => {\n const { t } = useTranslation(meta.profile.key);\n const { invokePromise } = useOperationInvoker();\n const identity = useIdentity();\n const [displayName, setDisplayNameDirectly] = useState(identity?.displayName ?? '');\n const [emoji, setEmojiDirectly] = useState<string>(getEmojiValue(identity));\n const [hue, setHueDirectly] = useState<string>(getHueValue(identity));\n\n const updateProfile = useMemo(\n () =>\n debounce(\n // Merge onto the current profile data so unrelated metadata is preserved.\n (profile: Partial<UserProfile>, currentData?: Record<string, unknown>) =>\n invokePromise(ClientOperation.UpdateProfile, {\n displayName: profile.displayName,\n data: {\n ...currentData,\n emoji: profile.emoji,\n hue: profile.hue,\n },\n }),\n 2_000,\n ),\n [invokePromise],\n );\n\n const handleChange = useCallback(\n (profile: Partial<UserProfile>, meta: FormUpdateMeta<UserProfile>) => {\n for (const [path, changed] of Object.entries(meta.changed)) {\n if (changed) {\n switch (path) {\n case 'displayName':\n setDisplayNameDirectly(profile.displayName ?? '');\n break;\n case 'emoji':\n setEmojiDirectly(profile.emoji ?? getDefaultEmojiValue(identity));\n break;\n case 'hue':\n setHueDirectly(profile.hue ?? getDefaultHueValue(identity));\n break;\n default:\n break;\n }\n }\n }\n\n void updateProfile(profile, identity?.data);\n },\n [identity, updateProfile],\n );\n\n const values = useMemo(\n () => ({\n did: identity?.did,\n displayName,\n emoji,\n hue,\n }),\n [identity, displayName, emoji, hue],\n );\n\n // TODO(wittjosiah): Integrate descriptions with the form schema.\n const fieldMap = useMemo<FormFieldMap>(\n () => ({\n displayName: ({ type, label, getValue, onValueChange }) => {\n const handleChange = useCallback(\n ({ target: { value } }: ChangeEvent<HTMLInputElement>) => onValueChange(type, value),\n [onValueChange, type],\n );\n\n return (\n <Form.Row label={label} description={t('display-name.description')}>\n <Input.Root>\n <Input.TextInput\n value={getValue()}\n onChange={handleChange}\n placeholder={t('display-name-input.placeholder')}\n classNames='min-w-64'\n />\n </Input.Root>\n </Form.Row>\n );\n },\n emoji: ({ type, label, getValue, onValueChange }) => {\n const handleChange = useCallback((nextEmoji: string) => onValueChange(type, nextEmoji), [onValueChange, type]);\n const handleEmojiReset = useCallback(\n () => onValueChange(type, getDefaultEmojiValue(identity)),\n [onValueChange, type],\n );\n\n return (\n <Form.Row label={label} description={t('icon.description')}>\n <EmojiPickerBlock\n triggerVariant='default'\n emoji={getValue()}\n onChangeEmoji={handleChange}\n onClickClear={handleEmojiReset}\n classNames='justify-self-end'\n />\n </Form.Row>\n );\n },\n hue: ({ type, label, getValue, onValueChange }) => {\n const handleChange = useCallback((nextHue: string) => onValueChange(type, nextHue), [onValueChange, type]);\n const handleHueReset = useCallback(\n () => onValueChange(type, getDefaultHueValue(identity)),\n [onValueChange, type],\n );\n\n return (\n <Form.Row label={label} description={t('hue.description')}>\n <div className='flex justify-self-end'>\n <HuePicker value={getValue()} onChange={handleChange} onReset={handleHueReset} />\n </div>\n </Form.Row>\n );\n },\n // TODO(wittjosiah): We need text input annotations for disabled and copyable.\n did: ({ label, getValue }) => {\n return (\n <Form.Row label={label} description={t('did.description')}>\n <Input.Root>\n <ButtonGroup classNames='w-full'>\n <Input.TextInput value={getValue()} disabled classNames='min-w-64' />\n <Clipboard.IconButton value={getValue() ?? ''} />\n </ButtonGroup>\n </Input.Root>\n </Form.Row>\n );\n },\n }),\n [t],\n );\n\n return (\n <Clipboard.Provider>\n <Form.Root\n variant='settings'\n schema={UserProfile}\n values={values}\n fieldMap={fieldMap}\n onValuesChanged={handleChange}\n >\n <Form.Viewport scroll>\n <Form.Content>\n <Form.Section title={t('profile.label')} description={t('profile.description')}>\n <Form.FieldSet />\n </Form.Section>\n </Form.Content>\n </Form.Viewport>\n </Form.Root>\n </Clipboard.Provider>\n );\n};\n\nProfileContainer.displayName = 'ProfileContainer';\n"],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import { meta } from "#meta";
2
+ import { useCallback, useState } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { AlertDialog, Button, Clipboard, Input, useTranslation } from "@dxos/react-ui";
5
+ //#region src/containers/RecoveryCodeDialog/RecoveryCodeDialog.tsx
6
+ var RecoveryCodeDialog = ({ code }) => {
7
+ const { t } = useTranslation(meta.profile.key);
8
+ const [confirmation, setConfirmation] = useState(false);
9
+ const handleConfirmation = useCallback((checked) => setConfirmation(checked), []);
10
+ return /* @__PURE__ */ jsxs(AlertDialog.Content, {
11
+ size: "md",
12
+ classNames: "min-h-[15rem]",
13
+ children: [/* @__PURE__ */ jsxs(AlertDialog.Body, { children: [
14
+ /* @__PURE__ */ jsx(AlertDialog.Title, { children: t("recovery-code-dialog.title") }),
15
+ /* @__PURE__ */ jsx(AlertDialog.Description, {
16
+ classNames: "py-4",
17
+ children: t("recovery-code-dialog.description")
18
+ }),
19
+ /* @__PURE__ */ jsx(Clipboard.Provider, { children: /* @__PURE__ */ jsx(Code, { code }) }),
20
+ /* @__PURE__ */ jsxs("div", {
21
+ className: "flex flex-col py-4 gap-2",
22
+ children: [/* @__PURE__ */ jsx("p", { children: t("recovery-code-dialog-warning-1.message") }), /* @__PURE__ */ jsx("p", { children: t("recovery-code-dialog-warning-2.message") })]
23
+ }),
24
+ /* @__PURE__ */ jsx("div", {
25
+ className: "flex items-center gap-2 pb-4",
26
+ children: /* @__PURE__ */ jsxs(Input.Root, { children: [/* @__PURE__ */ jsx(Input.Checkbox, {
27
+ "data-testid": "recoveryCode.confirm",
28
+ checked: confirmation,
29
+ onCheckedChange: handleConfirmation
30
+ }), /* @__PURE__ */ jsx(Input.Label, { children: t("recovery-code-confirmation.label") })] })
31
+ })
32
+ ] }), /* @__PURE__ */ jsx(AlertDialog.ActionBar, { children: /* @__PURE__ */ jsx(AlertDialog.Action, {
33
+ asChild: true,
34
+ children: /* @__PURE__ */ jsx(Button, {
35
+ "data-testid": "recoveryCode.continue",
36
+ variant: "primary",
37
+ disabled: !confirmation,
38
+ children: t("continue.label")
39
+ })
40
+ }) })]
41
+ });
42
+ };
43
+ var Code = ({ code }) => {
44
+ const words = code.split(" ");
45
+ return /* @__PURE__ */ jsxs("div", {
46
+ className: "relative p-2 border border-separator rounded-sm group",
47
+ children: [/* @__PURE__ */ jsx(Clipboard.IconButton, {
48
+ value: code,
49
+ classNames: "absolute top-2 right-2 invisible group-hover:visible"
50
+ }), /* @__PURE__ */ jsx("div", {
51
+ className: "grid grid-cols-4",
52
+ children: words.map((word, i) => /* @__PURE__ */ jsxs("div", {
53
+ className: "flex items-center p-2 gap-2",
54
+ children: [/* @__PURE__ */ jsx("div", {
55
+ className: "w-4 text-xs text-center text-subdued",
56
+ children: i + 1
57
+ }), /* @__PURE__ */ jsx("div", {
58
+ className: "text-sm",
59
+ children: word
60
+ })]
61
+ }, i))
62
+ })]
63
+ });
64
+ };
65
+ RecoveryCodeDialog.displayName = "RecoveryCodeDialog";
66
+ //#endregion
67
+ //#region src/containers/RecoveryCodeDialog/index.ts
68
+ var RecoveryCodeDialog_default = RecoveryCodeDialog;
69
+ //#endregion
70
+ export { RecoveryCodeDialog, RecoveryCodeDialog_default as default };
71
+
72
+ //# sourceMappingURL=chunk-RecoveryCodeDialog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-RecoveryCodeDialog.mjs","names":[],"sources":["../../src/containers/RecoveryCodeDialog/RecoveryCodeDialog.tsx","../../src/containers/RecoveryCodeDialog/index.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { useCallback, useState } from 'react';\n\nimport { AlertDialog, Button, Clipboard, Input, useTranslation } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\n\nexport type RecoveryCodeDialogProps = {\n code: string;\n};\n\n// TODO(burdon): Should have cancel button.\nexport const RecoveryCodeDialog = ({ code }: RecoveryCodeDialogProps) => {\n const { t } = useTranslation(meta.profile.key);\n const [confirmation, setConfirmation] = useState(false);\n\n const handleConfirmation = useCallback((checked: boolean) => setConfirmation(checked), []);\n\n return (\n <AlertDialog.Content size='md' classNames='min-h-[15rem]'>\n <AlertDialog.Body>\n <AlertDialog.Title>{t('recovery-code-dialog.title')}</AlertDialog.Title>\n <AlertDialog.Description classNames='py-4'>{t('recovery-code-dialog.description')}</AlertDialog.Description>\n <Clipboard.Provider>\n <Code code={code} />\n </Clipboard.Provider>\n <div className='flex flex-col py-4 gap-2'>\n <p>{t('recovery-code-dialog-warning-1.message')}</p>\n <p>{t('recovery-code-dialog-warning-2.message')}</p>\n </div>\n <div className='flex items-center gap-2 pb-4'>\n <Input.Root>\n <Input.Checkbox\n data-testid='recoveryCode.confirm'\n checked={confirmation}\n onCheckedChange={handleConfirmation}\n />\n <Input.Label>{t('recovery-code-confirmation.label')}</Input.Label>\n </Input.Root>\n </div>\n </AlertDialog.Body>\n <AlertDialog.ActionBar>\n <AlertDialog.Action asChild>\n <Button data-testid='recoveryCode.continue' variant='primary' disabled={!confirmation}>\n {t('continue.label')}\n </Button>\n </AlertDialog.Action>\n </AlertDialog.ActionBar>\n </AlertDialog.Content>\n );\n};\n\nconst Code = ({ code }: { code: string }) => {\n const words = code.split(' ');\n return (\n <div className='relative p-2 border border-separator rounded-sm group'>\n <Clipboard.IconButton value={code} classNames='absolute top-2 right-2 invisible group-hover:visible' />\n <div className='grid grid-cols-4'>\n {words.map((word, i) => (\n <div key={i} className='flex items-center p-2 gap-2'>\n <div className='w-4 text-xs text-center text-subdued'>{i + 1}</div>\n <div className='text-sm'>{word}</div>\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nRecoveryCodeDialog.displayName = 'RecoveryCodeDialog';\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { RecoveryCodeDialog } from './RecoveryCodeDialog';\n\nexport * from './RecoveryCodeDialog';\nexport default RecoveryCodeDialog;\n"],"mappings":";;;;;AAeA,IAAa,sBAAsB,EAAE,WAAoC;CACvE,MAAM,EAAE,MAAM,eAAe,KAAK,QAAQ,GAAG;CAC7C,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CAEtD,MAAM,qBAAqB,aAAa,YAAqB,gBAAgB,OAAO,GAAG,CAAC,CAAC;CAEzF,OACE,qBAAC,YAAY,SAAb;EAAqB,MAAK;EAAK,YAAW;YAA1C,CACE,qBAAC,YAAY,MAAb,EAAA,UAAA;GACE,oBAAC,YAAY,OAAb,EAAA,UAAoB,EAAE,4BAA4B,EAAqB,CAAA;GACvE,oBAAC,YAAY,aAAb;IAAyB,YAAW;cAAQ,EAAE,kCAAkC;GAA2B,CAAA;GAC3G,oBAAC,UAAU,UAAX,EAAA,UACE,oBAAC,MAAD,EAAY,KAAO,CAAA,EACD,CAAA;GACpB,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,KAAD,EAAA,UAAI,EAAE,wCAAwC,EAAK,CAAA,GACnD,oBAAC,KAAD,EAAA,UAAI,EAAE,wCAAwC,EAAK,CAAA,CAChD;;GACL,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,MAAM,MAAP,EAAA,UAAA,CACE,oBAAC,MAAM,UAAP;KACE,eAAY;KACZ,SAAS;KACT,iBAAiB;IAClB,CAAA,GACD,oBAAC,MAAM,OAAP,EAAA,UAAc,EAAE,kCAAkC,EAAe,CAAA,CACvD,EAAA,CAAA;GACT,CAAA;EACW,EAAA,CAAA,GAClB,oBAAC,YAAY,WAAb,EAAA,UACE,oBAAC,YAAY,QAAb;GAAoB,SAAA;aAClB,oBAAC,QAAD;IAAQ,eAAY;IAAwB,SAAQ;IAAU,UAAU,CAAC;cACtE,EAAE,gBAAgB;GACb,CAAA;EACU,CAAA,EACC,CAAA,CACJ;;AAEzB;AAEA,IAAM,QAAQ,EAAE,WAA6B;CAC3C,MAAM,QAAQ,KAAK,MAAM,GAAG;CAC5B,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,UAAU,YAAX;GAAsB,OAAO;GAAM,YAAW;EAAwD,CAAA,GACtG,oBAAC,OAAD;GAAK,WAAU;aACZ,MAAM,KAAK,MAAM,MAChB,qBAAC,OAAD;IAAa,WAAU;cAAvB,CACE,oBAAC,OAAD;KAAK,WAAU;eAAwC,IAAI;IAAO,CAAA,GAClE,oBAAC,OAAD;KAAK,WAAU;eAAW;IAAU,CAAA,CACjC;MAHK,CAGL,CACN;EACE,CAAA,CACF;;AAET;AAEA,mBAAmB,cAAc;;;ACjEjC,IAAA,6BAAe"}
@@ -0,0 +1,65 @@
1
+ import { meta } from "#meta";
2
+ import { ClientOperation } from "#operations";
3
+ import "react";
4
+ import { useOperationInvoker } from "@dxos/app-framework/ui";
5
+ import { useCredentials } from "@dxos/halo-react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { Icon, IconButton, Message, useTranslation } from "@dxos/react-ui";
8
+ import { Form } from "@dxos/react-ui-form";
9
+ import { Listbox } from "@dxos/react-ui-list";
10
+ `${meta.profile.key}`;
11
+ var RecoveryCredentialsContainer = () => {
12
+ const { t } = useTranslation(meta.profile.key);
13
+ const { invokePromise } = useOperationInvoker();
14
+ const recoveryCredentials = useCredentials().filter((credential) => credential.type === "dxos.halo.credentials.IdentityRecovery");
15
+ return /* @__PURE__ */ jsx(Form.Root, {
16
+ variant: "settings",
17
+ children: /* @__PURE__ */ jsx(Form.Viewport, {
18
+ scroll: true,
19
+ children: /* @__PURE__ */ jsxs(Form.Content, { children: [/* @__PURE__ */ jsxs(Form.Section, {
20
+ title: t("recovery-setup-dialog.title"),
21
+ description: t("recovery-setup-dialog.description"),
22
+ children: [/* @__PURE__ */ jsx(Form.Row, {
23
+ label: t("create-passkey.label"),
24
+ description: t("create-passkey.description"),
25
+ children: /* @__PURE__ */ jsx(IconButton, {
26
+ label: t("create-passkey.label"),
27
+ icon: "ph--key--duotone",
28
+ variant: "primary",
29
+ onClick: () => invokePromise(ClientOperation.CreatePasskey)
30
+ })
31
+ }), /* @__PURE__ */ jsx(Form.Row, {
32
+ label: t("create-recovery-code.label"),
33
+ description: t("create-recovery-code.description"),
34
+ children: /* @__PURE__ */ jsx(IconButton, {
35
+ label: t("create-recovery-code.label"),
36
+ icon: "ph--receipt--duotone",
37
+ variant: "default",
38
+ onClick: () => invokePromise(ClientOperation.CreateRecoveryCode)
39
+ })
40
+ })]
41
+ }), /* @__PURE__ */ jsx(Form.Section, {
42
+ title: t("credentials-list.label"),
43
+ children: recoveryCredentials.length < 1 ? /* @__PURE__ */ jsxs(Message.Root, {
44
+ valence: "error",
45
+ children: [/* @__PURE__ */ jsx(Message.Title, {
46
+ icon: "ph--shield-warning--duotone",
47
+ children: t("no-credentials.title")
48
+ }), /* @__PURE__ */ jsx(Message.Body, { children: t("no-credentials.message") })]
49
+ }) : /* @__PURE__ */ jsx(Listbox.Root, { children: /* @__PURE__ */ jsx(Listbox.Content, {
50
+ classNames: "gap-1",
51
+ children: recoveryCredentials.map((credential, index) => /* @__PURE__ */ jsxs(Listbox.Item, {
52
+ id: credential.id ?? `${index}`,
53
+ classNames: "gap-2",
54
+ children: [/* @__PURE__ */ jsx(Icon, { icon: "ph--key--regular" }), /* @__PURE__ */ jsx(Listbox.ItemLabel, { children: credential.issuanceDate?.toLocaleString() })]
55
+ }, credential.id ?? index))
56
+ }) })
57
+ })] })
58
+ })
59
+ });
60
+ };
61
+ RecoveryCredentialsContainer.displayName = "RecoveryCredentialsContainer";
62
+ //#endregion
63
+ export { RecoveryCredentialsContainer as default };
64
+
65
+ //# sourceMappingURL=chunk-RecoveryCredentialsContainer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-RecoveryCredentialsContainer.mjs","names":[],"sources":["../../src/containers/RecoveryCredentialsContainer/RecoveryCredentialsContainer.tsx"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useOperationInvoker } from '@dxos/app-framework/ui';\nimport { useCredentials } from '@dxos/halo-react';\nimport { Icon, IconButton, Message, useTranslation } from '@dxos/react-ui';\nimport { Form } from '@dxos/react-ui-form';\nimport { Listbox } from '@dxos/react-ui-list';\n\nimport { meta } from '#meta';\nimport { ClientOperation } from '#operations';\n\nexport const MANAGE_CREDENTIALS_DIALOG = `${meta.profile.key}.ManageCredentialsDialog`;\n\nexport const RecoveryCredentialsContainer = () => {\n const { t } = useTranslation(meta.profile.key);\n const { invokePromise } = useOperationInvoker();\n const credentials = useCredentials();\n const recoveryCredentials = credentials.filter(\n (credential) => credential.type === 'dxos.halo.credentials.IdentityRecovery',\n );\n\n return (\n <Form.Root variant='settings'>\n <Form.Viewport scroll>\n <Form.Content>\n <Form.Section title={t('recovery-setup-dialog.title')} description={t('recovery-setup-dialog.description')}>\n <Form.Row label={t('create-passkey.label')} description={t('create-passkey.description')}>\n <IconButton\n label={t('create-passkey.label')}\n icon='ph--key--duotone'\n variant='primary'\n onClick={() => invokePromise(ClientOperation.CreatePasskey)}\n />\n </Form.Row>\n <Form.Row label={t('create-recovery-code.label')} description={t('create-recovery-code.description')}>\n <IconButton\n label={t('create-recovery-code.label')}\n icon='ph--receipt--duotone'\n variant='default'\n onClick={() => invokePromise(ClientOperation.CreateRecoveryCode)}\n />\n </Form.Row>\n </Form.Section>\n <Form.Section title={t('credentials-list.label')}>\n {recoveryCredentials.length < 1 ? (\n <Message.Root valence='error'>\n <Message.Title icon='ph--shield-warning--duotone'>{t('no-credentials.title')}</Message.Title>\n <Message.Body>{t('no-credentials.message')}</Message.Body>\n </Message.Root>\n ) : (\n <Listbox.Root>\n <Listbox.Content classNames='gap-1'>\n {recoveryCredentials.map((credential, index) => (\n <Listbox.Item key={credential.id ?? index} id={credential.id ?? `${index}`} classNames='gap-2'>\n <Icon icon='ph--key--regular' />\n <Listbox.ItemLabel>{credential.issuanceDate?.toLocaleString()}</Listbox.ItemLabel>\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n )}\n </Form.Section>\n </Form.Content>\n </Form.Viewport>\n </Form.Root>\n );\n};\n\nRecoveryCredentialsContainer.displayName = 'RecoveryCredentialsContainer';\n"],"mappings":";;;;;;;;;AAeyC,GAAG,KAAK,QAAQ,IAAhB;AAEzC,IAAa,qCAAqC;CAChD,MAAM,EAAE,MAAM,eAAe,KAAK,QAAQ,GAAG;CAC7C,MAAM,EAAE,kBAAkB,oBAAoB;CAE9C,MAAM,sBADc,eACQ,CAAA,CAAY,QACrC,eAAe,WAAW,SAAS,wCACtC;CAEA,OACE,oBAAC,KAAK,MAAN;EAAW,SAAQ;YACjB,oBAAC,KAAK,UAAN;GAAe,QAAA;aACb,qBAAC,KAAK,SAAN,EAAA,UAAA,CACE,qBAAC,KAAK,SAAN;IAAc,OAAO,EAAE,6BAA6B;IAAG,aAAa,EAAE,mCAAmC;cAAzG,CACE,oBAAC,KAAK,KAAN;KAAU,OAAO,EAAE,sBAAsB;KAAG,aAAa,EAAE,4BAA4B;eACrF,oBAAC,YAAD;MACE,OAAO,EAAE,sBAAsB;MAC/B,MAAK;MACL,SAAQ;MACR,eAAe,cAAc,gBAAgB,aAAa;KAC3D,CAAA;IACO,CAAA,GACV,oBAAC,KAAK,KAAN;KAAU,OAAO,EAAE,4BAA4B;KAAG,aAAa,EAAE,kCAAkC;eACjG,oBAAC,YAAD;MACE,OAAO,EAAE,4BAA4B;MACrC,MAAK;MACL,SAAQ;MACR,eAAe,cAAc,gBAAgB,kBAAkB;KAChE,CAAA;IACO,CAAA,CACE;OACd,oBAAC,KAAK,SAAN;IAAc,OAAO,EAAE,wBAAwB;cAC5C,oBAAoB,SAAS,IAC5B,qBAAC,QAAQ,MAAT;KAAc,SAAQ;eAAtB,CACE,oBAAC,QAAQ,OAAT;MAAe,MAAK;gBAA+B,EAAE,sBAAsB;KAAiB,CAAA,GAC5F,oBAAC,QAAQ,MAAT,EAAA,UAAe,EAAE,wBAAwB,EAAgB,CAAA,CAC7C;SAEd,oBAAC,QAAQ,MAAT,EAAA,UACE,oBAAC,QAAQ,SAAT;KAAiB,YAAW;eACzB,oBAAoB,KAAK,YAAY,UACpC,qBAAC,QAAQ,MAAT;MAA2C,IAAI,WAAW,MAAM,GAAG;MAAS,YAAW;gBAAvF,CACE,oBAAC,MAAD,EAAM,MAAK,mBAAoB,CAAA,GAC/B,oBAAC,QAAQ,WAAT,EAAA,UAAoB,WAAW,cAAc,eAAe,EAAqB,CAAA,CACrE;QAHK,WAAW,MAAM,KAGtB,CACf;IACc,CAAA,EACL,CAAA;GAEJ,CAAA,CACF,EAAA,CAAA;EACD,CAAA;CACN,CAAA;AAEf;AAEA,6BAA6B,cAAc"}
@@ -0,0 +1,47 @@
1
+ import { Capability } from "@dxos/app-framework";
2
+ import { LayoutOperation } from "@dxos/app-toolkit";
3
+ import * as Effect from "effect/Effect";
4
+ import { useCallback } from "react";
5
+ import { ConfirmReset, translationKey } from "@dxos/shell/react";
6
+ import { EffectEx } from "@dxos/effect";
7
+ import { useOperationInvoker } from "@dxos/app-framework/ui";
8
+ import { useClient } from "@dxos/react-client";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { Dialog, useTranslation } from "@dxos/react-ui";
11
+ //#region src/containers/ResetDialog/ResetDialog.tsx
12
+ var ResetDialog = ({ mode, onReset, onBeforeReset, capabilityManager }) => {
13
+ const { t } = useTranslation(translationKey);
14
+ const { invokePromise } = useOperationInvoker();
15
+ const client = useClient();
16
+ const handleReset = useCallback(async () => {
17
+ if (onBeforeReset) await onBeforeReset();
18
+ await client.reset();
19
+ const target = mode === "join-new-identity" ? "deviceInvitation" : mode === "recover" ? "recoverIdentity" : void 0;
20
+ if (onReset) await EffectEx.runAndForwardErrors(onReset({ target }).pipe(Effect.provideService(Capability.Service, capabilityManager)));
21
+ }, [
22
+ client,
23
+ mode,
24
+ onReset,
25
+ capabilityManager
26
+ ]);
27
+ const handleCancel = useCallback(() => {
28
+ invokePromise(LayoutOperation.UpdateDialog, { state: false });
29
+ }, [invokePromise]);
30
+ return /* @__PURE__ */ jsxs(Dialog.Content, { children: [/* @__PURE__ */ jsx(Dialog.Header, { children: /* @__PURE__ */ jsx(Dialog.Title, { children: t("reset-dialog.title") }) }), /* @__PURE__ */ jsxs(Dialog.Body, { children: [/* @__PURE__ */ jsx(Dialog.Description, {
31
+ classNames: "sr-only",
32
+ children: t("reset-dialog.description")
33
+ }), /* @__PURE__ */ jsx(ConfirmReset, {
34
+ active: true,
35
+ mode,
36
+ onConfirm: handleReset,
37
+ onCancel: handleCancel
38
+ })] })] });
39
+ };
40
+ ResetDialog.displayName = "ResetDialog";
41
+ //#endregion
42
+ //#region src/containers/ResetDialog/index.ts
43
+ var ResetDialog_default = ResetDialog;
44
+ //#endregion
45
+ export { ResetDialog, ResetDialog_default as default };
46
+
47
+ //# sourceMappingURL=chunk-ResetDialog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-ResetDialog.mjs","names":[],"sources":["../../src/containers/ResetDialog/ResetDialog.tsx","../../src/containers/ResetDialog/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport React, { useCallback } from 'react';\n\nimport { Capability, type CapabilityManager } from '@dxos/app-framework';\nimport { useOperationInvoker } from '@dxos/app-framework/ui';\nimport { LayoutOperation } from '@dxos/app-toolkit';\nimport { EffectEx } from '@dxos/effect';\nimport { useClient } from '@dxos/react-client';\nimport { Dialog, useTranslation } from '@dxos/react-ui';\nimport { ConfirmReset, type ConfirmResetProps, translationKey } from '@dxos/shell/react';\n\nimport { type ClientPluginOptions } from '#types';\n\nexport type ResetDialogProps = Pick<ConfirmResetProps, 'mode'> &\n Pick<ClientPluginOptions, 'onReset'> & {\n capabilityManager: CapabilityManager.CapabilityManager;\n /**\n * Optional async action run before `client.reset()`. Throwing here aborts the\n * reset so callers can surface errors without wiping local state.\n */\n onBeforeReset?: () => Promise<void>;\n };\n\nexport const ResetDialog = ({ mode, onReset, onBeforeReset, capabilityManager }: ResetDialogProps) => {\n const { t } = useTranslation(translationKey);\n const { invokePromise } = useOperationInvoker();\n const client = useClient();\n\n const handleReset = useCallback(async () => {\n if (onBeforeReset) {\n await onBeforeReset();\n }\n await client.reset();\n const target =\n mode === 'join-new-identity' ? 'deviceInvitation' : mode === 'recover' ? 'recoverIdentity' : undefined;\n if (onReset) {\n await EffectEx.runAndForwardErrors(\n onReset({ target }).pipe(Effect.provideService(Capability.Service, capabilityManager)),\n );\n }\n }, [client, mode, onReset, capabilityManager]);\n\n const handleCancel = useCallback(() => {\n void invokePromise(LayoutOperation.UpdateDialog, { state: false });\n }, [invokePromise]);\n\n return (\n <Dialog.Content>\n <Dialog.Header>\n <Dialog.Title>{t('reset-dialog.title')}</Dialog.Title>\n </Dialog.Header>\n <Dialog.Body>\n <Dialog.Description classNames='sr-only'>{t('reset-dialog.description')}</Dialog.Description>\n <ConfirmReset active mode={mode} onConfirm={handleReset} onCancel={handleCancel} />\n </Dialog.Body>\n </Dialog.Content>\n );\n};\n\nResetDialog.displayName = 'ResetDialog';\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { ResetDialog } from './ResetDialog';\n\nexport * from './ResetDialog';\nexport default ResetDialog;\n"],"mappings":";;;;;;;;;;;AA2BA,IAAa,eAAe,EAAE,MAAM,SAAS,eAAe,wBAA0C;CACpG,MAAM,EAAE,MAAM,eAAe,cAAc;CAC3C,MAAM,EAAE,kBAAkB,oBAAoB;CAC9C,MAAM,SAAS,UAAU;CAEzB,MAAM,cAAc,YAAY,YAAY;EAC1C,IAAI,eACF,MAAM,cAAc;EAEtB,MAAM,OAAO,MAAM;EACnB,MAAM,SACJ,SAAS,sBAAsB,qBAAqB,SAAS,YAAY,oBAAoB,KAAA;EAC/F,IAAI,SACF,MAAM,SAAS,oBACb,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,WAAW,SAAS,iBAAiB,CAAC,CACvF;CAEJ,GAAG;EAAC;EAAQ;EAAM;EAAS;CAAiB,CAAC;CAE7C,MAAM,eAAe,kBAAkB;EACrC,cAAmB,gBAAgB,cAAc,EAAE,OAAO,MAAM,CAAC;CACnE,GAAG,CAAC,aAAa,CAAC;CAElB,OACE,qBAAC,OAAO,SAAR,EAAA,UAAA,CACE,oBAAC,OAAO,QAAR,EAAA,UACE,oBAAC,OAAO,OAAR,EAAA,UAAe,EAAE,oBAAoB,EAAgB,CAAA,EACxC,CAAA,GACf,qBAAC,OAAO,MAAR,EAAA,UAAA,CACE,oBAAC,OAAO,aAAR;EAAoB,YAAW;YAAW,EAAE,0BAA0B;CAAsB,CAAA,GAC5F,oBAAC,cAAD;EAAc,QAAA;EAAa;EAAM,WAAW;EAAa,UAAU;CAAe,CAAA,CACvE,EAAA,CAAA,CACC,EAAA,CAAA;AAEpB;AAEA,YAAY,cAAc;;;ACxD1B,IAAA,sBAAe"}
@@ -0,0 +1,217 @@
1
+ import { t as useHubHttpClient } from "./chunk-hooks.mjs";
2
+ import * as Schema from "effect/Schema";
3
+ import { meta } from "#meta";
4
+ import { Context } from "@dxos/context";
5
+ import { log } from "@dxos/log";
6
+ import { useCallback, useMemo, useState } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { Message, Status, useAsyncEffect, useTranslation } from "@dxos/react-ui";
9
+ import { Form } from "@dxos/react-ui-form";
10
+ //#region src/containers/UsageContainer/UsageView.tsx
11
+ /**
12
+ * Whether a usage row falls under a limit. Subtype segments are matched positionally against
13
+ * `subtypePattern` where `*` matches any segment.
14
+ */
15
+ var usageMatchesLimit = (item, limit) => {
16
+ if (item.eventType !== limit.eventType || item.valueKey !== limit.valueKey) return false;
17
+ return limit.subtypePattern.every((pattern, index) => pattern === "*" || pattern === item.subtypePattern[index]);
18
+ };
19
+ /** Sum every usage item that falls under the limit. */
20
+ var sumUsageForLimit = (usage, limit) => usage.reduce((total, item) => usageMatchesLimit(item, limit) ? total + item.amount : total, 0);
21
+ /** Humanize a camelCase value key, e.g. `outputTokens` → `output tokens`. */
22
+ var formatValueKey = (valueKey) => valueKey.replace(/([A-Z])/g, " $1").trim().toLowerCase();
23
+ /**
24
+ * Human label for a limit: a scope followed by the value key, e.g.
25
+ * `{ eventType: 'ai', valueKey: 'outputTokens', subtypePattern: ['*'] }` → `All models · output tokens`,
26
+ * `{ eventType: 'ai', valueKey: 'inputTokens', subtypePattern: ['claude-opus-4'] }` → `claude-opus-4 · input tokens`.
27
+ */
28
+ var formatLimitLabel = (limit, t) => {
29
+ const metric = formatValueKey(limit.valueKey);
30
+ const subtype = limit.subtypePattern.filter((segment) => segment && segment !== "*").join("/");
31
+ if (limit.eventType === "ai") return `${subtype || t("usage-all-models.label")} · ${metric}`;
32
+ return `${subtype ? `${limit.eventType}/${subtype}` : limit.eventType} · ${metric}`;
33
+ };
34
+ var formatAmount = (amount) => amount.toLocaleString();
35
+ var SECONDS_PER_HOUR = 3600;
36
+ /** Render `windowHours` as a localized "N months / days / hours" string. */
37
+ var formatWindow = (windowHours, t) => {
38
+ if (windowHours % 720 === 0) return t("usage-window-months.label", { count: windowHours / 720 });
39
+ if (windowHours % 24 === 0) return t("usage-window-days.label", { count: windowHours / 24 });
40
+ return t("usage-window-hours.label", { count: windowHours });
41
+ };
42
+ /** One display row per limit, shorter windows first. A `null` limit is reported as unlimited. */
43
+ var computeRows = (data, t) => data.limits.map((limit) => {
44
+ const used = sumUsageForLimit(data.usage, limit);
45
+ const label = formatLimitLabel(limit, t);
46
+ const windowHours = limit.windowDuration / SECONDS_PER_HOUR;
47
+ const window = formatWindow(windowHours, t);
48
+ const key = `${limit.eventType}/${limit.subtypePattern.join(",")}/${limit.valueKey}/${limit.windowDuration}/${limit.limit ?? "unlimited"}`;
49
+ if (limit.limit === null) return {
50
+ key,
51
+ label,
52
+ caption: t("usage-unlimited.description", {
53
+ used: formatAmount(used),
54
+ window
55
+ }),
56
+ windowHours
57
+ };
58
+ const percent = limit.limit > 0 ? Math.min(100, Math.round(used / limit.limit * 100)) : used > 0 ? 100 : 0;
59
+ return {
60
+ key,
61
+ label,
62
+ caption: `${t("usage-percent-used.label", { percent })} · ${t("usage-limit.description", {
63
+ used: formatAmount(used),
64
+ limit: formatAmount(limit.limit),
65
+ window
66
+ })}`,
67
+ percent,
68
+ windowHours
69
+ };
70
+ }).sort((left, right) => left.windowHours - right.windowHours);
71
+ /**
72
+ * A single usage field: an optional number carrying its label/caption as `title`/`description`
73
+ * annotations and the consumption percentage as its value. Optional so the form renders no required
74
+ * markers; `Schema.Number` keeps the field context-free (`R = never`) so the struct stays assignable to `Form`.
75
+ */
76
+ var usageField = (title, description) => Schema.optional(Schema.Number.annotations({
77
+ title,
78
+ description
79
+ }));
80
+ /**
81
+ * Build the Effect schema (one annotated field per limit) and matching values. Unlimited limits have no
82
+ * value, so their field reads `undefined` and the renderer shows the "Unlimited" label instead of a meter.
83
+ */
84
+ var buildUsageForm = (rows) => {
85
+ const fields = {};
86
+ const values = {};
87
+ rows.forEach((row, index) => {
88
+ const field = `metric_${index}`;
89
+ fields[field] = usageField(row.label, row.caption);
90
+ if (row.percent !== void 0) values[field] = row.percent;
91
+ });
92
+ return {
93
+ schema: Schema.Struct(fields),
94
+ values
95
+ };
96
+ };
97
+ /** Non-data states shown as a single `Message`, keyed by message variant (translation keys for the copy). */
98
+ var STATE_MESSAGES = {
99
+ unavailable: {
100
+ valence: "warning",
101
+ icon: "ph--cloud-slash--duotone",
102
+ title: "usage-unavailable.title",
103
+ description: "usage-unavailable.description"
104
+ },
105
+ error: {
106
+ valence: "error",
107
+ icon: "ph--cloud-x--duotone",
108
+ title: "usage-offline.title",
109
+ description: "usage-offline.description"
110
+ },
111
+ empty: {
112
+ valence: "neutral",
113
+ icon: "ph--chart-bar--duotone",
114
+ title: "usage-empty.title",
115
+ description: "usage-empty.description"
116
+ }
117
+ };
118
+ /**
119
+ * Presentational view of profile usage: renders loading/error/unavailable/empty states, or a
120
+ * schema-driven settings form (one read-only field per limit), plus a refresh control and a
121
+ * collapsible raw-response viewer. Pure — all data via props.
122
+ */
123
+ var UsageView = ({ state, data, lastUpdated, onRefresh }) => {
124
+ const { t } = useTranslation(meta.profile.key);
125
+ const [rawExpanded, setRawExpanded] = useState(false);
126
+ const { schema, values, empty } = useMemo(() => {
127
+ const rows = data ? computeRows(data, t) : [];
128
+ return {
129
+ ...buildUsageForm(rows),
130
+ empty: rows.length === 0
131
+ };
132
+ }, [data, t]);
133
+ const message = state === "unavailable" ? STATE_MESSAGES.unavailable : state === "error" ? STATE_MESSAGES.error : state === "ready" && empty ? STATE_MESSAGES.empty : void 0;
134
+ const meterFieldProvider = useCallback(({ fieldProps: { label, description, getValue } }) => {
135
+ const percent = getValue();
136
+ return /* @__PURE__ */ jsx(Form.Row, {
137
+ label,
138
+ description,
139
+ children: typeof percent === "number" ? /* @__PURE__ */ jsx(Status, {
140
+ progress: percent / 100,
141
+ "aria-label": t("usage-percent-used.label", { percent })
142
+ }) : t("usage-unlimited.label")
143
+ });
144
+ }, [t]);
145
+ return /* @__PURE__ */ jsx(Form.Root, {
146
+ variant: "settings",
147
+ layout: "static",
148
+ schema,
149
+ values,
150
+ children: /* @__PURE__ */ jsx(Form.Viewport, {
151
+ scroll: true,
152
+ children: /* @__PURE__ */ jsx(Form.Content, { children: /* @__PURE__ */ jsx(Form.Section, {
153
+ title: t("usage-section.title"),
154
+ description: t("usage-section.description"),
155
+ children: message ? /* @__PURE__ */ jsxs(Message.Root, {
156
+ valence: message.valence,
157
+ children: [/* @__PURE__ */ jsx(Message.Title, {
158
+ icon: message.icon,
159
+ children: t(message.title)
160
+ }), /* @__PURE__ */ jsx(Message.Body, { children: t(message.description) })]
161
+ }) : /* @__PURE__ */ jsx(Form.FieldSet, { fieldProvider: meterFieldProvider })
162
+ }) })
163
+ })
164
+ });
165
+ };
166
+ UsageView.displayName = "UsageView";
167
+ //#endregion
168
+ //#region src/containers/UsageContainer/UsageContainer.tsx
169
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-client/src/containers/UsageContainer/UsageContainer.tsx";
170
+ /**
171
+ * Fetches rolling-window profile usage from the hub service and renders it.
172
+ * Connected wrapper around the presentational {@link UsageView}.
173
+ */
174
+ var UsageContainer = () => {
175
+ const hubHttp = useHubHttpClient();
176
+ const [fetchState, setFetchState] = useState({ state: "loading" });
177
+ const [lastUpdated, setLastUpdated] = useState();
178
+ const [refreshCount, setRefreshCount] = useState(0);
179
+ useAsyncEffect(async () => {
180
+ if (!hubHttp) {
181
+ setFetchState({ state: "unavailable" });
182
+ return;
183
+ }
184
+ setFetchState((previous) => previous.state === "ready" ? previous : { state: "loading" });
185
+ try {
186
+ const result = await hubHttp.getProfileUsage(new Context(void 0, {
187
+ "~LogMeta": "~LogMeta",
188
+ F: __dxlog_file,
189
+ L: 43
190
+ }));
191
+ setFetchState({
192
+ state: "ready",
193
+ data: result
194
+ });
195
+ setLastUpdated(Date.now());
196
+ } catch (err) {
197
+ log.catch(err, void 0, {
198
+ "~LogMeta": "~LogMeta",
199
+ F: __dxlog_file,
200
+ L: 47,
201
+ S: void 0
202
+ });
203
+ setFetchState({ state: "error" });
204
+ }
205
+ }, [hubHttp, refreshCount]);
206
+ const handleRefresh = useCallback(() => setRefreshCount((count) => count + 1), []);
207
+ return /* @__PURE__ */ jsx(UsageView, {
208
+ ...fetchState,
209
+ lastUpdated,
210
+ onRefresh: handleRefresh
211
+ });
212
+ };
213
+ UsageContainer.displayName = "UsageContainer";
214
+ //#endregion
215
+ export { UsageContainer as default };
216
+
217
+ //# sourceMappingURL=chunk-UsageContainer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-UsageContainer.mjs","names":[],"sources":["../../src/containers/UsageContainer/UsageView.tsx","../../src/containers/UsageContainer/UsageContainer.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport { type GetProfileUsageResponse, type MeteringLimit, type MeteringUsageItem } from '@dxos/protocols';\nimport { Message, Status, useTranslation } from '@dxos/react-ui';\nimport { Form, type FormFieldProvider } from '@dxos/react-ui-form';\n\nimport { meta } from '#meta';\n\nexport type UsageViewState = 'loading' | 'ready' | 'error' | 'unavailable';\n\ntype UsageViewCommonProps = {\n /** Epoch milliseconds of the last successful fetch. */\n lastUpdated?: number;\n /** Invoked when the user requests a refresh. */\n onRefresh?: () => void;\n};\n\n/**\n * Discriminated on `state`: the payload is required (and only present) when `state` is `'ready'`, so a\n * missing payload can't be silently rendered as an empty plan.\n */\nexport type UsageViewProps =\n | (UsageViewCommonProps & { state: Exclude<UsageViewState, 'ready'>; data?: undefined })\n | (UsageViewCommonProps & { state: 'ready'; data: GetProfileUsageResponse });\n\ntype TFunction = (key: string, options?: Record<string, unknown>) => string;\n\n/**\n * Whether a usage row falls under a limit. Subtype segments are matched positionally against\n * `subtypePattern` where `*` matches any segment.\n */\nconst usageMatchesLimit = (item: MeteringUsageItem, limit: MeteringLimit): boolean => {\n if (item.eventType !== limit.eventType || item.valueKey !== limit.valueKey) {\n return false;\n }\n return limit.subtypePattern.every((pattern, index) => pattern === '*' || pattern === item.subtypePattern[index]);\n};\n\n/** Sum every usage item that falls under the limit. */\nconst sumUsageForLimit = (usage: GetProfileUsageResponse['usage'], limit: MeteringLimit): number =>\n usage.reduce((total, item) => (usageMatchesLimit(item, limit) ? total + item.amount : total), 0);\n\n/** Humanize a camelCase value key, e.g. `outputTokens` → `output tokens`. */\nconst formatValueKey = (valueKey: string): string =>\n valueKey\n .replace(/([A-Z])/g, ' $1')\n .trim()\n .toLowerCase();\n\n/**\n * Human label for a limit: a scope followed by the value key, e.g.\n * `{ eventType: 'ai', valueKey: 'outputTokens', subtypePattern: ['*'] }` → `All models · output tokens`,\n * `{ eventType: 'ai', valueKey: 'inputTokens', subtypePattern: ['claude-opus-4'] }` → `claude-opus-4 · input tokens`.\n */\nconst formatLimitLabel = (limit: MeteringLimit, t: TFunction): string => {\n const metric = formatValueKey(limit.valueKey);\n const subtype = limit.subtypePattern.filter((segment) => segment && segment !== '*').join('/');\n if (limit.eventType === 'ai') {\n return `${subtype || t('usage-all-models.label')} · ${metric}`;\n }\n return `${subtype ? `${limit.eventType}/${subtype}` : limit.eventType} · ${metric}`;\n};\n\nconst formatAmount = (amount: number): string => amount.toLocaleString();\n\nconst SECONDS_PER_HOUR = 60 * 60;\n\n/** Render `windowHours` as a localized \"N months / days / hours\" string. */\nconst formatWindow = (windowHours: number, t: TFunction): string => {\n if (windowHours % (24 * 30) === 0) {\n return t('usage-window-months.label', { count: windowHours / (24 * 30) });\n }\n if (windowHours % 24 === 0) {\n return t('usage-window-days.label', { count: windowHours / 24 });\n }\n return t('usage-window-hours.label', { count: windowHours });\n};\n\ntype UsageRow = {\n key: string;\n /** Field label (schema `title` annotation). */\n label: string;\n /** Field caption (schema `description` annotation). */\n caption: string;\n /** Consumption as a whole percentage (`0`–`100`); `undefined` for an unlimited limit. */\n percent?: number;\n windowHours: number;\n};\n\n/** One display row per limit, shorter windows first. A `null` limit is reported as unlimited. */\nconst computeRows = (data: GetProfileUsageResponse, t: TFunction): UsageRow[] =>\n data.limits\n .map((limit): UsageRow => {\n const used = sumUsageForLimit(data.usage, limit);\n const label = formatLimitLabel(limit, t);\n const windowHours = limit.windowDuration / SECONDS_PER_HOUR;\n const window = formatWindow(windowHours, t);\n const key = `${limit.eventType}/${limit.subtypePattern.join(',')}/${limit.valueKey}/${limit.windowDuration}/${limit.limit ?? 'unlimited'}`;\n if (limit.limit === null) {\n return {\n key,\n label,\n caption: t('usage-unlimited.description', { used: formatAmount(used), window }),\n windowHours,\n };\n }\n const percent = limit.limit > 0 ? Math.min(100, Math.round((used / limit.limit) * 100)) : used > 0 ? 100 : 0;\n return {\n key,\n label,\n caption: `${t('usage-percent-used.label', { percent })} · ${t('usage-limit.description', { used: formatAmount(used), limit: formatAmount(limit.limit), window })}`,\n percent,\n windowHours,\n };\n })\n .sort((left, right) => left.windowHours - right.windowHours);\n\n/**\n * A single usage field: an optional number carrying its label/caption as `title`/`description`\n * annotations and the consumption percentage as its value. Optional so the form renders no required\n * markers; `Schema.Number` keeps the field context-free (`R = never`) so the struct stays assignable to `Form`.\n */\nconst usageField = (title: string, description: string) =>\n Schema.optional(Schema.Number.annotations({ title, description }));\n\n/**\n * Build the Effect schema (one annotated field per limit) and matching values. Unlimited limits have no\n * value, so their field reads `undefined` and the renderer shows the \"Unlimited\" label instead of a meter.\n */\nconst buildUsageForm = (rows: UsageRow[]) => {\n const fields: Record<string, ReturnType<typeof usageField>> = {};\n const values: Record<string, number> = {};\n rows.forEach((row, index) => {\n const field = `metric_${index}`;\n fields[field] = usageField(row.label, row.caption);\n if (row.percent !== undefined) {\n values[field] = row.percent;\n }\n });\n return { schema: Schema.Struct(fields), values };\n};\n\n/** Non-data states shown as a single `Message`, keyed by message variant (translation keys for the copy). */\nconst STATE_MESSAGES = {\n unavailable: {\n valence: 'warning',\n icon: 'ph--cloud-slash--duotone',\n title: 'usage-unavailable.title',\n description: 'usage-unavailable.description',\n },\n error: {\n valence: 'error',\n icon: 'ph--cloud-x--duotone',\n title: 'usage-offline.title',\n description: 'usage-offline.description',\n },\n empty: {\n valence: 'neutral',\n icon: 'ph--chart-bar--duotone',\n title: 'usage-empty.title',\n description: 'usage-empty.description',\n },\n} as const;\n\n/**\n * Presentational view of profile usage: renders loading/error/unavailable/empty states, or a\n * schema-driven settings form (one read-only field per limit), plus a refresh control and a\n * collapsible raw-response viewer. Pure — all data via props.\n */\nexport const UsageView = ({ state, data, lastUpdated, onRefresh }: UsageViewProps) => {\n const { t } = useTranslation(meta.profile.key);\n const [rawExpanded, setRawExpanded] = useState(false);\n\n const { schema, values, empty } = useMemo(() => {\n const rows = data ? computeRows(data, t) : [];\n return { ...buildUsageForm(rows), empty: rows.length === 0 };\n }, [data, t]);\n\n // Non-data states resolve to a `Message`; `loading` shows a spinner and `ready` with data shows the form.\n const message =\n state === 'unavailable'\n ? STATE_MESSAGES.unavailable\n : state === 'error'\n ? STATE_MESSAGES.error\n : state === 'ready' && empty\n ? STATE_MESSAGES.empty\n : undefined;\n\n // Render each metric as a meter from its percentage value; unlimited limits (no value) show a label.\n const meterFieldProvider = useCallback<FormFieldProvider>(\n ({ fieldProps: { label, description, getValue } }) => {\n const percent = getValue();\n return (\n <Form.Row label={label} description={description}>\n {typeof percent === 'number' ? (\n <Status progress={percent / 100} aria-label={t('usage-percent-used.label', { percent })} />\n ) : (\n t('usage-unlimited.label')\n )}\n </Form.Row>\n );\n },\n [t],\n );\n\n return (\n <Form.Root variant='settings' layout='static' schema={schema} values={values}>\n <Form.Viewport scroll>\n <Form.Content>\n <Form.Section title={t('usage-section.title')} description={t('usage-section.description')}>\n {message ? (\n <Message.Root valence={message.valence}>\n <Message.Title icon={message.icon}>{t(message.title)}</Message.Title>\n <Message.Body>{t(message.description)}</Message.Body>\n </Message.Root>\n ) : (\n <Form.FieldSet fieldProvider={meterFieldProvider} />\n )}\n </Form.Section>\n\n {/* {state === 'ready' && data && (\n <Form.Section>\n <Form.Row\n label={\n lastUpdated !== undefined\n ? t('usage-last-updated.label', { time: new Date(lastUpdated).toLocaleTimeString() })\n : t('usage-refresh.label')\n }\n >\n {onRefresh && (\n <IconButton\n iconOnly\n variant='ghost'\n icon='ph--arrow-clockwise--regular'\n label={t('usage-refresh.label')}\n onClick={onRefresh}\n />\n )}\n </Form.Row>\n </Form.Section>\n )} */}\n\n {/* {state === 'ready' && data && (\n <Form.Section>\n <Form.Row label={t('usage-raw-json.label')}>\n <ToggleIconButton\n iconOnly\n variant='ghost'\n active={rawExpanded}\n icon='ph--caret-right--regular'\n label={t('usage-raw-json.label')}\n onClick={() => setRawExpanded((value) => !value)}\n />\n </Form.Row>\n {rawExpanded && <JsonHighlighter data={data} testId='usage-raw-json' />}\n </Form.Section>\n )} */}\n </Form.Content>\n </Form.Viewport>\n </Form.Root>\n );\n};\n\nUsageView.displayName = 'UsageView';\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useCallback, useState } from 'react';\n\nimport { Context } from '@dxos/context';\nimport { log } from '@dxos/log';\nimport { type GetProfileUsageResponse } from '@dxos/protocols';\nimport { useAsyncEffect } from '@dxos/react-ui';\n\nimport { useHubHttpClient } from '../../hooks';\nimport { UsageView, type UsageViewState } from './UsageView';\n\n/** State + payload kept together so `ready` always carries data (mirrors the discriminated `UsageViewProps`). */\ntype UsageFetchState =\n | {\n state: Exclude<UsageViewState, 'ready'>;\n }\n | {\n state: 'ready';\n data: GetProfileUsageResponse;\n };\n\n/**\n * Fetches rolling-window profile usage from the hub service and renders it.\n * Connected wrapper around the presentational {@link UsageView}.\n */\nexport const UsageContainer = () => {\n const hubHttp = useHubHttpClient();\n const [fetchState, setFetchState] = useState<UsageFetchState>({ state: 'loading' });\n const [lastUpdated, setLastUpdated] = useState<number | undefined>();\n const [refreshCount, setRefreshCount] = useState(0);\n\n useAsyncEffect(async () => {\n if (!hubHttp) {\n setFetchState({ state: 'unavailable' });\n return;\n }\n // Keep prior data visible while refetching; only show the loading state on first load.\n setFetchState((previous) => (previous.state === 'ready' ? previous : { state: 'loading' }));\n try {\n const result = await hubHttp.getProfileUsage(new Context());\n setFetchState({ state: 'ready', data: result });\n setLastUpdated(Date.now());\n } catch (err) {\n log.catch(err);\n setFetchState({ state: 'error' });\n }\n }, [hubHttp, refreshCount]);\n\n const handleRefresh = useCallback(() => setRefreshCount((count) => count + 1), []);\n\n return <UsageView {...fetchState} lastUpdated={lastUpdated} onRefresh={handleRefresh} />;\n};\n\nUsageContainer.displayName = 'UsageContainer';\n"],"mappings":"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"}