smoodly 0.0.23 → 0.0.24

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.
Files changed (39) hide show
  1. package/README.md +11 -4
  2. package/dist/admin/auth.d.ts +10 -5
  3. package/dist/admin/auth.js +14 -13
  4. package/dist/admin/client-ops.js +1 -1
  5. package/dist/admin/editor/PageSettings.js +6 -0
  6. package/dist/admin/index.d.ts +2 -0
  7. package/dist/admin/next/index.d.ts +2 -0
  8. package/dist/admin/ops-impl.js +69 -1
  9. package/dist/admin/ops.d.ts +13 -2
  10. package/dist/admin/shell/AdminApp.js +26 -3
  11. package/dist/admin/shell/EntryForm.js +17 -0
  12. package/dist/admin/shell/IconRail.d.ts +3 -1
  13. package/dist/admin/shell/IconRail.js +4 -3
  14. package/dist/admin/shell/InviteModal.d.ts +6 -0
  15. package/dist/admin/shell/InviteModal.js +24 -0
  16. package/dist/admin/shell/LoginView.js +34 -5
  17. package/dist/admin/shell/MembersPage.d.ts +2 -1
  18. package/dist/admin/shell/MembersPage.js +72 -25
  19. package/dist/admin/shell/PagesList.js +7 -0
  20. package/dist/admin/shell/SetPasswordView.d.ts +7 -0
  21. package/dist/admin/shell/SetPasswordView.js +41 -0
  22. package/dist/admin/shell/SettingsView.d.ts +5 -1
  23. package/dist/admin/shell/SettingsView.js +25 -4
  24. package/dist/admin/shell/live-url.d.ts +9 -0
  25. package/dist/admin/shell/live-url.js +10 -0
  26. package/dist/admin/shell/members-list.d.ts +13 -1
  27. package/dist/admin/shell/members-list.js +19 -7
  28. package/dist/admin/shell/session.d.ts +6 -0
  29. package/dist/admin/shell/session.js +17 -2
  30. package/dist/admin/supabase-auth.js +6 -5
  31. package/dist/index.d.ts +4 -2
  32. package/dist/index.js +2 -1
  33. package/dist/member-store.d.ts +30 -1
  34. package/dist/member-store.js +37 -6
  35. package/dist/permissions.d.ts +7 -0
  36. package/dist/permissions.js +19 -0
  37. package/dist/supabase-member-store.d.ts +8 -1
  38. package/dist/supabase-member-store.js +62 -2
  39. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { sortMembers } from "./member-store.js";
1
+ import { memberErrors, sortMembers } from "./member-store.js";
2
2
  export class SupabaseMemberStore {
3
3
  constructor(db) {
4
4
  this.db = db;
@@ -7,7 +7,7 @@ export class SupabaseMemberStore {
7
7
  const res = await this.db.from("members").select("user_id, email, role");
8
8
  if (res.error)
9
9
  throw new Error(`smoodly: ${res.error.message}`);
10
- return sortMembers(res.data.map((r) => ({ userId: r.user_id, email: r.email, role: r.role })));
10
+ return sortMembers(res.data.map((r) => this.toRecord(r)));
11
11
  }
12
12
  async consoleUrl() {
13
13
  const res = await this.db.from("spaces").select("console_url").limit(1).maybeSingle();
@@ -15,4 +15,64 @@ export class SupabaseMemberStore {
15
15
  throw new Error(`smoodly: ${res.error.message}`);
16
16
  return res.data?.console_url ?? null;
17
17
  }
18
+ toRecord(row) {
19
+ return { userId: row.user_id, email: row.email, role: row.role };
20
+ }
21
+ /** The admin API has no lookup by email: page through the users (tens, not thousands). */
22
+ async userIdByEmail(email) {
23
+ const wanted = email.toLowerCase();
24
+ for (let page = 1; page <= 50; page++) {
25
+ const res = await this.db.auth.admin.listUsers({ page, perPage: 200 });
26
+ if (res.error)
27
+ throw new Error(`smoodly: ${res.error.message}`);
28
+ const hit = res.data.users.find((u) => u.email?.toLowerCase() === wanted);
29
+ if (hit)
30
+ return hit.id;
31
+ if (res.data.users.length < 200)
32
+ break;
33
+ }
34
+ throw memberErrors.noAccount(email);
35
+ }
36
+ async invite(input) {
37
+ // Self-host: the content client is the auth project's service role, so
38
+ // the admin API is reachable. A cloud write key never gets here — the
39
+ // ops refuse behind the console URL first.
40
+ const sent = await this.db.auth.admin.inviteUserByEmail(input.email, { redirectTo: input.redirectTo });
41
+ let userId;
42
+ let invited;
43
+ if (!sent.error) {
44
+ userId = sent.data.user.id;
45
+ invited = true;
46
+ }
47
+ else if (sent.error.code === "email_exists" || /already (been )?registered/i.test(sent.error.message)) {
48
+ userId = await this.userIdByEmail(input.email);
49
+ invited = false;
50
+ }
51
+ else {
52
+ throw new Error(`smoodly: ${sent.error.message}`);
53
+ }
54
+ const res = await this.db
55
+ .from("members")
56
+ .upsert({ user_id: userId, email: input.email, role: input.role }, { onConflict: "space_id,user_id" })
57
+ .select("user_id, email, role")
58
+ .single();
59
+ if (res.error)
60
+ throw new Error(`smoodly: ${res.error.message}`);
61
+ return { member: this.toRecord(res.data), invited };
62
+ }
63
+ async setRole(userId, role) {
64
+ const res = await this.db.from("members").update({ role }).eq("user_id", userId).select("user_id, email, role").maybeSingle();
65
+ if (res.error)
66
+ throw new Error(`smoodly: ${res.error.message}`);
67
+ if (!res.data)
68
+ throw memberErrors.notFound(userId);
69
+ return this.toRecord(res.data);
70
+ }
71
+ async remove(userId) {
72
+ const res = await this.db.from("members").delete().eq("user_id", userId).select("user_id");
73
+ if (res.error)
74
+ throw new Error(`smoodly: ${res.error.message}`);
75
+ if (!res.data || res.data.length === 0)
76
+ throw memberErrors.notFound(userId);
77
+ }
18
78
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smoodly",
3
- "version": "0.0.23",
3
+ "version": "0.0.24",
4
4
  "description": "Open-source, code-first CMS for Next.js on Supabase: define a component once, it becomes a typed, editable building block.",
5
5
  "license": "MIT",
6
6
  "repository": {