@mindstudio-ai/remy 0.1.209 → 0.1.211
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.
|
@@ -34,6 +34,7 @@ Remy apps can have and manage their own users. Auth is opt-in: configure it in t
|
|
|
34
34
|
- `email-code` — 6-digit code sent via email
|
|
35
35
|
- `sms-code` — 6-digit code sent via SMS
|
|
36
36
|
- `api-key` — programmatic access via `Authorization: Bearer sk_...` header. Resolves to a user with full RBAC.
|
|
37
|
+
- `remy` — platform-delegated sign-in ("Sign in with Remy"). The platform resolves who the user is; roles and verification are platform-managed. Only usable when the app's owning organization has it enabled — the `<org_auth_context>` block signals availability. See *Organization-Managed Sign-In* above.
|
|
37
38
|
- **`auth.table.name`** — name of the `defineTable` table that holds user records.
|
|
38
39
|
- **`auth.table.columns`** — maps platform-managed fields to column names in the developer's table.
|
|
39
40
|
- `email` — required if `email-code` is in methods
|
|
@@ -85,6 +86,7 @@ interface AppUser {
|
|
|
85
86
|
phone: string | null;
|
|
86
87
|
roles: string[];
|
|
87
88
|
apiKey: string | null; // masked value (sk_...xxxx), null if no key
|
|
89
|
+
provider?: 'remy' | null; // 'remy' = delegated sign-in (platform-managed); null/absent = app-verified
|
|
88
90
|
createdAt: string;
|
|
89
91
|
}
|
|
90
92
|
```
|
|
@@ -97,9 +99,12 @@ interface AppUser {
|
|
|
97
99
|
auth.getCurrentUser() // AppUser | null
|
|
98
100
|
auth.currentUser // AppUser | null (sync getter, same as getCurrentUser())
|
|
99
101
|
auth.isAuthenticated() // boolean
|
|
100
|
-
auth.
|
|
101
|
-
|
|
102
|
-
//
|
|
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.
|
|
103
108
|
```
|
|
104
109
|
|
|
105
110
|
Use `onAuthStateChanged` in React instead of reading `currentUser` once at render time:
|
|
@@ -128,6 +133,37 @@ const { verificationId } = await auth.sendSmsCode('+15551234567');
|
|
|
128
133
|
const user = await auth.verifySmsCode(verificationId, '123456');
|
|
129
134
|
```
|
|
130
135
|
|
|
136
|
+
## Organization-Managed Sign-In ("Sign in with Remy")
|
|
137
|
+
|
|
138
|
+
Some apps are owned by an organization that centralizes sign-in. When that applies to the current app, the system prompt includes an `<org_auth_context>` block (near the end) stating the organization name and whether delegated sign-in is available. Sign in with Remy is a way to make authentication seamless for internal apps - it should not be used for public-facing applications. The app owner will need to add users to their workspace's team on the Remy platform and those users will need Remy accounts for it to work.
|
|
139
|
+
|
|
140
|
+
- **When it says "Sign in with Remy" is available** — offer delegated sign-in: a **"Continue with {Org}"** button wired to the `remy` method (see *Sign in with Remy (delegated)* below). Use the exact organization name from the block for the label. For an org-owned app this is usually the primary sign-in — the members already have platform identities, so a verification-code form is redundant.
|
|
141
|
+
- **When it says the organization requires delegated sign-in** — `remy` is the *only* human method: do not add `email-code` or `sms-code`. Those are blocked at the platform edge for the org's apps, so building them yields a login that can't work.
|
|
142
|
+
|
|
143
|
+
When no `<org_auth_context>` block is present — the common case — do not build it or offer to build it. This is an auth scheme for enterprises building internal apps only, and it requires a Remy enterprise plan to use. When enabled, the platform decides who the user is (like "Sign in with Google"); the app just starts the flow and reads the result.
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// "Continue with {Org}" button — must be triggered by a user gesture (click).
|
|
147
|
+
<button onClick={() => auth.signInWithRemy()}>Continue with Acme</button>
|
|
148
|
+
|
|
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
|
|
160
|
+
```
|
|
161
|
+
|
|
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.**
|
|
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.
|
|
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.
|
|
166
|
+
|
|
131
167
|
### Email/Phone Changes (must be authenticated)
|
|
132
168
|
|
|
133
169
|
```typescript
|
|
@@ -175,6 +211,9 @@ All auth methods throw on failure with a `code` property:
|
|
|
175
211
|
| `not_authenticated` | 401 | No active session |
|
|
176
212
|
| `invalid_session` | 401 | Session expired or invalid |
|
|
177
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 |
|
|
178
217
|
|
|
179
218
|
### Phone Helpers
|
|
180
219
|
|
|
@@ -360,6 +399,8 @@ Consult the `visualDesignExpert` to help you work through authentication at a hi
|
|
|
360
399
|
### Rules for Building Auth Screens
|
|
361
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!
|
|
362
401
|
|
|
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.
|
|
403
|
+
|
|
363
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.
|
|
364
405
|
|
|
365
406
|
**The send/resend flow:** After the user enters their email or phone and taps "Send code," show clear confirmation that the code was sent ("Check your email" with the address displayed). Include a resend option with a cooldown timer (e.g., "Resend in 30s"). The transition from "enter email/phone" to "enter code" should feel smooth, not like a page reload. Always make sure the user can cancel and exit the flow (e.g., they had a typo in their email, or remembered they used a different email to sign up).
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
| Field | Type | Required | Description |
|
|
72
72
|
|-------|------|----------|-------------|
|
|
73
73
|
| `enabled` | `boolean` | Yes | `true` to enable auth |
|
|
74
|
-
| `methods` | `string[]` | Yes | Auth methods: `"email-code"`, `"sms-code"`, `"api-key"
|
|
74
|
+
| `methods` | `string[]` | Yes | Auth methods: `"email-code"`, `"sms-code"`, `"api-key"`, `"remy"` (platform-delegated sign-in, org-owned apps). At least one required. |
|
|
75
75
|
| `table.name` | `string` | Yes | Name of the `defineTable` table holding user records |
|
|
76
76
|
| `table.columns.email` | `string` | If email-code | Column name for email (platform-managed, read-only from code) |
|
|
77
77
|
| `table.columns.phone` | `string` | If sms-code | Column name for phone (platform-managed, read-only from code) |
|
|
@@ -41,6 +41,7 @@ When writing `db` filter predicates that reference outer-scope values (`input.*`
|
|
|
41
41
|
- Frontend interfaces are always untrusted. Always enforce auth in backend methods. Use frontend auth and role information as a hint to conditionally show/hide UI to make the experience pleasant and seamless for users depending on their state, but remember to always use backend methods for gating data that is conditional on auth.
|
|
42
42
|
- For signup and login, verification code inputs must feel polished — clear feedback on send, auto-send on paste, a "resend" option, and error messages for wrong/expired codes.
|
|
43
43
|
- The auth table is the user profile. Add custom fields (displayName, avatar, plan, etc.) alongside the platform-managed columns. Don't create a separate profile table.
|
|
44
|
+
- When delegated sign-in ("Sign in with Remy") is available for the org, prefer a "Continue with {Org}" button (`auth.signInWithRemy()`) and call `auth.handleRemyRedirect()` once on app load. Drive UI off `onAuthStateChanged`, not the sign-in return value (top-level sign-in redirects away and never returns). See the auth docs.
|
|
44
45
|
- For apps with roles, create scenarios that seed users with different roles so the developer can test each perspective. Use the scenario `roles` field for impersonation.
|
|
45
46
|
|
|
46
47
|
### CSS & Layout
|
|
@@ -18,7 +18,9 @@ When specifying sheets, drawers, modals, or any surface that slides/fades into v
|
|
|
18
18
|
|
|
19
19
|
Login and signup screens set the tone for the user's entire experience with the app and are important to get right - they should feel like exciting entry points into the next level of the user journy. A janky login form with misaligned inputs and no feedback dminishes excitement and undermines trust before the user even gets in.
|
|
20
20
|
|
|
21
|
-
Authentication moments must feel natural and intuitive - they should not feel jarring or surprising. Take care to integrate them into the entire experience when building. Remy apps support SMS code verification, email verification, or
|
|
21
|
+
Authentication moments must feel natural and intuitive - they should not feel jarring or surprising. Take care to integrate them into the entire experience when building. Remy apps support SMS code verification, email verification, delegated "Sign in with Remy", or a combination, depending on how the app is configured.
|
|
22
|
+
|
|
23
|
+
**"Continue with {Org}" (delegated sign-in):** Some apps are internal business tools that are owned by an organization and sign members in through the platform — a single "Continue with {Org}" button, no verification-code step at all. For these apps this button is often the primary (sometimes only) path, so give it real presence in the branded login moment rather than tucking it away, and label it with the organization's actual name. If the app also offers code methods, lead with the delegated button and place the code form beneath. This scheme should ONLY be used for internal apps AND when it is explicitly enabled in <org_auth_context> - it should not be used for public-facing apps.
|
|
22
24
|
|
|
23
25
|
**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, 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.
|
|
24
26
|
|