@refai.code/vite-boost 0.1.0 → 0.1.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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -0
  3. package/bin/vite-boost +456 -93
  4. package/package.json +21 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Refai.Code
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # @refai.code/vite-boost
2
+
3
+ CLI tool to supercharge **Vite Vanilla JavaScript** projects.
4
+
5
+ ---
6
+
7
+ ## 🚀 What it does
8
+ `vite-boost` helps you quickly scaffold and enhance a **Vite Vanilla JS** project with a clean architecture and optional features.
9
+
10
+ ### It can:
11
+ - Create a clean project structure:
12
+ - `router/`, `pages/`, `components/`, `services/`, `utils/`, `styles/`
13
+ - Optionally add:
14
+ - 🎨 TailwindCSS
15
+ - 📡 Axios (Fetch is default)
16
+ - 📱 PWA support
17
+ - 🗄️ JSON Server (`db.json` + dev scripts)
18
+
19
+ ---
20
+
21
+ ## 📦 Requirements
22
+ - Node.js **>= 18**
23
+ - A **Vite Vanilla JavaScript** project
24
+ (must contain: `package.json`, `index.html`, `src/`)
25
+
26
+ > ❌ Not intended for React or TypeScript templates.
27
+
28
+ ---
29
+
30
+ ## ▶️ Usage (recommended)
31
+
32
+ Inside your Vite project folder:
33
+
34
+ ```bash
35
+ npm i -D @refai.code/vite-boost
36
+ npx vite-boost
37
+ ```
38
+ ## ▶️ Run without installing
39
+
40
+ ```bash
41
+ npx @refai.code/vite-boost
42
+ ```
43
+
44
+ ## 🏃 After running
45
+
46
+ ### Start dev server:
47
+
48
+ ```bash
49
+ npm run dev
50
+ ```
51
+ ### If you enabled JSON Server:
52
+ ```bash
53
+ npm run dev:full
54
+ ```
55
+
56
+ ## ⚠️ Important Notes
57
+
58
+ - This tool targets Vanilla JavaScript only
59
+ - Some files under src/ may be overwritten
60
+ - Existing files are backed up before modification when possible
61
+ - Safe to re-run (will not blindly duplicate router code)
62
+
63
+ ## 🧑‍💻 Author
64
+
65
+ Created by **Refai.Code**
66
+ CLI & tooling for modern Vite projects
package/bin/vite-boost CHANGED
@@ -11,54 +11,216 @@ set -u
11
11
  # - Real JSON Server Auth (Users save to db.json)
12
12
  # - Concurrent Run (Vite + JSON Server)
13
13
 
14
- echo "\n🚀 \033[1;36mVite Boost: Refai.Code Final Edition\033[0m\n"
14
+ # Handle exit vs return safely
15
+ terminate() {
16
+ local code="${1:-0}"
17
+ # Check if we are being sourced
18
+ if [[ "$ZSH_EVAL_CONTEXT" == "toplevel" || "$ZSH_EVAL_CONTEXT" == "shfunc" ]]; then
19
+ return "$code" 2>/dev/null || exit "$code"
20
+ else
21
+ exit "$code"
22
+ fi
23
+ }
24
+
25
+ die() { print -P "%F{red}❌ $*%f" >&2; terminate 1; }
26
+ warn() { print -P "%F{yellow}⚠️ $*%f" >&2; }
27
+ ok() { print -P "%F{green}✅ $*%f"; }
28
+
29
+ VERSION="0.1.0"
30
+
31
+ # -----------------------------
32
+ # Help / Version
33
+ # -----------------------------
34
+ if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
35
+ cat <<'EOF'
36
+ vite-boost (Refai.Code)
37
+
38
+ Usage:
39
+ npx vite-boost
40
+ npx vite-boost --help
41
+ npx vite-boost --version
42
+
43
+ Notes:
44
+ - Run inside a Vite Vanilla JS project folder (package.json, index.html, src/)
45
+ EOF
46
+ terminate 0
47
+ fi
48
+
49
+ if [[ "${1:-}" == "--version" || "${1:-}" == "-v" ]]; then
50
+ print "vite-boost v${VERSION}"
51
+ terminate 0
52
+ fi
53
+
54
+ print ""
55
+ print "🚀 \033[1;36mVite Boost: Refai.Code Final Edition\033[0m"
56
+ print ""
15
57
 
