@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/dist/index.d.mts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/packem_chunks/cli.mjs +2 -2
- package/dist/packem_chunks/handler2.mjs +1 -1
- package/dist/packem_chunks/runDevCommand.mjs +4 -4
- package/dist/packem_chunks/runInitCommand.mjs +83 -59
- package/dist/packem_shared/storage-CAiRP6Gr.mjs +1 -0
- package/package.json +3 -3
- package/skills/lunora-setup-auth/SKILL.md +43 -1
- package/dist/packem_shared/storage-DNzYhXR-.mjs +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/cli",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
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.
|
|
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.
|
|
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};
|