@remit/web-client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/harness/build.mjs +84 -0
  2. package/harness/index.html +37 -0
  3. package/harness/vite-preset.ts +29 -0
  4. package/index.html +47 -0
  5. package/package.json +147 -0
  6. package/public/config.js +5 -0
  7. package/public/locales/de/common.json +1 -0
  8. package/public/locales/de/errors.json +1 -0
  9. package/public/locales/de/mail.json +13 -0
  10. package/public/locales/de/settings.json +1 -0
  11. package/public/locales/en/common.json +26 -0
  12. package/public/locales/en/errors.json +1 -0
  13. package/public/locales/en/mail.json +69 -0
  14. package/public/locales/en/settings.json +1 -0
  15. package/public/locales/fr/common.json +1 -0
  16. package/public/locales/fr/errors.json +1 -0
  17. package/public/locales/fr/mail.json +13 -0
  18. package/public/locales/fr/settings.json +1 -0
  19. package/public/locales/nl/common.json +1 -0
  20. package/public/locales/nl/errors.json +1 -0
  21. package/public/locales/nl/mail.json +13 -0
  22. package/public/locales/nl/settings.json +1 -0
  23. package/src/auth/AccountMenu.tsx +58 -0
  24. package/src/auth/AccountSession.tsx +19 -0
  25. package/src/auth/BetterAuthShell.tsx +198 -0
  26. package/src/auth/account-menu-mode.test.ts +64 -0
  27. package/src/auth/account-menu-mode.ts +28 -0
  28. package/src/auth/amplify-config.test.ts +158 -0
  29. package/src/auth/amplify-config.ts +60 -0
  30. package/src/auth/auth-error.test.ts +109 -0
  31. package/src/auth/auth-error.ts +107 -0
  32. package/src/auth/auth-interceptor.test.ts +86 -0
  33. package/src/auth/auth-interceptor.ts +23 -0
  34. package/src/auth/auth.css +334 -0
  35. package/src/auth/better-auth/BetterAuthAccount.tsx +25 -0
  36. package/src/auth/better-auth-config.ts +85 -0
  37. package/src/auth/better-auth-provider.tsx +20 -0
  38. package/src/auth/cognito/CognitoAccount.tsx +48 -0
  39. package/src/auth/cognito/CognitoShell.tsx +266 -0
  40. package/src/auth/cognito/cognito-token.test.ts +110 -0
  41. package/src/auth/cognito/cognito-token.ts +47 -0
  42. package/src/auth/cognito/cognito.css +21 -0
  43. package/src/auth/cognito-provider.tsx +22 -0
  44. package/src/auth/combined-provider.tsx +42 -0
  45. package/src/auth/composition.test.ts +136 -0
  46. package/src/auth/provider.tsx +63 -0
  47. package/src/auth/sign-out-visibility.test.ts +40 -0
  48. package/src/auth/sign-out-visibility.ts +10 -0
  49. package/src/auth/sign-up-disabled.test.ts +23 -0
  50. package/src/components/compose/AddressField.tsx +237 -0
  51. package/src/components/compose/ComposeBody.tsx +36 -0
  52. package/src/components/compose/ComposeForm.tsx +676 -0
  53. package/src/components/compose/ComposeProvider.tsx +133 -0
  54. package/src/components/compose/ComposeSmtpMissingBanner.tsx +49 -0
  55. package/src/components/compose/FromSelector.tsx +67 -0
  56. package/src/components/compose/FullCompose.tsx +82 -0
  57. package/src/components/compose/InlineCompose.tsx +29 -0
  58. package/src/components/compose/MobileComposeSheet.tsx +152 -0
  59. package/src/components/compose/PlateEditor.tsx +86 -0
  60. package/src/components/compose/PlateToolbar.tsx +110 -0
  61. package/src/components/compose/SubjectField.tsx +19 -0
  62. package/src/components/compose/draft-discard-banner.test.ts +76 -0
  63. package/src/components/compose/index.ts +6 -0
  64. package/src/components/compose/sanitize-quote-html.ts +23 -0
  65. package/src/components/layout/AppShellSkeleton.tsx +53 -0
  66. package/src/components/layout/ComposeFab.tsx +86 -0
  67. package/src/components/layout/Drawer.tsx +105 -0
  68. package/src/components/mail/AutoMovedIndicator.tsx +48 -0
  69. package/src/components/mail/BlockedImagesNotice.render.test.ts +65 -0
  70. package/src/components/mail/BlockedImagesNotice.tsx +41 -0
  71. package/src/components/mail/BriefPane.tsx +289 -0
  72. package/src/components/mail/ConversationView.tsx +462 -0
  73. package/src/components/mail/DailyBrief.tsx +451 -0
  74. package/src/components/mail/DraftsView.tsx +279 -0
  75. package/src/components/mail/FlaggedList.tsx +170 -0
  76. package/src/components/mail/FlaggedPane.tsx +217 -0
  77. package/src/components/mail/IntelligencePane.test.ts +123 -0
  78. package/src/components/mail/IntelligencePane.tsx +441 -0
  79. package/src/components/mail/MailListHeader.tsx +187 -0
  80. package/src/components/mail/MailNav.tsx +70 -0
  81. package/src/components/mail/MailSidebarAdapter.tsx +351 -0
  82. package/src/components/mail/MailViewChrome.tsx +95 -0
  83. package/src/components/mail/MailboxPane.tsx +1219 -0
  84. package/src/components/mail/MessageActionMenu.tsx +368 -0
  85. package/src/components/mail/MessageBody.tsx +207 -0
  86. package/src/components/mail/MessageBodyErrorBanner.render.test.ts +85 -0
  87. package/src/components/mail/MessageBodyErrorBanner.test.ts +86 -0
  88. package/src/components/mail/MessageBodyErrorBanner.tsx +90 -0
  89. package/src/components/mail/MessageCard.tsx +401 -0
  90. package/src/components/mail/MessageDetail.tsx +153 -0
  91. package/src/components/mail/MessageList.tsx +804 -0
  92. package/src/components/mail/MessageListItem.tsx +267 -0
  93. package/src/components/mail/MessageToolbar.render.test.ts +57 -0
  94. package/src/components/mail/MessageToolbar.tsx +166 -0
  95. package/src/components/mail/MobileMessageBar.tsx +142 -0
  96. package/src/components/mail/MoveToTrigger.tsx +250 -0
  97. package/src/components/mail/NavMenuButton.tsx +25 -0
  98. package/src/components/mail/OutboxPane.tsx +531 -0
  99. package/src/components/mail/PullToRefresh.tsx +24 -0
  100. package/src/components/mail/RawMessageView.tsx +84 -0
  101. package/src/components/mail/ReadingPaneEmpty.render.test.ts +42 -0
  102. package/src/components/mail/SelectionToolbar.tsx +139 -0
  103. package/src/components/mail/SpamRescue.render.test.ts +35 -0
  104. package/src/components/mail/SpamRescue.tsx +138 -0
  105. package/src/components/mail/SwipeableMessageRow.tsx +148 -0
  106. package/src/components/mail/message-body-error-banner-content.ts +87 -0
  107. package/src/components/mail/organize/OrganizeDialog.render.test.ts +37 -0
  108. package/src/components/mail/organize/OrganizeDialog.tsx +83 -0
  109. package/src/components/mail/organize/OrganizePanel.render.test.ts +102 -0
  110. package/src/components/mail/organize/OrganizePanel.tsx +344 -0
  111. package/src/components/onboarding/OnboardingWizard.tsx +1547 -0
  112. package/src/components/settings/AccountFormPanel.test.ts +72 -0
  113. package/src/components/settings/AccountFormPanel.tsx +942 -0
  114. package/src/components/settings/DangerZone.tsx +30 -0
  115. package/src/components/settings/DeleteAccountDialog.render.test.ts +47 -0
  116. package/src/components/settings/DeleteAccountDialog.tsx +224 -0
  117. package/src/components/settings/FiltersList.render.test.ts +71 -0
  118. package/src/components/settings/FiltersList.tsx +93 -0
  119. package/src/components/settings/account-form-helpers.test.ts +172 -0
  120. package/src/components/settings/account-form-helpers.ts +105 -0
  121. package/src/components/ui/AppVersion.tsx +50 -0
  122. package/src/components/ui/BugReportButton.tsx +45 -0
  123. package/src/components/ui/ConfirmDialog.tsx +125 -0
  124. package/src/components/ui/DropdownMenu.tsx +105 -0
  125. package/src/components/ui/EmptyState.tsx +11 -0
  126. package/src/components/ui/ErrorBanner.tsx +88 -0
  127. package/src/components/ui/ErrorBannerProvider.tsx +77 -0
  128. package/src/components/ui/ErrorBannerStack.tsx +34 -0
  129. package/src/components/ui/ErrorState.tsx +80 -0
  130. package/src/components/ui/FatalErrorOverlay.render.test.ts +66 -0
  131. package/src/components/ui/FatalErrorOverlay.tsx +151 -0
  132. package/src/components/ui/KeyboardShortcutsModal.tsx +120 -0
  133. package/src/components/ui/SlidePanel.tsx +72 -0
  134. package/src/components/ui/error-banners.test.ts +207 -0
  135. package/src/components/ui/error-banners.ts +111 -0
  136. package/src/hooks/queries/keys.ts +38 -0
  137. package/src/hooks/useArchiveMailbox.ts +104 -0
  138. package/src/hooks/useAutoMovedBadge.ts +77 -0
  139. package/src/hooks/useCurrentMailboxName.ts +99 -0
  140. package/src/hooks/useDebouncedValue.ts +12 -0
  141. package/src/hooks/useDeleteMessages.test.ts +103 -0
  142. package/src/hooks/useDeleteMessages.ts +226 -0
  143. package/src/hooks/useFilters.ts +112 -0
  144. package/src/hooks/useIntelligenceData.test.ts +269 -0
  145. package/src/hooks/useIntelligenceData.ts +284 -0
  146. package/src/hooks/useIsDark.ts +27 -0
  147. package/src/hooks/useKeyboardNavigation.ts +192 -0
  148. package/src/hooks/useLayoutTier.test.ts +47 -0
  149. package/src/hooks/useLayoutTier.ts +44 -0
  150. package/src/hooks/useLongPress.test.ts +291 -0
  151. package/src/hooks/useLongPress.ts +87 -0
  152. package/src/hooks/useMailboxAccount.ts +62 -0
  153. package/src/hooks/useMailboxNameIndex.ts +32 -0
  154. package/src/hooks/useMarkAsRead.test.ts +165 -0
  155. package/src/hooks/useMarkAsRead.ts +319 -0
  156. package/src/hooks/useMediaQuery.ts +39 -0
  157. package/src/hooks/useMessageBodyContent.test.ts +370 -0
  158. package/src/hooks/useMessageBodyContent.ts +380 -0
  159. package/src/hooks/useMoveMessages.test.ts +63 -0
  160. package/src/hooks/useMoveMessages.ts +221 -0
  161. package/src/hooks/useOrganizeJob.ts +90 -0
  162. package/src/hooks/useOrganizePreview.ts +40 -0
  163. package/src/hooks/useRescueCandidates.test.ts +217 -0
  164. package/src/hooks/useRescueCandidates.ts +48 -0
  165. package/src/hooks/useSaveDraft.ts +118 -0
  166. package/src/hooks/useSelection.test.ts +75 -0
  167. package/src/hooks/useSelection.ts +211 -0
  168. package/src/hooks/useSemanticSearch.ts +94 -0
  169. package/src/hooks/useSignature.ts +69 -0
  170. package/src/hooks/useStaleAccountSync.test.ts +211 -0
  171. package/src/hooks/useStaleAccountSync.ts +246 -0
  172. package/src/hooks/useSwipeNavigation.test.ts +35 -0
  173. package/src/hooks/useSwipeNavigation.ts +99 -0
  174. package/src/hooks/useToggleStar.ts +187 -0
  175. package/src/hooks/useToggleTrusted.test.ts +102 -0
  176. package/src/hooks/useToggleTrusted.ts +161 -0
  177. package/src/hooks/useTriageKeyboard.ts +103 -0
  178. package/src/hooks/useTriggerSync.test.ts +24 -0
  179. package/src/hooks/useTriggerSync.ts +58 -0
  180. package/src/hooks/useUpdateAddressFlags.ts +125 -0
  181. package/src/hooks/useVisualViewport.test.ts +127 -0
  182. package/src/hooks/useVisualViewport.ts +51 -0
  183. package/src/index.css +19 -0
  184. package/src/lib/account-order.test.ts +84 -0
  185. package/src/lib/account-order.ts +13 -0
  186. package/src/lib/adjacent-message.test.ts +43 -0
  187. package/src/lib/adjacent-message.ts +20 -0
  188. package/src/lib/api.ts +82 -0
  189. package/src/lib/app-info.ts +15 -0
  190. package/src/lib/auto-moved.test.ts +140 -0
  191. package/src/lib/auto-moved.ts +68 -0
  192. package/src/lib/autodiscovery.test.ts +94 -0
  193. package/src/lib/autodiscovery.ts +354 -0
  194. package/src/lib/brief.test.ts +366 -0
  195. package/src/lib/brief.ts +180 -0
  196. package/src/lib/bug-report.test.ts +213 -0
  197. package/src/lib/bug-report.ts +176 -0
  198. package/src/lib/client.ts +36 -0
  199. package/src/lib/console-errors.test.ts +64 -0
  200. package/src/lib/console-errors.ts +92 -0
  201. package/src/lib/conversation-target.test.ts +68 -0
  202. package/src/lib/conversation-target.ts +59 -0
  203. package/src/lib/display-category.ts +20 -0
  204. package/src/lib/drafts.test.ts +241 -0
  205. package/src/lib/drafts.ts +121 -0
  206. package/src/lib/error-classifier.test.ts +133 -0
  207. package/src/lib/error-classifier.ts +96 -0
  208. package/src/lib/fatal-error.test.ts +97 -0
  209. package/src/lib/fatal-error.ts +165 -0
  210. package/src/lib/folder-roles.test.ts +113 -0
  211. package/src/lib/folder-roles.ts +112 -0
  212. package/src/lib/format.test.ts +115 -0
  213. package/src/lib/format.ts +198 -0
  214. package/src/lib/i18n.ts +36 -0
  215. package/src/lib/intelligence-pref.test.ts +57 -0
  216. package/src/lib/intelligence-pref.ts +25 -0
  217. package/src/lib/keymap-dispatch.test.ts +178 -0
  218. package/src/lib/keymap-dispatch.ts +187 -0
  219. package/src/lib/keymap.test.ts +49 -0
  220. package/src/lib/keymap.ts +178 -0
  221. package/src/lib/mail-context.ts +64 -0
  222. package/src/lib/mail-route.test.ts +80 -0
  223. package/src/lib/mail-route.ts +44 -0
  224. package/src/lib/message-body-source.test.ts +98 -0
  225. package/src/lib/message-body-source.ts +48 -0
  226. package/src/lib/move-targets.test.ts +195 -0
  227. package/src/lib/move-targets.ts +74 -0
  228. package/src/lib/onboarding-completion.test.ts +64 -0
  229. package/src/lib/onboarding-completion.ts +23 -0
  230. package/src/lib/organize/filter-status.test.ts +99 -0
  231. package/src/lib/organize/filter-status.ts +86 -0
  232. package/src/lib/organize/organize-copy.test.ts +93 -0
  233. package/src/lib/organize/organize-copy.ts +61 -0
  234. package/src/lib/organize/organize-model.test.ts +104 -0
  235. package/src/lib/organize/organize-model.ts +105 -0
  236. package/src/lib/organize/organize-poll.test.ts +37 -0
  237. package/src/lib/organize/organize-poll.ts +28 -0
  238. package/src/lib/outbox-status.test.ts +64 -0
  239. package/src/lib/outbox-status.ts +75 -0
  240. package/src/lib/plate-serializer.ts +164 -0
  241. package/src/lib/provider-presets.test.ts +96 -0
  242. package/src/lib/provider-presets.ts +81 -0
  243. package/src/lib/query-error-handler.test.ts +144 -0
  244. package/src/lib/query-error-handler.ts +34 -0
  245. package/src/lib/query-escalation.integration.test.ts +138 -0
  246. package/src/lib/recent-searches.test.ts +53 -0
  247. package/src/lib/recent-searches.ts +34 -0
  248. package/src/lib/rescue-candidates.test.ts +94 -0
  249. package/src/lib/rescue-candidates.ts +35 -0
  250. package/src/lib/rescue-telemetry.test.ts +75 -0
  251. package/src/lib/rescue-telemetry.ts +55 -0
  252. package/src/lib/rum-adapter.test.ts +299 -0
  253. package/src/lib/rum-adapter.ts +107 -0
  254. package/src/lib/saved-searches.test.ts +80 -0
  255. package/src/lib/saved-searches.ts +52 -0
  256. package/src/lib/search-pending.test.ts +61 -0
  257. package/src/lib/search-pending.ts +24 -0
  258. package/src/lib/search-query.test.ts +35 -0
  259. package/src/lib/search-query.ts +11 -0
  260. package/src/lib/search-result.test.ts +160 -0
  261. package/src/lib/search-result.ts +102 -0
  262. package/src/lib/search-schemas.ts +34 -0
  263. package/src/lib/search-token-index.test.ts +112 -0
  264. package/src/lib/search-token-index.ts +56 -0
  265. package/src/lib/search-tokens.test.ts +218 -0
  266. package/src/lib/search-tokens.ts +133 -0
  267. package/src/lib/telemetry-context.tsx +9 -0
  268. package/src/lib/telemetry.ts +17 -0
  269. package/src/lib/theme-preference.ts +46 -0
  270. package/src/lib/theme.ts +33 -0
  271. package/src/lib/utils.ts +4 -0
  272. package/src/main.tsx +10 -0
  273. package/src/routeTree.gen.ts +392 -0
  274. package/src/router.test.ts +81 -0
  275. package/src/router.tsx +31 -0
  276. package/src/routes/__root.tsx +69 -0
  277. package/src/routes/index.tsx +7 -0
  278. package/src/routes/mail/$mailboxId.tsx +27 -0
  279. package/src/routes/mail/flagged.tsx +37 -0
  280. package/src/routes/mail/index.tsx +41 -0
  281. package/src/routes/mail/outbox.tsx +13 -0
  282. package/src/routes/mail.tsx +413 -0
  283. package/src/routes/onboarding.tsx +35 -0
  284. package/src/routes/settings/-accounts.test.ts +65 -0
  285. package/src/routes/settings/accounts.tsx +542 -0
  286. package/src/routes/settings/advanced.tsx +55 -0
  287. package/src/routes/settings/appearance.tsx +140 -0
  288. package/src/routes/settings/filters.tsx +141 -0
  289. package/src/routes/settings/folders.tsx +216 -0
  290. package/src/routes/settings/index.tsx +5 -0
  291. package/src/routes/settings/senders.tsx +466 -0
  292. package/src/routes/settings/suggested-vips.tsx +10 -0
  293. package/src/routes/settings.tsx +66 -0
  294. package/src/runtime-config.ts +75 -0
  295. package/src/shell/index.tsx +98 -0
  296. package/src/types/index.ts +73 -0
  297. package/src/vite-env.d.ts +4 -0
  298. package/vite.base.ts +43 -0
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ // Reference distributor build over the web-client primitives. Composes the app
3
+ // shell with one auth provider and bundles a servable app with vite. This is
4
+ // the "build CLI as convenience over the primitives" — the primitives are the
5
+ // contract; this wraps them for the common case (reader's own self-host image
6
+ // build uses it).
7
+ //
8
+ // Usage: node harness/build.mjs [--auth <combined|cognito|better-auth>] [--out <dir>]
9
+ // --auth which identity system to compose in. Default: combined (both,
10
+ // selected at runtime). `better-auth` and `cognito` omit the other
11
+ // shell from the bundle entirely.
12
+ // --out output directory (relative to the package). Default: dist.
13
+ //
14
+ // The chosen provider can also be given via REMIT_AUTH_PROVIDER; the flag wins.
15
+ import { cpSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
16
+ import { dirname, join, resolve } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { build } from "vite";
19
+ // Loaded through tsx (see the `build:dist` script) so the .ts preset and the
20
+ // shared vite.base resolve without a prior compile step.
21
+ import { webClientPreset } from "./vite-preset.ts";
22
+
23
+ const harnessDir = dirname(fileURLToPath(import.meta.url));
24
+ const packageDir = resolve(harnessDir, "..");
25
+
26
+ const parseArgs = (argv) => {
27
+ const args = { auth: process.env.REMIT_AUTH_PROVIDER ?? "combined", out: "dist" };
28
+ for (let i = 0; i < argv.length; i += 1) {
29
+ if (argv[i] === "--auth") args.auth = argv[(i += 1)];
30
+ else if (argv[i] === "--out") args.out = argv[(i += 1)];
31
+ }
32
+ return args;
33
+ };
34
+
35
+ const PROVIDERS = {
36
+ combined: { specifier: "@remit/web-client/auth/combined", name: "combinedAuthProvider", cognitoCss: true },
37
+ cognito: { specifier: "@remit/web-client/auth/cognito", name: "cognitoAuthProvider", cognitoCss: true },
38
+ "better-auth": { specifier: "@remit/web-client/auth/better-auth", name: "betterAuthProvider", cognitoCss: false },
39
+ };
40
+
41
+ const entrySource = (provider) =>
42
+ [
43
+ provider.cognitoCss ? 'import "@remit/web-client/styles/cognito.css";' : null,
44
+ 'import { mountApp } from "@remit/web-client/shell";',
45
+ `import { ${provider.name} } from "${provider.specifier}";`,
46
+ "",
47
+ `mountApp({ authProvider: ${provider.name} });`,
48
+ "",
49
+ ]
50
+ .filter((line) => line !== null)
51
+ .join("\n");
52
+
53
+ const run = async () => {
54
+ const { auth, out } = parseArgs(process.argv.slice(2));
55
+ const provider = PROVIDERS[auth];
56
+ if (!provider) {
57
+ console.error(`Unknown --auth "${auth}". Expected one of: ${Object.keys(PROVIDERS).join(", ")}.`);
58
+ process.exit(1);
59
+ }
60
+
61
+ // A throwaway root holding just the entry and index.html. Everything else —
62
+ // the shell, screens, styles, config.js — resolves out of the installed
63
+ // package and its public dir, exactly as an external distributor's would.
64
+ const root = join(packageDir, ".harness-build");
65
+ rmSync(root, { recursive: true, force: true });
66
+ mkdirSync(root, { recursive: true });
67
+ cpSync(join(harnessDir, "index.html"), join(root, "index.html"));
68
+ writeFileSync(join(root, "entry.tsx"), entrySource(provider));
69
+
70
+ try {
71
+ await build({
72
+ root,
73
+ publicDir: join(packageDir, "public"),
74
+ build: { outDir: resolve(packageDir, out), emptyOutDir: true },
75
+ ...webClientPreset(),
76
+ });
77
+ } finally {
78
+ rmSync(root, { recursive: true, force: true });
79
+ }
80
+
81
+ console.log(`Built web client (auth: ${auth}) to ${resolve(packageDir, out)}`);
82
+ };
83
+
84
+ run();
@@ -0,0 +1,37 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Remit</title>
7
+ <!--
8
+ Pre-paint theme to avoid a flash-of-wrong-theme on reload. Mirrors
9
+ theme-preference.ts: a stored "remit.theme" of "light"/"dark" wins;
10
+ "system" (or no key) follows prefers-color-scheme.
11
+ -->
12
+ <script>
13
+ (function () {
14
+ try {
15
+ var pref = localStorage.getItem("remit.theme");
16
+ var isDark =
17
+ pref === "dark" ||
18
+ (pref !== "light" &&
19
+ window.matchMedia &&
20
+ window.matchMedia("(prefers-color-scheme: dark)").matches);
21
+ document.documentElement.classList.toggle("dark", isDark);
22
+ } catch (_) {}
23
+ })();
24
+ </script>
25
+ </head>
26
+ <body>
27
+ <div id="root"></div>
28
+ <!--
29
+ Runtime deployment config. A classic (non-module) script so it runs before
30
+ the deferred module bundle: it sets window.__REMIT_CONFIG__, read by the
31
+ runtime-config primitive. Served from the distributor's public dir and
32
+ replaced per deployment; never bundled.
33
+ -->
34
+ <script src="/config.js"></script>
35
+ <script type="module" src="./entry.tsx"></script>
36
+ </body>
37
+ </html>
@@ -0,0 +1,29 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import type { UserConfig } from "vite";
3
+ import {
4
+ webClientAlias,
5
+ webClientDefine,
6
+ webClientPlugins,
7
+ } from "../vite.base.ts";
8
+
9
+ /**
10
+ * Reference vite configuration for composing the web-client primitives into a
11
+ * servable bundle. A distributor spreads this into its own vite config (or uses
12
+ * the `build.mjs` CLI, which wraps it). It reuses the shared build base and
13
+ * points the route generator at the installed package's source, so an external
14
+ * consumer's bundler resolves the primitives without further wiring.
15
+ *
16
+ * The auth shell is chosen by which provider the entry imports — not by this
17
+ * config — so there is nothing here to select per deployment.
18
+ */
19
+ const packageFile = (relative: string): string =>
20
+ fileURLToPath(new URL(relative, import.meta.url));
21
+
22
+ export const webClientPreset = (): UserConfig => ({
23
+ plugins: webClientPlugins({
24
+ routesDirectory: packageFile("../src/routes"),
25
+ generatedRouteTree: packageFile("../src/routeTree.gen.ts"),
26
+ }),
27
+ resolve: { alias: webClientAlias() },
28
+ define: webClientDefine(),
29
+ });
package/index.html ADDED
@@ -0,0 +1,47 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Remit</title>
7
+ <!--
8
+ Hint the browser to start the TLS handshake to API Gateway in parallel
9
+ with the JS bundle download. Saves ~150-300ms before the first /config
10
+ request fires. Hardcoded to the prod API origin; in local dev this
11
+ preconnect is harmless (it's just a hint and the dev API is proxied
12
+ through the Vite server).
13
+ -->
14
+ <link rel="preconnect" href="https://cr0f00ych7.execute-api.eu-west-1.amazonaws.com" crossorigin />
15
+ <!--
16
+ Pre-paint theme to avoid a flash-of-wrong-theme on reload. Mirrors
17
+ theme-preference.ts: a stored "remit.theme" of "light"/"dark" wins;
18
+ "system" (or no key) follows prefers-color-scheme. Keep this in sync
19
+ with src/lib/theme-preference.ts (STORAGE_KEY / resolution logic).
20
+ -->
21
+ <script>
22
+ (function () {
23
+ try {
24
+ var pref = localStorage.getItem("remit.theme");
25
+ var isDark =
26
+ pref === "dark" ||
27
+ (pref !== "light" &&
28
+ window.matchMedia &&
29
+ window.matchMedia("(prefers-color-scheme: dark)").matches);
30
+ document.documentElement.classList.toggle("dark", isDark);
31
+ } catch (_) {}
32
+ })();
33
+ </script>
34
+ </head>
35
+ <body>
36
+ <div id="root"></div>
37
+ <!--
38
+ Runtime deployment config. A classic (non-module) script so it runs before
39
+ the deferred module bundle: it sets window.__REMIT_CONFIG__, which
40
+ src/runtime-config.ts reads. Served as a static default in the built dist
41
+ and replaced per deployment; never bundled, so one build serves every
42
+ deployment.
43
+ -->
44
+ <script src="/config.js"></script>
45
+ <script type="module" src="/src/main.tsx"></script>
46
+ </body>
47
+ </html>
package/package.json ADDED
@@ -0,0 +1,147 @@
1
+ {
2
+ "name": "@remit/web-client",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "description": "Remit web client, published as composable primitives — the app shell, auth shells, and runtime config. A distributor imports what it composes and bundles it.",
6
+ "exports": {
7
+ "./shell": "./src/shell/index.tsx",
8
+ "./config": "./src/runtime-config.ts",
9
+ "./auth/provider": "./src/auth/provider.tsx",
10
+ "./auth/cognito": "./src/auth/cognito-provider.tsx",
11
+ "./auth/better-auth": "./src/auth/better-auth-provider.tsx",
12
+ "./auth/combined": "./src/auth/combined-provider.tsx",
13
+ "./styles/app.css": "./src/index.css",
14
+ "./styles/cognito.css": "./src/auth/cognito/cognito.css",
15
+ "./vite-preset": "./harness/vite-preset.ts"
16
+ },
17
+ "files": [
18
+ "src",
19
+ "harness",
20
+ "vite.base.ts",
21
+ "public",
22
+ "index.html"
23
+ ],
24
+ "scripts": {
25
+ "dev": "vite",
26
+ "generate:routes": "node scripts/generate-routes.mjs",
27
+ "prepack": "npm run generate:routes",
28
+ "build": "npm run generate:routes && tsc -b && vite build",
29
+ "build:dist": "npm run generate:routes && node --import tsx harness/build.mjs",
30
+ "preview": "vite preview",
31
+ "test:typecheck": "npm run generate:routes && tsgo --noEmit",
32
+ "test:run": "node --import tsx --import ./test-support/register.mjs --test 'src/**/*.test.ts'",
33
+ "test": "npm run test:typecheck && npm run test:run",
34
+ "test:smoke": "npx playwright test --config playwright.smoke.config.ts",
35
+ "test:smoke:pg": "npx playwright test --config playwright.smoke.pg.config.ts",
36
+ "test:smoke:ui": "npx playwright test --config playwright.smoke.config.ts --ui",
37
+ "test:e2e": "npx playwright test --config playwright.e2e.config.ts",
38
+ "test:e2e:pg": "npx playwright test --config playwright.e2e.pg.config.ts",
39
+ "test:e2e:ui": "npx playwright test --config playwright.e2e.config.ts --ui",
40
+ "test:visual:fetch": "bash scripts/visual-baselines.sh fetch",
41
+ "test:visual:publish": "bash scripts/visual-baselines.sh publish",
42
+ "test:visual:status": "bash scripts/visual-baselines.sh status",
43
+ "test:visual": "npm run test:visual:fetch && npx playwright test --config playwright.visual.config.ts",
44
+ "test:visual:ui": "npm run test:visual:fetch && npx playwright test --config playwright.visual.config.ts --ui",
45
+ "test:visual:update": "npm run test:visual:fetch && npx playwright test --config playwright.visual.config.ts --update-snapshots=all && echo '\\nBaselines updated locally. Run: npm run test:visual:publish -w packages/web-client'",
46
+ "playwright:install": "npx playwright install chromium",
47
+ "parity:montage": "node --import tsx visual-regression/parity/montage.ts",
48
+ "parity:capture": "node --import tsx visual-regression/parity/capture-parity.ts",
49
+ "parity:capture:dev": "PARITY_TARGET=dev node --import tsx visual-regression/parity/capture-parity-dev.ts",
50
+ "parity:report": "node --import tsx visual-regression/parity/report.scaffold.ts"
51
+ },
52
+ "peerDependencies": {
53
+ "react": "^19",
54
+ "react-dom": "^19",
55
+ "vite": "^7",
56
+ "@vitejs/plugin-react": "^4",
57
+ "@tailwindcss/vite": "^4",
58
+ "tailwindcss": "^4",
59
+ "@tanstack/router-plugin": "^1"
60
+ },
61
+ "peerDependenciesMeta": {
62
+ "vite": {
63
+ "optional": true
64
+ },
65
+ "@vitejs/plugin-react": {
66
+ "optional": true
67
+ },
68
+ "@tailwindcss/vite": {
69
+ "optional": true
70
+ },
71
+ "tailwindcss": {
72
+ "optional": true
73
+ },
74
+ "@tanstack/router-plugin": {
75
+ "optional": true
76
+ }
77
+ },
78
+ "dependencies": {
79
+ "@hookform/resolvers": "*",
80
+ "@platejs/autoformat": "*",
81
+ "@platejs/basic-nodes": "*",
82
+ "@platejs/link": "*",
83
+ "@remit/api-http-client": "*",
84
+ "@remit/domain-enums": "*",
85
+ "@remit/ui": "*",
86
+ "@tanstack/react-query": "^5",
87
+ "@tanstack/react-query-devtools": "^5",
88
+ "@tanstack/react-router": "^1",
89
+ "@tanstack/react-virtual": "^3.13.18",
90
+ "@tanstack/zod-adapter": "^1",
91
+ "aws-amplify": "^6",
92
+ "@aws-amplify/ui-react": "^6",
93
+ "aws-rum-web": "^3",
94
+ "better-auth": "^1.6.23",
95
+ "clsx": "^2",
96
+ "dompurify": "^3.4.7",
97
+ "i18next": "^24",
98
+ "i18next-browser-languagedetector": "^8",
99
+ "i18next-http-backend": "^3.0.6",
100
+ "lucide-react": "^0.468",
101
+ "p-map": "*",
102
+ "platejs": "*",
103
+ "prop-types": "^15.8.1",
104
+ "react-hook-form": "*",
105
+ "react-i18next": "^15",
106
+ "react-resizable-panels": "^2.1.9",
107
+ "tailwind-merge": "^2",
108
+ "vaul": "^1.1.2",
109
+ "zod": "^3"
110
+ },
111
+ "devDependencies": {
112
+ "@aws-sdk/client-dynamodb": "*",
113
+ "@aws-sdk/client-sqs": "*",
114
+ "@aws-sdk/lib-dynamodb": "*",
115
+ "@types/nodemailer": "*",
116
+ "nodemailer": "^9.0.3",
117
+ "@playwright/test": "1.58.2",
118
+ "@remit/drizzle-service": "*",
119
+ "@remit/electrodb-entities": "*",
120
+ "@remit/secrets-service": "*",
121
+ "@tailwindcss/vite": "^4",
122
+ "@tanstack/router-generator": "^1",
123
+ "@tanstack/router-plugin": "^1",
124
+ "@types/dompurify": "*",
125
+ "@types/pngjs": "^6.0.5",
126
+ "@types/react-dom": "^19",
127
+ "@vitejs/plugin-react": "^4",
128
+ "electrodb": "*",
129
+ "esbuild": "*",
130
+ "expect-env": "*",
131
+ "pngjs": "^5",
132
+ "react": "^19",
133
+ "react-dom": "^19.2.4",
134
+ "tailwindcss": "^4",
135
+ "typescript": "*",
136
+ "vite": "^7.3.6"
137
+ },
138
+ "license": "MIT",
139
+ "publishConfig": {
140
+ "access": "public"
141
+ },
142
+ "repository": {
143
+ "type": "git",
144
+ "url": "git+https://github.com/remit-mail/reader.git",
145
+ "directory": "packages/web-client"
146
+ }
147
+ }
@@ -0,0 +1,5 @@
1
+ // Runtime deployment configuration, read by src/runtime-config.ts before the
2
+ // app boots. This default serves the self-host stack (better-auth identity).
3
+ // Each deployment replaces this file: the AWS deploy writes Cognito values, and
4
+ // the dev server injects it from REMIT_RUNTIME_CONFIG.
5
+ window.__REMIT_CONFIG__ = { betterAuthEnabled: true };
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,13 @@
1
+ {
2
+ "sidebar": {
3
+ "inbox": "Posteingang",
4
+ "sent": "Gesendet",
5
+ "drafts": "Entwürfe",
6
+ "trash": "Papierkorb",
7
+ "archive": "Archiv",
8
+ "spam": "Spam",
9
+ "junk": "Spam",
10
+ "flagged": "Markiert",
11
+ "all": "Alle E-Mails"
12
+ }
13
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,26 @@
1
+ {
2
+ "app": {
3
+ "title": "Remit",
4
+ "loading": "Loading...",
5
+ "error": "Something went wrong"
6
+ },
7
+ "actions": {
8
+ "save": "Save",
9
+ "cancel": "Cancel",
10
+ "delete": "Delete",
11
+ "close": "Close",
12
+ "confirm": "Confirm"
13
+ },
14
+ "pagination": {
15
+ "previous": "Previous",
16
+ "next": "Next",
17
+ "page": "Page {{current}} of {{total}}",
18
+ "showing": "Showing {{from}}-{{to}} of {{total}}"
19
+ },
20
+ "accessibility": {
21
+ "skipToContent": "Skip to main content",
22
+ "loading": "Loading content",
23
+ "menuOpen": "Open menu",
24
+ "menuClose": "Close menu"
25
+ }
26
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,69 @@
1
+ {
2
+ "sidebar": {
3
+ "inbox": "Inbox",
4
+ "sent": "Sent",
5
+ "drafts": "Drafts",
6
+ "trash": "Trash",
7
+ "archive": "Archive",
8
+ "spam": "Spam",
9
+ "junk": "Spam",
10
+ "flagged": "Starred",
11
+ "all": "All Mail",
12
+ "noAccounts": "No accounts configured",
13
+ "noMailboxes": "No mailboxes"
14
+ },
15
+ "emptyState": {
16
+ "selectMailbox": "Select a mailbox to view messages",
17
+ "selectMessage": "Select a message to read",
18
+ "noMessages": "No messages in this mailbox",
19
+ "messageNotFound": "Message not found"
20
+ },
21
+ "inbox": {
22
+ "title": "Inbox",
23
+ "empty": "No messages in your inbox",
24
+ "emptyFiltered": "No {{filter}} messages",
25
+ "noSubject": "(No subject)"
26
+ },
27
+ "thread": {
28
+ "messageCount": "{{count}} message",
29
+ "messageCount_other": "{{count}} messages",
30
+ "unreadCount": "{{count}} unread",
31
+ "participants": "{{count}} participant",
32
+ "participants_other": "{{count}} participants"
33
+ },
34
+ "filters": {
35
+ "all": "All",
36
+ "unread": "Unread",
37
+ "starred": "Starred",
38
+ "attachments": "Has attachments"
39
+ },
40
+ "actions": {
41
+ "compose": "Compose",
42
+ "reply": "Reply",
43
+ "replyAll": "Reply all",
44
+ "forward": "Forward",
45
+ "archive": "Archive",
46
+ "markRead": "Mark as read",
47
+ "markUnread": "Mark as unread",
48
+ "star": "Star",
49
+ "unstar": "Remove star",
50
+ "moveToTrash": "Move to trash"
51
+ },
52
+ "compose": {
53
+ "title": "New message",
54
+ "description": "Compose a new email message",
55
+ "to": "To",
56
+ "cc": "Cc",
57
+ "bcc": "Bcc",
58
+ "subject": "Subject",
59
+ "body": "Message",
60
+ "send": "Send",
61
+ "discard": "Discard",
62
+ "attachFiles": "Attach files"
63
+ },
64
+ "time": {
65
+ "justNow": "Just now",
66
+ "today": "Today",
67
+ "yesterday": "Yesterday"
68
+ }
69
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,13 @@
1
+ {
2
+ "sidebar": {
3
+ "inbox": "Boîte de réception",
4
+ "sent": "Envoyés",
5
+ "drafts": "Brouillons",
6
+ "trash": "Corbeille",
7
+ "archive": "Archives",
8
+ "spam": "Indésirables",
9
+ "junk": "Indésirables",
10
+ "flagged": "Suivis",
11
+ "all": "Tous les messages"
12
+ }
13
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,13 @@
1
+ {
2
+ "sidebar": {
3
+ "inbox": "Postvak IN",
4
+ "sent": "Verzonden",
5
+ "drafts": "Concepten",
6
+ "trash": "Prullenbak",
7
+ "archive": "Archief",
8
+ "spam": "Ongewenst",
9
+ "junk": "Ongewenst",
10
+ "flagged": "Met ster",
11
+ "all": "Alle berichten"
12
+ }
13
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,58 @@
1
+ import { Avatar } from "@remit/ui";
2
+ import { useNavigate } from "@tanstack/react-router";
3
+ import { LogOut, Settings } from "lucide-react";
4
+ import {
5
+ DropdownMenu,
6
+ DropdownMenuItem,
7
+ DropdownMenuSeparator,
8
+ } from "@/components/ui/DropdownMenu";
9
+ import { AccountSession } from "./AccountSession";
10
+
11
+ interface AccountMenuViewProps {
12
+ email: string | null;
13
+ onSignOut: () => void;
14
+ }
15
+
16
+ const AccountMenuView = ({ email, onSignOut }: AccountMenuViewProps) => {
17
+ const navigate = useNavigate();
18
+ const displayName = email ?? "Account";
19
+
20
+ return (
21
+ <DropdownMenu
22
+ trigger={
23
+ <Avatar name={displayName} email={email ?? undefined} size="sm" />
24
+ }
25
+ align="right"
26
+ >
27
+ {email && (
28
+ <>
29
+ <div
30
+ className="px-3 py-2 text-xs text-fg-muted truncate"
31
+ title={email}
32
+ data-testid="account-menu-email"
33
+ >
34
+ {email}
35
+ </div>
36
+ <DropdownMenuSeparator />
37
+ </>
38
+ )}
39
+ <DropdownMenuItem onClick={() => navigate({ to: "/settings/accounts" })}>
40
+ <Settings className="size-4" />
41
+ Settings
42
+ </DropdownMenuItem>
43
+ <DropdownMenuSeparator />
44
+ <DropdownMenuItem onClick={onSignOut}>
45
+ <LogOut className="size-4" />
46
+ Sign out
47
+ </DropdownMenuItem>
48
+ </DropdownMenu>
49
+ );
50
+ };
51
+
52
+ export const AccountMenu = () => (
53
+ <AccountSession>
54
+ {({ email, signOut }) => (
55
+ <AccountMenuView email={email} onSignOut={signOut} />
56
+ )}
57
+ </AccountSession>
58
+ );
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ import { type AuthAccount, useAuthProvider } from "./provider";
3
+
4
+ export type AccountSessionValue = AuthAccount;
5
+
6
+ interface AccountSessionProps {
7
+ children: (session: AccountSessionValue) => ReactNode;
8
+ }
9
+
10
+ /**
11
+ * Hands the signed-in account's email and a `signOut` action to its children,
12
+ * sourced from whichever identity provider the app was composed with. Renders
13
+ * nothing when no session is active, so the same account affordances mount in
14
+ * every auth mode without a surface knowing which provider is in play.
15
+ */
16
+ export const AccountSession = ({ children }: AccountSessionProps) => {
17
+ const { Account } = useAuthProvider();
18
+ return <Account>{children}</Account>;
19
+ };