58
+ # -----------------------------
59
+ # Validation: Must be in a Vite project folder
60
+ # -----------------------------
16
61
  # --- Validation: Check if it's a Vite project ---
17
- if [ ! -f "package.json" ]; then
18
- echo "❌ Error: package.json not found. Are you in the right directory?"
19
- return 1
62
+ if [[ ! -f package.json ]]; then
63
+ print -u2 "❌ Error: package.json not found. Are you in the right directory?"
64
+ terminate 1
20
65
  fi
21
66
 
22
- # Check if Vite is in dependencies or devDependencies
23
- if ! grep -q '"vite"' package.json; then
24
- echo "⚠️ Warning: Vite not found in package.json."
25
- if read -q "choice?This doesn't look like a Vite project. Continue anyway? (y/N) "; then
67
+ if ! grep -q '"vite"' package.json 2>/dev/null; then
68
+ print -u2 "⚠️ Warning: Vite not found in package.json."
69
+ if ! read -k 1 "choice?This doesn't look like a Vite project. Continue anyway? (y/N) "; then
26
70
  echo ""
27
- else
28
- echo "\n❌ Setup cancelled."
29
- return 1
71
+ print -u2 "❌ Setup cancelled."
72
+ terminate 1
30
73
  fi
74
+ echo ""
31
75
  fi
32
-
33
- echo "✅ Detected Vite project. Proceeding...\n"
76
+ ok "Proceeding..."
77
+ print ""
34
78
 
35
79
  # --- 1. Interactive Prompts ---
36
80
  ask() {
37
- if read -q "choice?📦 Install $1? (y/N) "; then
38
- echo "\n Selected $1"
81
+ print -n "📦 Install $1? (y/N) "
82
+ read -k 1 choice
83
+ echo ""
84
+ if [[ "$choice" == [Yy] ]]; then
85
+ print " ✅ Selected $1"
39
86
  eval "$2=true"
40
87
  else
41
- echo "\n ❌ Skipped $1"
88
+ print " ❌ Skipped $1"
42
89
  eval "$2=false"
43
90
  fi
44
- echo ""
91
+ print ""
45
92
  }
46
93
 
47
94
  # Helper: Check file overwrite
95
+ # returns: 0 always (never trips set -e)
96
+ # sets global var: OVERWRITE_OK=true/false
48
97
  check_overwrite() {
49
- local file=$1
50
- if [ -f "$file" ]; then
51
- if read -q "choice?⚠️ $file already exists. Overwrite? (y/N) "; then
52
- echo ""
98
+ local file="$1"
99
+ if [[ -f "$file" ]]; then
100
+ print -n "⚠️ $file already exists. Overwrite? (y/N) "
101
+ read -k 1 choice
102
+ echo ""
103
+ if [[ "$choice" == [Yy] ]]; then
53
104
  return 0 # Yes, overwrite
54
105
  else
55
- echo "\n ⏭️ Skipped $file"
106
+ print " ⏭️ Skipped $file"
56
107
  return 1 # No, skip
57
108
  fi
58
109
  fi
59
- return 0 # File doesn't exist, proceed
110
+ return 0
111
+ }
112
+
113
+ # write file with preview diff + choices
114
+ write_file() {
115
+ local file="$1"
116
+ local tmp dir
117
+ tmp="$(mktemp)"
118
+
119
+ cat > "$tmp"
120
+
121
+ dir="$(dirname -- "$file")"
122
+ mkdir -p "$dir"
123
+
124
+ # if file doesn't exist, optionally still ask
125
+ if [[ ! -f "$file" ]]; then
126
+ if [[ "${ALWAYS_CONFIRM_OVERWRITE:-false}" == "true" ]]; then
127
+ if [[ "$choice" == [Nn] ]]; then
128
+ rm -f "$tmp"
129
+ warn "Skipped $file"
130
+ return 0 # Continue script
131
+ fi
132
+ fi
133
+ mv "$tmp" "$file"
134
+ ok "Created $file"
135
+ return 0
136
+ fi
137
+
138
+ # same content => do nothing
139
+ if cmp -s "$tmp" "$file" 2>/dev/null; then
140
+ rm -f "$tmp"
141
+ ok "Unchanged $file"
142
+ return 0
143
+ fi
144
+
145
+ while true; do
146
+ print -n "⚠️ ${file} exists. [y] overwrite / [n] skip / [d] diff (n): "
147
+ local ans; IFS= read -r ans
148
+ ans="${ans:l}"
149
+ case "$ans" in
150
+ y|yes)
151
+ mv "$tmp" "$file"
152
+ ok "Overwritten $file"
153
+ return 0
154
+ ;;
155
+ d|diff)
156
+ if command -v git >/dev/null 2>&1; then
157
+ git --no-pager diff --no-index -- "$file" "$tmp" || true
158
+ else
159
+ diff -u -- "$file" "$tmp" || true
160
+ fi
161
+ ;;
162
+ ""|n|no)
163
+ rm -f "$tmp"
164
+ warn "Skipped $file"
165
+ return 0 # Continue script
166
+ ;;
167
+ *)
168
+ warn "Choose y / n / d"
169
+ ;;
170
+ esac
171
+ done
60
172
  }
