@dxos/plugin-client 0.9.0 → 0.9.1-staging.ee54ba693a

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 (236) hide show
  1. package/dist/lib/neutral/{AccountContainer-FZ3IC6H4.mjs → AccountContainer-7SF53UON.mjs} +17 -13
  2. package/dist/lib/neutral/AccountContainer-7SF53UON.mjs.map +7 -0
  3. package/dist/lib/neutral/ClientPlugin.node.mjs +477 -370
  4. package/dist/lib/neutral/ClientPlugin.node.mjs.map +4 -4
  5. package/dist/lib/neutral/{DevicesContainer-6MWNUC3I.mjs → DevicesContainer-PRWIN36N.mjs} +36 -27
  6. package/dist/lib/neutral/DevicesContainer-PRWIN36N.mjs.map +7 -0
  7. package/dist/lib/neutral/{InvitationsContainer-ME722VKS.mjs → InvitationsContainer-BI5RAWET.mjs} +43 -32
  8. package/dist/lib/neutral/InvitationsContainer-BI5RAWET.mjs.map +7 -0
  9. package/dist/lib/neutral/{JoinDialog-2NXAKPLP.mjs → JoinDialog-4BWV4CYB.mjs} +2 -2
  10. package/dist/lib/neutral/JoinDialog-4BWV4CYB.mjs.map +7 -0
  11. package/dist/lib/neutral/{ProfileContainer-VPX3FPWG.mjs → ProfileContainer-YEAYOTX5.mjs} +22 -21
  12. package/dist/lib/neutral/ProfileContainer-YEAYOTX5.mjs.map +7 -0
  13. package/dist/lib/neutral/{RecoveryCodeDialog-EWHB6U5T.mjs → RecoveryCodeDialog-7EPNKCLB.mjs} +2 -2
  14. package/dist/lib/neutral/RecoveryCodeDialog-7EPNKCLB.mjs.map +7 -0
  15. package/dist/lib/neutral/{RecoveryCredentialsContainer-IPBGDMIA.mjs → RecoveryCredentialsContainer-6BZ2IWX7.mjs} +24 -15
  16. package/dist/lib/neutral/RecoveryCredentialsContainer-6BZ2IWX7.mjs.map +7 -0
  17. package/dist/lib/neutral/UsageContainer-2DWCVVE4.mjs +241 -0
  18. package/dist/lib/neutral/UsageContainer-2DWCVVE4.mjs.map +7 -0
  19. package/dist/lib/neutral/account-cache-YVQKLNV2.mjs +16 -0
  20. package/dist/lib/neutral/account-cache-YVQKLNV2.mjs.map +7 -0
  21. package/dist/lib/neutral/{app-graph-builder-A74W7C36.mjs → app-graph-builder-RVXTD6OE.mjs} +30 -16
  22. package/dist/lib/neutral/app-graph-builder-RVXTD6OE.mjs.map +7 -0
  23. package/dist/lib/neutral/capabilities/index.mjs +6 -6
  24. package/dist/lib/neutral/capabilities/node.mjs +3 -3
  25. package/dist/lib/neutral/chunk-6G4KZLBG.mjs +28 -0
  26. package/dist/lib/neutral/chunk-6G4KZLBG.mjs.map +7 -0
  27. package/dist/lib/neutral/{chunk-D6HPCLTS.mjs → chunk-7DEIKHB7.mjs} +16 -2
  28. package/dist/lib/neutral/chunk-7DEIKHB7.mjs.map +7 -0
  29. package/dist/lib/neutral/chunk-A7WDDIWY.mjs +162 -0
  30. package/dist/lib/neutral/chunk-A7WDDIWY.mjs.map +7 -0
  31. package/dist/lib/neutral/chunk-GSKMAS3S.mjs +13 -0
  32. package/dist/lib/neutral/chunk-GSKMAS3S.mjs.map +7 -0
  33. package/dist/lib/neutral/{chunk-JEF2FQGB.mjs → chunk-JY35S2CN.mjs} +2 -2
  34. package/dist/lib/neutral/{chunk-JEF2FQGB.mjs.map → chunk-JY35S2CN.mjs.map} +1 -1
  35. package/dist/lib/neutral/chunk-ZFABGG2E.mjs +8 -0
  36. package/dist/lib/neutral/{chunk-NTVDGDQ3.mjs.map → chunk-ZFABGG2E.mjs.map} +2 -2
  37. package/dist/lib/neutral/containers/index.mjs +10 -8
  38. package/dist/lib/neutral/containers/index.mjs.map +3 -3
  39. package/dist/lib/neutral/{create-agent-6HLW4D3A.mjs → create-agent-6UKJMZS5.mjs} +3 -3
  40. package/dist/lib/neutral/{create-identity-JIWAR5GW.mjs → create-identity-ULCRB3YH.mjs} +3 -3
  41. package/dist/lib/neutral/{create-passkey-FOXEMXGF.mjs → create-passkey-I7VDS3AC.mjs} +7 -7
  42. package/dist/lib/neutral/create-passkey-I7VDS3AC.mjs.map +7 -0
  43. package/dist/lib/neutral/{create-recovery-code-ZWDKLPH4.mjs → create-recovery-code-DH2B6EGP.mjs} +4 -4
  44. package/dist/lib/neutral/index.mjs +6 -4
  45. package/dist/lib/neutral/{join-identity-QEQFAE2S.mjs → join-identity-PJCHDNLH.mjs} +3 -3
  46. package/dist/lib/neutral/{layer-specs-CQLXQBQJ.mjs → layer-specs-YI7BVWKZ.mjs} +6 -8
  47. package/dist/lib/neutral/layer-specs-YI7BVWKZ.mjs.map +7 -0
  48. package/dist/lib/neutral/meta.json +1 -1
  49. package/dist/lib/neutral/meta.mjs +1 -1
  50. package/dist/lib/neutral/{navigation-handler-LU26CDFR.mjs → navigation-handler-MQ6MZXLX.mjs} +3 -3
  51. package/dist/lib/neutral/open-usage-OJVTPGOY.mjs +27 -0
  52. package/dist/lib/neutral/open-usage-OJVTPGOY.mjs.map +7 -0
  53. package/dist/lib/neutral/operations/index.mjs +2 -2
  54. package/dist/lib/neutral/plugin.mjs +3 -3
  55. package/dist/lib/neutral/{react-context-B5LXMHVM.mjs → react-context-V74T6JOJ.mjs} +2 -2
  56. package/dist/lib/neutral/{react-context-B5LXMHVM.mjs.map → react-context-V74T6JOJ.mjs.map} +3 -3
  57. package/dist/lib/neutral/{react-surface-DEKGWTCD.mjs → react-surface-HPXRA65U.mjs} +8 -3
  58. package/dist/lib/neutral/react-surface-HPXRA65U.mjs.map +7 -0
  59. package/dist/lib/neutral/{recover-identity-JNFKLCUD.mjs → recover-identity-B7YM2BR4.mjs} +3 -3
  60. package/dist/lib/neutral/{redeem-passkey-4SBAI4AG.mjs → redeem-passkey-TYP4XLHO.mjs} +10 -10
  61. package/dist/lib/neutral/redeem-passkey-TYP4XLHO.mjs.map +7 -0
  62. package/dist/lib/neutral/{redeem-token-POBD6TMN.mjs → redeem-token-2J33R3PV.mjs} +3 -3
  63. package/dist/lib/neutral/{reset-storage-LQKUV5RA.mjs → reset-storage-K47HZTGP.mjs} +3 -3
  64. package/dist/lib/neutral/{share-identity-KNQ2XNXV.mjs → share-identity-TOROBLWL.mjs} +6 -6
  65. package/dist/lib/neutral/share-identity-TOROBLWL.mjs.map +7 -0
  66. package/dist/lib/neutral/testing/index.mjs +2 -2
  67. package/dist/lib/neutral/testing/index.mjs.map +3 -3
  68. package/dist/lib/neutral/translations.mjs +24 -1
  69. package/dist/lib/neutral/translations.mjs.map +3 -3
  70. package/dist/lib/neutral/types/index.mjs +3 -1
  71. package/dist/types/dx.config.d.ts +28 -0
  72. package/dist/types/dx.config.d.ts.map +1 -0
  73. package/dist/types/src/capabilities/account-cache.d.ts +1 -31
  74. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -2
  75. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  76. package/dist/types/src/capabilities/client.d.ts +1 -2
  77. package/dist/types/src/capabilities/client.d.ts.map +1 -1
  78. package/dist/types/src/capabilities/hub-http-client.d.ts +1 -2
  79. package/dist/types/src/capabilities/hub-http-client.d.ts.map +1 -1
  80. package/dist/types/src/capabilities/index.d.ts +9 -43
  81. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  82. package/dist/types/src/capabilities/layer-specs.d.ts +1 -2
  83. package/dist/types/src/capabilities/layer-specs.d.ts.map +1 -1
  84. package/dist/types/src/capabilities/migrations.d.ts +1 -1
  85. package/dist/types/src/capabilities/navigation-handler/index.d.ts +1 -1
  86. package/dist/types/src/capabilities/navigation-handler/index.d.ts.map +1 -1
  87. package/dist/types/src/capabilities/navigation-handler/navigation-handler.d.ts +1 -2
  88. package/dist/types/src/capabilities/navigation-handler/navigation-handler.d.ts.map +1 -1
  89. package/dist/types/src/capabilities/node.d.ts +6 -6
  90. package/dist/types/src/capabilities/node.d.ts.map +1 -1
  91. package/dist/types/src/capabilities/react-context.d.ts +1 -6
  92. package/dist/types/src/capabilities/react-context.d.ts.map +1 -1
  93. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  94. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  95. package/dist/types/src/capabilities/schema-defs.d.ts +1 -1
  96. package/dist/types/src/commands/account/index.d.ts +3 -0
  97. package/dist/types/src/commands/account/index.d.ts.map +1 -0
  98. package/dist/types/src/commands/account/login/index.d.ts +2 -0
  99. package/dist/types/src/commands/account/login/index.d.ts.map +1 -0
  100. package/dist/types/src/commands/account/login/login.d.ts +12 -0
  101. package/dist/types/src/commands/account/login/login.d.ts.map +1 -0
  102. package/dist/types/src/commands/account/logout/index.d.ts +2 -0
  103. package/dist/types/src/commands/account/logout/index.d.ts.map +1 -0
  104. package/dist/types/src/commands/account/logout/logout.d.ts +9 -0
  105. package/dist/types/src/commands/account/logout/logout.d.ts.map +1 -0
  106. package/dist/types/src/commands/halo/join/join.d.ts +1 -1
  107. package/dist/types/src/commands/halo/join/join.d.ts.map +1 -1
  108. package/dist/types/src/commands/halo/util.d.ts +4 -0
  109. package/dist/types/src/commands/halo/util.d.ts.map +1 -1
  110. package/dist/types/src/commands/index.d.ts +1 -0
  111. package/dist/types/src/commands/index.d.ts.map +1 -1
  112. package/dist/types/src/constants.d.ts.map +1 -1
  113. package/dist/types/src/containers/AccountContainer/AccountContainer.d.ts.map +1 -1
  114. package/dist/types/src/containers/AccountContainer/AccountContainer.stories.d.ts +14 -0
  115. package/dist/types/src/containers/AccountContainer/AccountContainer.stories.d.ts.map +1 -0
  116. package/dist/types/src/containers/DevicesContainer/DevicesContainer.d.ts.map +1 -1
  117. package/dist/types/src/containers/InvitationsContainer/InvitationsContainer.d.ts.map +1 -1
  118. package/dist/types/src/containers/InvitationsContainer/InvitationsContainer.stories.d.ts +14 -0
  119. package/dist/types/src/containers/InvitationsContainer/InvitationsContainer.stories.d.ts.map +1 -0
  120. package/dist/types/src/containers/ProfileContainer/ProfileContainer.d.ts.map +1 -1
  121. package/dist/types/src/containers/RecoveryCredentialsContainer/RecoveryCredentialsContainer.d.ts.map +1 -1
  122. package/dist/types/src/containers/UsageContainer/UsageContainer.d.ts +7 -0
  123. package/dist/types/src/containers/UsageContainer/UsageContainer.d.ts.map +1 -0
  124. package/dist/types/src/containers/UsageContainer/UsageView.d.ts +28 -0
  125. package/dist/types/src/containers/UsageContainer/UsageView.d.ts.map +1 -0
  126. package/dist/types/src/containers/UsageContainer/UsageView.stories.d.ts +21 -0
  127. package/dist/types/src/containers/UsageContainer/UsageView.stories.d.ts.map +1 -0
  128. package/dist/types/src/containers/UsageContainer/index.d.ts +2 -0
  129. package/dist/types/src/containers/UsageContainer/index.d.ts.map +1 -0
  130. package/dist/types/src/containers/index.d.ts +1 -0
  131. package/dist/types/src/containers/index.d.ts.map +1 -1
  132. package/dist/types/src/hooks/index.d.ts +2 -0
  133. package/dist/types/src/hooks/index.d.ts.map +1 -0
  134. package/dist/types/src/{state/use-hub-http.d.ts → hooks/useHubClient.d.ts} +1 -1
  135. package/dist/types/src/hooks/useHubClient.d.ts.map +1 -0
  136. package/dist/types/src/meta.d.ts +32 -2
  137. package/dist/types/src/meta.d.ts.map +1 -1
  138. package/dist/types/src/operations/create-passkey.d.ts.map +1 -1
  139. package/dist/types/src/operations/definitions.d.ts +1 -0
  140. package/dist/types/src/operations/definitions.d.ts.map +1 -1
  141. package/dist/types/src/operations/index.d.ts.map +1 -1
  142. package/dist/types/src/operations/open-usage.d.ts +5 -0
  143. package/dist/types/src/operations/open-usage.d.ts.map +1 -0
  144. package/dist/types/src/testing/initializeIdentity.d.ts.map +1 -1
  145. package/dist/types/src/translations.d.ts.map +1 -1
  146. package/dist/types/src/{state → types}/account-cache.d.ts.map +1 -1
  147. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  148. package/dist/types/src/types/events.d.ts.map +1 -1
  149. package/dist/types/src/types/index.d.ts +1 -0
  150. package/dist/types/src/types/index.d.ts.map +1 -1
  151. package/dist/types/src/types/schema.d.ts +1 -0
  152. package/dist/types/src/types/schema.d.ts.map +1 -1
  153. package/dist/types/tsconfig.tsbuildinfo +1 -1
  154. package/dx.config.ts +19 -0
  155. package/package.json +47 -44
  156. package/src/ClientPlugin.node.ts +2 -2
  157. package/src/ClientPlugin.test.ts +1 -1
  158. package/src/capabilities/account-cache.ts +1 -3
  159. package/src/capabilities/app-graph-builder.ts +81 -71
  160. package/src/capabilities/layer-specs.ts +4 -6
  161. package/src/capabilities/react-context.tsx +1 -1
  162. package/src/capabilities/react-surface.tsx +6 -0
  163. package/src/commands/account/index.ts +13 -0
  164. package/src/commands/account/login/index.ts +5 -0
  165. package/src/commands/account/login/login.ts +147 -0
  166. package/src/commands/account/logout/index.ts +5 -0
  167. package/src/commands/account/logout/logout.ts +49 -0
  168. package/src/commands/halo/create/create.ts +2 -2
  169. package/src/commands/halo/index.ts +6 -6
  170. package/src/commands/halo/join/join.ts +2 -13
  171. package/src/commands/halo/util.ts +24 -0
  172. package/src/commands/index.ts +1 -0
  173. package/src/constants.ts +3 -3
  174. package/src/containers/AccountContainer/AccountContainer.stories.tsx +46 -0
  175. package/src/containers/AccountContainer/AccountContainer.tsx +67 -63
  176. package/src/containers/DevicesContainer/DevicesContainer.tsx +72 -54
  177. package/src/containers/InvitationsContainer/InvitationsContainer.stories.tsx +46 -0
  178. package/src/containers/InvitationsContainer/InvitationsContainer.tsx +65 -62
  179. package/src/containers/JoinDialog/JoinDialog.tsx +1 -1
  180. package/src/containers/ProfileContainer/ProfileContainer.tsx +38 -28
  181. package/src/containers/RecoveryCodeDialog/RecoveryCodeDialog.tsx +1 -1
  182. package/src/containers/RecoveryCredentialsContainer/RecoveryCredentialsContainer.tsx +52 -43
  183. package/src/containers/UsageContainer/UsageContainer.tsx +48 -0
  184. package/src/containers/UsageContainer/UsageView.stories.tsx +127 -0
  185. package/src/containers/UsageContainer/UsageView.tsx +270 -0
  186. package/src/containers/UsageContainer/index.ts +5 -0
  187. package/src/containers/index.ts +1 -0
  188. package/src/hooks/index.ts +5 -0
  189. package/src/meta.ts +3 -12
  190. package/src/operations/create-passkey.ts +6 -4
  191. package/src/operations/definitions.ts +12 -1
  192. package/src/operations/index.ts +1 -0
  193. package/src/operations/open-usage.ts +24 -0
  194. package/src/operations/redeem-passkey.ts +7 -7
  195. package/src/operations/share-identity.ts +3 -3
  196. package/src/testing/initializeIdentity.ts +5 -2
  197. package/src/translations.ts +25 -1
  198. package/src/types/capabilities.ts +8 -6
  199. package/src/types/events.ts +5 -5
  200. package/src/types/index.ts +1 -0
  201. package/src/types/schema.ts +23 -16
  202. package/dist/lib/neutral/AccountContainer-FZ3IC6H4.mjs.map +0 -7
  203. package/dist/lib/neutral/DevicesContainer-6MWNUC3I.mjs.map +0 -7
  204. package/dist/lib/neutral/InvitationsContainer-ME722VKS.mjs.map +0 -7
  205. package/dist/lib/neutral/JoinDialog-2NXAKPLP.mjs.map +0 -7
  206. package/dist/lib/neutral/ProfileContainer-VPX3FPWG.mjs.map +0 -7
  207. package/dist/lib/neutral/RecoveryCodeDialog-EWHB6U5T.mjs.map +0 -7
  208. package/dist/lib/neutral/RecoveryCredentialsContainer-IPBGDMIA.mjs.map +0 -7
  209. package/dist/lib/neutral/account-cache-4EKGEUJI.mjs +0 -43
  210. package/dist/lib/neutral/account-cache-4EKGEUJI.mjs.map +0 -7
  211. package/dist/lib/neutral/app-graph-builder-A74W7C36.mjs.map +0 -7
  212. package/dist/lib/neutral/chunk-D6HPCLTS.mjs.map +0 -7
  213. package/dist/lib/neutral/chunk-JOCCVODY.mjs +0 -21
  214. package/dist/lib/neutral/chunk-JOCCVODY.mjs.map +0 -7
  215. package/dist/lib/neutral/chunk-NTVDGDQ3.mjs +0 -8
  216. package/dist/lib/neutral/chunk-TUK3ELUU.mjs +0 -135
  217. package/dist/lib/neutral/chunk-TUK3ELUU.mjs.map +0 -7
  218. package/dist/lib/neutral/chunk-WWCVZG3K.mjs +0 -13
  219. package/dist/lib/neutral/chunk-WWCVZG3K.mjs.map +0 -7
  220. package/dist/lib/neutral/create-passkey-FOXEMXGF.mjs.map +0 -7
  221. package/dist/lib/neutral/layer-specs-CQLXQBQJ.mjs.map +0 -7
  222. package/dist/lib/neutral/react-surface-DEKGWTCD.mjs.map +0 -7
  223. package/dist/lib/neutral/redeem-passkey-4SBAI4AG.mjs.map +0 -7
  224. package/dist/lib/neutral/share-identity-KNQ2XNXV.mjs.map +0 -7
  225. package/dist/types/src/state/use-hub-http.d.ts.map +0 -1
  226. /package/dist/lib/neutral/{create-agent-6HLW4D3A.mjs.map → create-agent-6UKJMZS5.mjs.map} +0 -0
  227. /package/dist/lib/neutral/{create-identity-JIWAR5GW.mjs.map → create-identity-ULCRB3YH.mjs.map} +0 -0
  228. /package/dist/lib/neutral/{create-recovery-code-ZWDKLPH4.mjs.map → create-recovery-code-DH2B6EGP.mjs.map} +0 -0
  229. /package/dist/lib/neutral/{join-identity-QEQFAE2S.mjs.map → join-identity-PJCHDNLH.mjs.map} +0 -0
  230. /package/dist/lib/neutral/{navigation-handler-LU26CDFR.mjs.map → navigation-handler-MQ6MZXLX.mjs.map} +0 -0
  231. /package/dist/lib/neutral/{recover-identity-JNFKLCUD.mjs.map → recover-identity-B7YM2BR4.mjs.map} +0 -0
  232. /package/dist/lib/neutral/{redeem-token-POBD6TMN.mjs.map → redeem-token-2J33R3PV.mjs.map} +0 -0
  233. /package/dist/lib/neutral/{reset-storage-LQKUV5RA.mjs.map → reset-storage-K47HZTGP.mjs.map} +0 -0
  234. /package/dist/types/src/{state → types}/account-cache.d.ts +0 -0
  235. /package/src/{state/use-hub-http.ts → hooks/useHubClient.ts} +0 -0
  236. /package/src/{state → types}/account-cache.ts +0 -0
