@lunora/cli 1.0.0-alpha.440 → 1.0.0-alpha.441

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/cli",
3
- "version": "1.0.0-alpha.440",
3
+ "version": "1.0.0-alpha.441",
4
4
  "description": "The Lunora CLI: init, dev, deploy, codegen, migrate, seed, doctor, insights, logs, registry, and the rest of the project commands",
5
5
  "keywords": [
6
6
  "agent-skills",
@@ -59,12 +59,12 @@
59
59
  "@lunora/advisor": "1.0.0-alpha.261",
60
60
  "@lunora/bindings": "1.0.0-alpha.136",
61
61
  "@lunora/codegen": "1.0.0-alpha.362",
62
- "@lunora/config": "1.0.0-alpha.416",
62
+ "@lunora/config": "1.0.0-alpha.417",
63
63
  "@lunora/container": "1.0.0-alpha.93",
64
64
  "@lunora/d1": "1.0.0-alpha.211",
65
65
  "@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
66
66
  "@lunora/mcp": "1.0.0-alpha.265",
67
- "@lunora/runtime": "1.0.0-alpha.243",
67
+ "@lunora/runtime": "1.0.0-alpha.244",
68
68
  "@lunora/seed": "1.0.0-alpha.259",
69
69
  "@visulima/cerebro": "4.0.1",
70
70
  "@visulima/error": "6.1.0",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lunora-setup-auth
3
- description: Adds authentication to a Lunora app with the `auth` registry item (better-auth via `@lunora/auth`, users and sessions in D1). Covers email/password sign-up and sign-in, Clerk or Auth0 OAuth, magic link, email OTP, copy-in auth screens (`lunora add auth-ui`), wiring `/api/auth/*` and `resolveIdentity` into the Worker, and gating functions on `ctx.auth.userId`. Use when the user asks to "add auth", "add login/sign-in/sign-up", "protect this query", or "add Clerk/Auth0/magic link/OTP", runs `lunora add auth` or `lunora registry add auth`, edits `lunora/auth/index.ts`, or `ctx.auth.userId` is unexpectedly `null`.
3
+ description: Adds authentication to a Lunora app with the `auth` registry item (better-auth via `@lunora/auth`, users and sessions in D1). Covers email/password sign-up and sign-in, Clerk or Auth0 OAuth, magic link, email OTP, copy-in auth screens (`lunora add auth-ui`), wiring `/api/auth/*` and `resolveIdentity` into the Worker, and gating functions on `ctx.auth.userId`. Use when the user asks to "add auth", "add login/sign-in/sign-up", "protect this query", or "add Clerk/Auth0/magic link/OTP", wants to keep an external identity provider (Clerk, WorkOS, Auth0, Supabase, any OIDC JWT) as the session owner, runs `lunora add auth` or `lunora registry add auth`, edits `lunora/auth/index.ts`, or `ctx.auth.userId` is unexpectedly `null`.
4
4
  ---
5
5
 
6
6
  # Lunora Setup Auth
@@ -13,6 +13,48 @@ instead of D1, use `LunoraAuthDO` / `.auth({ namespace, internalSecret })`.
13
13
 
14
14
  If the project has no Lunora backend yet, start with `lunora-quickstart`.
15
15
 
16
+ ## Already have an identity provider? Skip better-auth
17
+
18
+ If the app's users sign in through Clerk, WorkOS AuthKit, Auth0, Supabase or any
19
+ OIDC issuer, and that provider should keep owning the session, don't add the
20
+ `auth` item. Verify the provider's JWT instead with `@lunora/jwt-auth`:
21
+
22
+ ```bash
23
+ lunora init --auth=clerk # new project: or workos | auth0 (wires everything below)
24
+ lunora registry add auth-clerk-jwt # existing project: or auth-workos-jwt | auth-auth0-jwt
25
+ ```
26
+
27
+ ```ts
28
+ import { clerk } from "@lunora/jwt-auth"; // workos, auth0, supabase, jwtIdentityResolver
29
+ import { memoizeIdentity } from "lunorash/runtime";
30
+
31
+ defineApp<Env>()
32
+ .shard((env) => env.SHARD)
33
+ .extend((env) => ({
34
+ resolveIdentity: memoizeIdentity(clerk({ publishableKey: env.CLERK_PUBLISHABLE_KEY ?? "", authorizedParties: env.CLERK_AUTHORIZED_PARTIES ?? "" })),
35
+ }))
36
+ .build();
37
+ ```
38
+
39
+ On the client, create the `LunoraClient` with `authTokenOnUpgrade: true` and,
40
+ once signed in, call `setAuthTokenProvider(client, getToken, { subject: userId })`
41
+ from `lunorash/client`. It refreshes before `exp` and on `onTokenExpired`; map
42
+ the provider's "signed out" error (WorkOS `LoginRequiredError`, Auth0
43
+ `login_required`) to `null`. `authTokenOnUpgrade` is what authenticates
44
+ live-query sockets: the browser offers the bearer as a `Sec-WebSocket-Protocol`
45
+ entry. Without it, a WorkOS or Auth0 socket, or a cross-origin Clerk one, is
46
+ anonymous.
47
+
48
+ Org claims arrive as `orgId` with the org role (`orgRole` for Clerk, `role` /
49
+ `orgRoles` for WorkOS); no preset sets the app-wide `roles` RLS reads, since
50
+ any Clerk user can create an organization and be its admin. Check the org role
51
+ together with `orgId` in a policy. `CLERK_AUTHORIZED_PARTIES` is required.
52
+ Full guide:
53
+ `/docs/concepts/external-auth`, with runnable apps in `examples/clerk-auth` and
54
+ `examples/workos-auth`.
55
+
56
+ The rest of this skill covers the better-auth path.
57
+
16
58
  ## Step 1: Add the item