173
+ upsert_block() {
174
+ local file="$1"
175
+ local start="$2"
176
+ local end="$3"
177
+ local tmp
178
+ tmp="$(mktemp)"
179
+
180
+ # Read stdin into tmp (the new block content)
181
+ cat > "$tmp"
182
+
183
+ # If file doesn't exist, just write it
184
+ if [[ ! -f "$file" ]]; then
185
+ mkdir -p "${file:h}"
186
+ cat "$tmp" > "$file"
187
+ rm -f "$tmp"
188
+ return 0
189
+ fi
190
+
191
+ # If markers exist, replace block
192
+ if grep -qF "$start" "$file" && grep -qF "$end" "$file"; then
193
+ # keep everything before start + new block + everything after end
194
+ awk -v s="$start" -v e="$end" '
195
+ BEGIN{in=0}
196
+ index($0,s){print; in=1; next}
197
+ index($0,e){in=0; print; next}
198
+ in==0{print}
199
+ ' "$file" > "${file}.tmp"
200
+
201
+ # Insert new content between markers
202
+ awk -v s="$start" -v e="$end" '
203
+ {print}
204
+ index($0,s){
205
+ while ((getline line < "'"$tmp"'") > 0) print line
206
+ close("'"$tmp"'")
207
+ }
208
+ ' "${file}.tmp" > "$file"
209
+
210
+ rm -f "${file}.tmp" "$tmp"
211
+ else
212
+ # markers not found => append safely once
213
+ cat >> "$file" <<EOF
61
214
 
215
+ $start
216
+ EOF
217
+ cat "$tmp" >> "$file"
218
+ cat >> "$file" <<EOF
219
+ $end
220
+ EOF
221
+ rm -f "$tmp"
222
+ fi
223
+ }
62
224
  # Defaults
63
225
  tail=false
64
226
  expr=false
@@ -77,13 +239,14 @@ ask "JSON Server (Real Database & Auth)" json
77
239
  # ==========================================
78
240
  # 🛠️ Architecture Setup
79
241
  # ==========================================
80
- echo "\n📁 Creating project structure..."
242
+ print ""
243
+ print "📁 Creating project structure..."
81
244
  mkdir -p src/{components,pages,router,styles,services,utils,assets}
82
245
 
83
246
  # -----------------------------
84
247
  # 1. Utilities
85
248
  # -----------------------------
86
- echo "\n🔧 Generating utility files..."
249
+ print "\n🔧 Generating utility files..."
87
250
  if check_overwrite "src/utils/helpers.js"; then
88
251
  cat > src/utils/helpers.js <<'EOF'