@@ -0,0 +1,270 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import React, { useCallback, useMemo, useState } from 'react';
7
+
8
+ import { type GetProfileUsageResponse, type MeteringLimit, type MeteringUsageItem } from '@dxos/protocols';
9
+ import { IconButton, Message, Status, ToggleIconButton, useTranslation } from '@dxos/react-ui';
10
+ import { Form, type FormFieldProvider } from '@dxos/react-ui-form';
11
+ import { JsonHighlighter } from '@dxos/react-ui-syntax-highlighter';
12
+
13
+ import { meta } from '#meta';
14
+
15
+ export type UsageViewState = 'loading' | 'ready' | 'error' | 'unavailable';
16
+
17
+ type UsageViewCommonProps = {
18
+ /** Epoch milliseconds of the last successful fetch. */
19
+ lastUpdated?: number;
20
+ /** Invoked when the user requests a refresh. */
21
+ onRefresh?: () => void;
22
+ };
23
+
24
+ /**
25
+ * Discriminated on `state`: the payload is required (and only present) when `state` is `'ready'`, so a
26
+ * missing payload can't be silently rendered as an empty plan.
27
+ */
28
+ export type UsageViewProps =
29
+ | (UsageViewCommonProps & { state: Exclude<UsageViewState, 'ready'>; data?: undefined })
30
+ | (UsageViewCommonProps & { state: 'ready'; data: GetProfileUsageResponse });
31
+
32
+ type TFunction = (key: string, options?: Record<string, unknown>) => string;
33
+
34
+ /**
35
+ * Whether a usage row falls under a limit. Subtype segments are matched positionally against
36
+ * `subtypePattern` where `*` matches any segment.
37
+ */
38
+ const usageMatchesLimit = (item: MeteringUsageItem, limit: MeteringLimit): boolean => {
39
+ if (item.eventType !== limit.eventType || item.valueKey !== limit.valueKey) {
40
+ return false;
41
+ }
42
+ return limit.subtypePattern.every((pattern, index) => pattern === '*' || pattern === item.subtypePattern[index]);
43
+ };
44
+
45
+ /** Sum every usage item that falls under the limit. */
46
+ const sumUsageForLimit = (usage: GetProfileUsageResponse['usage'], limit: MeteringLimit): number =>
47
+ usage.reduce((total, item) => (usageMatchesLimit(item, limit) ? total + item.amount : total), 0);
48
+
49
+ /** Humanize a camelCase value key, e.g. `outputTokens` → `output tokens`. */
50
+ const formatValueKey = (valueKey: string): string =>
51
+ valueKey
52
+ .replace(/([A-Z])/g, ' $1')
53
+ .trim()
54
+ .toLowerCase();
55
+
56
+ /**
57
+ * Human label for a limit: a scope followed by the value key, e.g.
58
+ * `{ eventType: 'ai', valueKey: 'outputTokens', subtypePattern: ['*'] }` → `All models · output tokens`,
59
+ * `{ eventType: 'ai', valueKey: 'inputTokens', subtypePattern: ['claude-opus-4'] }` → `claude-opus-4 · input tokens`.
60
+ */
61
+ const formatLimitLabel = (limit: MeteringLimit, t: TFunction): string => {
62
+ const metric = formatValueKey(limit.valueKey);
63
+ const subtype = limit.subtypePattern.filter((segment) => segment && segment !== '*').join('/');
64
+ if (limit.eventType === 'ai') {
65
+ return `${subtype || t('usage-all-models.label')} · ${metric}`;
66
+ }
67
+ return `${subtype ? `${limit.eventType}/${subtype}` : limit.eventType} · ${metric}`;
68
+ };
69
+
70
+ const formatAmount = (amount: number): string => amount.toLocaleString();
71
+
72
+ const SECONDS_PER_HOUR = 60 * 60;
73
+
74
+ /** Render `windowHours` as a localized "N months / days / hours" string. */
75
+ const formatWindow = (windowHours: number, t: TFunction): string => {
76
+ if (windowHours % (24 * 30) === 0) {
77
+ return t('usage-window-months.label', { count: windowHours / (24 * 30) });
78
+ }
79
+ if (windowHours % 24 === 0) {
80
+ return t('usage-window-days.label', { count: windowHours / 24 });
81
+ }
82
+ return t('usage-window-hours.label', { count: windowHours });
83
+ };
84
+
85
+ type UsageRow = {
86
+ key: string;
87
+ /** Field label (schema `title` annotation). */
88
+ label: string;
89
+ /** Field caption (schema `description` annotation). */
90
+ caption: string;
91
+ /** Consumption as a whole percentage (`0`–`100`); `undefined` for an unlimited limit. */
92
+ percent?: number;
93
+ windowHours: number;
94
+ };
95
+
96
+ /** One display row per limit, shorter windows first. A `null` limit is reported as unlimited. */
97
+ const computeRows = (data: GetProfileUsageResponse, t: TFunction): UsageRow[] =>
98
+ data.limits
99
+ .map((limit): UsageRow => {
100
+ const used = sumUsageForLimit(data.usage, limit);
101
+ const label = formatLimitLabel(limit, t);
102
+ const windowHours = limit.windowDuration / SECONDS_PER_HOUR;
103
+ const window = formatWindow(windowHours, t);
104
+ const key = `${limit.eventType}/${limit.subtypePattern.join(',')}/${limit.valueKey}/${limit.windowDuration}/${limit.limit ?? 'unlimited'}`;
105
+ if (limit.limit === null) {
106
+ return {
107
+ key,
108
+ label,
109
+ caption: t('usage-unlimited.description', { used: formatAmount(used), window }),
110
+ windowHours,
111
+ };
112
+ }
113
+ const percent = limit.limit > 0 ? Math.min(100, Math.round((used / limit.limit) * 100)) : used > 0 ? 100 : 0;
114
+ return {
115
+ key,
116
+ label,
117
+ caption: `${t('usage-percent-used.label', { percent })} · ${t('usage-limit.description', { used: formatAmount(used), limit: formatAmount(limit.limit), window })}`,
118
+ percent,
119
+ windowHours,
120
+ };
121
+ })
122
+ .sort((left, right) => left.windowHours - right.windowHours);
123
+
124
+ /**
125
+ * A single usage field: an optional number carrying its label/caption as `title`/`description`
126
+ * annotations and the consumption percentage as its value. Optional so the form renders no required
127
+ * markers; `Schema.Number` keeps the field context-free (`R = never`) so the struct stays assignable to `Form`.
128
+ */
129
+ const usageField = (title: string, description: string) =>
130
+ Schema.optional(Schema.Number.annotations({ title, description }));
131
+
132
+ /**
133
+ * Build the Effect schema (one annotated field per limit) and matching values. Unlimited limits have no
134
+ * value, so their field reads `undefined` and the renderer shows the "Unlimited" label instead of a meter.
135
+ */
136
+ const buildUsageForm = (rows: UsageRow[]) => {
137
+ const fields: Record<string, ReturnType<typeof usageField>> = {};
138
+ const values: Record<string, number> = {};
139
+ rows.forEach((row, index) => {
140
+ const field = `metric_${index}`;
141
+ fields[field] = usageField(row.label, row.caption);
142
+ if (row.percent !== undefined) {
143
+ values[field] = row.percent;
144
+ }
145
+ });
146
+ return { schema: Schema.Struct(fields), values };
147
+ };
148
+
149
+ /** Non-data states shown as a single `Message`, keyed by message variant (translation keys for the copy). */
150
+ const STATE_MESSAGES = {
151
+ unavailable: {
152
+ valence: 'warning',
153
+ icon: 'ph--cloud-slash--duotone',
154
+ title: 'usage-unavailable.title',
155
+ description: 'usage-unavailable.description',
156
+ },
157
+ error: {
158
+ valence: 'error',
159
+ icon: 'ph--cloud-x--duotone',
160
+ title: 'usage-offline.title',
161
+ description: 'usage-offline.description',
162
+ },
163
+ empty: {
164
+ valence: 'neutral',
165
+ icon: 'ph--chart-bar--duotone',
166
+ title: 'usage-empty.title',
167
+ description: 'usage-empty.description',
168
+ },
169
+ } as const;
170
+
171
+ /**
172
+ * Presentational view of profile usage: renders loading/error/unavailable/empty states, or a
173
+ * schema-driven settings form (one read-only field per limit), plus a refresh control and a
174
+ * collapsible raw-response viewer. Pure — all data via props.
175
+ */
176
+ export const UsageView = ({ state, data, lastUpdated, onRefresh }: UsageViewProps) => {
177
+ const { t } = useTranslation(meta.profile.key);
178
+ const [rawExpanded, setRawExpanded] = useState(false);
179
+
180
+ const { schema, values, empty } = useMemo(() => {
181
+ const rows = data ? computeRows(data, t) : [];
182
+ return { ...buildUsageForm(rows), empty: rows.length === 0 };
183
+ }, [data, t]);
184
+
185
+ // Non-data states resolve to a `Message`; `loading` shows a spinner and `ready` with data shows the form.
186
+ const message =
187
+ state === 'unavailable'
188
+ ? STATE_MESSAGES.unavailable
189
+ : state === 'error'
190
+ ? STATE_MESSAGES.error
191
+ : state === 'ready' && empty
192
+ ? STATE_MESSAGES.empty
193
+ : undefined;
194
+
195
+ // Render each metric as a meter from its percentage value; unlimited limits (no value) show a label.
196
+ const meterFieldProvider = useCallback<FormFieldProvider>(
197
+ ({ fieldProps: { label, description, getValue } }) => {
198
+ const percent = getValue();
199
+ return (
200
+ <Form.Row label={label} description={description}>
201
+ {typeof percent === 'number' ? (
202
+ <Status progress={percent / 100} aria-label={t('usage-percent-used.label', { percent })} />
203
+ ) : (
204
+ t('usage-unlimited.label')
205
+ )}
206
+ </Form.Row>
207
+ );
208
+ },
209
+ [t],
210
+ );
211
+
212
+ return (
213
+ <Form.Root variant='settings' layout='static' schema={schema} values={values}>
214
+ <Form.Viewport scroll>
215
+ <Form.Content>
216
+ <Form.Section title={t('usage-section.title')} description={t('usage-section.description')}>
217
+ {state === 'loading' ? (
218
+ <Status indeterminate aria-label={t('usage-section.title')} />
219
+ ) : message ? (
220
+ <Message.Root valence={message.valence}>
221
+ <Message.Title icon={message.icon}>{t(message.title)}</Message.Title>
222
+ <Message.Content>{t(message.description)}</Message.Content>
223
+ </Message.Root>
224
+ ) : (
225
+ <Form.FieldSet fieldProvider={meterFieldProvider} />
226
+ )}
227
+ </Form.Section>
228
+
229
+ {state === 'ready' && data && (
230
+ <Form.Section>
231
+ <Form.Row
232
+ label={
233
+ lastUpdated !== undefined
234
+ ? t('usage-last-updated.label', { time: new Date(lastUpdated).toLocaleTimeString() })
235
+ : t('usage-refresh.label')
236
+ }
237
+ >
238
+ {onRefresh && (
239
+ <IconButton
240
+ iconOnly
241
+ variant='ghost'
242
+ icon='ph--arrow-clockwise--regular'
243
+ label={t('usage-refresh.label')}
244
+ onClick={onRefresh}
245
+ />
246
+ )}
247
+ </Form.Row>
248
+ </Form.Section>
249
+ )}
250
+
251
+ {state === 'ready' && data && (
252
+ <Form.Section>
253
+ <Form.Row label={t('usage-raw-json.label')}>
254
+ <ToggleIconButton
255
+ iconOnly
256
+ variant='ghost'
257
+ active={rawExpanded}
258
+ icon='ph--caret-right--regular'
259
+ label={t('usage-raw-json.label')}
260
+ onClick={() => setRawExpanded((value) => !value)}
261
+ />
262
+ </Form.Row>
263
+ {rawExpanded && <JsonHighlighter data={data} testId='usage-raw-json' />}
264
+ </Form.Section>
265
+ )}
266
+ </Form.Content>
267
+ </Form.Viewport>
268
+ </Form.Root>
269
+ );
270
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { UsageContainer as default } from './UsageContainer';
@@ -10,6 +10,7 @@ export { type ResetDialogProps } from './ResetDialog';
10
10
  export const AccountContainer: ComponentType<any> = lazy(() => import('./AccountContainer'));
11
11
  export const DevicesContainer: ComponentType<any> = lazy(() => import('./DevicesContainer'));
12
12
  export const InvitationsContainer: ComponentType<any> = lazy(() => import('./InvitationsContainer'));
13
+ export const UsageContainer: ComponentType<any> = lazy(() => import('./UsageContainer'));
13
14
  export const JoinDialog: ComponentType<any> = lazy(() => import('./JoinDialog'));
14
15
  export const ProfileContainer: ComponentType<any> = lazy(() => import('./ProfileContainer'));
15
16
  export const RecoveryCodeDialog: ComponentType<any> = lazy(() => import('./RecoveryCodeDialog'));
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export * from './useHubClient';
package/src/meta.ts CHANGED
@@ -3,16 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Plugin } from '@dxos/app-framework';
6
- import { DXN } from '@dxos/keys';
7
- import { trim } from '@dxos/util';
8
6
 
