chore: initial hub repo structure

This commit is contained in:
asepharyana
2026-07-09 22:08:26 +07:00
commit b31fe9d188
83 changed files with 7969 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# Copy .env from root to all direct subprojects/packages (not nested, not build, not .git, not .github, not node_modules, not .turbo, not .next, not .vscode, not dist, not public, not src, not coverage, not logs, not .devcontainer, not .yarn, not target)
# Do NOT copy to /apps or /packages root, only to their subfolders.
ROOT_ENV="./.env"
if [ ! -f "$ROOT_ENV" ]; then
echo "Root .env file not found at $ROOT_ENV"
exit 1
fi
for parent in apps packages; do
for dir in ./$parent/*/; do
# Remove trailing slash
dir="${dir%/}"
base=$(basename "$dir")
if [[ "$base" =~ ^(\.git|\.github|node_modules|\.turbo|\.next|\.vscode|dist|public|src|coverage|logs|\.devcontainer|\.yarn|target)$ ]]; then
continue
fi
cp "$ROOT_ENV" "$dir/.env"
echo "Copied .env to $dir/.env"
done
done
+169
View File
@@ -0,0 +1,169 @@
<#
.SYNOPSIS
Clean all node_modules directories in the repository with optional cache and lockfile cleanup.
.DESCRIPTION
This script recursively finds and removes all 'node_modules' directories starting at the repo root.
Optionally, it can also remove build caches and lockfiles, and run 'pnpm store prune'.
.PARAMETER IncludeCache
Also remove common cache/build output directories (e.g., .next, .turbo, .vite, node_modules/.cache, dist, build, coverage, out, storybook-static).
.PARAMETER IncludeLock
Also remove lock files (pnpm-lock.yaml, package-lock.json, yarn.lock) in the repo.
.PARAMETER PruneStore
After deletion, try to run 'pnpm store prune' if pnpm is installed.
.PARAMETER Yes
Proceed without interactive confirmation (non-interactive mode).
.PARAMETER DryRun
Show what would be removed without deleting anything.
.EXAMPLE
# Preview what will be removed
./scripts/clean-node-modules.ps1 -DryRun
.EXAMPLE
# Clean node_modules only, no prompt
./scripts/clean-node-modules.ps1 -Yes
.EXAMPLE
# Deep clean including caches and lockfiles, and prune pnpm store
./scripts/clean-node-modules.ps1 -IncludeCache -IncludeLock -PruneStore -Yes
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[switch] $IncludeCache,
[switch] $IncludeLock,
[switch] $PruneStore,
[switch] $Yes,
[switch] $DryRun
)
$ErrorActionPreference = 'Stop'
function Write-Section($text) {
Write-Host "`n==== $text ====\n" -ForegroundColor Cyan
}
function Safe-RemoveDirectory {
param(
[Parameter(Mandatory=$true)][string] $Path,
[switch] $Preview
)
if (-not (Test-Path -LiteralPath $Path)) { return }
if ($Preview) { Write-Host "[dir] $Path"; return }
try {
# Use cmd rmdir for better handling of read-only/long paths on Windows PowerShell 5.1
& cmd.exe /c "rmdir /s /q \"$Path\"" | Out-Null
} catch {
try { Remove-Item -LiteralPath $Path -Recurse -Force -ErrorAction Stop } catch {
Write-Warning "Failed to remove directory: $Path -> $($_.Exception.Message)"
}
}
}
function Safe-RemoveFile {
param(
[Parameter(Mandatory=$true)][string] $Path,
[switch] $Preview
)
if (-not (Test-Path -LiteralPath $Path)) { return }
if ($Preview) { Write-Host "[file] $Path"; return }
try { Remove-Item -LiteralPath $Path -Force -ErrorAction Stop } catch {
Write-Warning "Failed to remove file: $Path -> $($_.Exception.Message)"
}
}
# Resolve repo root (this script lives in ./scripts)
$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
Set-Location -LiteralPath $RepoRoot
Write-Host "Repo root: $RepoRoot" -ForegroundColor DarkGray
# Accumulators
$DirsToDelete = New-Object System.Collections.Generic.List[string]
$FilesToDelete = New-Object System.Collections.Generic.List[string]
# 1) node_modules everywhere (including root)
Write-Section 'Scanning node_modules directories'
$nodeModulesDirs = Get-ChildItem -LiteralPath $RepoRoot -Directory -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.Name -eq 'node_modules' }
# Ensure root node_modules is included if present
$rootNM = Join-Path $RepoRoot 'node_modules'
if (Test-Path -LiteralPath $rootNM) {
$DirsToDelete.Add($rootNM)
}
foreach ($d in $nodeModulesDirs) {
if (-not $DirsToDelete.Contains($d.FullName)) { $DirsToDelete.Add($d.FullName) }
}
Write-Host ("Found {0} node_modules directory(ies)" -f $DirsToDelete.Count)
# 2) Optional caches/output folders
if ($IncludeCache) {
Write-Section 'Scanning cache/output directories'
$cacheNames = @(
'.next', '.turbo', '.vite', '.parcel-cache', '.cache',
'dist', 'build', 'coverage', 'out', 'storybook-static',
'.wrangler'
)
# node_modules/.cache is common; include it via name match too
$allDirs = Get-ChildItem -LiteralPath $RepoRoot -Directory -Recurse -Force -ErrorAction SilentlyContinue
foreach ($dir in $allDirs) {
if ($cacheNames -contains $dir.Name) {
if (-not $DirsToDelete.Contains($dir.FullName)) { $DirsToDelete.Add($dir.FullName) }
}
}
Write-Host ("Found {0} cache/output directory(ies)" -f ($DirsToDelete | Where-Object { Test-Path $_ }).Count)
}
# 3) Optional lockfiles
if ($IncludeLock) {
Write-Section 'Scanning lock files'
$lockGlobs = @('pnpm-lock.yaml', 'package-lock.json', 'yarn.lock')
foreach ($glob in $lockGlobs) {
$files = Get-ChildItem -LiteralPath $RepoRoot -Recurse -Force -File -Filter $glob -ErrorAction SilentlyContinue
foreach ($f in $files) { if (-not $FilesToDelete.Contains($f.FullName)) { $FilesToDelete.Add($f.FullName) } }
}
Write-Host ("Found {0} lock file(s)" -f $FilesToDelete.Count)
}
# 4) Summary
Write-Section 'Summary'
Write-Host ("Directories to delete: {0}" -f $DirsToDelete.Count)
Write-Host ("Files to delete: {0}" -f $FilesToDelete.Count)
$preview = $DryRun -or (-not $Yes)
if ($preview) {
Write-Host "Preview mode (no deletions). Use -Yes to confirm, or pass -DryRun:$false to hide this list." -ForegroundColor Yellow
foreach ($dir in $DirsToDelete) { Safe-RemoveDirectory -Path $dir -Preview }
foreach ($fil in $FilesToDelete) { Safe-RemoveFile -Path $fil -Preview }
if (-not $Yes) { Write-Host "\nRun again with -Yes to confirm deletion." -ForegroundColor Yellow }
exit 0
}
# 5) Deletion
Write-Section 'Deleting directories'
foreach ($dir in $DirsToDelete) { Safe-RemoveDirectory -Path $dir }
if ($FilesToDelete.Count -gt 0) {
Write-Section 'Deleting files'
foreach ($fil in $FilesToDelete) { Safe-RemoveFile -Path $fil }
}
# 6) Optional pnpm store prune
if ($PruneStore) {
Write-Section 'Pruning pnpm store'
$pnpm = Get-Command pnpm -ErrorAction SilentlyContinue
if ($null -ne $pnpm) {
try { & pnpm store prune } catch { Write-Warning "pnpm store prune failed: $($_.Exception.Message)" }
} else {
Write-Warning "pnpm not found on PATH; skipping 'pnpm store prune'."
}
}
Write-Host "\nDone." -ForegroundColor Green
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
set -euo pipefail
# Clean all node_modules directories with optional cache & lockfile cleanup.
# Usage:
# ./scripts/clean-node-modules.sh [--include-cache] [--include-lock] [--prune-store] [--yes] [--dry-run]
INCLUDE_CACHE=false
INCLUDE_LOCK=false
PRUNE_STORE=false
YES=false
DRY_RUN=false
for arg in "$@"; do
case "$arg" in
--include-cache) INCLUDE_CACHE=true ;;
--include-lock) INCLUDE_LOCK=true ;;
--prune-store) PRUNE_STORE=true ;;
--yes) YES=true ;;
--dry-run) DRY_RUN=true ;;
*) echo "Unknown option: $arg"; exit 2 ;;
esac
done
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
preview() {
if [[ "$DRY_RUN" == true || "$YES" == false ]]; then echo 1; else echo 0; fi
}
section() { echo -e "\n==== $* ====\n"; }
DIRS_TO_DELETE=()
FILES_TO_DELETE=()
section "Scanning node_modules directories"
while IFS= read -r -d '' d; do DIRS_TO_DELETE+=("$d"); done < <(find "$REPO_ROOT" -type d -name node_modules -print0)
if [[ -d "$REPO_ROOT/node_modules" ]]; then DIRS_TO_DELETE+=("$REPO_ROOT/node_modules"); fi
section "Summary so far"
echo "Found ${#DIRS_TO_DELETE[@]} node_modules directories"
if [[ "$INCLUDE_CACHE" == true ]]; then
section "Scanning cache/output directories"
while IFS= read -r -d '' d; do DIRS_TO_DELETE+=("$d"); done < <(find "$REPO_ROOT" -type d \( \
-name .next -o -name .turbo -o -name .vite -o -name .parcel-cache -o -name .cache -o \
-name dist -o -name build -o -name coverage -o -name out -o -name storybook-static -o -name .wrangler \
\) -print0)
fi
if [[ "$INCLUDE_LOCK" == true ]]; then
section "Scanning lock files"
while IFS= read -r -d '' f; do FILES_TO_DELETE+=("$f"); done < <(\
find "$REPO_ROOT" -type f \( -name pnpm-lock.yaml -o -name package-lock.json -o -name yarn.lock \) -print0)
fi
section "Summary"
echo "Directories to delete: ${#DIRS_TO_DELETE[@]}"
echo "Files to delete: ${#FILES_TO_DELETE[@]}"
if [[ $(preview) -eq 1 ]]; then
echo "Preview mode (no deletions). Re-run with --yes to confirm."
for d in "${DIRS_TO_DELETE[@]}"; do echo "[dir] $d"; done
for f in "${FILES_TO_DELETE[@]}"; do echo "[file] $f"; done
exit 0
fi
section "Deleting directories"
for d in "${DIRS_TO_DELETE[@]}"; do rm -rf -- "$d" || true; done
if [[ ${#FILES_TO_DELETE[@]} -gt 0 ]]; then
section "Deleting files"
for f in "${FILES_TO_DELETE[@]}"; do rm -f -- "$f" || true; done
fi
if [[ "$PRUNE_STORE" == true ]]; then
section "Pruning pnpm store"
if command -v pnpm >/dev/null 2>&1; then pnpm store prune || true; else echo "pnpm not found; skipping"; fi
fi
echo "Done."
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
# Cleanup script for old GitHub Container Registry (GHCR) images
# This script uses the 'gh' CLI to delete old package versions.
# Requires 'gh' CLI to be installed and authenticated with 'delete:packages' scope.
set -e
# Configuration
ORG="asepharyana"
PACKAGE_NAMES=("rust-api" "elysia-api" "nextjs-web")
echo "🚀 Starting GHCR cleanup for $ORG..."
for PACKAGE in "${PACKAGE_NAMES[@]}"; do
echo "------------------------------------------------"
echo "📦 Checking package: $PACKAGE"
# List versions that are NOT 'latest' and DON'T match the current SHAs
# This is a safe approach: list all versions and let the user decide or
# filter by date/tag patterns.
# For simplicity and safety, this script will list versions and
# provide the command to delete them.
# To AUTOMATICALLY delete, uncomment the 'gh api' call below.
echo "🔍 Fetching versions..."
VERSIONS=$(gh api "/orgs/$ORG/packages/container/$PACKAGE/versions" --paginate -q '.[] | "\(.id) \(.metadata.container.tags[0] // "no-tag") \(.updated_at)"')
if [ -z "$VERSIONS" ]; then
echo "✅ No versions found for $PACKAGE"
continue
fi
echo "$VERSIONS" | while read -r ID TAG DATE; do
if [[ "$TAG" == "latest" ]]; then
echo "✨ Skipping latest: $ID ($DATE)"
continue
fi
# Example: only delete if the tag doesn't start with 'sha-' (adjust as needed)
# Or delete very old ones.
echo "🗑️ Found old version: $ID | Tag: $TAG | Date: $DATE"
# UNCOMMENT THE LINE BELOW TO ENABLE AUTOMATIC DELETION
# gh api -X DELETE "/orgs/$ORG/packages/container/$PACKAGE/versions/$ID"
# echo "✅ Deleted $ID"
done
done
echo "------------------------------------------------"
echo "✅ Cleanup script finished."
echo "💡 Note: Deletion is commented out by default for safety. Edit the script to enable it."
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
echo "=== Setting up Git hooks ==="
REPO_ROOT=$(git rev-parse --show-toplevel)
cat <<EOF
️ This project uses Git submodules but does not enforce hooks via Husky anymore.
Each app submodule manages its own hooks independently.
To set up hooks locally, run:
cp -r scripts/git-hooks/ .git/hooks/
EOF
+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
echo "=== Syncing all submodules ==="
git submodule update --init --recursive
echo ""
echo "=== Latest submodule status ==="
git submodule status
echo ""
echo "✅ All submodules synced"
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
set -euo pipefail
# Define an array of directories to aggressively prune from the search tree
# This prevents exhaustive traversal into massive localized dependency stores, build caches,
# and anomalously created cache directories (e.g., literal '~').
PRUNE_DIRS=(
"node_modules"
"dist"
".next"
".bun"
"~"
"build"
".git"
"target"
)
# Construct the prune expression dynamically to feed the find command
PRUNE_ARGS=()
for dir in "${PRUNE_DIRS[@]}"; do
if [ ${#PRUNE_ARGS[@]} -gt 0 ]; then
PRUNE_ARGS+=("-o")
fi
PRUNE_ARGS+=("-name" "$dir")
done
echo "Scanning for top-level and workspace package.json manifests..."
# Perform an optimized find:
# 1. -prune halts traversal immediately upon matching a PRUNE_DIR, achieving extreme I/O efficiency.
# 2. -print0 strictly streams zero-byte delimited paths, immunizing the loop against spaces/newlines.
find . \( "${PRUNE_ARGS[@]}" \) -prune -o -name "package.json" -type f -print0 | while IFS= read -r -d '' filename; do
dir=$(dirname "$filename")
echo "--------------------------------------------------------------------------------"
echo "Initiating strict dependency update sequence in: $dir"
# Spawn a tightly scoped subshell. This isolates environment state and traps internal pathing failures.
(
# Strict directory entry checks.
cd "$dir" || {
echo "CRITICAL: Directory transition failed for $dir. Process aborted." >&2
exit 1
}
# Heuristic check: Ensure the manifest actually declares dependencies before thrashing the disk with ncu.
if ! grep -Eq '"(dependencies|devDependencies|peerDependencies)"[[:space:]]*:' package.json; then
echo "Notice: No valid dependency blocks detected in $dir/package.json. Bypassing node traversal."
exit 0
fi
# Delegate command resolution to bunx. This obliterates the 'command not found' failure mode
# by dynamically sourcing the npm-check-updates binary, completely ignoring global namespace pollution.
echo "Executing constraint-free updates via bunx..."
bunx --bun npm-check-updates -u
echo "Commencing rigorous package installation phase..."
bun install
) || {
echo "WARNING: Subshell failure encountered in $dir. Subsystem continues." >&2
}
done
echo "--------------------------------------------------------------------------------"
echo "SYSTEM STATE: All traversable dependencies aggressively updated."