89
252
  export const sanitize = (str) => {
@@ -379,7 +542,7 @@ EOF
379
542
  # -----------------------------
380
543
  # 4. Styles (Glass, Spinner, Cards)
381
544
  # -----------------------------
382
- cat > src/styles/main.css <<'EOF'
545
+ write_file "src/styles/main.css" <<'EOF'
383
546
  :root {
384
547
  --primary: #4f46e5;
385
548
  --bg: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
@@ -1097,20 +1260,20 @@ EOF
1097
1260
  # -----------------------------
1098
1261
  # 7. Main Entry Point
1099
1262
  # -----------------------------
1100
- # Smart handling: Append to existing main.js instead of replacing
1101
- if [ -f "src/main.js" ]; then
1102
- echo "\n⚠️ src/main.js already exists."
1103
- if read -q "choice?Do you want to append router code to it? (y/N) "; then
1104
- echo "\n✅ Appending router logic to existing main.js..."
1105
-
1106
- # Backup first
1107
- cp src/main.js src/main.js.backup
1108
- echo "📦 Backup created: src/main.js.backup"
1109
-
1110
- # Append router imports and setup
1111
- cat >> src/main.js <<'EOF'
1263
+ START_MARK='// ===== Refai.Code Router Setup (Auto-generated) ====='
1264
+ END_MARK='// ===== End Refai.Code Router Setup ====='
1265
+
1266
+ router_block() {
1267
+ local pwa_import=""
1268
+ local pwa_init=""
1269
+ if [[ "$pwa" == "true" ]]; then
1270
+ pwa_import="import { registerPWA } from './pwa/register.js';"
1271
+ pwa_init="registerPWA();"
1272
+ fi
1112
1273
 
1113
- // ===== Refai.Code Router Setup (Auto-generated) =====
1274
+ cat <<EOF
1275
+ import './styles/main.css';
1276
+ $pwa_import
1114
1277
  import { LiteRouter } from './router/LiteRouter.js';
1115
1278
  import { Layout } from './components/Layout.js';
1116
1279
  import { Navbar } from './components/Navbar.js';
@@ -1137,47 +1300,76 @@ authState.subscribe(() => {
1137
1300
  if (el) el.innerHTML = Navbar();
1138
1301
  });
1139
1302
 
1140
- const app = new LiteRouter(routes, '#app');
1141
- app.init();
1303
+ $pwa_init
1304
+ new LiteRouter(routes, '#app').init();
1142
1305
  EOF
1143
- else
1144
- echo "\n⏭️ Skipped modifying main.js"
1145
- fi
1146
- else
1147
- # File doesn't exist, create new one
1148
- cat > src/main.js <<'EOF'
1149
- import './styles/main.css';
1150
- import { LiteRouter } from './router/LiteRouter.js';
1151
- import { Layout } from './components/Layout.js';
1152
- import { Navbar } from './components/Navbar.js';
1153
- import { authState } from './services/auth.js';
1306
+ }
1154
1307
 
1155
- import { HomePage } from './pages/HomePage.js';
1156
- import { ProductsPage } from './pages/ProductsPage.js';
1157
- import { ProductDetailsPage } from './pages/ProductDetailsPage.js';
1158
- import { LoginPage } from './pages/LoginPage.js';
1159
- import { SignupPage } from './pages/SignupPage.js';
1308
+ ensure_main_js() {
1309
+ mkdir -p src
1310
+
1311
+ local block_content
1312
+ block_content=$(router_block)
1313
+
1314
+ if [[ -f "src/main.js" ]]; then
1315
+ # Case 1: Markers already exist => Replace content between them
1316
+ if grep -qF "$START_MARK" src/main.js && grep -qF "$END_MARK" src/main.js; then
1317
+ print -n "⚠️ Refai router block found in main.js. Update it? (y/N) "
1318
+ read -k 1 choice; echo ""
1319
+ if [[ "$choice" == [Yy] ]]; then
1320
+ # Use awk to replace block
1321
+ awk -v s="$START_MARK" -v e="$END_MARK" -v r="$block_content" '
1322
+ BEGIN {p=1}
1323
+ $0 == s {print s; print r; p=0}
1324
+ $0 == e {p=1; print e; next}
1325
+ p {print}
1326
+ ' src/main.js > src/main.js.tmp && mv src/main.js.tmp src/main.js
1327
+ ok "Updated router block in main.js"
1328
+ fi
1329
+ return 0
1330
+ fi
1160
1331
 
1161
- const routes = [
1162
- { path: '/', component: HomePage, layout: Layout, title: 'Home | Refai.Code' },
1163
- { path: '/products', component: ProductsPage, layout: Layout, title: 'Products' },
1164
- { path: '/products/:id', component: ProductDetailsPage, layout: Layout, title: 'Details' },
1165
- { path: '/login', component: LoginPage, layout: Layout, title: 'Login' },
1166
- { path: '/logout', component: () => { authState.logout(); return '<div></div>'; } },
1167
- { path: '/signup', component: SignupPage, layout: Layout, title: 'Signup' },
1168
- { path: '*', component: () => '<h1 class="container">404</h1>', layout: Layout }
1169
- ];
1332
+ # Case 2: No markers, but Refai code (LiteRouter) detected => Wrap it with markers or replace
1333
+ if grep -q "LiteRouter" src/main.js; then
1334
+ print -n "⚠️ LiteRouter detected but no markers found. Replace entire main.js to fix structure? (y/N) "
1335
+ read -k 1 choice; echo ""
1336
+ if [[ "$choice" == [Yy] ]]; then
1337
+ cp src/main.js "src/main.js.backup.$(date +%Y%m%d-%H%M%S)"
1338
+ {
1339
+ echo "$START_MARK"
1340
+ echo "$block_content"
1341
+ echo "$END_MARK"
1342
+ } > src/main.js
1343
+ ok "Replaced main.js with structured Refai block."
1344
+ fi
1345
+ return 0
1346
+ fi
1170
1347
 
1171
- // Subscribe Navbar to Auth Changes
1172
- authState.subscribe(() => {
1173
- const el = document.getElementById('nav-mount');
1174
- if (el) el.innerHTML = Navbar();
1175
- });
1348
+ # Case 3: Completely foreign file => Append block with markers
1349
+ print -n "⚠️ src/main.js exists. Append Refai router block at the end? (y/N) "
1350
+ read -k 1 choice; echo ""
1351
+ if [[ "$choice" == [Yy] ]]; then
1352
+ cp src/main.js "src/main.js.backup.$(date +%Y%m%d-%H%M%S)"
1353
+ {
1354
+ echo -e "\n$START_MARK"
1355
+ echo "$block_content"
1356
+ echo "$END_MARK"
1357
+ } >> src/main.js
1358
+ ok "Appended Refai block to main.js"
1359
+ fi
1360
+ else
1361
+ # File doesn't exist => Create new one WITH markers
1362
+ echo "📝 Creating new src/main.js..."
1363
+ {
1364
+ echo "$START_MARK"
1365
+ echo "$block_content"
1366
+ echo "$END_MARK"
1367
+ } > src/main.js
1368
+ ok "Created src/main.js with markers."
1369
+ fi
1370
+ }
1176
1371
 
1177
- const app = new LiteRouter(routes, '#app');
1178
- app.init();
1179
- EOF
1180
- fi
1372
+ ensure_main_js
1181
1373
 
1182
1374
  # -----------------------------
1183
1375
  # 8. Dependency & Concurrent
@@ -1230,12 +1422,10 @@ if [ "$tail" = true ]; then
1230
1422
  $PM install -D tailwindcss postcss autoprefixer
1231
1423
 
1232
1424
  # Initialize tailwind config
1233
- if [ "$PM" = "pnpm" ]; then
1234
- pnpm exec tailwindcss init -p
1235
- elif [ "$PM" = "yarn" ]; then
1236
- yarn tailwindcss init -p
1425
+ if [[ -f "node_modules/.bin/tailwindcss" ]]; then
1426
+ ./node_modules/.bin/tailwindcss init -p
1237
1427
  else
1238
- npx -y tailwindcss init -p
1428
+ npx -y --package tailwindcss tailwindcss init -p
1239
1429
  fi
1240
1430
 
1241
1431
  cat > src/styles/tailwind.css <<EOF
@@ -1263,11 +1453,132 @@ if [ "$json" = true ]; then
1263
1453
  fi
1264
1454
 
1265
1455
  # PWA Setup
1456
+ # -----------------------------
1457
+ # PWA Setup (FULL)
1458
+ # -----------------------------
1266
1459
  if [ "$pwa" = true ]; then
1267
1460
  echo "📱 Setting up PWA..."
1461
+
1462
+ # Install plugin
1268
1463
  $PM install -D vite-plugin-pwa
1269
1464
  installed_packages+=("Vite PWA Plugin")
1270
- cat > vite.config.js <<EOF
1465
+
1466
+ # Ensure public/ exists
1467
+ mkdir -p public
1468
+
1469
+ # 1) Generate real PNG icons (no external deps)
1470
+ # Creates:
1471
+ # - public/pwa-192x192.png
1472
+ # - public/pwa-512x512.png
1473
+ # - public/apple-touch-icon.png
1474
+ node - <<'NODE'
1475
+ const fs = require('fs');
1476
+ const zlib = require('zlib');
1477
+
1478
+ function crc32(buf) {
1479
+ let c = ~0;
1480
+ for (let i = 0; i < buf.length; i++) {
1481
+ c ^= buf[i];
1482
+ for (let k = 0; k < 8; k++) c = (c >>> 1) ^ (0xEDB88320 & (-(c & 1)));
1483
+ }
1484
+ return (~c) >>> 0;
1485
+ }
1486
+ function chunk(type, data) {
1487
+ const t = Buffer.from(type, 'ascii');
1488
+ const len = Buffer.alloc(4);
1489
+ len.writeUInt32BE(data.length, 0);
1490
+ const crc = Buffer.alloc(4);
1491
+ crc.writeUInt32BE(crc32(Buffer.concat([t, data])), 0);
1492
+ return Buffer.concat([len, t, data, crc]);
1493
+ }
1494
+ function makePng(size, outPath) {
1495
+ const width = size, height = size;
1496
+ const raw = Buffer.alloc(width * height * 4);
1497
+
1498
+ const bg = { r: 0x4f, g: 0x46, b: 0xe5, a: 0xff }; // #4f46e5
1499
+ const fg = { r: 0xff, g: 0xff, b: 0xff, a: 0xff }; // white
1500
+
1501
+ const badgeSize = Math.floor(size * 0.46);
1502
+ const badgeStart = Math.floor((size - badgeSize) / 2);
1503
+ const badgeEnd = badgeStart + badgeSize;
1504
+
1505
+ for (let y = 0; y < height; y++) {
1506
+ for (let x = 0; x < width; x++) {
1507
+ const i = (y * width + x) * 4;
1508
+ let c = bg;
1509
+ if (x >= badgeStart && x < badgeEnd && y >= badgeStart && y < badgeEnd) c = fg;
1510
+ raw[i+0] = c.r; raw[i+1] = c.g; raw[i+2] = c.b; raw[i+3] = c.a;
1511
+ }
1512
+ }
1513
+
1514
+ const stride = width * 4;
1515
+ const scan = Buffer.alloc((stride + 1) * height);
1516
+ for (let y = 0; y < height; y++) {
1517
+ scan[y * (stride + 1)] = 0; // filter 0
1518
+ raw.copy(scan, y * (stride + 1) + 1, y * stride, (y + 1) * stride);
1519
+ }
1520
+
1521
+ const signature = Buffer.from([0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A]);
1522
+ const ihdr = Buffer.alloc(13);
1523
+ ihdr.writeUInt32BE(width, 0);
1524
+ ihdr.writeUInt32BE(height, 4);
1525
+ ihdr[8] = 8; // bit depth
1526
+ ihdr[9] = 6; // color type RGBA
1527
+ ihdr[10] = 0; // compression
1528
+ ihdr[11] = 0; // filter
1529
+ ihdr[12] = 0; // interlace
1530
+
1531
+ const idatData = zlib.deflateSync(scan, { level: 9 });
1532
+ const png = Buffer.concat([
1533
+ signature,
1534
+ chunk('IHDR', ihdr),
1535
+ chunk('IDAT', idatData),
1536
+ chunk('IEND', Buffer.alloc(0)),
1537
+ ]);
1538
+
1539
+ fs.writeFileSync(outPath, png);
1540
+ }
1541
+
1542
+ fs.mkdirSync('public', { recursive: true });
1543
+ makePng(192, 'public/pwa-192x192.png');
1544
+ makePng(512, 'public/pwa-512x512.png');
1545
+ makePng(180, 'public/apple-touch-icon.png');
1546
+ console.log('✅ PWA icons generated: 192, 512, 180');
1547
+ NODE
1548
+
1549
+ # 2) Write manifest.webmanifest
1550
+ cat > public/manifest.webmanifest <<'EOF'
1551
+ {
1552
+ "name": "Refai App",
1553
+ "short_name": "Refai",
1554
+ "description": "Vite PWA powered by Refai.Code",
1555
+ "start_url": "/",
1556
+ "scope": "/",
1557
+ "display": "standalone",
1558
+ "background_color": "#ffffff",
1559
+ "theme_color": "#4f46e5",
1560
+ "icons": [
1561
+ { "src": "/pwa-192x192.png", "sizes": "192x192", "type": "image/png" },
1562
+ { "src": "/pwa-512x512.png", "sizes": "512x512", "type": "image/png" },
1563
+ { "src": "/pwa-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }
1564
+ ]
1565
+ }
1566
+ EOF
1567
+
1568
+ # 3) Ensure index.html links the manifest + theme color + apple touch icon
1569
+ if [ -f index.html ]; then
1570
+ # Add manifest link if missing
1571
+ if ! grep -q 'manifest\.webmanifest' index.html; then
1572
+ # insert before </head> using | as delimiter to avoid hex code # conflict
1573
+ perl -0777 -i -pe 's|</head>| <link rel="manifest" href="/manifest.webmanifest">\n <meta name="theme-color" content="#4f46e5">\n <link rel="apple-touch-icon" href="/apple-touch-icon.png">\n</head>|s' index.html
1574
+ echo "✅ Updated index.html (manifest + theme-color + apple-touch-icon)"
1575
+ else
1576
+ echo "✅ index.html already has manifest link"
1577
+ fi
1578
+ fi
1579
+
1580
+ # 4) Create/overwrite vite.config.js with correct PWA config
1581
+ cat > vite.config.js <<'EOF'
1271
1582
  import { defineConfig } from 'vite';
1272
1583
  import path from 'path';
1273
1584
  import { VitePWA } from 'vite-plugin-pwa';
@@ -1275,11 +1586,64 @@ import { VitePWA } from 'vite-plugin-pwa';
1275
1586
  export default defineConfig({
1276
1587
  resolve: { alias: { '@': path.resolve(__dirname, './src') } },
1277
1588
  plugins: [
1278
- VitePWA({ registerType: 'autoUpdate' }),
1589
+ VitePWA({
1590
+ registerType: 'autoUpdate',
1591
+ injectRegister: 'auto',
1592
+ devOptions: {
1593
+ enabled: true,
1594
+ type: 'module'
1595
+ },
1596
+ workbox: {
1597
+ globPatterns: ['**/*.{js,css,html,ico,png,svg,webmanifest}']
1598
+ },
1599
+ includeAssets: [
1600
+ 'apple-touch-icon.png',
1601
+ 'pwa-192x192.png',
1602
+ 'pwa-512x512.png'
1603
+ ],
1604
+ manifest: {
1605
+ name: 'Refai App',
1606
+ short_name: 'Refai',
1607
+ description: 'Vite PWA powered by Refai.Code',
1608
+ start_url: '/',
1609
+ scope: '/',
1610
+ display: 'standalone',
1611
+ background_color: '#ffffff',
1612
+ theme_color: '#4f46e5',
1613
+ icons: [
1614
+ { src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' },
1615
+ { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png' },
1616
+ { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' }
1617
+ ]
1618
+ }
1619
+ })
1279
1620
  ]
1280
1621
  });
1281
1622
  EOF
1623
+
1624
+ # 5) Add a small SW hook file (optional but useful) + include it from main.js
1625
+ # We'll create src/pwa/register.js and then import it from src/main.js (if main.js exists)
1626
+ mkdir -p src/pwa
1627
+
1628
+ cat > src/pwa/register.js <<'EOF'
1629
+ export function registerPWA() {
1630
+ // vite-plugin-pwa with injectRegister:'auto' registers automatically.
1631
+ // This file is just a safe place to add UX hooks (optional).
1632
+ if ('serviceWorker' in navigator) {
1633
+ // Optional: listen for SW updates
1634
+ navigator.serviceWorker.addEventListener('controllerchange', () => {
1635
+ // SW updated and controlling the page
1636
+ console.log('[PWA] controller changed');
1637
+ });
1638
+ }
1639
+ }
1640
+ EOF
1641
+
1642
+ # Note: PWA registration is now handled inside the main.js router block for consistency
1643
+ installed_packages+=("PWA (manifest + icons + SW)")
1644
+
1282
1645
  else
1646
+ # If PWA not selected, keep normal vite.config.js
1283
1647
  cat > vite.config.js <<EOF
1284
1648
  import { defineConfig } from 'vite';
1285
1649
  import path from 'path';
@@ -1289,25 +1653,24 @@ export default defineConfig({
1289
1653
  });
1290
1654
  EOF
1291
1655
  fi
1292
-
1293
1656
  # -----------------------------
1294
1657
  # Final Summary
1295
1658
  # -----------------------------
1296
- echo "\n✅ \033[1;32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m"
1297
- echo "\n🎉 \033[1;32mSetup Complete!\033[0m Created by Refai.Code\n"
1659
+ print "\n✅ \033[1;32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m"
1660
+ print "\n🎉 \033[1;32mSetup Complete!\033[0m Created by Refai.Code\n"
1298
1661
 
1299
1662
  if [ ${#installed_packages[@]} -gt 0 ]; then
1300
- echo "📦 \033[1;36mInstalled Packages:\033[0m"
1663
+ print "📦 \033[1;36mInstalled Packages:\033[0m"
1301
1664
  for pkg in "${installed_packages[@]}"; do
1302
- echo " ✓ $pkg"
1665
+ print " ✓ $pkg"
1303
1666
  done
1304
- echo ""
1667
+ print ""
1305
1668
  fi
1306
1669
 
1307
- echo "🚀 \033[1;33mNext Steps:\033[0m"
1308
- echo " 1. Run \033[1m$PM run dev\033[0m to start Vite dev server"
1670
+ print "🚀 \033[1;33mNext Steps:\033[0m"
1671
+ print " 1. Run \033[1m$PM run dev\033[0m to start Vite dev server"
1309
1672
  if [ "$json" = true ]; then
1310
- echo " 2. Run \033[1m$PM run dev:full\033[0m to start Vite + JSON Server together"
1311
- echo " 3. Or run \033[1mnpx json-server db.json --port 3000\033[0m in a separate terminal"
1673
+ print " 2. Run \033[1m$PM run dev:full\033[0m to start Vite + JSON Server together"
1674
+ print " 3. Or run \033[1mnpx json-server db.json --port 3000\033[0m in a separate terminal"
1312
1675
  fi
1313
- echo "\n✅ \033[1;32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n"
1676
+ print "\n✅ \033[1;32m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n"
package/package.json CHANGED
@@ -1,16 +1,34 @@
1
1
  {
2
2
  "name": "@refai.code/vite-boost",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Vite Vanilla JS booster script (optional Tailwind/Axios/PWA/JSON-server)",
5
5
  "license": "MIT",
6
6
  "private": false,
7
+ "homepage": "https://github.com/David-refai/vite-boost",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/David-refai/vite-boost.git"
11
+ },
7
12
  "bin": {
8
13
  "vite-boost": "bin/vite-boost"
9
14
  },
10
15
  "files": [
11
- "bin"
16
+ "bin",
17
+ "README.md",
18
+ "LICENSE"
12
19
  ],
13
20
  "engines": {
14
21
  "node": ">=18"
15
- }
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "keywords": [
27
+ "vite",
28
+ "cli",
29
+ "pwa",
30
+ "tailwind",
31
+ "json-server",
32
+ "scaffold"
33
+ ]
16
34
  }