17
59
 
18
60
  ```bash
@@ -1 +0,0 @@
1
- import{s}from"./index-oHZBGBwB.mjs";import{s as n}from"./commands-DvSfLvyt.mjs";const c=[{description:"Email + password on better-auth (default)",label:"Email & password",value:"auth"},{description:"Clerk-hosted auth",label:"Clerk",value:"auth-clerk"},{description:"Auth0 (OIDC)",label:"Auth0",value:"auth-auth0"}],r="auth",E=async t=>await t("Which auth provider?",c,{default:r})??r,O="mail",g=[{description:"Next, react-router, TanStack Start, Astro islands",label:"React",value:"auth-ui-react"},{description:"Nuxt, Vue + Vite",label:"Vue",value:"auth-ui-vue"},{description:"SvelteKit, Svelte + Vite",label:"Svelte",value:"auth-ui-svelte"},{description:"TanStack Start Solid, Solid 1.x + Vite",label:"Solid",value:"auth-ui-solid"},{description:"Solid 2.0 + Vite (@solidjs/web)",label:"Solid 2",value:"auth-ui-solid-v2"},{description:"Analog",label:"Angular",value:"auth-ui-angular"}],j="auth-ui-react",d=t=>Object.hasOwn(t,"react-native")||Object.hasOwn(t,"@lunora/react-native")||Object.hasOwn(t,"expo"),B="auth-ui has no React Native port — the screens render DOM elements and a stylesheet, which Metro has nothing to mount. Build the screens with React Native primitives against the same better-auth client (`@lunora/react-native/auth`); `lunora add auth` still installs the server half.",h=t=>{if(!(t===void 0||s.validRange(t)===null))return s.minVersion(t)?.major},v=t=>Object.hasOwn(t,"@solidjs/web")||(h(t["solid-js"])??0)>=2,U=t=>{const e=a=>Object.hasOwn(t,a);if(!d(t)){if(v(t))return"auth-ui-solid-v2";if(e("@lunora/react"))return"auth-ui-react";if(e("@lunora/vue"))return"auth-ui-vue";if(e("@lunora/svelte"))return"auth-ui-svelte";if(e("@lunora/solid"))return"auth-ui-solid";if(e("@lunora/angular"))return"auth-ui-angular";if(e("react")||e("next"))return"auth-ui-react";if(e("vue")||e("nuxt"))return"auth-ui-vue";if(e("svelte")||e("@sveltejs/kit"))return"auth-ui-svelte";if(e("solid-js"))return"auth-ui-solid";if(e("@angular/core"))return"auth-ui-angular"}},L=t=>{const e=t.trim();if(e==="")return;const a=e.toLowerCase();return a==="auth-ui"||a==="auth-ui-"?{kind:"auth-ui"}:a==="auth"?{kind:"auth"}:a==="email"||a==="mail"?{kind:"email"}:{item:a,kind:"item"}},m=/[^a-z0-9]+/u,u=(t,e,a)=>{let i=t.toLowerCase().split(m).filter(Boolean).join("-").slice(0,a);return i.endsWith("-")&&(i=i.slice(0,-1)),i.length>=e?i:void 0},f="DB",A="Name your D1 database (run `wrangler d1 create` to get its id, then put it in wrangler.jsonc)",o=t=>u(t,1,64),b="lunora-db",_=t=>o(`${t}-db`)??b,M=async(t,e)=>{const a=_(e);return o(await t(A,{default:a,placeholder:a}))??a},R=(t,e)=>n(t,"d1_databases",{key:"binding",value:f},"database_name",e),N="SEND_EMAIL",P="Verified destination email for production delivery (blank = set it later in wrangler.jsonc)",p=t=>{const e=t.trim();if(e.length===0||e.includes(" "))return!1;const a=e.indexOf("@");if(a<=0||a!==e.lastIndexOf("@"))return!1;const i=e.slice(a+1);return i.length>=3&&i.includes(".")&&!i.startsWith(".")&&!i.endsWith(".")},y=(t,e)=>{const a=t.trim();if(a!==""){if(!p(a)){e(`"${a}" doesn't look like an email — leaving the placeholder; set destination_address in wrangler.jsonc.`);return}return a}},V=(t,e)=>n(t,"send_email",{key:"name",value:N},"destination_address",e),I="UPLOADS",S="Name your R2 bucket (you can rename it in wrangler.jsonc later)",l=t=>u(t,3,63),T="lunora-uploads",k=t=>l(`${t}-uploads`)??T,C=async(t,e)=>{const a=k(e);return l(await t(S,{default:a,placeholder:a}))??a},x=(t,e)=>n(t,"r2_buckets",{key:"binding",value:I},"bucket_name",e);export{B as A,r as D,O as E,P as M,o as a,_ as b,M as c,k as d,E as e,U as f,j as g,g as h,d as i,c as j,V as k,R as l,L as n,C as p,y as r,l as s,x as w};