@revealui/setup 0.3.4 → 0.3.6

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/README.md CHANGED
@@ -306,14 +306,14 @@ pnpm test:coverage
306
306
  - You're building setup scripts or CLI tools that need environment variable management
307
307
  - You need cryptographically secure secret generation for JWT keys or database passwords
308
308
  - You want consistent, colored logging with progress bars for setup flows
309
- - **Not** for runtime config accessuse `@revealui/config` after setup is complete
310
- - **Not** for end-user-facing logginguse `@revealui/utils/logger` in application code
309
+ - **Not** for runtime config access - use `@revealui/config` after setup is complete
310
+ - **Not** for end-user-facing logging - use `@revealui/utils/logger` in application code
311
311
 
312
312
  ## JOSHUA Alignment
313
313
 
314
- - **Justifiable**: Every utility exists because `@revealui/cli` and setup scripts need itno speculative abstractions
314
+ - **Justifiable**: Every utility exists because `@revealui/cli` and setup scripts need it - no speculative abstractions
315
315
  - **Hermetic**: Validation catches missing or malformed variables before they propagate into runtime
316
- - **Sovereign**: Generates secrets locally with `crypto.randomBytes`no external service required
316
+ - **Sovereign**: Generates secrets locally with `crypto.randomBytes` - no external service required
317
317
 
318
318
  ## License
319
319
 
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Suite-wide bootstrap primitive for RevealUI.
3
+ *
4
+ * Creates the first admin user and seeds minimal content.
5
+ * Designed for three consumers (in priority order):
6
+ * 1. Agents / MCP clients (programmatic)
7
+ * 2. CLI (`pnpm admin:setup`)
8
+ * 3. Browser UI (`/setup` page)
9
+ *
10
+ * Self-disabling: refuses to run if any users already exist.
11
+ * The RevealUI instance is injected - this module has no direct
12
+ * dependency on @revealui/core or @revealui/db, keeping the
13
+ * setup package lightweight.
14
+ */
15
+ /** Minimal interface for the RevealUI admin instance (injected by consumer). */
16
+ interface RevealUILike {
17
+ find: (args: {
18
+ collection: string;
19
+ limit?: number;
20
+ depth?: number;
21
+ where?: Record<string, unknown>;
22
+ }) => Promise<{
23
+ totalDocs: number;
24
+ docs: Array<Record<string, unknown>>;
25
+ }>;
26
+ create: (args: {
27
+ collection: string;
28
+ data: Record<string, unknown>;
29
+ }) => Promise<Record<string, unknown>>;
30
+ }
31
+ interface BootstrapAdminConfig {
32
+ email: string;
33
+ password: string;
34
+ name?: string;
35
+ }
36
+ interface BootstrapOptions {
37
+ /** RevealUI admin instance (injected - keeps setup package lightweight). */
38
+ revealui: RevealUILike;
39
+ /** First admin user credentials. */
40
+ admin: BootstrapAdminConfig;
41
+ /** Seed minimal content (home page). Default: true. */
42
+ seed?: boolean;
43
+ }
44
+ interface BootstrapResult {
45
+ status: 'created' | 'locked' | 'error';
46
+ message: string;
47
+ user?: {
48
+ email: string;
49
+ role: string;
50
+ };
51
+ seeded?: boolean;
52
+ error?: string;
53
+ }
54
+ /**
55
+ * Bootstrap a fresh RevealUI instance.
56
+ *
57
+ * 1. Checks if any users exist (self-disabling gate)
58
+ * 2. Validates admin credentials
59
+ * 3. Creates the first admin user
60
+ * 4. Seeds minimal content (home page) if requested
61
+ *
62
+ * @returns BootstrapResult with status, message, and optional user/seed info.
63
+ */
64
+ declare function bootstrap(options: BootstrapOptions): Promise<BootstrapResult>;
65
+
66
+ export { type BootstrapAdminConfig, type BootstrapOptions, type BootstrapResult, type RevealUILike, bootstrap };
@@ -0,0 +1,147 @@
1
+ // src/bootstrap/index.ts
2
+ function richTextDoc(...nodes) {
3
+ return {
4
+ root: {
5
+ type: "root",
6
+ children: nodes,
7
+ direction: "ltr",
8
+ format: "",
9
+ indent: 0,
10
+ version: 1
11
+ }
12
+ };
13
+ }
14
+ function heading(text, tag = "h2") {
15
+ return {
16
+ type: "heading",
17
+ children: [{ type: "text", detail: 0, format: 0, mode: "normal", style: "", text, version: 1 }],
18
+ direction: "ltr",
19
+ format: "",
20
+ indent: 0,
21
+ tag,
22
+ version: 1
23
+ };
24
+ }
25
+ function paragraph(text) {
26
+ return {
27
+ type: "paragraph",
28
+ children: [{ type: "text", detail: 0, format: 0, mode: "normal", style: "", text, version: 1 }],
29
+ direction: "ltr",
30
+ format: "",
31
+ indent: 0,
32
+ textFormat: 0,
33
+ textStyle: "",
34
+ version: 1
35
+ };
36
+ }
37
+ var SEED_PAGES = [
38
+ {
39
+ title: "Home",
40
+ slug: "home",
41
+ path: "/",
42
+ layout: [
43
+ {
44
+ blockType: "content",
45
+ columns: [
46
+ {
47
+ size: "full",
48
+ richText: richTextDoc(
49
+ heading("Welcome to RevealUI"),
50
+ paragraph(
51
+ "Your agentic business runtime is ready. Visit /admin to manage content, configure collections, and build your application."
52
+ )
53
+ )
54
+ }
55
+ ]
56
+ }
57
+ ]
58
+ }
59
+ ];
60
+ async function bootstrap(options) {
61
+ const { revealui, admin, seed = true } = options;
62
+ try {
63
+ const existing = await revealui.find({
64
+ collection: "users",
65
+ limit: 1,
66
+ depth: 0
67
+ });
68
+ if (existing.totalDocs > 0) {
69
+ return {
70
+ status: "locked",
71
+ message: "Setup already completed. Users exist."
72
+ };
73
+ }
74
+ } catch (err) {
75
+ return {
76
+ status: "error",
77
+ message: "Database connection failed. Check POSTGRES_URL or DATABASE_URL.",
78
+ error: err instanceof Error ? err.message : String(err)
79
+ };
80
+ }
81
+ if (!(admin.email && admin.password)) {
82
+ return {
83
+ status: "error",
84
+ message: "Admin email and password are required."
85
+ };
86
+ }
87
+ if (admin.password.length < 12) {
88
+ return {
89
+ status: "error",
90
+ message: "Admin password must be at least 12 characters."
91
+ };
92
+ }
93
+ try {
94
+ await revealui.create({
95
+ collection: "users",
96
+ data: {
97
+ name: admin.name ?? "Admin",
98
+ email: admin.email,
99
+ password: admin.password,
100
+ role: "owner",
101
+ roles: ["super-admin"]
102
+ }
103
+ });
104
+ } catch (err) {
105
+ const pgCode = err.code;
106
+ if (pgCode === "23505") {
107
+ return {
108
+ status: "error",
109
+ message: "A user with that email already exists."
110
+ };
111
+ }
112
+ return {
113
+ status: "error",
114
+ message: "Failed to create admin user.",
115
+ error: err instanceof Error ? err.message : String(err)
116
+ };
117
+ }
118
+ let seeded = false;
119
+ if (seed) {
120
+ try {
121
+ for (const page of SEED_PAGES) {
122
+ const existing = await revealui.find({
123
+ collection: "pages",
124
+ where: { slug: { equals: page.slug } },
125
+ limit: 1
126
+ });
127
+ if (existing.docs.length === 0) {
128
+ await revealui.create({
129
+ collection: "pages",
130
+ data: page
131
+ });
132
+ }
133
+ }
134
+ seeded = true;
135
+ } catch {
136
+ }
137
+ }
138
+ return {
139
+ status: "created",
140
+ message: `Admin user created${seeded ? " and content seeded" : ""}. Sign in at /admin.`,
141
+ user: { email: admin.email, role: "owner" },
142
+ seeded
143
+ };
144
+ }
145
+ export {
146
+ bootstrap
147
+ };
@@ -5,10 +5,15 @@ function generateSecret(length = 32) {
5
5
  }
