vibecarbon 0.1.0 → 0.1.2
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
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/hyperformant/vibecarbon/main/carbon/src/client/assets/vibecarbon-logo-light.svg">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/hyperformant/vibecarbon/main/carbon/src/client/assets/vibecarbon-logo-dark.svg" alt="Vibecarbon" width="500" />
|
|
5
|
+
</picture>
|
|
3
6
|
</p>
|
|
4
7
|
|
|
5
8
|
<p align="center"><strong>Professional Grade SaaS Architecture & Starter Kit</strong></p>
|
|
@@ -55,12 +55,12 @@ npx vibecarbon create
|
|
|
55
55
|
|
|
56
56
|
# Power-user / CI
|
|
57
57
|
npx vibecarbon create my-saas -y -admin-email admin@example.com -admin-password secret123
|
|
58
|
-
npx vibecarbon create my-saas -
|
|
58
|
+
npx vibecarbon create my-saas -install
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
Generates secure secrets (JWT, database password, Supabase keys), copies the
|
|
62
|
-
template,
|
|
63
|
-
|
|
62
|
+
template, initializes a git repository (with pre-commit + pre-push hooks),
|
|
63
|
+
optionally runs `pnpm install`, and creates the admin user in Supabase Auth.
|
|
64
64
|
|
|
65
65
|
| Flag | Description |
|
|
66
66
|
|------|-------------|
|
|
@@ -68,9 +68,10 @@ repository, and creates the admin user in Supabase Auth.
|
|
|
68
68
|
| `-admin-email <email>` | Admin email for dashboard access |
|
|
69
69
|
| `-admin-password <pw>` | Admin password for dashboard access |
|
|
70
70
|
| `-pm <name>` | Package manager: `npm`, `pnpm` (default), or `bun` |
|
|
71
|
-
| `-git` | Initialize a git repository (default: off; opt-in) |
|
|
72
71
|
| `-install` | Run `<pm> install` during create (default: deferred to first `vibecarbon up`) |
|
|
73
72
|
|
|
73
|
+
A git repository is initialized automatically (with pre-commit + pre-push hooks). If `git` isn't on PATH, this step is skipped silently with a hint to run `git init` manually afterwards.
|
|
74
|
+
|
|
74
75
|
---
|
|
75
76
|
|
|
76
77
|
## up
|
|
@@ -3,10 +3,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
5
|
import { cn } from '@/lib/utils';
|
|
6
|
-
|
|
7
|
-
const SparkBurst = React.lazy(() =>
|
|
8
|
-
import('../effects/SparkBurst').then((m) => ({ default: m.SparkBurst }))
|
|
9
|
-
);
|
|
6
|
+
import { SparkBurst } from '../effects/SparkBurst';
|
|
10
7
|
|
|
11
8
|
const buttonVariants = cva(
|
|
12
9
|
"cursor-pointer focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-4xl border border-transparent text-sm leading-none font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:cursor-default [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
|
|
@@ -109,9 +106,7 @@ function Button({
|
|
|
109
106
|
>
|
|
110
107
|
{resolvedChildren}
|
|
111
108
|
{hasSparkle && (
|
|
112
|
-
<
|
|
113
|
-
<SparkBurst delay={0.05} count={10} palette="primary" trigger={sparkTrigger} />
|
|
114
|
-
</React.Suspense>
|
|
109
|
+
<SparkBurst delay={0.05} count={10} palette="primary" trigger={sparkTrigger} />
|
|
115
110
|
)}
|
|
116
111
|
</ButtonPrimitive>
|
|
117
112
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibecarbon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Create and manage production-ready Vibecarbon applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./src/cli.js",
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"@vitest/coverage-v8": "^4.1.1",
|
|
86
86
|
"autocannon": "^8.0.0",
|
|
87
87
|
"better-sqlite3": "^12.8.0",
|
|
88
|
+
"conventional-changelog-conventionalcommits": "^9.3.1",
|
|
88
89
|
"msw": "^2.12.14",
|
|
89
90
|
"semantic-release": "^23.0.8",
|
|
90
91
|
"tsx": "^4.21.0",
|
package/src/create.js
CHANGED
|
@@ -152,11 +152,6 @@ const SPEC = {
|
|
|
152
152
|
boolean: true,
|
|
153
153
|
description: 'Skip prompts (requires -admin-email and -admin-password)',
|
|
154
154
|
},
|
|
155
|
-
{
|
|
156
|
-
name: 'git',
|
|
157
|
-
boolean: true,
|
|
158
|
-
description: 'Initialize a git repository (default: off; opt-in)',
|
|
159
|
-
},
|
|
160
155
|
{
|
|
161
156
|
name: 'install',
|
|
162
157
|
boolean: true,
|
|
@@ -476,14 +471,13 @@ async function bootstrap(cliArgs) {
|
|
|
476
471
|
}
|
|
477
472
|
|
|
478
473
|
// Build the legacy `args` shape that the orchestration code reads.
|
|
479
|
-
//
|
|
480
|
-
//
|
|
474
|
+
// Git init always runs when `git` is on PATH; falls back to no-repo silently
|
|
475
|
+
// if git isn't installed. No CLI flag needed either way.
|
|
481
476
|
const args = {
|
|
482
477
|
projectName: positional.projectName || null,
|
|
483
478
|
yes: !!values.y,
|
|
484
479
|
install: !!values.install,
|
|
485
480
|
skipLockfile: !!values['skip-lockfile'],
|
|
486
|
-
noGit: !values.git,
|
|
487
481
|
packageManager: /** @type {string|null} */ (values.pm),
|
|
488
482
|
adminEmail: /** @type {string|null} */ (values['admin-email']),
|
|
489
483
|
adminPassword: /** @type {string|null} */ (values['admin-password']),
|
|
@@ -502,7 +496,6 @@ async function bootstrap(cliArgs) {
|
|
|
502
496
|
// and can't escape cwd (CVE-class path-traversal).
|
|
503
497
|
let projectName = args.projectName;
|
|
504
498
|
let packageManager = args.packageManager || detectPackageManager();
|
|
505
|
-
let initGit = !args.noGit;
|
|
506
499
|
let adminEmail = args.adminEmail;
|
|
507
500
|
let adminPassword = args.adminPassword;
|
|
508
501
|
|
|
@@ -566,13 +559,6 @@ async function bootstrap(cliArgs) {
|
|
|
566
559
|
initialValue: packageManager,
|
|
567
560
|
});
|
|
568
561
|
},
|
|
569
|
-
git: () => {
|
|
570
|
-
if (args.noGit) return Promise.resolve(false);
|
|
571
|
-
return p.confirm({
|
|
572
|
-
message: 'Initialize a git repository for version control?',
|
|
573
|
-
initialValue: true,
|
|
574
|
-
});
|
|
575
|
-
},
|
|
576
562
|
},
|
|
577
563
|
{
|
|
578
564
|
onCancel: () => {
|
|
@@ -586,7 +572,6 @@ async function bootstrap(cliArgs) {
|
|
|
586
572
|
adminEmail = project.adminEmail;
|
|
587
573
|
adminPassword = project.adminPassword;
|
|
588
574
|
packageManager = project.packageManager;
|
|
589
|
-
initGit = project.git;
|
|
590
575
|
} else {
|
|
591
576
|
// Non-interactive validation
|
|
592
577
|
if (!projectName) {
|
|
@@ -633,7 +618,6 @@ async function bootstrap(cliArgs) {
|
|
|
633
618
|
`Project: ${projectName}`,
|
|
634
619
|
`Admin: ${adminEmail}`,
|
|
635
620
|
`Package manager: ${packageManager}`,
|
|
636
|
-
`Git: ${initGit ? 'yes' : 'no'}`,
|
|
637
621
|
].join('\n'),
|
|
638
622
|
'Configuration',
|
|
639
623
|
);
|
|
@@ -1120,8 +1104,16 @@ async function bootstrap(cliArgs) {
|
|
|
1120
1104
|
}
|
|
1121
1105
|
}
|
|
1122
1106
|
|
|
1123
|
-
// Initialize git
|
|
1124
|
-
if (
|
|
1107
|
+
// Initialize git. Always attempted; skipped silently with a friendly note
|
|
1108
|
+
// if the `git` binary isn't on PATH (no flag exposed for opt-out).
|
|
1109
|
+
let gitAvailable = true;
|
|
1110
|
+
try {
|
|
1111
|
+
execFileSync('git', ['--version'], { stdio: 'ignore' });
|
|
1112
|
+
} catch {
|
|
1113
|
+
gitAvailable = false;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
if (gitAvailable) {
|
|
1125
1117
|
s.message('Initializing git repository');
|
|
1126
1118
|
copyTemplate('.gitignore', join(projectDir, '.gitignore'), variables);
|
|
1127
1119
|
|
|
@@ -1205,6 +1197,10 @@ ${runCmd} test:prepush
|
|
|
1205
1197
|
writeFileSync(join(hooksDir, 'pre-push'), prePushHook);
|
|
1206
1198
|
chmodSync(join(hooksDir, 'pre-push'), 0o755);
|
|
1207
1199
|
await tick();
|
|
1200
|
+
} else {
|
|
1201
|
+
p.log.info(
|
|
1202
|
+
"git not found on PATH — skipping repo init. Install git and run 'git init' in this directory to enable version control + pre-commit/pre-push hooks.",
|
|
1203
|
+
);
|
|
1208
1204
|
}
|
|
1209
1205
|
|
|
1210
1206
|
// Store template version and file checksums for `vibecarbon upgrade`
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
-- Create initial admin user in auth.users (Development Version)
|
|
2
|
-
-- Uses credentials provided during `vibecarbon create`
|
|
3
|
-
|
|
4
|
-
DO $$
|
|
5
|
-
DECLARE
|
|
6
|
-
admin_email TEXT := 'admin@example.com';
|
|
7
|
-
admin_password_hash TEXT := '$2b$10$OWzZo/eSlFAb2S9oX4Ps5.prj7LzVfAWo7N1cFrL3N8Z3HLUZtvOm';
|
|
8
|
-
new_user_id UUID;
|
|
9
|
-
BEGIN
|
|
10
|
-
-- Only create if admin email is provided and not empty
|
|
11
|
-
IF admin_email IS NOT NULL AND admin_email != '' THEN
|
|
12
|
-
|
|
13
|
-
-- Check if user already exists
|
|
14
|
-
IF NOT EXISTS (SELECT 1 FROM auth.users WHERE email = admin_email) THEN
|
|
15
|
-
-- Generate a new UUID for the user
|
|
16
|
-
new_user_id := gen_random_uuid();
|
|
17
|
-
|
|
18
|
-
-- Create admin user with bcrypt-hashed password
|
|
19
|
-
-- Note: GoTrue expects token columns to be empty strings, not NULL
|
|
20
|
-
INSERT INTO auth.users (
|
|
21
|
-
instance_id,
|
|
22
|
-
id,
|
|
23
|
-
aud,
|
|
24
|
-
role,
|
|
25
|
-
email,
|
|
26
|
-
encrypted_password,
|
|
27
|
-
email_confirmed_at,
|
|
28
|
-
confirmation_sent_at,
|
|
29
|
-
raw_app_meta_data,
|
|
30
|
-
raw_user_meta_data,
|
|
31
|
-
created_at,
|
|
32
|
-
updated_at,
|
|
33
|
-
confirmation_token,
|
|
34
|
-
recovery_token,
|
|
35
|
-
email_change_token_new,
|
|
36
|
-
email_change_token_current,
|
|
37
|
-
email_change,
|
|
38
|
-
phone,
|
|
39
|
-
phone_change,
|
|
40
|
-
phone_change_token,
|
|
41
|
-
reauthentication_token
|
|
42
|
-
) VALUES (
|
|
43
|
-
'00000000-0000-0000-0000-000000000000',
|
|
44
|
-
new_user_id,
|
|
45
|
-
'authenticated',
|
|
46
|
-
'authenticated',
|
|
47
|
-
admin_email,
|
|
48
|
-
admin_password_hash,
|
|
49
|
-
NOW(),
|
|
50
|
-
NOW(),
|
|
51
|
-
jsonb_build_object(
|
|
52
|
-
'provider', 'email',
|
|
53
|
-
'providers', ARRAY['email'],
|
|
54
|
-
'role', 'super_admin'
|
|
55
|
-
),
|
|
56
|
-
'{}'::jsonb,
|
|
57
|
-
NOW(),
|
|
58
|
-
NOW(),
|
|
59
|
-
'',
|
|
60
|
-
'',
|
|
61
|
-
'',
|
|
62
|
-
'',
|
|
63
|
-
'',
|
|
64
|
-
'',
|
|
65
|
-
'',
|
|
66
|
-
'',
|
|
67
|
-
''
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
-- Create identity record for email provider
|
|
71
|
-
INSERT INTO auth.identities (
|
|
72
|
-
id,
|
|
73
|
-
user_id,
|
|
74
|
-
identity_data,
|
|
75
|
-
provider,
|
|
76
|
-
provider_id,
|
|
77
|
-
last_sign_in_at,
|
|
78
|
-
created_at,
|
|
79
|
-
updated_at
|
|
80
|
-
) VALUES (
|
|
81
|
-
gen_random_uuid(),
|
|
82
|
-
new_user_id,
|
|
83
|
-
jsonb_build_object(
|
|
84
|
-
'sub', new_user_id::text,
|
|
85
|
-
'email', admin_email,
|
|
86
|
-
'email_verified', true
|
|
87
|
-
),
|
|
88
|
-
'email',
|
|
89
|
-
new_user_id::text,
|
|
90
|
-
NOW(),
|
|
91
|
-
NOW(),
|
|
92
|
-
NOW()
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
RAISE NOTICE 'Created dev admin user: % with id: %', admin_email, new_user_id;
|
|
96
|
-
ELSE
|
|
97
|
-
-- Update existing user to have super_admin role if they don't already
|
|
98
|
-
UPDATE auth.users
|
|
99
|
-
SET raw_app_meta_data = raw_app_meta_data || '{"role": "super_admin"}'::jsonb,
|
|
100
|
-
updated_at = NOW()
|
|
101
|
-
WHERE email = admin_email
|
|
102
|
-
AND (raw_app_meta_data->>'role' IS NULL OR raw_app_meta_data->>'role' != 'super_admin');
|
|
103
|
-
|
|
104
|
-
IF FOUND THEN
|
|
105
|
-
RAISE NOTICE 'Updated existing user % to admin role', admin_email;
|
|
106
|
-
ELSE
|
|
107
|
-
RAISE NOTICE 'User % already exists with admin role', admin_email;
|
|
108
|
-
END IF;
|
|
109
|
-
END IF;
|
|
110
|
-
ELSE
|
|
111
|
-
RAISE NOTICE 'Skipping admin user creation - no admin email configured';
|
|
112
|
-
END IF;
|
|
113
|
-
END $$;
|