@mindstudio-ai/remy 0.1.210 → 0.1.212
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/dist/headless.js +2 -2
- package/dist/index.js +2 -2
- package/dist/prompt/compiled/auth.md +22 -9
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -7308,14 +7308,14 @@ function buildUploadHeader(results) {
|
|
|
7308
7308
|
}
|
|
7309
7309
|
if (succeeded.length === 1) {
|
|
7310
7310
|
const r = succeeded[0];
|
|
7311
|
-
const parts = [`[Uploaded file: ${r.localPath}
|
|
7311
|
+
const parts = [`[Uploaded file: ${r.localPath}`];
|
|
7312
7312
|
if (r.extractedTextPath) {
|
|
7313
7313
|
parts.push(`extracted text: ${r.extractedTextPath}`);
|
|
7314
7314
|
}
|
|
7315
7315
|
return parts.join(" \u2014 ") + "]";
|
|
7316
7316
|
}
|
|
7317
7317
|
const lines = succeeded.map((r) => {
|
|
7318
|
-
const parts = [`- ${r.localPath}
|
|
7318
|
+
const parts = [`- ${r.localPath}`];
|
|
7319
7319
|
if (r.extractedTextPath) {
|
|
7320
7320
|
parts.push(` extracted text: ${r.extractedTextPath}`);
|
|
7321
7321
|
}
|
package/dist/index.js
CHANGED
|
@@ -8081,14 +8081,14 @@ function buildUploadHeader(results) {
|
|
|
8081
8081
|
}
|
|
8082
8082
|
if (succeeded.length === 1) {
|
|
8083
8083
|
const r = succeeded[0];
|
|
8084
|
-
const parts = [`[Uploaded file: ${r.localPath}
|
|
8084
|
+
const parts = [`[Uploaded file: ${r.localPath}`];
|
|
8085
8085
|
if (r.extractedTextPath) {
|
|
8086
8086
|
parts.push(`extracted text: ${r.extractedTextPath}`);
|
|
8087
8087
|
}
|
|
8088
8088
|
return parts.join(" \u2014 ") + "]";
|
|
8089
8089
|
}
|
|
8090
8090
|
const lines = succeeded.map((r) => {
|
|
8091
|
-
const parts = [`- ${r.localPath}
|
|
8091
|
+
const parts = [`- ${r.localPath}`];
|
|
8092
8092
|
if (r.extractedTextPath) {
|
|
8093
8093
|
parts.push(` extracted text: ${r.extractedTextPath}`);
|
|
8094
8094
|
}
|
|
@@ -99,9 +99,12 @@ interface AppUser {
|
|
|
99
99
|
auth.getCurrentUser() // AppUser | null
|
|
100
100
|
auth.currentUser // AppUser | null (sync getter, same as getCurrentUser())
|
|
101
101
|
auth.isAuthenticated() // boolean
|
|
102
|
-
auth.
|
|
103
|
-
|
|
104
|
-
//
|
|
102
|
+
auth.authStatus // 'authenticating' | 'authenticated' | 'unauthenticated' (sync getter)
|
|
103
|
+
auth.onAuthStateChanged(cb) // fires immediately with current user, then on every transition —
|
|
104
|
+
// verify/confirm/logout AND each authStatus change (a Sign in with Remy
|
|
105
|
+
// handshake starting or settling). During 'authenticating' it may fire
|
|
106
|
+
// null; that's expected — read authStatus to tell it apart from
|
|
107
|
+
// logged-out. Returns an unsubscribe function.
|
|
105
108
|
```
|
|
106
109
|
|
|
107
110
|
Use `onAuthStateChanged` in React instead of reading `currentUser` once at render time:
|
|
@@ -143,15 +146,22 @@ When no `<org_auth_context>` block is present — the common case — do not bui
|
|
|
143
146
|
// "Continue with {Org}" button — must be triggered by a user gesture (click).
|
|
144
147
|
<button onClick={() => auth.signInWithRemy()}>Continue with Acme</button>
|
|
145
148
|
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
// On return from the handshake (or when opened from the Remy dashboard), the app
|
|
150
|
+
// cold-loads with sign-in still completing. Track authStatus and render a
|
|
151
|
+
// "Completing sign-in…" state — NOT the login screen — while it's 'authenticating'.
|
|
152
|
+
const [user, setUser] = useState(auth.currentUser);
|
|
153
|
+
const [status, setStatus] = useState(auth.authStatus);
|
|
154
|
+
useEffect(() => auth.onAuthStateChanged(() => {
|
|
155
|
+
setUser(auth.currentUser);
|
|
156
|
+
setStatus(auth.authStatus);
|
|
157
|
+
}), []);
|
|
158
|
+
useEffect(() => { auth.handleRemyRedirect().catch(() => {}); }, []); // no-op if nothing to redeem
|
|
159
|
+
// status === 'authenticating' → <CompletingSignIn/>; user → app; else → login
|
|
151
160
|
```
|
|
152
161
|
|
|
153
162
|
- `auth.signInWithRemy(options?)` → `Promise<AppUser | null>`. Auto-detects context: a top-level app redirects to the platform and back — **the page navigates away, so the promise never settles; don't await it to gate UI**. An app embedded in a cross-origin iframe (the dev IDE preview) uses a popup and the promise resolves with the user (or `null` if the popup is closed). Options: `redirectUri` (default current URL), `state` (CSRF, auto-generated), `mode: 'auto' | 'popup' | 'redirect'` (default `'auto'` — leave it). Because of the redirect case, **drive UI off `onAuthStateChanged`, not the return value.**
|
|
154
163
|
- `auth.handleRemyRedirect()` → `Promise<AppUser | null>`. Call once on load. Handles both the "Continue with {Org}" return and being opened from the Remy dashboard; on success it updates the session in-place (fires `onAuthStateChanged`) and cleans the URL.
|
|
164
|
+
- **Render the completing state, not the login screen, on return.** A redirect return (or dashboard launch) cold-loads with `auth.authStatus === 'authenticating'` — set *before first paint* and held until the exchange settles. Gate the UI on `authStatus`: `'authenticating'` → a brief "Completing sign-in…" state; a user → the app; `'unauthenticated'` → the login screen. Don't infer this from the URL `?code` (it's stripped when redemption starts) or treat the initial `null` user as logged-out — that flashes the login screen over a successful sign-in.
|
|
155
165
|
- Delegated users have `provider: 'remy'`. Their **roles and email are platform-managed** (like `email`/`phone` for code users) — enforce access with `requireRole`/`hasRole` on the backend as usual, but don't assign roles from app code; the platform owns them.
|
|
156
166
|
|
|
157
167
|
### Email/Phone Changes (must be authenticated)
|
|
@@ -201,6 +211,9 @@ All auth methods throw on failure with a `code` property:
|
|
|
201
211
|
| `not_authenticated` | 401 | No active session |
|
|
202
212
|
| `invalid_session` | 401 | Session expired or invalid |
|
|
203
213
|
| `not_supported` | 400 | Feature not enabled for this app (e.g. API keys without `api-key` in methods) |
|
|
214
|
+
| `invalid_state` | 400 | Sign in with Remy: returned CSRF state didn't match (stale/replayed redirect) |
|
|
215
|
+
| `popup_blocked` | — | Sign in with Remy (embedded): popup was blocked — prompt to allow popups and retry |
|
|
216
|
+
| `signin_timeout` | — | Sign in with Remy (embedded): popup didn't complete in time |
|
|
204
217
|
|
|
205
218
|
### Phone Helpers
|
|
206
219
|
|
|
@@ -386,7 +399,7 @@ Consult the `visualDesignExpert` to help you work through authentication at a hi
|
|
|
386
399
|
### Rules for Building Auth Screens
|
|
387
400
|
**Auth modes:** Think about which mode(s) makes the most sense for the type of app you are building. Consumer apps likely to be used on mobile should probably tend toward SMS auth as the default - business apps used on desktop make more sense to use email verification - or allow both, there's no harm in giving the user choice!
|
|
388
401
|
|
|
389
|
-
**"Continue with {Org}" (delegated):** When `<org_auth_context>` says delegated sign-in is available, a single "Continue with {Org}" button is the primary path — often the *only* one — and there's no verification-code step to design at all (the platform handles it). Give the button real weight in the branded login moment rather than treating it as a secondary option, and use the exact organization name. If the org also allows code methods, delegated goes first with the code form beneath.
|
|
402
|
+
**"Continue with {Org}" (delegated):** When `<org_auth_context>` says delegated sign-in is available, a single "Continue with {Org}" button is the primary path — often the *only* one — and there's no verification-code step to design at all (the platform handles it). Give the button real weight in the branded login moment rather than treating it as a secondary option, and use the exact organization name. If the org also allows code methods, delegated goes first with the code form beneath. On return from the handshake (and on dashboard launch), render a brief "Completing sign-in…" state driven by `auth.authStatus === 'authenticating'` — never the login form — so a successful sign-in doesn't flash the logged-out screen.
|
|
390
403
|
|
|
391
404
|
**Verification code input:** The 6-digit code entry is the critical moment. Prefer to design it as individual digit boxes (not a single text input), with auto-advance between digits, a beautiful animation and auto-submit on paste, and clear visual feedback. The boxes should be large enough to tap easily on mobile. Show a subtle animation on successful verification. Error states should be inline and immediate, not a separate alert. Make sure there is no layout shift when loading in the success/error states - loading spinners must never pop in below the input and shift the content, for example.
|
|
392
405
|
|