@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 +4 -4
- package/dist/bootstrap/index.d.ts +66 -0
- package/dist/bootstrap/index.js +147 -0
- package/dist/environment/index.js +8 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +506 -4
- package/dist/system-tune/index.d.ts +152 -0
- package/dist/system-tune/index.js +353 -0
- package/dist/utils/index.js +0 -1
- package/dist/validators/index.js +0 -1
- package/package.json +20 -8
- package/dist/environment/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/validators/index.js.map +0 -1
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 access
|
|
310
|
-
- **Not** for end-user-facing logging
|
|
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 it
|
|
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`
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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';
|