6
6
  function generatePassword(length = 16) {
7
7
  const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*";
8
+ const maxValid = 256 - 256 % chars.length;
8
9
  let password = "";
9
- const randomValues = randomBytes(length);
10
- for (let i = 0; i < length; i++) {
11
- password += chars[randomValues[i] % chars.length];
10
+ while (password.length < length) {
11
+ const buf = randomBytes(length - password.length + 16);
12
+ for (let i = 0; i < buf.length && password.length < length; i++) {
13
+ if (buf[i] < maxValid) {
14
+ password += chars[buf[i] % chars.length];
15
+ }
16
+ }
12
17
  }
13
18
  return password;
14
19
  }
@@ -459,4 +464,3 @@ export {
459
464
  setupEnvironment,
460
465
  updateEnvValue
461
466
  };
462
- //# sourceMappingURL=index.js.map
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { BootstrapAdminConfig, BootstrapOptions, BootstrapResult, RevealUILike, bootstrap } from './bootstrap/index.js';
1
2
  export { SetupEnvironmentOptions, SetupEnvironmentResult, generatePassword, generateSecret, parseEnvContent, setupEnvironment, updateEnvValue } from './environment/index.js';
3
+ export { PROFILES, PlanAction, PlatformClass, SystemInfo, TunePlan, TuneProfile, TuneValues, WslConfigTune, detectSystem, generateAutoplan, generatePlan, matchProfile } from './system-tune/index.js';
2
4
  export { LogLevel, Logger, LoggerOptions, createLogger, handleASTParseError, logger } from './utils/index.js';
3
5
  export { EnvVariable, OPTIONAL_ENV_VARS, REQUIRED_ENV_VARS, ValidationResult, validateEnv, validators } from './validators/index.js';