@webtwizz/cloud 0.4.0 → 0.4.1

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/AI_GUIDE.md CHANGED
@@ -41,7 +41,7 @@ if (error) setMessage(authMessage(error));
41
41
 
42
42
  For wording that fits the site, pass overrides: `authMessage(error, { USER_ALREADY_EXISTS: 'You already have a booking account.' })`.
43
43
 
44
- When the owner turns on Confirm email, sign-up returns no session and the 6-digit code is emailed automatically. Show a code step: `authClient.emailOtp.verifyEmail({ email, otp })`, then sign them in, with a "Send a new code" button that calls `authClient.emailOtp.sendVerificationOtp({ email, type: 'email-verification' })`. Never send the first code yourself.
44
+ Confirm email is off unless the owner turns it on in Settings > Cloud > Users, so sign-up signs people straight in and an unconfirmed email never stops a sign-in. When the owner turns on Confirm email, sign-up returns no session and the 6-digit code is emailed automatically. Show a code step: `authClient.emailOtp.verifyEmail({ email, otp })`, then sign them in, with a "Send a new code" button that calls `authClient.emailOtp.sendVerificationOtp({ email, type: 'email-verification' })`. Never send the first code yourself.
45
45
 
46
46
  5. Protect pages in `src/proxy.ts`, listing only the protected routes in the matcher (a matcher over every path blocks the sign-in page's own scripts):
47
47
 
@@ -66,6 +66,15 @@ Never destructure `{ user }` from the top level.
66
66
 
67
67
  8. Every sign-in page gets a "Forgot password?" link to `/reset-password`, a client page in two steps: their email, then `authClient.forgetPassword.emailOtp({ email })`, which emails a 6-digit code; then the code and a new password, then `authClient.emailOtp.resetPassword({ email, otp, password })`, then send them to sign in. Leave `/reset-password` out of the proxy matcher. The owner can also send a reset code from the Data panel, and it lands on this page.
68
68
 
69
+ 9. Admins are accounts whose role is `'admin'`. Admin pages and admin writes check it on the server, the same way as step 6:
70
+
71
+ ```ts
72
+ const { data: session } = await auth.getSession();
73
+ if (session?.user?.role !== 'admin') return Response.json({ error: 'Admins only' }, { status: 403 });
74
+ ```
75
+
76
+ The first admin is the owner's own account on the site: they sign up like any visitor (their WebTwizz account is separate), then make that account an admin under Users in the Data panel, or ask you to do it. A new role reaches their session within a few minutes, or right away when they sign in again.
77
+
69
78
  Sign-ins are email and password only. Sign-in emails (reset codes, confirmations) are sent for the site automatically; never build email sending or add an email service for them. If the user asks for another way to sign in, say WebTwizz Cloud sign-ins are email and password for now and build that.
70
79
 
71
80
  Sites built before this package import sign-ins from another package in `src/lib/auth/`. When you work on their sign-ins, move `server.ts`, `client.ts` and the auth route to the files above (same sign-ins, same users) and remove the old package.
@@ -102,6 +111,17 @@ The database can pause or fill up on the owner's plan. Wrap reads and saves in t
102
111
 
103
112
  Pages that only show data set `export const revalidate = 60`, and the server action that saves calls `revalidatePath` for them. Pages for a signed-in user stay dynamic.
104
113
 
114
+ The database runs while pages read or save data and stops after 5 quiet minutes; its running time comes out of the owner's monthly allowance. So a page that refreshes data on a timer (a feed, a chat, a dashboard) refreshes only while the tab is visible, and again when the visitor comes back:
115
+
116
+ ```ts
117
+ useEffect(() => {
118
+ const refresh = () => { if (document.visibilityState === 'visible') load(); };
119
+ const timer = setInterval(refresh, 60_000);
120
+ document.addEventListener('visibilitychange', refresh);
121
+ return () => { clearInterval(timer); document.removeEventListener('visibilitychange', refresh); };
122
+ }, []);
123
+ ```
124
+
105
125
  ## Files
106
126
 
107
127
  Two buckets: `public` (anyone can view, for images shown on the site) and `private` (documents, opened through short-lived links). Images you place on pages yourself keep using the usual image tools; this is for what visitors or the site's features upload.
@@ -132,4 +152,4 @@ Show files with `createFiles().publicUrl(key)` in a plain `<img>` or link, or `a
132
152
 
133
153
  ## Owner tools
134
154
 
135
- The owner manages users under Users in the Data panel (password reset, block, delete with their rows, export), sets who can sign up and the sign-in emails in Settings > Cloud > Users, and downloads everything from Settings > Cloud > Database. Point them there when they ask.
155
+ The owner manages users under Users in the Data panel (make admin, password reset, block, delete with their rows, export), sets who can sign up and the sign-in emails in Settings > Cloud > Users, and downloads everything from Settings > Cloud > Database. Point them there when they ask.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @webtwizz/cloud
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 67343d5: Signed-in visitors can sign out, and `authClient` can read their session: since 0.2.0 the sign-in route answered both with a server error inside Next, because it copied a request Next hands over as a Proxy. Visitors who pressed Sign out stayed signed in.
8
+
3
9
  ## 0.4.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -40,6 +40,8 @@ npm run build
40
40
 
41
41
  `test/fixture` is a small Next app that CI builds against the packed tarball.
42
42
 
43
+ To try a change in the local WebTwizz preview site without publishing: `npm run preview` builds the package, puts it in the preview container's `node_modules` under a unique dev version, and restarts its dev server (about 10 seconds). `npm run dev` does the same on every save.
44
+
43
45
  ## Releases
44
46
 
45
47
  - Add a changeset (`npx changeset`) to any PR that changes what sites get.
package/dist/server.js CHANGED
@@ -1435,7 +1435,8 @@ function forLibrary(request, make) {
1435
1435
  if (translated === cookie) return request;
1436
1436
  const headers2 = new Headers(request.headers);
1437
1437
  headers2.set("cookie", translated);
1438
- return make(request, headers2);
1438
+ const body = request.method === "GET" || request.method === "HEAD" ? void 0 : request.body;
1439
+ return make(request.url, { method: request.method, headers: headers2, body, signal: request.signal, ...body ? { duplex: "half" } : {} });
1439
1440
  }
1440
1441
  function forBrowser(response) {
1441
1442
  const provider = [...response.headers.keys()].filter((name) => PROVIDER_HEADER.test(name));
@@ -1481,7 +1482,7 @@ function createAuth(options = {}) {
1481
1482
  const middleware = auth.middleware.bind(auth);
1482
1483
  auth.handler = () => {
1483
1484
  const methods = handler();
1484
- const wrap = (method) => async (request, context) => forBrowser(await method(forLibrary(request, (original, headers2) => new Request(original, { headers: headers2 })), context));
1485
+ const wrap = (method) => async (request, context) => forBrowser(await method(forLibrary(request, (url, init) => new Request(url, init)), context));
1485
1486
  const post = wrap(methods.POST);
1486
1487
  const signUp = async (request, context) => {
1487
1488
  const response = await post(request, context);
@@ -1493,7 +1494,7 @@ function createAuth(options = {}) {
1493
1494
  };
1494
1495
  auth.middleware = (config) => {
1495
1496
  const run = middleware(config);
1496
- return async (request) => forBrowser(await run(forLibrary(request, (original, headers2) => new NextRequest2(original, { headers: headers2 }))));
1497
+ return async (request) => forBrowser(await run(forLibrary(request, (url, init) => new NextRequest2(url, init))));
1497
1498
  };
1498
1499
  return auth;
1499
1500
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webtwizz/cloud",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Sign-ins, database and file storage for sites built on WebTwizz Cloud",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -55,7 +55,9 @@
55
55
  "typecheck": "tsc --noEmit",
56
56
  "test": "vitest run",
57
57
  "test:integration": "npm run build && vitest run --config vitest.integration.config.ts",
58
- "prepublishOnly": "npm run build && npm run typecheck && npm test"
58
+ "prepublishOnly": "npm run build && npm run typecheck && npm test",
59
+ "preview": "tsup && node scripts/preview.mjs",
60
+ "dev": "tsup --watch --onSuccess \"node scripts/preview.mjs\""
59
61
  },
60
62
  "engines": {
61
63
  "node": ">=20"