9
- export const meta = Plugin.makeMeta({
10
- key: DXN.make('org.dxos.plugin.client'),
11
- name: 'Client',
12
- author: 'DXOS',
13
- description: trim`
14
- Core client connectivity and peer-to-peer networking infrastructure.
15
- Manages identity, authentication, and real-time synchronization across devices.
16
- `,
17
- tags: ['system'],
18
- });
7
+ import config from '../dx.config';
8
+
9
+ export const meta = Plugin.getMetaFromConfig(config);
@@ -6,7 +6,7 @@ import * as Effect from 'effect/Effect';
6
6
  import * as Match from 'effect/Match';
7
7
 
8
8
  import { Capability } from '@dxos/app-framework';
9
- import { supportsNativePasskeys, createNativePasskey, extractPublicKeyFromAttestation } from '@dxos/app-toolkit';
9
+ import { NativePasskey } from '@dxos/app-toolkit';
10
10
  import { PublicKey } from '@dxos/client';
11
11
  import { Operation } from '@dxos/compute';
12
12
  import { invariant } from '@dxos/invariant';
@@ -23,16 +23,18 @@ const handler: Operation.WithHandler<typeof CreatePasskey> = CreatePasskey.pipe(
23
23
 
24
24
  const lookupKey = PublicKey.random();
25
25
 
26
- const { recoveryKey, algorithm } = yield* Match.value(supportsNativePasskeys()).pipe(
26
+ const { recoveryKey, algorithm } = yield* Match.value(NativePasskey.supportsNativePasskeys()).pipe(
27
27
  Match.when(true, () =>
28
28
  Effect.gen(function* () {
29
29
  const result = yield* Effect.promise(() =>
30
- createNativePasskey({
30
+ NativePasskey.createNativePasskey({
31
31
  username: identity.did,
32
32
  userId: lookupKey.asUint8Array(),
33
33
  }),
34
34
  );
35
- const { publicKey, algorithm: alg } = extractPublicKeyFromAttestation(result.attestation_object);
35
+ const { publicKey, algorithm: alg } = NativePasskey.extractPublicKeyFromAttestation(
36
+ result.attestation_object,
37
+ );
36
38
  return {
37
39
  recoveryKey: PublicKey.from(publicKey),
38
40
  algorithm: alg === -7 ? 'ES256' : 'ED25519',
@@ -10,7 +10,7 @@ import { DXN, IdentityDid, SpaceId } from '@dxos/keys';
10
10
 
11
11
  import { meta } from '#meta';
12
12
 
13
- const makeKey = (name: string) => DXN.make(`${meta.id}.operation.${name}`);
13
+ const makeKey = (name: string) => DXN.make(`${meta.profile.key}.operation.${name}`);
14
14
 
15
15
  const IdentitySchema = Schema.Struct({
16
16
  identityDid: IdentityDid,
@@ -57,6 +57,17 @@ export const ShareIdentity = Operation.make({
57
57
  output: Schema.Void,
58
58
  });
59
59
 
60
+ export const OpenUsage = Operation.make({
61
+ meta: {
62
+ key: makeKey('openUsage'),
63
+ name: 'Open Usage',
64
+ icon: 'ph--chart-bar--regular',
65
+ },
66
+ services: [Capability.Service],
67
+ input: Schema.Void,
68
+ output: Schema.Void,
69
+ });
70
+
60
71
  export const RecoverIdentity = Operation.make({
61
72
  meta: { key: makeKey('recoverIdentity'), name: 'Recover Identity', icon: 'ph--key--regular' },
62
73
  services: [Capability.Service],
@@ -12,6 +12,7 @@ export const ClientOperationHandlerSet = OperationHandlerSet.lazy(
12
12
  () => import('./create-passkey'),
13
13
  () => import('./create-recovery-code'),
14
14
  () => import('./join-identity'),
15
+ () => import('./open-usage'),
15
16
  () => import('./recover-identity'),
16
17
  () => import('./redeem-passkey'),
17
18
  () => import('./redeem-token'),
@@ -0,0 +1,24 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { LayoutOperation, Paths } from '@dxos/app-toolkit';
8
+ import { Operation } from '@dxos/compute';
9
+
10
+ import { Account } from '../types';
11
+ import { OpenUsage } from './definitions';
12
+
13
+ const handler: Operation.WithHandler<typeof OpenUsage> = OpenUsage.pipe(
14
+ Operation.withHandler(
15
+ Effect.fnUntraced(function* () {
16
+ yield* Operation.invoke(LayoutOperation.SwitchWorkspace, { subject: Paths.getSpacePath(Account.id) });
17
+ yield* Operation.invoke(LayoutOperation.Open, {
18
+ subject: [Paths.getSpacePath(Account.id, Account.Usage)],
19
+ });
20
+ }),
21
+ ),
22
+ );
23
+
24
+ export default handler;
@@ -6,7 +6,7 @@ import * as Effect from 'effect/Effect';
6
6
  import * as Match from 'effect/Match';
7
7
 
8
8
  import { Capability } from '@dxos/app-framework';
9
- import { decodeUrlSafeBase64, supportsNativePasskeys, loginNativePasskey } from '@dxos/app-toolkit';
9
+ import { NativePasskey } from '@dxos/app-toolkit';
10
10
  import { PublicKey } from '@dxos/client';
11
11
  import { Operation } from '@dxos/compute';
12
12
  import { invariant } from '@dxos/invariant';
@@ -24,19 +24,19 @@ const handler: Operation.WithHandler<typeof RedeemPasskey> = RedeemPasskey.pipe(
24
24
  );
25
25
 
26
26
  const { lookupKey, signature, clientDataJson, authenticatorData } = yield* Match.value(
27
- supportsNativePasskeys(),
27
+ NativePasskey.supportsNativePasskeys(),
28
28
  ).pipe(
29
29
  Match.when(true, () =>
30
30
  Effect.gen(function* () {
31
31
  const result = yield* Effect.promise(() =>
32
- loginNativePasskey({ challenge: Uint8Array.from(Buffer.from(challenge, 'base64')) }),
32
+ NativePasskey.loginNativePasskey({ challenge: Uint8Array.from(Buffer.from(challenge, 'base64')) }),
33
33
  );
34
34
  invariant(result, 'Native passkey login returned no result');
35
35
  return {
36
- lookupKey: PublicKey.from(decodeUrlSafeBase64(result.user_handle)),
37
- signature: Buffer.from(decodeUrlSafeBase64(result.signature)),
38
- clientDataJson: Buffer.from(decodeUrlSafeBase64(result.client_data_json)),
39
- authenticatorData: Buffer.from(decodeUrlSafeBase64(result.authenticator_data)),
36
+ lookupKey: PublicKey.from(NativePasskey.decodeUrlSafeBase64(result.user_handle)),
37
+ signature: Buffer.from(NativePasskey.decodeUrlSafeBase64(result.signature)),
38
+ clientDataJson: Buffer.from(NativePasskey.decodeUrlSafeBase64(result.client_data_json)),
39
+ authenticatorData: Buffer.from(NativePasskey.decodeUrlSafeBase64(result.authenticator_data)),
40
40
  };
41
41
  }),
42
42
  ),
@@ -4,7 +4,7 @@
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
- import { LayoutOperation, getSpacePath } from '@dxos/app-toolkit';
7
+ import { LayoutOperation, Paths } from '@dxos/app-toolkit';
8
8
  import { Operation } from '@dxos/compute';
9
9
  import { ObservabilityOperation } from '@dxos/plugin-observability';
10
10
 
@@ -14,9 +14,9 @@ import { ShareIdentity } from './definitions';
14
14
  const handler: Operation.WithHandler<typeof ShareIdentity> = ShareIdentity.pipe(
15
15
  Operation.withHandler(
16
16
  Effect.fnUntraced(function* () {
17
- yield* Operation.invoke(LayoutOperation.SwitchWorkspace, { subject: getSpacePath(Account.id) });
17
+ yield* Operation.invoke(LayoutOperation.SwitchWorkspace, { subject: Paths.getSpacePath(Account.id) });
18
18
  yield* Operation.invoke(LayoutOperation.Open, {
19
- subject: [`${getSpacePath(Account.id)}/${Account.Profile}`],
19
+ subject: [Paths.getSpacePath(Account.id, Account.Profile)],
20
20
  });
21
21
  yield* Operation.schedule(ObservabilityOperation.SendEvent, { name: 'identity.share' });
22
22
  }),
@@ -4,13 +4,14 @@
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
- import { PERSONAL_SPACE_TAG } from '@dxos/app-toolkit';
7
+ import { AppSpace } from '@dxos/app-toolkit';
8
8
  import { type Client } from '@dxos/client';
9
9
  import { type Space } from '@dxos/client-protocol';
10
10
  import { type Identity } from '@dxos/protocols/proto/dxos/client/services';
11
11
 
12
12
  export type InitializeIdentityResult = {
13
13
  identity: Identity;
14
+ // TODO(burdon): Rename to space.
14
15
  personalSpace: Space;
15
16
  };
16
17
 
@@ -21,7 +22,9 @@ export type InitializeIdentityResult = {
21
22
  export const initializeIdentity = (client: Client): Effect.Effect<InitializeIdentityResult, never, never> =>
22
23
  Effect.gen(function* () {
23
24
  const identity = yield* Effect.promise(() => client.halo.createIdentity());
24
- const personalSpace = yield* Effect.promise(() => client.spaces.create({}, { tags: [PERSONAL_SPACE_TAG] }));
25
+ const personalSpace = yield* Effect.promise(() =>
26
+ client.spaces.create({}, { tags: [AppSpace.PERSONAL_SPACE_TAG] }),
27
+ );
25
28
  yield* Effect.promise(() => personalSpace.waitUntilReady());
26
29
  return {
27
30
  identity,
@@ -11,7 +11,7 @@ import { meta } from '#meta';
11
11
  const pluginTranslations = [
12
12
  {
13
13
  'en-US': {
14
- [meta.id]: {
14
+ [meta.profile.key]: {
15
15
  'account.label': 'User profile',
16
16
  'profile.label': 'Profile',
17
17
  'profile.description': 'User profile and account settings.',
@@ -27,6 +27,30 @@ const pluginTranslations = [
27
27
  'security.label': 'Security',
28
28
  'account-panel.label': 'Account',
29
29
  'invitations-panel.label': 'Invitations',
30
+ 'usage-panel.label': 'Usage',
31
+ 'usage-section.title': 'Usage',
32
+ 'usage-section.description':
33
+ 'Rolling-window consumption against your plan limits for edge services such as AI inference.',
34
+ 'usage-unavailable.title': 'Usage unavailable',
35
+ 'usage-unavailable.description': 'Hub service is not configured, so usage data cannot be loaded.',
36
+ 'usage-offline.title': 'Couldn’t load usage',
37
+ 'usage-offline.description': 'Reconnect and reopen this panel to refresh usage and limits.',
38
+ 'usage-empty.title': 'No usage recorded',
39
+ 'usage-empty.description': 'Usage will appear here once you start using metered edge services.',
40
+ 'usage-limit.description': '{{used}} of {{limit}} in the last {{window}}',
41
+ 'usage-window-hours.label_one': '{{count}} hour',
42
+ 'usage-window-hours.label_other': '{{count}} hours',
43
+ 'usage-window-days.label_one': '{{count}} day',
44
+ 'usage-window-days.label_other': '{{count}} days',
45
+ 'usage-window-months.label_one': '{{count}} month',
46
+ 'usage-window-months.label_other': '{{count}} months',
47
+ 'usage-percent-used.label': '{{percent}}% used',
48
+ 'usage-all-models.label': 'All models',
49
+ 'usage-unlimited.label': 'Unlimited',
50
+ 'usage-unlimited.description': '{{used}} used in the last {{window}}',
51
+ 'usage-last-updated.label': 'Last updated {{time}}',
52
+ 'usage-refresh.label': 'Refresh',
53
+ 'usage-raw-json.label': 'Raw JSON',
30
54
  'account-section.title': 'Account',
31
55
  'account-section.description':
32
56
  'Your identity on this device is bound to a DXOS account that gates access to edge services like sync, agents, and AI.',
@@ -12,12 +12,14 @@ import { type HubHttpClient } from '@dxos/edge-client';
12
12
 
13
13
  import { meta } from '#meta';
14
14
 
15
- import { type AccountCache as AccountCacheType } from '../state/account-cache';
15
+ import { type AccountCache as AccountCacheType } from './account-cache';
16
16
 
17
17
  export namespace ClientCapabilities {
18
- export const Client = Capability.make<Client>(`${meta.id}.capability.client`);
19
- export const Schema = Capability.make<Type.AnyEntity[]>(`${meta.id}.capability.schema`);
20
- export const Migration = Capability.make<ObjectMigration[]>(`${meta.id}.capability.migration`);
21
- export const AccountCache = Capability.make<Atom.Writable<AccountCacheType>>(`${meta.id}.capability.accountCache`);
22
- export const HubHttpClient = Capability.make<HubHttpClient>(`${meta.id}.capability.hubHttpClient`);
18
+ export const Client = Capability.make<Client>(`${meta.profile.key}.capability.client`);
19
+ export const Schema = Capability.make<Type.AnyEntity[]>(`${meta.profile.key}.capability.schema`);
20
+ export const Migration = Capability.make<ObjectMigration[]>(`${meta.profile.key}.capability.migration`);
21
+ export const AccountCache = Capability.make<Atom.Writable<AccountCacheType>>(
22
+ `${meta.profile.key}.capability.accountCache`,
23
+ );
24
+ export const HubHttpClient = Capability.make<HubHttpClient>(`${meta.profile.key}.capability.hubHttpClient`);
23
25
  }
@@ -7,9 +7,9 @@ import { ActivationEvent } from '@dxos/app-framework';
7
7
  import { meta } from '#meta';
8
8
 
9
9
  export namespace ClientEvents {
10
- export const ClientReady = ActivationEvent.make(`${meta.id}.event.client-ready`);
11
- export const SetupSchema = ActivationEvent.make(`${meta.id}.event.setup-schema`);
12
- export const SetupMigration = ActivationEvent.make(`${meta.id}.event.setup-migration`);
13
- export const IdentityCreated = ActivationEvent.make(`${meta.id}.event.identity-created`);
14
- export const SpacesReady = ActivationEvent.make(`${meta.id}.event.spaces-ready`);
10
+ export const ClientReady = ActivationEvent.make(`${meta.profile.key}.event.clientReady`);
11
+ export const SetupSchema = ActivationEvent.make(`${meta.profile.key}.event.setupSchema`);
12
+ export const SetupMigration = ActivationEvent.make(`${meta.profile.key}.event.setupMigration`);
13
+ export const IdentityCreated = ActivationEvent.make(`${meta.profile.key}.event.identityCreated`);
14
+ export const SpacesReady = ActivationEvent.make(`${meta.profile.key}.event.spacesReady`);
15
15
  }
@@ -2,6 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ export * from './account-cache';
5
6
  export * from './capabilities';
6
7
  export * from './events';
7
8
  export * from './schema';