@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 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} (CDN: ${r.remoteUrl})`];
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} (CDN: ${r.remoteUrl})`];
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} (CDN: ${r.remoteUrl})`];
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} (CDN: ${r.remoteUrl})`];
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.onAuthStateChanged(cb) // fires immediately with current user, then on every
103
- // auth transition (verify, confirm, logout).
104
- // Returns an unsubscribe function.
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
- // Call once on app load completes sign-in when the user returns from the
147
- // handshake, or when the app is opened from the Remy dashboard. No-op when
148
- // there's no code to redeem, so it's safe to run on every mount.
149
- useEffect(() => { auth.handleRemyRedirect(); }, []);
150
- useEffect(() => auth.onAuthStateChanged(setUser), []);
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.210",
3
+ "version": "0.1.212",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",