@entropy-softworks/ui 2026.8.40 → 2026.8.42
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.
- package/CHANGELOG.md +121 -97
- package/lib/components/item-icon.d.ts +16 -0
- package/lib/components/item-icon.d.ts.map +1 -1
- package/lib/components/item-icon.jsx +2 -2
- package/lib/components/item-icon.jsx.map +1 -1
- package/lib/hooks/index.d.ts +1 -1
- package/lib/hooks/index.d.ts.map +1 -1
- package/lib/hooks/index.js +1 -1
- package/lib/hooks/index.js.map +1 -1
- package/lib/hooks/useUploadBlobUrl.d.ts +49 -5
- package/lib/hooks/useUploadBlobUrl.d.ts.map +1 -1
- package/lib/hooks/useUploadBlobUrl.js +92 -13
- package/lib/hooks/useUploadBlobUrl.js.map +1 -1
- package/lib/screens/auth/AuthScreen.d.ts.map +1 -1
- package/lib/screens/auth/AuthScreen.jsx +18 -0
- package/lib/screens/auth/AuthScreen.jsx.map +1 -1
- package/package.json +1 -1
- package/src/components/item-icon.tsx +18 -2
- package/src/hooks/__tests__/useUploadBlobUrl.test.tsx +128 -16
- package/src/hooks/index.ts +6 -1
- package/src/hooks/useUploadBlobUrl.ts +140 -16
- package/src/screens/auth/AuthScreen.tsx +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,137 +7,161 @@ are CalVer — `YYYY.M.D` of the publish date, with leading zeros dropped (npm's
|
|
|
7
7
|
them), matching the `entropy-auth` crate. The `0.1.0` entry below predates the switch and was never
|
|
8
8
|
published to npm.
|
|
9
9
|
|
|
10
|
+
## 2026.8.42
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Custom uploaded icons never rendered on a phone. `useUploadBlobUrl` built its URI with
|
|
15
|
+
`URL.createObjectURL`, which is a browser API — React Native's `URL` does not implement it in any
|
|
16
|
+
way that can be relied on, so the call either threw or produced something no image loader would
|
|
17
|
+
open, and every upload fell through to the fallback glyph on every native consumer. Web still gets
|
|
18
|
+
a blob URL (no copy, and revocable); native now reads the bytes and builds
|
|
19
|
+
`data:<type>;base64,...`, which every RN image loader accepts. Base64 inflates by a third and the
|
|
20
|
+
string lives as long as the row is mounted, which is affordable for icons — vault caps an upload
|
|
21
|
+
at 256KB — and is why the two platforms differ rather than both taking the data URI.
|
|
22
|
+
- The base64 encoder is hand-rolled rather than `btoa`. React Native ships no `btoa`, so whether one
|
|
23
|
+
exists depends on which polyfill the consuming app installed, which is not something a library can
|
|
24
|
+
assume.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `useUploadBlobUrl` takes an options object — `{ uploadsPath, resolve }` — in place of the bare
|
|
29
|
+
path, which still works. `resolve` produces the URI for an upload id without going through
|
|
30
|
+
`apiFetch` at all, for a consumer whose uploads are not behind a server: vault's device-only
|
|
31
|
+
vaults keep theirs in on-device SQLite. Returning `null` reports `errored`, so an id that does not
|
|
32
|
+
resolve draws the same fallback a failed fetch does. The resolver is held in a ref and only
|
|
33
|
+
`uploadId` / `uploadsPath` re-run the effect, so an arrow defined inline at the call site cannot
|
|
34
|
+
turn every render into a refetch.
|
|
35
|
+
- `ItemIcon` takes `resolveUpload`, passed straight through. Without it such a consumer had to
|
|
36
|
+
pre-resolve the reference into a `data:` URI and hand it over as `iconUrl` — which works only
|
|
37
|
+
because anything that is not `custom:` is treated as a plain URL, and hides the intent completely.
|
|
38
|
+
|
|
39
|
+
## 2026.8.41
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- `AuthScreen`'s form-height lock skipped its measuring pass for any consumer that resolves
|
|
44
|
+
`signUpEnabled` asynchronously. `probed` was initialised from `signUpEnabled`, which is right when
|
|
45
|
+
the consumer knows its registration policy at mount — but one that has to ASK for it (Access's
|
|
46
|
+
portal fetches the tenant's policy and starts at the conservative "closed") mounted with sign-up
|
|
47
|
+
off, skipped the pre-measure, and turned sign-up on a moment later with nothing measured. The
|
|
48
|
+
first real toggle was then the one that grew the card: it resized once, then held still forever,
|
|
49
|
+
which is exactly the symptom the lock exists to remove. The probe now re-arms on the false -> true
|
|
50
|
+
edge.
|
|
51
|
+
|
|
10
52
|
## 2026.8.40
|
|
11
53
|
|
|
12
54
|
### Added
|
|
13
55
|
|
|
14
|
-
- `AuthScreen` takes `lockFormHeight` (default `true`). The card reserves the
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
already wrapped in a layout animation, so the change eases rather than jumps.
|
|
56
|
+
- `AuthScreen` takes `lockFormHeight` (default `true`). The card reserves the height of the taller
|
|
57
|
+
of Sign In / Sign Up so the two toggle without the layout moving; the cost is slack, left as empty
|
|
58
|
+
space above the shorter mode's submit button. Where Sign Up carries several more fields that gap
|
|
59
|
+
is the more visible flaw of the two — most people only ever sign in, and they all see it — so a
|
|
60
|
+
consumer can now let the card resize instead. The body is already wrapped in a layout animation,
|
|
61
|
+
so the change eases rather than jumps.
|
|
21
62
|
|
|
22
63
|
## 2026.8.39
|
|
23
64
|
|
|
24
65
|
### Added
|
|
25
66
|
|
|
26
|
-
- `SocialConnections` takes `showEntropy` (default `true`), which drops the
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
simple-finance renders the whole row with no handlers at all, and inference
|
|
34
|
-
would silently take that button away from it.
|
|
67
|
+
- `SocialConnections` takes `showEntropy` (default `true`), which drops the first-party "Continue
|
|
68
|
+
with Entropy" button from the row. Unlike the other three, that one is not a staged-rollout
|
|
69
|
+
placeholder waiting for its connector: on Entropy Access's own sign-in surfaces it offers to sign
|
|
70
|
+
in to the identity provider with the identity provider, which is a button that can never mean
|
|
71
|
+
anything. A flag rather than inferring intent from a missing `onEntropy`, because rendering an
|
|
72
|
+
unhandled provider is deliberate here — simple-finance renders the whole row with no handlers at
|
|
73
|
+
all, and inference would silently take that button away from it.
|
|
35
74
|
|
|
36
75
|
## 2026.8.35
|
|
37
76
|
|
|
38
77
|
### Fixed
|
|
39
78
|
|
|
40
|
-
- `AuthService.getCurrentUser()` destroyed the session it was asked about. It
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
The request is shared with `refreshUserData()` through a private `fetchMe`,
|
|
62
|
-
parameterised on whether a 401 should log out: a refresh of a session
|
|
63
|
-
believed live that 401s means the session died, while a lookup that 401s is
|
|
64
|
-
just an anonymous visitor and must not tear anything down.
|
|
79
|
+
- `AuthService.getCurrentUser()` destroyed the session it was asked about. It returned
|
|
80
|
+
`loadPersistedUser()` and nothing else, and on web that reads a module-level variable which is
|
|
81
|
+
null in every freshly loaded document — so it answered "nobody" on each page load and refresh
|
|
82
|
+
while the session cookie was perfectly valid. `useAuth.checkAuth` treats that as a session it
|
|
83
|
+
cannot resolve and calls `logout()`, which POSTs `/auth/logout` and ends the session server-side:
|
|
84
|
+
the user was signed out by the act of loading the page.
|
|
85
|
+
|
|
86
|
+
Observed on Access, whose portal and admin console are separate SPAs on one origin — so every
|
|
87
|
+
navigation between them is a fresh document and therefore a guaranteed logout, presenting as an
|
|
88
|
+
infinite sign-in loop. Its audit log recorded the logouts nobody had asked for.
|
|
89
|
+
|
|
90
|
+
Native was affected too, if less visibly: `isAuthenticated()` there is satisfied by a token in
|
|
91
|
+
SecureStore, so a token that outlived its cached user record produced the same spurious logout.
|
|
92
|
+
|
|
93
|
+
`getCurrentUser()` now falls back to `GET /auth/me` when nothing is persisted. It deliberately
|
|
94
|
+
does not route through `isAuthenticated()`, whose web branch falls back to calling
|
|
95
|
+
`getCurrentUser()` — going the other way would recurse until the stack gave out, on exactly the
|
|
96
|
+
signed-out path this makes cheap. The request is shared with `refreshUserData()` through a private
|
|
97
|
+
`fetchMe`, parameterised on whether a 401 should log out: a refresh of a session believed live
|
|
98
|
+
that 401s means the session died, while a lookup that 401s is just an anonymous visitor and must
|
|
99
|
+
not tear anything down.
|
|
65
100
|
|
|
66
101
|
## 2026.8.17
|
|
67
102
|
|
|
68
103
|
### Fixed
|
|
69
104
|
|
|
70
|
-
- The systemic bare-CSS-var-no-`dark:`-fallback pattern flagged as a known
|
|
71
|
-
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
stretching to match its own `w-full` Pressable child — surfaced as the
|
|
86
|
-
"Sign In" button rendering with a runaway width specifically once its
|
|
87
|
-
content swapped from label text to the loading spinner (the one thing
|
|
88
|
-
that actually changes Yoga's layout resolution for that ambiguous case).
|
|
89
|
-
Added `items-stretch` alongside `flex-col` at every call site.
|
|
105
|
+
- The systemic bare-CSS-var-no-`dark:`-fallback pattern flagged as a known follow-up in 2026.8.15 —
|
|
106
|
+
completed across the rest of the package: `Card`, `ContextMenu`, `DataTable`, `DropdownMenu`,
|
|
107
|
+
`Popover`, `SettingsRow`, `PinPad`, `PasswordGenerator`, `EntropyByline`, `ErrorBoundary` (severe:
|
|
108
|
+
its retry button's label was invisible white-on-white in dark mode), `Pagination`, `LockOverlay`,
|
|
109
|
+
`ProtectedRoute`, and every screen under `src/screens/auth/*` (root backgrounds, plus scattered
|
|
110
|
+
destructive-text and `ServerConfigScreen`'s from-scratch raw-`Text` markup).
|
|
111
|
+
- `CardFooter`'s base `items-center` was never overridden by the `flex-col` className every
|
|
112
|
+
consuming screen passes it (`AuthScreen`, `LoginScreen`, `RegisterScreen`, and ~10 others) —
|
|
113
|
+
`flex-row`→`flex-col` and `border-t`→ `border-t-0` correctly override via tailwind-merge's
|
|
114
|
+
same-property matching, but `items-center` has no `items-*` counterpart in that className to
|
|
115
|
+
conflict with, so it silently survived. Left the submit button's wrapping view with ambiguous
|
|
116
|
+
(content-fit) width instead of stretching to match its own `w-full` Pressable child — surfaced as
|
|
117
|
+
the "Sign In" button rendering with a runaway width specifically once its content swapped from
|
|
118
|
+
label text to the loading spinner (the one thing that actually changes Yoga's layout resolution
|
|
119
|
+
for that ambiguous case). Added `items-stretch` alongside `flex-col` at every call site.
|
|
90
120
|
|
|
91
121
|
## 2026.8.15
|
|
92
122
|
|
|
93
123
|
### Fixed
|
|
94
124
|
|
|
95
|
-
- Several components colored themselves with a bare CSS-variable utility
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
`
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
text
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
pattern is present in roughly 15 more files in this package
|
|
113
|
-
(`password-generator.tsx`, `pin-pad.tsx`, `tag-chip.tsx`, several other
|
|
114
|
-
still-active auth screens, …) — scoped out of this release to unblock the
|
|
115
|
-
reported bug; needs its own pass.
|
|
125
|
+
- Several components colored themselves with a bare CSS-variable utility (`bg-primary`,
|
|
126
|
+
`bg-background`, `border-border`, `bg-destructive`, …) and no `dark:` fallback — on native Android
|
|
127
|
+
that value stays stuck on its light setting regardless of actual system theme; only components
|
|
128
|
+
carrying an explicit `dark:`-prefixed class (the existing pattern in `Heading`/`Text`/
|
|
129
|
+
`MutedText`) reacted correctly. Added matching `dark:` variants — one per CSS variable's own
|
|
130
|
+
`.dark` value in `styles/globals.css` — to `Button`, `Input`, `Dialog`'s destructive variant,
|
|
131
|
+
`legal-dialog`'s body text, and `AuthScreen`'s root background. Surfaced as vault's "Get Started"
|
|
132
|
+
screen going render-broken in dark mode: invisible button, invisible heading/legal text, and a
|
|
133
|
+
background that stayed white.
|
|
134
|
+
- `AuthScreen`'s tagline and "← Back" link used the plain `Text` component with a
|
|
135
|
+
`text-muted-foreground` override that fought `Text`'s own base `dark:text-white` — the override
|
|
136
|
+
lost to the base class's `dark:` variant, so both rendered bright white instead of muted in dark
|
|
137
|
+
mode. Switched both to `MutedText`, which carries the correct `dark:text-neutral-400`.
|
|
138
|
+
- Known follow-up, not fixed here: the same bare-CSS-var-no-dark:-fallback pattern is present in
|
|
139
|
+
roughly 15 more files in this package (`password-generator.tsx`, `pin-pad.tsx`, `tag-chip.tsx`,
|
|
140
|
+
several other still-active auth screens, …) — scoped out of this release to unblock the reported
|
|
141
|
+
bug; needs its own pass.
|
|
116
142
|
|
|
117
143
|
## 2026.8.2
|
|
118
144
|
|
|
119
145
|
### Fixed
|
|
120
146
|
|
|
121
|
-
- `registerTelemetry` and the rest of the telemetry registry were exported from
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
barrel now re-exports them only through `./services`.
|
|
147
|
+
- `registerTelemetry` and the rest of the telemetry registry were exported from the root barrel
|
|
148
|
+
twice — once through `export * from "./services"` and once by name. Metro's CommonJS interop
|
|
149
|
+
resolved the duplicate ambiguously and consumers got `undefined` at runtime despite the types
|
|
150
|
+
checking. The root barrel now re-exports them only through `./services`.
|
|
126
151
|
|
|
127
152
|
## 2026.8.1
|
|
128
153
|
|
|
129
154
|
### Added
|
|
130
155
|
|
|
131
|
-
- Telemetry registry (`registerTelemetry`, `trackClick`, `withClickTracking`). The
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
- `telemetryId` prop on `Button` and `IconButton`. Reports a stable,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
each of them re-tagging the packaged screens.
|
|
156
|
+
- Telemetry registry (`registerTelemetry`, `trackClick`, `withClickTracking`). The package reports
|
|
157
|
+
interactions to a sink the host app supplies; it knows nothing about batching, authentication or
|
|
158
|
+
transport. No sink registered means every entry point is a no-op, so consumers that do not opt in
|
|
159
|
+
are unaffected.
|
|
160
|
+
- `telemetryId` prop on `Button` and `IconButton`. Reports a stable, author-assigned id when the
|
|
161
|
+
control is activated. Wired through `onPress`, so a disabled or loading button records nothing.
|
|
162
|
+
- All 69 interactive controls across the 18 auth screens carry a `telemetryId`, making sign-in,
|
|
163
|
+
sign-up, MFA and consent measurable by consuming apps without each of them re-tagging the packaged
|
|
164
|
+
screens.
|
|
141
165
|
|
|
142
166
|
## [Unreleased]
|
|
143
167
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { type UploadResolver } from "../hooks/useUploadBlobUrl";
|
|
2
3
|
export interface ItemIconProps {
|
|
3
4
|
/**
|
|
4
5
|
* Stored icon reference. Either a literal URL, a `custom:<uploadId>`
|
|
@@ -22,6 +23,21 @@ export interface ItemIconProps {
|
|
|
22
23
|
faviconPath?: string;
|
|
23
24
|
/** Upload-fetch path prefix. Defaults to `/uploads`. */
|
|
24
25
|
uploadsPath?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a `custom:<uploadId>` reference yourself instead of letting this
|
|
28
|
+
* component fetch it.
|
|
29
|
+
*
|
|
30
|
+
* For a consumer whose uploads are not behind `apiFetch` at all — vault's
|
|
31
|
+
* device-only vaults keep them in on-device SQLite, with no server to ask.
|
|
32
|
+
* Without this, such a consumer has to either fork the component or
|
|
33
|
+
* pre-resolve the reference into a `data:` URI and pass it as `iconUrl`,
|
|
34
|
+
* which works by accident (anything that is not `custom:` is treated as a
|
|
35
|
+
* plain URL) and hides the intent.
|
|
36
|
+
*
|
|
37
|
+
* Return `null` for an id that does not resolve; the fallback glyph is drawn,
|
|
38
|
+
* exactly as for a fetch that fails.
|
|
39
|
+
*/
|
|
40
|
+
resolveUpload?: UploadResolver;
|
|
25
41
|
}
|
|
26
42
|
/**
|
|
27
43
|
* Per-item icon: shows the custom upload, falls back to the favicon
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"item-icon.d.ts","sourceRoot":"","sources":["../../src/components/item-icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"item-icon.d.ts","sourceRoot":"","sources":["../../src/components/item-icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,OAAO,EAAE,KAAK,cAAc,EAAoB,MAAM,2BAA2B,CAAC;AAElF,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;;OAaG;IACH,aAAa,CAAC,EAAE,cAAc,CAAC;CAChC;AAQD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,2CAoEnB,CAAC"}
|
|
@@ -13,12 +13,12 @@ const WEB_LAZY_PROPS = Platform.OS === "web" ? { loading: "lazy", decoding: "asy
|
|
|
13
13
|
* proxy, then to a generic globe glyph on a tile-toned square. Shared
|
|
14
14
|
* between RN clients (mobile) and RN-Web (extension popup).
|
|
15
15
|
*/
|
|
16
|
-
export const ItemIcon = React.memo(function ItemIcon({ iconUrl, siteUrl, size = 40, imageSize, borderRadius, background, fallbackColor, faviconPath = "/favicon", uploadsPath = "/uploads", }) {
|
|
16
|
+
export const ItemIcon = React.memo(function ItemIcon({ iconUrl, siteUrl, size = 40, imageSize, borderRadius, background, fallbackColor, faviconPath = "/favicon", uploadsPath = "/uploads", resolveUpload, }) {
|
|
17
17
|
const { colorScheme } = useColorScheme();
|
|
18
18
|
const isDark = colorScheme === "dark";
|
|
19
19
|
const resolved = resolveIcon({ iconUrl, siteUrl, faviconPath });
|
|
20
20
|
const uploadId = resolved.kind === "upload" ? resolved.uploadId : null;
|
|
21
|
-
const upload = useUploadBlobUrl(uploadId, uploadsPath);
|
|
21
|
+
const upload = useUploadBlobUrl(uploadId, { uploadsPath, resolve: resolveUpload });
|
|
22
22
|
const directUri = resolved.kind === "url" ? resolved.uri : null;
|
|
23
23
|
const [urlErrored, setUrlErrored] = useState(false);
|
|
24
24
|
useEffect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"item-icon.jsx","sourceRoot":"","sources":["../../src/components/item-icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,
|
|
1
|
+
{"version":3,"file":"item-icon.jsx","sourceRoot":"","sources":["../../src/components/item-icon.tsx"],"names":[],"mappings":"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"}
|
package/lib/hooks/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ export { AuthProvider, useAuth, useRole, useRequireAuth, useSession, type AuthPr
|
|
|
2
2
|
export { useShakeAnimation } from "./useShakeAnimation";
|
|
3
3
|
export { useDebouncedValue } from "./useDebouncedValue";
|
|
4
4
|
export { useAutoLock, type UseAutoLockOptions } from "./useAutoLock";
|
|
5
|
-
export {
|
|
5
|
+
export { type UploadBlobUrlOptions, type UploadBlobUrlResult, type UploadResolver, useUploadBlobUrl, } from "./useUploadBlobUrl";
|
|
6
6
|
export { usePasswordGenerator, getPasswordStrength, type UsePasswordGeneratorResult, type PasswordStrength, type BreachState, } from "./usePasswordGenerator";
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/hooks/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,OAAO,EACP,OAAO,EACP,cAAc,EACd,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,GAC7B,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,OAAO,EACP,OAAO,EACP,cAAc,EACd,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,GAC7B,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC"}
|
package/lib/hooks/index.js
CHANGED
|
@@ -2,6 +2,6 @@ export { AuthProvider, useAuth, useRole, useRequireAuth, useSession, } from "./u
|
|
|
2
2
|
export { useShakeAnimation } from "./useShakeAnimation";
|
|
3
3
|
export { useDebouncedValue } from "./useDebouncedValue";
|
|
4
4
|
export { useAutoLock } from "./useAutoLock";
|
|
5
|
-
export { useUploadBlobUrl } from "./useUploadBlobUrl";
|
|
5
|
+
export { useUploadBlobUrl, } from "./useUploadBlobUrl";
|
|
6
6
|
export { usePasswordGenerator, getPasswordStrength, } from "./usePasswordGenerator";
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/lib/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,OAAO,EACP,OAAO,EACP,cAAc,EACd,UAAU,GAKX,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,WAAW,EAA2B,MAAM,eAAe,CAAC;AAErE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,OAAO,EACP,OAAO,EACP,cAAc,EACd,UAAU,GAKX,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,WAAW,EAA2B,MAAM,eAAe,CAAC;AAErE,OAAO,EAIL,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GAIpB,MAAM,wBAAwB,CAAC"}
|
|
@@ -4,10 +4,54 @@ export interface UploadBlobUrlResult {
|
|
|
4
4
|
setErrored: (v: boolean) => void;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Produce a renderable URI for an upload id without going through
|
|
8
|
+
* `apiFetch`.
|
|
9
|
+
*
|
|
10
|
+
* For a consumer that keeps uploads somewhere this package cannot reach — an
|
|
11
|
+
* on-device database, a cache it populated itself — the resolver is the whole
|
|
12
|
+
* seam. Return `null` for an id that does not resolve; the hook reports that
|
|
13
|
+
* as `errored`, which is what a renderer draws its fallback on.
|
|
14
|
+
*
|
|
15
|
+
* The `signal` aborts with the effect, so a resolver doing real work can stop
|
|
16
|
+
* when the row scrolls away.
|
|
11
17
|
*/
|
|
12
|
-
export
|
|
18
|
+
export type UploadResolver = (uploadId: string, signal: AbortSignal) => Promise<string | null>;
|
|
19
|
+
export interface UploadBlobUrlOptions {
|
|
20
|
+
/** Upload-fetch path prefix. Defaults to `/uploads`. */
|
|
21
|
+
uploadsPath?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the URI yourself instead of fetching it.
|
|
24
|
+
*
|
|
25
|
+
* Identity does not have to be stable: the resolver is held in a ref and
|
|
26
|
+
* only `uploadId` / `uploadsPath` re-run the effect. An inline arrow would
|
|
27
|
+
* otherwise refetch on every render, and what identifies the resource is the
|
|
28
|
+
* id, not the function that happens to fetch it.
|
|
29
|
+
*/
|
|
30
|
+
resolve?: UploadResolver;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A URI for an upload, fetched through `apiFetch` unless the consumer resolves
|
|
34
|
+
* it itself.
|
|
35
|
+
*
|
|
36
|
+
* # Web gets a blob URL; native gets a data URI
|
|
37
|
+
*
|
|
38
|
+
* `URL.createObjectURL` is a browser API. React Native's `URL` does not
|
|
39
|
+
* implement it in any way that can be relied on across both platforms — so on
|
|
40
|
+
* native this hook used to hand `<Image>` a URI built by a function that
|
|
41
|
+
* either threw or produced something the image loader could not open, and the
|
|
42
|
+
* fetch fell into the `catch` below. The visible symptom was that custom
|
|
43
|
+
* uploaded icons never appeared on a phone: they resolved to the fallback
|
|
44
|
+
* glyph every time, on every consumer, and looked like a missing-image problem
|
|
45
|
+
* rather than a URL one.
|
|
46
|
+
*
|
|
47
|
+
* Native therefore reads the bytes and builds `data:<type>;base64,…`, which
|
|
48
|
+
* every RN image loader accepts. The cost is that base64 inflates by a third
|
|
49
|
+
* and the string sits in the JS heap for as long as the row is mounted, which
|
|
50
|
+
* is affordable for the icons this exists to draw (the vault caps an upload at
|
|
51
|
+
* 256KB) and is why web keeps the blob URL — no copy, and revocable.
|
|
52
|
+
*
|
|
53
|
+
* The second argument accepts a bare path for backwards compatibility with
|
|
54
|
+
* `useUploadBlobUrl(id, "/uploads")`; new call sites should pass options.
|
|
55
|
+
*/
|
|
56
|
+
export declare function useUploadBlobUrl(uploadId: string | null | undefined, options?: string | UploadBlobUrlOptions): UploadBlobUrlResult;
|
|
13
57
|
//# sourceMappingURL=useUploadBlobUrl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUploadBlobUrl.d.ts","sourceRoot":"","sources":["../../src/hooks/useUploadBlobUrl.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useUploadBlobUrl.d.ts","sourceRoot":"","sources":["../../src/hooks/useUploadBlobUrl.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE/F,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,OAAO,GAAE,MAAM,GAAG,oBAAyB,GAC1C,mBAAmB,CAgGrB"}
|
|
@@ -1,15 +1,39 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { Platform } from "react-native";
|
|
2
3
|
import { apiFetch } from "../utils/api-fetch";
|
|
3
4
|
const FETCH_TIMEOUT_MS = 15_000;
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* A URI for an upload, fetched through `apiFetch` unless the consumer resolves
|
|
7
|
+
* it itself.
|
|
8
|
+
*
|
|
9
|
+
* # Web gets a blob URL; native gets a data URI
|
|
10
|
+
*
|
|
11
|
+
* `URL.createObjectURL` is a browser API. React Native's `URL` does not
|
|
12
|
+
* implement it in any way that can be relied on across both platforms — so on
|
|
13
|
+
* native this hook used to hand `<Image>` a URI built by a function that
|
|
14
|
+
* either threw or produced something the image loader could not open, and the
|
|
15
|
+
* fetch fell into the `catch` below. The visible symptom was that custom
|
|
16
|
+
* uploaded icons never appeared on a phone: they resolved to the fallback
|
|
17
|
+
* glyph every time, on every consumer, and looked like a missing-image problem
|
|
18
|
+
* rather than a URL one.
|
|
19
|
+
*
|
|
20
|
+
* Native therefore reads the bytes and builds `data:<type>;base64,…`, which
|
|
21
|
+
* every RN image loader accepts. The cost is that base64 inflates by a third
|
|
22
|
+
* and the string sits in the JS heap for as long as the row is mounted, which
|
|
23
|
+
* is affordable for the icons this exists to draw (the vault caps an upload at
|
|
24
|
+
* 256KB) and is why web keeps the blob URL — no copy, and revocable.
|
|
25
|
+
*
|
|
26
|
+
* The second argument accepts a bare path for backwards compatibility with
|
|
27
|
+
* `useUploadBlobUrl(id, "/uploads")`; new call sites should pass options.
|
|
9
28
|
*/
|
|
10
|
-
export function useUploadBlobUrl(uploadId,
|
|
29
|
+
export function useUploadBlobUrl(uploadId, options = {}) {
|
|
30
|
+
const { uploadsPath = "/uploads", resolve } = typeof options === "string" ? { uploadsPath: options, resolve: undefined } : options;
|
|
11
31
|
const [uri, setUri] = useState(null);
|
|
12
32
|
const [errored, setErrored] = useState(false);
|
|
33
|
+
// See `UploadBlobUrlOptions.resolve`: kept in a ref so a resolver defined
|
|
34
|
+
// inline at the call site cannot turn every render into a refetch.
|
|
35
|
+
const resolveRef = useRef(resolve);
|
|
36
|
+
resolveRef.current = resolve;
|
|
13
37
|
useEffect(() => {
|
|
14
38
|
setErrored(false);
|
|
15
39
|
if (!uploadId) {
|
|
@@ -19,21 +43,51 @@ export function useUploadBlobUrl(uploadId, uploadsPath = "/uploads") {
|
|
|
19
43
|
const controller = new AbortController();
|
|
20
44
|
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
21
45
|
let createdUrl = null;
|
|
22
|
-
|
|
23
|
-
|
|
46
|
+
const load = async () => {
|
|
47
|
+
const resolver = resolveRef.current;
|
|
48
|
+
if (resolver) {
|
|
49
|
+
return resolver(uploadId, controller.signal);
|
|
50
|
+
}
|
|
51
|
+
const response = await apiFetch(`${uploadsPath}/${encodeURIComponent(uploadId)}`, {
|
|
52
|
+
signal: controller.signal,
|
|
53
|
+
});
|
|
24
54
|
if (controller.signal.aborted) {
|
|
25
|
-
return;
|
|
55
|
+
return null;
|
|
26
56
|
}
|
|
27
57
|
if (!response.ok) {
|
|
28
58
|
throw new Error(`Failed to load upload (${response.status})`);
|
|
29
59
|
}
|
|
30
|
-
|
|
60
|
+
if (Platform.OS === "web") {
|
|
61
|
+
const blob = await response.blob();
|
|
62
|
+
if (controller.signal.aborted) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
createdUrl = URL.createObjectURL(blob);
|
|
66
|
+
return createdUrl;
|
|
67
|
+
}
|
|
68
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
69
|
+
if (controller.signal.aborted) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
// The server sends the stored content type; anything else is a server
|
|
73
|
+
// that has lost track of what it is holding, and `<Image>` will refuse
|
|
74
|
+
// the URI rather than guess — which surfaces as the fallback glyph, the
|
|
75
|
+
// same outcome a failed fetch gives.
|
|
76
|
+
const contentType = response.headers.get("content-type") ?? "application/octet-stream";
|
|
77
|
+
return `data:${contentType};base64,${toBase64(bytes)}`;
|
|
78
|
+
};
|
|
79
|
+
load()
|
|
80
|
+
.then((next) => {
|
|
31
81
|
if (controller.signal.aborted) {
|
|
32
82
|
return;
|
|
33
83
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
84
|
+
if (next === null) {
|
|
85
|
+
// A resolver that has nothing for this id, or an aborted read. Either
|
|
86
|
+
// way there is no image, which is what `errored` means to a renderer.
|
|
87
|
+
setErrored(true);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
setUri(next);
|
|
37
91
|
})
|
|
38
92
|
.catch((e) => {
|
|
39
93
|
if (controller.signal.aborted) {
|
|
@@ -57,4 +111,29 @@ export function useUploadBlobUrl(uploadId, uploadsPath = "/uploads") {
|
|
|
57
111
|
}, [uploadId, uploadsPath]);
|
|
58
112
|
return { uri, errored, setErrored };
|
|
59
113
|
}
|
|
114
|
+
const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
115
|
+
/**
|
|
116
|
+
* Base64, without depending on the host having `btoa`.
|
|
117
|
+
*
|
|
118
|
+
* React Native ships no `btoa`, and whether one exists depends entirely on
|
|
119
|
+
* which polyfill the consuming app happened to install — a library cannot
|
|
120
|
+
* assume it. Encoding by hand is a dozen lines and removes the question.
|
|
121
|
+
*
|
|
122
|
+
* The `?? 0` on the tail bytes is the padding rule rather than a guard: base64
|
|
123
|
+
* completes a short final group with zero bits and then marks the missing
|
|
124
|
+
* bytes with `=`. Reading past the end is therefore correct here, and doing it
|
|
125
|
+
* this way keeps the loop free of the non-null assertions
|
|
126
|
+
* `noUncheckedIndexedAccess` would otherwise demand at every lookup.
|
|
127
|
+
*/
|
|
128
|
+
function toBase64(bytes) {
|
|
129
|
+
const chars = [];
|
|
130
|
+
for (let index = 0; index < bytes.length; index += 3) {
|
|
131
|
+
const b0 = bytes[index] ?? 0;
|
|
132
|
+
const b1 = bytes[index + 1] ?? 0;
|
|
133
|
+
const b2 = bytes[index + 2] ?? 0;
|
|
134
|
+
const remaining = bytes.length - index;
|
|
135
|
+
chars.push(BASE64_ALPHABET.charAt(b0 >> 2), BASE64_ALPHABET.charAt(((b0 & 3) << 4) | (b1 >> 4)), remaining > 1 ? BASE64_ALPHABET.charAt(((b1 & 15) << 2) | (b2 >> 6)) : "=", remaining > 2 ? BASE64_ALPHABET.charAt(b2 & 63) : "=");
|
|
136
|
+
}
|
|
137
|
+
return chars.join("");
|
|
138
|
+
}
|
|
60
139
|
//# sourceMappingURL=useUploadBlobUrl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUploadBlobUrl.js","sourceRoot":"","sources":["../../src/hooks/useUploadBlobUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useUploadBlobUrl.js","sourceRoot":"","sources":["../../src/hooks/useUploadBlobUrl.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthScreen.d.ts","sourceRoot":"","sources":["../../../src/screens/auth/AuthScreen.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"AuthScreen.d.ts","sourceRoot":"","sources":["../../../src/screens/auth/AuthScreen.tsx"],"names":[],"mappings":"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"}
|