@habeetat/cli 0.1.0-dev.20260324202418.70eccf7 → 0.1.0-dev.20260324204704.66fdba5

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/dist/bin.js CHANGED
@@ -826,6 +826,8 @@ async function destroyCommand(options) {
826
826
  process.exit(1);
827
827
  }
828
828
  }
829
+ var SEED_SCRIPT_PATH = path__default.default.resolve(__dirname, "scripts/nhp-seed-dev.ts");
830
+ var SEED_SCRIPT_REMOTE = "/tmp/nhp-seed-dev.ts";
829
831
  function loadEnv2(projectDir) {
830
832
  const envPath = path__default.default.join(projectDir, ".env");
831
833
  if (!fs2__default.default.existsSync(envPath)) return {};
@@ -841,6 +843,27 @@ function loadEnv2(projectDir) {
841
843
  return env;
842
844
  }
843
845
  async function runSeedScript(projectDir, command, args) {
846
+ if (!fs2__default.default.existsSync(SEED_SCRIPT_PATH)) {
847
+ throw new Error(
848
+ `Seed script not found at ${SEED_SCRIPT_PATH}. This is a bug \u2014 please reinstall @habeetat/cli.`
849
+ );
850
+ }
851
+ const scriptContent = fs2__default.default.readFileSync(SEED_SCRIPT_PATH, "utf-8");
852
+ await execa.execa(
853
+ "docker",
854
+ [
855
+ "compose",
856
+ "-f",
857
+ COMPOSE_FILE,
858
+ "exec",
859
+ "-T",
860
+ "backend",
861
+ "sh",
862
+ "-c",
863
+ `cat > ${SEED_SCRIPT_REMOTE}`
864
+ ],
865
+ { cwd: projectDir, input: scriptContent, stdio: "pipe" }
866
+ );
844
867
  const { stdout, stderr } = await execa.execa(
845
868
  "docker",
846
869
  [
@@ -852,7 +875,7 @@ async function runSeedScript(projectDir, command, args) {
852
875
  "backend",
853
876
  "npx",
854
877
  "tsx",
855
- "scripts/nhp-seed-dev.ts",
878
+ SEED_SCRIPT_REMOTE,
856
879
  command,
857
880
  ...args
858
881
  ],
@@ -905,7 +928,16 @@ function printSdkConfig(config, env, parts) {
905
928
  console.log(chalk3__default.default.cyan("\u2550".repeat(56)));
906
929
  console.log("");
907
930
  }
931
+ function validateSlug(slug, entity) {
932
+ if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(slug) && !/^[a-z0-9]$/.test(slug)) {
933
+ logger.error(
934
+ `Invalid ${entity} slug "${slug}": must be lowercase alphanumeric with hyphens (e.g. get-master)`
935
+ );
936
+ process.exit(1);
937
+ }
938
+ }
908
939
  async function seedTenantCommand(options) {
940
+ validateSlug(options.slug, "tenant");
909
941
  const projectDir = getProjectDir();
910
942
  const config = loadConfig(projectDir);
911
943
  const env = loadEnv2(projectDir);
@@ -931,6 +963,7 @@ async function seedTenantCommand(options) {
931
963
  printSdkConfig(config.platform, env, { tenant: result.slug });
932
964
  }
933
965
  async function seedAppCommand(options) {
966
+ validateSlug(options.slug, "app");
934
967
  const projectDir = getProjectDir();
935
968
  const config = loadConfig(projectDir);
936
969
  const env = loadEnv2(projectDir);
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/logger.ts","../src/constants.ts","../src/utils/config.ts","../src/utils/docker.ts","../src/commands/init.ts","../src/commands/up.ts","../src/commands/down.ts","../src/commands/status.ts","../src/commands/logs.ts","../src/commands/restart.ts","../src/commands/doctor.ts","../src/commands/destroy.ts","../src/commands/seed.ts","../src/bin.ts"],"names":["chalk","path","fs","execaCommand","ora","execa","createInterface","loadEnv","program","readFileSync","Command"],"mappings":"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","file":"bin.js","sourcesContent":["import chalk from 'chalk';\n\nconst prefix = chalk.cyan('[habeetat]');\n\nexport const logger = {\n info: (msg: string) => console.log(`${prefix} ${msg}`),\n success: (msg: string) => console.log(`${prefix} ${chalk.green('✓')} ${msg}`),\n warn: (msg: string) => console.log(`${prefix} ${chalk.yellow('⚠')} ${msg}`),\n error: (msg: string) => console.error(`${prefix} ${chalk.red('✗')} ${msg}`),\n phase: (msg: string) => {\n console.log('');\n console.log(chalk.cyan('═'.repeat(56)));\n console.log(chalk.cyan(` ${msg}`));\n console.log(chalk.cyan('═'.repeat(56)));\n console.log('');\n },\n banner: () => {\n console.log('');\n console.log(chalk.cyan('╔══════════════════════════════════════════════╗'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('║ Habeetat Platform CLI ║'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('╚══════════════════════════════════════════════╝'));\n console.log('');\n },\n};\n","export const CONFIG_FILE = 'habeetat.json';\nexport const ENV_FILE = '.env';\nexport const COMPOSE_FILE = 'docker-compose.yml';\n\nexport const DOCKER_REGISTRY = 'docker.io/capriisland';\n\nexport const IMAGES = {\n backend: 'capriisland/habeetat-backend',\n launcher: 'capriisland/habeetat-launcher',\n orgManager: 'capriisland/habeetat-org-manager',\n platformManager: 'capriisland/habeetat-platform-manager',\n sampleCrm: 'capriisland/habeetat-sample-crm',\n logtoConfig: 'capriisland/habeetat-logto-config',\n} as const;\n\nexport const THIRD_PARTY_IMAGES = {\n postgres: 'postgres:15-alpine',\n logto: 'svhd/logto:1.33',\n nginx: 'nginx:1.25-alpine',\n certbot: 'certbot/certbot',\n} as const;\n\nexport const DEFAULT_PORTS = {\n http: 80,\n https: 443,\n hostNginx: 8080,\n} as const;\n\nexport const SERVICES = [\n 'logto-db',\n 'platform-db',\n 'logto-core',\n 'backend',\n 'launcher',\n 'organization-manager',\n 'platform-manager',\n 'sample-crm',\n 'nginx',\n] as const;\n\nexport type ServiceName = (typeof SERVICES)[number];\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_FILE } from '../constants.js';\nimport type { HabeetatConfig } from '../types.js';\n\nexport function findProjectRoot(startDir: string = process.cwd()): string | null {\n let dir = startDir;\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, CONFIG_FILE))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n return null;\n}\n\nexport function loadConfig(projectDir?: string): HabeetatConfig {\n const dir = projectDir || findProjectRoot();\n if (!dir) {\n throw new Error(\n `Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`,\n );\n }\n const configPath = path.join(dir, CONFIG_FILE);\n const raw = fs.readFileSync(configPath, 'utf-8');\n return JSON.parse(raw) as HabeetatConfig;\n}\n\nexport function saveConfig(config: HabeetatConfig, projectDir: string): void {\n const configPath = path.join(projectDir, CONFIG_FILE);\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function getProjectDir(): string {\n const dir = findProjectRoot();\n if (!dir) {\n throw new Error(\n `Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`,\n );\n }\n return dir;\n}\n","import { execaCommand } from 'execa';\nimport { logger } from './logger.js';\n\nexport async function checkDocker(): Promise<boolean> {\n try {\n const { stdout } = await execaCommand('docker --version');\n const match = stdout.match(/Docker version (\\d+)/);\n if (match && parseInt(match[1], 10) >= 20) {\n return true;\n }\n logger.error(`Docker >= 20.0 required. Found: ${stdout.trim()}`);\n return false;\n } catch {\n logger.error('Docker is not installed or not in PATH');\n logger.info('Install Docker: https://docs.docker.com/get-docker/');\n return false;\n }\n}\n\nexport async function checkDockerCompose(): Promise<boolean> {\n try {\n await execaCommand('docker compose version');\n return true;\n } catch {\n logger.error('Docker Compose V2 is not available');\n logger.info('Docker Compose V2 is included with Docker Desktop');\n return false;\n }\n}\n\nexport async function checkPrerequisites(): Promise<boolean> {\n const docker = await checkDocker();\n const compose = await checkDockerCompose();\n return docker && compose;\n}\n\nexport interface ComposeExecOptions {\n cwd: string;\n composeFile?: string;\n silent?: boolean;\n}\n\nexport async function composeUp(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} up -d`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeDown(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} down`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeDestroy(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} down -v --remove-orphans`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composePs(opts: ComposeExecOptions): Promise<string> {\n const file = opts.composeFile || 'docker-compose.yml';\n const { stdout } = await execaCommand(`docker compose -f ${file} ps`, {\n cwd: opts.cwd,\n });\n return stdout;\n}\n\nexport async function composeLogs(\n opts: ComposeExecOptions & { service?: string; follow?: boolean; tail?: number },\n): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n const parts = ['docker', 'compose', '-f', file, 'logs'];\n if (opts.follow) parts.push('-f');\n if (opts.tail) parts.push('--tail', String(opts.tail));\n if (opts.service) parts.push(opts.service);\n\n await execaCommand(parts.join(' '), {\n cwd: opts.cwd,\n stdio: 'inherit',\n });\n}\n\nexport async function composeRestart(\n opts: ComposeExecOptions & { service?: string },\n): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n const cmd = opts.service\n ? `docker compose -f ${file} restart ${opts.service}`\n : `docker compose -f ${file} restart`;\n\n await execaCommand(cmd, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeExec(\n opts: ComposeExecOptions & { service: string; command: string },\n): Promise<string> {\n const file = opts.composeFile || 'docker-compose.yml';\n const { stdout } = await execaCommand(\n `docker compose -f ${file} exec -T ${opts.service} ${opts.command}`,\n { cwd: opts.cwd },\n );\n return stdout;\n}\n\nexport async function dockerPull(image: string): Promise<void> {\n await execaCommand(`docker pull ${image}`, { stdio: 'inherit' });\n}\n","import ora from 'ora';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { execa, execaCommand } from 'execa';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { COMPOSE_FILE } from '../constants.js';\n\nconst INITIALIZED_FILE = '.initialized';\n\nexport function isInitialized(projectDir: string): boolean {\n return fs.existsSync(path.join(projectDir, INITIALIZED_FILE));\n}\n\nfunction markInitialized(projectDir: string): void {\n fs.writeFileSync(\n path.join(projectDir, INITIALIZED_FILE),\n JSON.stringify({ initializedAt: new Date().toISOString() }, null, 2) + '\\n',\n );\n}\n\nfunction loadEnv(projectDir: string): Record<string, string> {\n const envPath = path.join(projectDir, '.env');\n if (!fs.existsSync(envPath)) return {};\n const lines = fs.readFileSync(envPath, 'utf-8').split('\\n');\n const env: Record<string, string> = {};\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIdx = trimmed.indexOf('=');\n if (eqIdx === -1) continue;\n env[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);\n }\n return env;\n}\n\nasync function execCompose(projectDir: string, args: string): Promise<string> {\n const { stdout } = await execaCommand(\n `docker compose -f ${COMPOSE_FILE} ${args}`,\n { cwd: projectDir },\n );\n return stdout;\n}\n\nasync function waitForService(\n projectDir: string,\n service: string,\n checkCmd: string,\n timeoutSec: number,\n): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutSec * 1000) {\n try {\n await execCompose(projectDir, `exec -T ${service} ${checkCmd}`);\n return true;\n } catch {\n await new Promise((r) => setTimeout(r, 3000));\n }\n }\n return false;\n}\n\nasync function getContainerState(\n projectDir: string,\n service: string,\n): Promise<{ state: string; health: string } | null> {\n try {\n const { stdout } = await execaCommand(\n `docker compose -f ${COMPOSE_FILE} ps ${service} --format json`,\n { cwd: projectDir },\n );\n const lines = stdout.trim().split('\\n');\n for (const line of lines) {\n try {\n const info = JSON.parse(line);\n return { state: info.State || '', health: info.Health || '' };\n } catch { /* skip non-json lines */ }\n }\n } catch { /* container may not exist yet */ }\n return null;\n}\n\nasync function waitForDockerRunning(\n projectDir: string,\n service: string,\n timeoutSec: number,\n): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutSec * 1000) {\n const info = await getContainerState(projectDir, service);\n if (info && info.state === 'running') return true;\n await new Promise((r) => setTimeout(r, 3000));\n }\n return false;\n}\n\nasync function waitForDockerHealthy(\n projectDir: string,\n service: string,\n timeoutSec: number,\n): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutSec * 1000) {\n const info = await getContainerState(projectDir, service);\n if (info) {\n if (info.health === 'healthy') return true;\n if (info.state === 'running' && !info.health) return true;\n }\n await new Promise((r) => setTimeout(r, 5000));\n }\n return false;\n}\n\nfunction buildSeedLogtoAppsSql(env: Record<string, string>): string {\n const protocol = env.PROTOCOL || 'https';\n const domain = env.DOMAIN || 'localhost';\n const launcherUrl = env.LAUNCHER_URL || `${protocol}://launcher.${domain}`;\n const orgManagerUrl = env.ORG_MANAGER_URL || `${protocol}://organization-manager.${domain}`;\n const platformManagerUrl = env.PLATFORM_MANAGER_URL || `${protocol}://platform-manager.${domain}`;\n const sampleCrmUrl = env.SAMPLE_CRM_URL || `${protocol}://sample-crm.${domain}`;\n const apiResource = env.IAM_AUDIENCE || `${protocol}://api.${domain}/api`;\n const m2mAppId = 'nhp-m2m-config';\n const m2mAppSecret = env.LOGTO_M2M_APP_SECRET || '';\n\n return `BEGIN;\n\n-- API Resource\nINSERT INTO resources (tenant_id, id, name, indicator, is_default, access_token_ttl)\nVALUES ('default', 'nhp-backend-resource', 'NHP Backend API', '${apiResource}', false, 3600)\nON CONFLICT (id) DO UPDATE\nSET name = EXCLUDED.name, indicator = EXCLUDED.indicator, access_token_ttl = EXCLUDED.access_token_ttl;\n\n-- Scope for API Resource\nINSERT INTO scopes (tenant_id, id, resource_id, name, description)\nVALUES ('default', 'nhp-backend-scope', 'nhp-backend-resource', 'nhp:all', 'Full access to NHP backend API')\nON CONFLICT (id) DO UPDATE\nSET resource_id = EXCLUDED.resource_id, name = EXCLUDED.name, description = EXCLUDED.description;\n\n-- Launcher SPA\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', 'nhp-launcher', 'Habeetat Launcher', 'spa-secret-nhp-launcher', 'Main launcher application', 'SPA',\n jsonb_build_object('redirectUris', ARRAY['${launcherUrl}', '${launcherUrl}/callback'], 'postLogoutRedirectUris', ARRAY['${launcherUrl}']),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, type = EXCLUDED.type, oidc_client_metadata = EXCLUDED.oidc_client_metadata;\n\n-- Organization Manager SPA\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', 'nhp-org-manager', 'Organization Manager', 'spa-secret-nhp-org-manager', 'Organization management application', 'SPA',\n jsonb_build_object('redirectUris', ARRAY['${orgManagerUrl}', '${orgManagerUrl}/callback'], 'postLogoutRedirectUris', ARRAY['${orgManagerUrl}']),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, type = EXCLUDED.type, oidc_client_metadata = EXCLUDED.oidc_client_metadata;\n\n-- Platform Manager SPA\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', 'nhp-plat-mgr', 'Platform Manager', 'spa-secret-nhp-plat-mgr', 'Platform administration application', 'SPA',\n jsonb_build_object('redirectUris', ARRAY['${platformManagerUrl}', '${platformManagerUrl}/callback'], 'postLogoutRedirectUris', ARRAY['${platformManagerUrl}']),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, type = EXCLUDED.type, oidc_client_metadata = EXCLUDED.oidc_client_metadata;\n\n-- Sample CRM SPA\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', 'nhp-sample-crm', 'Sample CRM', 'spa-secret-nhp-sample-crm', 'Sample CRM application', 'SPA',\n jsonb_build_object('redirectUris', ARRAY['${sampleCrmUrl}', '${sampleCrmUrl}/callback'], 'postLogoutRedirectUris', ARRAY['${sampleCrmUrl}']),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, type = EXCLUDED.type, oidc_client_metadata = EXCLUDED.oidc_client_metadata;\n\n-- M2M Application for backend\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', '${m2mAppId}', 'NHP M2M Config', '${m2mAppSecret}', 'Machine-to-machine application for backend services', 'MachineToMachine',\n jsonb_build_object('redirectUris', ARRAY[]::text[], 'postLogoutRedirectUris', ARRAY[]::text[]),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, secret = EXCLUDED.secret, description = EXCLUDED.description, type = EXCLUDED.type;\n\n-- Assign Management API role to M2M app\nDO $$\nDECLARE\n v_role_id TEXT;\nBEGIN\n SELECT id INTO v_role_id FROM roles\n WHERE tenant_id = 'default' AND name = 'Logto Management API access' AND type = 'MachineToMachine'\n LIMIT 1;\n\n IF v_role_id IS NULL THEN\n v_role_id := 'role_m2m_mgmt_api';\n INSERT INTO roles (tenant_id, id, name, description, type)\n VALUES ('default', v_role_id, 'Logto Management API access', 'Access to Logto Management API', 'MachineToMachine');\n\n INSERT INTO roles_scopes (tenant_id, id, role_id, scope_id)\n SELECT 'default', 'rs_' || s.id, v_role_id, s.id\n FROM scopes s WHERE s.resource_id = 'management-api' AND s.tenant_id = 'default'\n ON CONFLICT DO NOTHING;\n END IF;\n\n INSERT INTO applications_roles (tenant_id, id, application_id, role_id)\n VALUES ('default', 'ar_m2m_${m2mAppId}', '${m2mAppId}', v_role_id)\n ON CONFLICT DO NOTHING;\nEND $$;\n\n-- Update admin-console redirect URIs\nUPDATE applications\nSET oidc_client_metadata = jsonb_build_object(\n 'redirectUris', ARRAY['${protocol}://iam-console.${domain}/callback'],\n 'postLogoutRedirectUris', ARRAY['${protocol}://iam-console.${domain}']\n)\nWHERE id = 'admin-console' AND tenant_id = 'admin';\n\nCOMMIT;`;\n}\n\nfunction buildInitPlatformSql(env: Record<string, string>): string {\n const protocol = env.PROTOCOL || 'https';\n const domain = env.DOMAIN || 'localhost';\n const adminEmail = env.PLATFORM_ADMIN_EMAIL || 'admin@habeetat.local';\n const orgName = env.ORGANIZATION_NAME || 'Default Organization';\n const orgSlug = orgName.toLowerCase().replace(/\\s+/g, '-').replace(/[^a-z0-9-]/g, '');\n\n return `\n-- Seed system applications\nINSERT INTO applications (id, slug, name, description, category, is_internal, is_system_app, is_hidden, auto_install, status, logto_app_id, created_at, updated_at)\nVALUES\n ('app_launcher', 'launcher', 'Habeetat Launcher', 'Main launcher and navigation hub', 'system', true, true, true, true, 'PUBLISHED', 'nhp-launcher', NOW(), NOW()),\n ('app_org_manager', 'organization-manager', 'Organization Manager', 'Manage organizations, users and roles', 'system', true, true, false, true, 'PUBLISHED', 'nhp-org-manager', NOW(), NOW()),\n ('app_plat_manager', 'platform-manager', 'Platform Manager', 'Platform administration and configuration', 'system', true, true, true, false, 'PUBLISHED', 'nhp-plat-mgr', NOW(), NOW()),\n ('app_sample_crm', 'sample-crm', 'Sample CRM', 'Sample CRM application for demonstration', 'demo', true, false, false, false, 'PUBLISHED', 'nhp-sample-crm', NOW(), NOW())\nON CONFLICT (slug) DO UPDATE SET\n name = EXCLUDED.name,\n description = EXCLUDED.description,\n logto_app_id = EXCLUDED.logto_app_id,\n is_system_app = EXCLUDED.is_system_app,\n is_hidden = EXCLUDED.is_hidden,\n auto_install = EXCLUDED.auto_install,\n status = EXCLUDED.status;\n\n-- Create initial versions for system apps\nINSERT INTO application_versions (id, app_id, version, manifest, status, created_at)\nVALUES\n ('ver_launcher_100', 'app_launcher', '1.0.0', jsonb_build_object('endpoints', jsonb_build_object('main', '${protocol}://launcher.${domain}')), 'ACTIVE', NOW()),\n ('ver_org_manager_100', 'app_org_manager', '1.0.0', jsonb_build_object('endpoints', jsonb_build_object('main', '${protocol}://organization-manager.${domain}')), 'ACTIVE', NOW()),\n ('ver_plat_manager_100', 'app_plat_manager', '1.0.0', jsonb_build_object('endpoints', jsonb_build_object('main', '${protocol}://platform-manager.${domain}')), 'ACTIVE', NOW()),\n ('ver_sample_crm_100', 'app_sample_crm', '1.0.0', jsonb_build_object('endpoints', jsonb_build_object('main', '${protocol}://sample-crm.${domain}')), 'ACTIVE', NOW())\nON CONFLICT (app_id, version) DO UPDATE SET manifest = EXCLUDED.manifest;\n\n-- Create default tenant\nINSERT INTO tenants (id, display_name, slug, status, created_at, updated_at)\nSELECT\n 'tenant_${orgSlug}',\n '${orgName}',\n '${orgSlug}',\n 'ACTIVE',\n NOW(),\n NOW()\nWHERE NOT EXISTS (\n SELECT 1 FROM tenants WHERE slug = '${orgSlug}'\n);\n\n-- Initialize tenant, admin user, roles, memberships, and app installations\nDO $$\nDECLARE\n v_tenant_id TEXT;\n v_user_id TEXT;\n v_admin_role_id TEXT;\nBEGIN\n SELECT id INTO v_tenant_id FROM tenants WHERE slug = '${orgSlug}' LIMIT 1;\n\n IF v_tenant_id IS NULL THEN\n RAISE NOTICE 'Tenant not found, skipping user setup';\n RETURN;\n END IF;\n\n SELECT id INTO v_user_id FROM users\n WHERE external_identity_id = 'usr_admin01'\n OR primary_email = '${adminEmail}'\n LIMIT 1;\n\n IF v_user_id IS NULL THEN\n v_user_id := 'usr_plat_admin01';\n INSERT INTO users (id, external_identity_id, primary_email, username, display_name, status, created_at, updated_at)\n VALUES (v_user_id, 'usr_admin01', '${adminEmail}', 'admin', 'Platform Admin', 'ACTIVE', NOW(), NOW());\n ELSE\n UPDATE users SET external_identity_id = 'usr_admin01'\n WHERE id = v_user_id AND external_identity_id IS NULL;\n END IF;\n\n SELECT id INTO v_admin_role_id FROM tenant_roles WHERE name = 'TENANT_ADMIN' LIMIT 1;\n\n IF v_admin_role_id IS NULL THEN\n v_admin_role_id := 'role_tenant_admin';\n INSERT INTO tenant_roles (id, name, description, created_at, updated_at)\n VALUES (v_admin_role_id, 'TENANT_ADMIN', 'Tenant Administrator', NOW(), NOW());\n END IF;\n\n INSERT INTO tenant_memberships (id, user_id, tenant_id, status, created_at, updated_at)\n SELECT 'tm_admin_${orgSlug}', v_user_id, v_tenant_id, 'ACTIVE', NOW(), NOW()\n WHERE NOT EXISTS (\n SELECT 1 FROM tenant_memberships WHERE user_id = v_user_id AND tenant_id = v_tenant_id\n );\n\n INSERT INTO tenant_membership_roles (id, membership_id, role_id, created_at)\n SELECT 'tmr_admin_${orgSlug}', 'tm_admin_${orgSlug}', v_admin_role_id, NOW()\n WHERE NOT EXISTS (\n SELECT 1 FROM tenant_membership_roles\n WHERE membership_id = 'tm_admin_${orgSlug}' AND role_id = v_admin_role_id\n );\nEND $$;\n\n-- Auto-install published non-hidden apps for the default tenant\nINSERT INTO tenant_application_installations (id, tenant_id, app_id, app_version_id, status, is_enabled, installed_at, updated_at)\nSELECT 'tai_${orgSlug}_' || a.slug, t.id, a.id, v.id, 'INSTALLED', true, NOW(), NOW()\nFROM tenants t\nJOIN applications a ON a.status = 'PUBLISHED' AND a.is_hidden = false\nJOIN application_versions v ON v.app_id = a.id AND v.version = '1.0.0'\nWHERE t.slug = '${orgSlug}'\nON CONFLICT (tenant_id, app_id) DO NOTHING;`;\n}\n\nexport async function initPlatform(projectDir: string): Promise<void> {\n const config = loadConfig(projectDir);\n const env = loadEnv(projectDir);\n const domain = config.platform.domain;\n\n // --- Phase 1: Wait for databases ---\n const dbSpinner = ora('Waiting for databases...').start();\n\n const logtoDbReady = await waitForService(\n projectDir, 'logto-db', 'pg_isready -U logto -d logto', 60,\n );\n if (!logtoDbReady) {\n dbSpinner.fail('logto-db did not become ready');\n throw new Error('logto-db timeout');\n }\n\n const platformDbReady = await waitForService(\n projectDir, 'platform-db',\n `pg_isready -U ${env.PLATFORM_DB_USER || 'habeetat'} -d ${env.PLATFORM_DB_NAME || 'habeetat_platform'}`,\n 60,\n );\n if (!platformDbReady) {\n dbSpinner.fail('platform-db did not become ready');\n throw new Error('platform-db timeout');\n }\n dbSpinner.succeed('Databases ready');\n\n // --- Phase 2: Wait for Logto to be healthy ---\n const logtoSpinner = ora('Waiting for Logto to be healthy (this may take up to 2 min)...').start();\n const logtoReady = await waitForService(\n projectDir, 'logto-core',\n 'wget -q --spider http://localhost:3001/oidc/.well-known/openid-configuration',\n 180,\n );\n if (!logtoReady) {\n logtoSpinner.fail('logto-core did not become healthy');\n throw new Error('logto-core timeout');\n }\n logtoSpinner.succeed('Logto is healthy');\n\n // --- Phase 3: Seed Logto applications (SQL) ---\n const logtoSeedSpinner = ora('Seeding Logto applications...').start();\n try {\n const sql = buildSeedLogtoAppsSql(env);\n await execaCommand(\n `docker compose -f ${COMPOSE_FILE} exec -T logto-db psql -U logto -d logto`,\n { cwd: projectDir, input: sql },\n );\n logtoSeedSpinner.succeed('Logto applications seeded');\n } catch (err) {\n logtoSeedSpinner.fail('Failed to seed Logto applications');\n logger.error(String(err));\n throw err;\n }\n\n // --- Phase 4: Bootstrap Logto users/orgs/roles (via Node container) ---\n const bootstrapSpinner = ora('Bootstrapping Logto users and organizations...').start();\n try {\n const orgName = env.ORGANIZATION_NAME || config.platform.organization || 'Default';\n const orgSlug = orgName.toLowerCase().replace(/\\s+/g, '-').replace(/[^a-z0-9-]/g, '');\n const adminEmail = env.PLATFORM_ADMIN_EMAIL || config.platform.adminEmail;\n const adminPassword = env.PLATFORM_ADMIN_PASSWORD || 'Habeetat_01';\n const adminUsername = adminEmail.split('@')[0];\n const logtoDbUrl = `postgres://${env.LOGTO_DB_USER || 'logto'}:${env.LOGTO_DB_PASSWORD || 'logto'}@logto-db:5432/${env.LOGTO_DB_NAME || 'logto'}`;\n\n const bootstrapScriptPath = path.join(projectDir, 'scripts', 'nhp-seed-logto-bootstrap.mjs');\n const hasLocalScript = fs.existsSync(bootstrapScriptPath);\n\n if (hasLocalScript) {\n await execa('docker', [\n 'run', '--rm', '--network', 'habeetat_habeetat-network',\n '-e', `NHP_LOGTO_DB_URL=${logtoDbUrl}`,\n '-e', `NHP_PLATFORM_ADMIN_USERNAME=${adminUsername}`,\n '-e', `NHP_PLATFORM_ADMIN_EMAIL=${adminEmail}`,\n '-e', `NHP_PLATFORM_ADMIN_PASSWORD=${adminPassword}`,\n '-e', `NHP_PLATFORM_ADMIN_DISPLAY_NAME=Platform Admin`,\n '-e', `NHP_DEFAULT_TENANT_NAME=${orgName}`,\n '-e', `NHP_DEFAULT_TENANT_SLUG=${orgSlug}`,\n '-v', `${bootstrapScriptPath}:/app/bootstrap.mjs:ro`,\n '-w', '/app',\n 'node:20-alpine',\n 'sh', '-c', 'npm init -y >/dev/null 2>&1 && npm install --no-package-lock pg hash-wasm nanoid 2>/dev/null && node bootstrap.mjs',\n ],\n { cwd: projectDir, stdio: 'pipe' },\n );\n bootstrapSpinner.succeed('Logto users and organizations bootstrapped');\n } else {\n bootstrapSpinner.warn('Bootstrap script not found — skipping Logto user/org setup');\n logger.info('You may need to create the admin user manually via the Logto admin console');\n }\n } catch (err) {\n bootstrapSpinner.fail('Logto bootstrap failed');\n logger.error(String(err));\n logger.info('You may need to create the admin user manually via the Logto admin console');\n }\n\n // --- Phase 5: Wait for backend container to be running ---\n const backendRunSpinner = ora('Waiting for backend container to start...').start();\n const backendRunning = await waitForDockerRunning(projectDir, 'backend', 90);\n if (!backendRunning) {\n backendRunSpinner.fail('Backend container did not start');\n throw new Error('backend container timeout');\n }\n backendRunSpinner.succeed('Backend container is running');\n\n // --- Phase 6: Run Prisma migrations (before health check — tables must exist first) ---\n const migrateSpinner = ora('Running database migrations...').start();\n try {\n await execCompose(projectDir, 'exec -T backend npx prisma migrate deploy');\n migrateSpinner.succeed('Database migrations completed');\n } catch (err) {\n migrateSpinner.fail('Migrations failed');\n logger.error(String(err));\n logger.info('Run manually: docker compose exec backend npx prisma migrate deploy');\n }\n\n // --- Phase 7: Run Prisma seed ---\n const seedSpinner = ora('Seeding platform database...').start();\n try {\n const orgName = env.ORGANIZATION_NAME || config.platform.organization || 'Default';\n const orgSlug = orgName.toLowerCase().replace(/\\s+/g, '-').replace(/[^a-z0-9-]/g, '');\n const adminEmail = env.PLATFORM_ADMIN_EMAIL || config.platform.adminEmail;\n\n await execa('docker', [\n 'compose', '-f', COMPOSE_FILE, 'exec', '-T',\n '-e', `NHP_PLATFORM_ADMIN_USER=${adminEmail.split('@')[0]}`,\n '-e', `NHP_PLATFORM_ADMIN_EMAIL=${adminEmail}`,\n '-e', `NHP_PLATFORM_ADMIN_DISPLAY_NAME=Platform Admin`,\n '-e', `NHP_DEFAULT_TENANT_NAME=${orgName}`,\n '-e', `NHP_DEFAULT_TENANT_SLUG=${orgSlug}`,\n 'backend', 'npx', 'tsx', 'prisma/seed.ts',\n ], { cwd: projectDir, stdio: 'pipe' });\n seedSpinner.succeed('Platform database seeded');\n } catch {\n seedSpinner.warn('Prisma seed skipped (may not be available in Docker image)');\n }\n\n // --- Phase 8: Wait for backend to become healthy (tables now exist) ---\n const backendSpinner = ora('Waiting for backend to be healthy...').start();\n const backendReady = await waitForDockerHealthy(\n projectDir, 'backend', 180,\n );\n if (!backendReady) {\n backendSpinner.fail('Backend did not become healthy');\n logger.info('Check logs: docker compose logs backend');\n } else {\n backendSpinner.succeed('Backend is healthy');\n }\n\n // --- Phase 9: Initialize platform SQL (system apps, tenant, admin) ---\n const platformSpinner = ora('Initializing platform data...').start();\n try {\n const sql = buildInitPlatformSql(env);\n await execaCommand(\n `docker compose -f ${COMPOSE_FILE} exec -T platform-db psql -U ${env.PLATFORM_DB_USER || 'habeetat'} -d ${env.PLATFORM_DB_NAME || 'habeetat_platform'}`,\n { cwd: projectDir, input: sql },\n );\n platformSpinner.succeed('Platform data initialized');\n } catch (err) {\n platformSpinner.fail('Platform initialization failed');\n logger.error(String(err));\n logger.info('You may need to initialize the platform manually after first login');\n }\n\n // Mark as initialized\n markInitialized(projectDir);\n\n console.log('');\n logger.info(`✓ Platform initialized for ${domain}`);\n logger.info(` Admin: ${env.PLATFORM_ADMIN_EMAIL || config.platform.adminEmail}`);\n logger.info(` Organization: ${env.ORGANIZATION_NAME || config.platform.organization}`);\n}\n","import ora from 'ora';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { composeUp, checkPrerequisites } from '../utils/docker.js';\nimport { isInitialized, initPlatform } from './init.js';\n\nexport async function upCommand(): Promise<void> {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n\n logger.info(`Starting Habeetat Platform (${config.platform.domain})...`);\n\n if (!(await checkPrerequisites())) {\n process.exit(1);\n }\n\n const freshInstall = !isInitialized(projectDir);\n const spinner = ora('Starting services...').start();\n\n try {\n await composeUp({ cwd: projectDir });\n spinner.succeed('All services started');\n } catch (err) {\n spinner.fail('Failed to start services');\n logger.error(String(err));\n process.exit(1);\n }\n\n if (freshInstall) {\n console.log('');\n logger.info('First run detected — initializing platform...');\n console.log('');\n try {\n await initPlatform(projectDir);\n } catch (err) {\n logger.error('Platform initialization failed');\n logger.error(String(err));\n logger.info('You can retry with: npx habeetat init');\n process.exit(1);\n }\n }\n\n const proto = config.platform.protocol;\n const domain = config.platform.domain;\n\n console.log('');\n logger.info('Platform URLs:');\n console.log(` Launcher: ${proto}://launcher.${domain}`);\n console.log(` Organization Manager: ${proto}://organization-manager.${domain}`);\n console.log(` Platform Manager: ${proto}://platform-manager.${domain}`);\n console.log(` Backend API: ${proto}://api.${domain}`);\n console.log(` Logto IAM: ${proto}://iam.${domain}`);\n console.log(` Logto Admin Console: ${proto}://iam-console.${domain}`);\n console.log('');\n logger.info('Run `habeetat status` to check service health');\n}\n","import ora from 'ora';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir } from '../utils/config.js';\nimport { composeDown } from '../utils/docker.js';\n\nexport async function downCommand(): Promise<void> {\n const projectDir = getProjectDir();\n const spinner = ora('Stopping services...').start();\n\n try {\n await composeDown({ cwd: projectDir });\n spinner.succeed('All services stopped');\n } catch (err) {\n spinner.fail('Failed to stop services');\n logger.error(String(err));\n process.exit(1);\n }\n}\n","import { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { composePs } from '../utils/docker.js';\n\nexport async function statusCommand(): Promise<void> {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n\n logger.info(`Habeetat Platform — ${config.platform.domain}`);\n logger.info(`Version: ${config.version}`);\n logger.info(`Image tag: ${config.docker.imageTag}`);\n console.log('');\n\n try {\n const output = await composePs({ cwd: projectDir });\n console.log(output);\n } catch (err) {\n logger.error('Could not get service status. Is the platform running?');\n logger.info('Run `habeetat up` to start the platform');\n process.exit(1);\n }\n}\n","import { logger } from '../utils/logger.js';\nimport { getProjectDir } from '../utils/config.js';\nimport { composeLogs } from '../utils/docker.js';\nimport { SERVICES } from '../constants.js';\n\nexport async function logsCommand(\n service?: string,\n options?: { follow?: boolean; tail?: number },\n): Promise<void> {\n const projectDir = getProjectDir();\n\n if (service && !(SERVICES as readonly string[]).includes(service)) {\n logger.error(`Unknown service: ${service}`);\n logger.info(`Available services: ${SERVICES.join(', ')}`);\n process.exit(1);\n }\n\n try {\n await composeLogs({\n cwd: projectDir,\n service,\n follow: options?.follow,\n tail: options?.tail,\n });\n } catch {\n // User interrupted with Ctrl+C — that's fine\n }\n}\n","import ora from 'ora';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir } from '../utils/config.js';\nimport { composeRestart } from '../utils/docker.js';\nimport { SERVICES } from '../constants.js';\n\nexport async function restartCommand(service?: string): Promise<void> {\n const projectDir = getProjectDir();\n\n if (service && !(SERVICES as readonly string[]).includes(service)) {\n logger.error(`Unknown service: ${service}`);\n logger.info(`Available services: ${SERVICES.join(', ')}`);\n process.exit(1);\n }\n\n const label = service || 'all services';\n const spinner = ora(`Restarting ${label}...`).start();\n\n try {\n await composeRestart({ cwd: projectDir, service });\n spinner.succeed(`Restarted ${label}`);\n } catch (err) {\n spinner.fail(`Failed to restart ${label}`);\n logger.error(String(err));\n process.exit(1);\n }\n}\n","import chalk from 'chalk';\nimport { logger } from '../utils/logger.js';\nimport { checkDocker, checkDockerCompose } from '../utils/docker.js';\nimport { findProjectRoot, loadConfig } from '../utils/config.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_FILE, COMPOSE_FILE, ENV_FILE } from '../constants.js';\n\nexport async function doctorCommand(): Promise<void> {\n logger.phase('Habeetat Doctor — Diagnostics');\n let issues = 0;\n\n // Check Docker\n const dockerOk = await checkDocker();\n console.log(` Docker: ${dockerOk ? chalk.green('✓ Installed') : chalk.red('✗ Not found')}`);\n if (!dockerOk) issues++;\n\n // Check Docker Compose\n const composeOk = await checkDockerCompose();\n console.log(` Docker Compose: ${composeOk ? chalk.green('✓ Available') : chalk.red('✗ Not found')}`);\n if (!composeOk) issues++;\n\n // Check project directory\n const projectDir = findProjectRoot();\n console.log(` Project dir: ${projectDir ? chalk.green(`✓ ${projectDir}`) : chalk.yellow('⚠ Not in a Habeetat project')}`);\n if (!projectDir) {\n issues++;\n console.log('');\n logger.info(`Run \\`npm create habeetat my-platform\\` to create a new project`);\n return;\n }\n\n // Check config file\n const configExists = fs.existsSync(path.join(projectDir, CONFIG_FILE));\n console.log(` ${CONFIG_FILE}: ${configExists ? chalk.green('✓ Found') : chalk.red('✗ Missing')}`);\n if (!configExists) issues++;\n\n // Check compose file\n const composeExists = fs.existsSync(path.join(projectDir, COMPOSE_FILE));\n console.log(` ${COMPOSE_FILE}: ${composeExists ? chalk.green('✓ Found') : chalk.red('✗ Missing')}`);\n if (!composeExists) issues++;\n\n // Check env file\n const envExists = fs.existsSync(path.join(projectDir, ENV_FILE));\n console.log(` ${ENV_FILE}: ${envExists ? chalk.green('✓ Found') : chalk.red('✗ Missing')}`);\n if (!envExists) issues++;\n\n // Check nginx config\n const nginxExists = fs.existsSync(path.join(projectDir, 'nginx', 'platform.conf'));\n console.log(` nginx/platform.conf: ${nginxExists ? chalk.green('✓ Found') : chalk.red('✗ Missing')}`);\n if (!nginxExists) issues++;\n\n // Load config and check images\n if (configExists) {\n try {\n const config = loadConfig(projectDir);\n console.log(` Version: ${chalk.cyan(config.version)}`);\n console.log(` Domain: ${chalk.cyan(config.platform.domain)}`);\n console.log(` Protocol: ${chalk.cyan(config.platform.protocol)}`);\n } catch (err) {\n console.log(` Config: ${chalk.red('✗ Invalid JSON')}`);\n issues++;\n }\n }\n\n console.log('');\n if (issues === 0) {\n logger.success('No issues found');\n } else {\n logger.warn(`${issues} issue(s) found`);\n }\n}\n","import ora from 'ora';\nimport { createInterface } from 'node:readline';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { composeDestroy } from '../utils/docker.js';\n\nasync function confirm(message: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${message} (y/N) `, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y');\n });\n });\n}\n\nexport async function destroyCommand(options: { force?: boolean }): Promise<void> {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n const domain = config.platform.domain;\n\n logger.warn(`This will permanently destroy the Habeetat Platform (${domain}):`);\n console.log(' - Stop and remove all containers');\n console.log(' - Delete all Docker volumes (databases, data)');\n console.log(' - Remove orphan containers');\n console.log('');\n\n if (!options.force) {\n const ok = await confirm('Are you sure you want to continue?');\n if (!ok) {\n logger.info('Aborted');\n return;\n }\n }\n\n const spinner = ora('Destroying platform...').start();\n\n try {\n await composeDestroy({ cwd: projectDir });\n spinner.succeed('Platform destroyed — all containers and volumes removed');\n console.log('');\n logger.info('To reinstall, run: npx habeetat up');\n } catch (err) {\n spinner.fail('Failed to destroy platform');\n logger.error(String(err));\n process.exit(1);\n }\n}\n","import ora from 'ora';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport chalk from 'chalk';\nimport { execa } from 'execa';\nimport type { Command } from 'commander';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { COMPOSE_FILE } from '../constants.js';\n\nfunction loadEnv(projectDir: string): Record<string, string> {\n const envPath = path.join(projectDir, '.env');\n if (!fs.existsSync(envPath)) return {};\n const lines = fs.readFileSync(envPath, 'utf-8').split('\\n');\n const env: Record<string, string> = {};\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIdx = trimmed.indexOf('=');\n if (eqIdx === -1) continue;\n env[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);\n }\n return env;\n}\n\nasync function runSeedScript(\n projectDir: string,\n command: string,\n args: string[],\n): Promise<Record<string, unknown>> {\n const { stdout, stderr } = await execa(\n 'docker',\n [\n 'compose',\n '-f',\n COMPOSE_FILE,\n 'exec',\n '-T',\n 'backend',\n 'npx',\n 'tsx',\n 'scripts/nhp-seed-dev.ts',\n command,\n ...args,\n ],\n { cwd: projectDir, stdio: 'pipe' },\n );\n\n // Forward container stderr to our stderr for debugging\n if (stderr) process.stderr.write(stderr + '\\n');\n\n const jsonLine = stdout.trim().split('\\n').pop() ?? '';\n try {\n return JSON.parse(jsonLine) as Record<string, unknown>;\n } catch {\n throw new Error(`Script produced unexpected output: ${stdout}`);\n }\n}\n\nfunction printSdkConfig(\n config: { protocol: string; domain: string },\n env: Record<string, string>,\n parts: { tenant?: string; logtoAppId?: string; email?: string; password?: string },\n) {\n const protocol = config.protocol || 'https';\n const domain = config.domain;\n const iamUrl = env.LOGTO_EXTERNAL_ENDPOINT || `${protocol}://iam.${domain}`;\n const apiUrl = env.IAM_AUDIENCE\n ? env.IAM_AUDIENCE.replace(/\\/api$/, '')\n : `${protocol}://api.${domain}`;\n\n console.log('');\n console.log(chalk.cyan('═'.repeat(56)));\n console.log(chalk.cyan(' SDK Configuration'));\n console.log(chalk.cyan('═'.repeat(56)));\n console.log('');\n\n if (parts.logtoAppId) {\n console.log(chalk.bold(' Frontend SDK (@logto/react + @habeetat/sdk-frontend)'));\n console.log(chalk.dim(' ' + '─'.repeat(50)));\n console.log(` VITE_LOGTO_ENDPOINT=${chalk.green(iamUrl)}`);\n console.log(` VITE_LOGTO_APP_ID=${chalk.green(parts.logtoAppId)}`);\n console.log(` VITE_LOGTO_API_RESOURCE=${chalk.green(env.IAM_AUDIENCE || `${protocol}://api.${domain}/api`)}`);\n if (parts.tenant) {\n console.log(` VITE_APP_TENANT=${chalk.green(parts.tenant)}`);\n }\n console.log('');\n }\n\n if (parts.tenant) {\n console.log(chalk.bold(' Backend SDK (@habeetat/sdk-backend)'));\n console.log(chalk.dim(' ' + '─'.repeat(50)));\n console.log(` HABEETAT_ENDPOINT=${chalk.green(apiUrl)}`);\n console.log(` HABEETAT_TENANT_SLUG=${chalk.green(parts.tenant)}`);\n console.log('');\n }\n\n if (parts.email && parts.password) {\n console.log(chalk.bold(' Test credentials'));\n console.log(chalk.dim(' ' + '─'.repeat(50)));\n console.log(` Email: ${chalk.green(parts.email)}`);\n console.log(` Password: ${chalk.green(parts.password)}`);\n console.log(` IAM: ${chalk.green(iamUrl)}`);\n console.log('');\n }\n\n console.log(chalk.cyan('═'.repeat(56)));\n console.log('');\n}\n\n// ---------------------------------------------------------------------------\n// seed tenant\n// ---------------------------------------------------------------------------\nexport async function seedTenantCommand(options: {\n name: string;\n slug: string;\n description?: string;\n}) {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n const env = loadEnv(projectDir);\n\n const args = [\n '--name', options.name,\n '--slug', options.slug,\n ...(options.description ? ['--description', options.description] : []),\n ];\n\n const spinner = ora(`Creating tenant \"${options.slug}\"...`).start();\n let result: Record<string, unknown>;\n try {\n result = await runSeedScript(projectDir, 'create-tenant', args);\n spinner.succeed(`Tenant created: ${chalk.bold(result.slug)} (${result.displayName})`);\n } catch (err) {\n spinner.fail('Failed to create tenant');\n logger.error(String(err));\n process.exit(1);\n }\n\n logger.info(` ID: ${result.id}`);\n logger.info(` Logto Org ID: ${result.logtoOrganizationId}`);\n\n printSdkConfig(config.platform, env, { tenant: result.slug as string });\n}\n\n// ---------------------------------------------------------------------------\n// seed app\n// ---------------------------------------------------------------------------\nexport async function seedAppCommand(options: {\n name: string;\n slug: string;\n redirectUri?: string[];\n logoutUri?: string[];\n corsOrigin?: string[];\n description?: string;\n tenant?: string;\n}) {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n const env = loadEnv(projectDir);\n\n const args: string[] = [\n '--name', options.name,\n '--slug', options.slug,\n ...(options.description ? ['--description', options.description] : []),\n ...(options.tenant ? ['--tenant', options.tenant] : []),\n ...(options.redirectUri?.flatMap((u) => ['--redirect-uri', u]) ?? []),\n ...(options.logoutUri?.flatMap((u) => ['--logout-uri', u]) ?? []),\n ...(options.corsOrigin?.flatMap((o) => ['--cors-origin', o]) ?? []),\n ];\n\n const spinner = ora(`Creating app \"${options.slug}\"...`).start();\n let result: Record<string, unknown>;\n try {\n result = await runSeedScript(projectDir, 'create-app', args);\n spinner.succeed(`App created: ${chalk.bold(result.slug)} (Logto app: ${result.logtoAppId})`);\n } catch (err) {\n spinner.fail('Failed to create app');\n logger.error(String(err));\n process.exit(1);\n }\n\n logger.info(` ID: ${result.id}`);\n logger.info(` Logto App ID: ${result.logtoAppId}`);\n if (result.redirectUris && (result.redirectUris as string[]).length > 0) {\n logger.info(` Redirect URIs: ${(result.redirectUris as string[]).join(', ')}`);\n }\n if (result.tenantSlug) {\n logger.info(` Installed on: ${result.tenantSlug}`);\n }\n\n printSdkConfig(config.platform, env, {\n tenant: (result.tenantSlug as string) || options.tenant,\n logtoAppId: result.logtoAppId as string,\n });\n}\n\n// ---------------------------------------------------------------------------\n// seed user\n// ---------------------------------------------------------------------------\nexport async function seedUserCommand(options: {\n email: string;\n password: string;\n tenant: string;\n username?: string;\n displayName?: string;\n role?: string;\n}) {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n const env = loadEnv(projectDir);\n\n const args: string[] = [\n '--email', options.email,\n '--password', options.password,\n '--tenant', options.tenant,\n ...(options.username ? ['--username', options.username] : []),\n ...(options.displayName ? ['--display-name', options.displayName] : []),\n ...(options.role ? ['--role', options.role] : []),\n ];\n\n const spinner = ora(`Creating user \"${options.email}\" in tenant \"${options.tenant}\"...`).start();\n let result: Record<string, unknown>;\n try {\n result = await runSeedScript(projectDir, 'create-user', args);\n spinner.succeed(`User created: ${chalk.bold(result.email)} (Logto ID: ${result.logtoUserId})`);\n } catch (err) {\n spinner.fail('Failed to create user');\n logger.error(String(err));\n process.exit(1);\n }\n\n logger.info(` Logto User ID: ${result.logtoUserId}`);\n logger.info(` Username: ${result.username}`);\n logger.info(` Tenant: ${result.tenantSlug}`);\n logger.info(` Role: ${result.role}${result.roleAssigned ? '' : ' (not assigned — role not found in Logto)'}`);\n if (result.note) logger.info(` Note: ${result.note}`);\n\n printSdkConfig(config.platform, env, {\n tenant: result.tenantSlug as string,\n email: result.email as string,\n password: result.password as string,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Command registration\n// ---------------------------------------------------------------------------\nexport function registerSeedCommand(program: Command) {\n const seed = program\n .command('seed')\n .description('Seed dev data — create tenants, apps and users for local development');\n\n seed\n .command('tenant')\n .description('Create a new tenant (Logto org + platform DB)')\n .requiredOption('--name <name>', 'Display name (e.g. \"Acme Corp\")')\n .requiredOption('--slug <slug>', 'Unique slug, lowercase alphanumeric + hyphens (e.g. acme)')\n .option('--description <desc>', 'Optional description')\n .action((opts: { name: string; slug: string; description?: string }) => {\n return seedTenantCommand(opts);\n });\n\n seed\n .command('app')\n .description('Create a new OIDC application (Logto SPA app + platform DB)')\n .requiredOption('--name <name>', 'App display name (e.g. \"My CRM\")')\n .requiredOption('--slug <slug>', 'Unique slug, lowercase alphanumeric + hyphens (e.g. my-crm)')\n .option('--redirect-uri <uri...>', 'OIDC redirect URI(s) (e.g. http://localhost:3000/callback)')\n .option('--logout-uri <uri...>', 'Post-logout redirect URI(s)')\n .option('--cors-origin <origin...>', 'CORS allowed origin(s)')\n .option('--description <desc>', 'Optional description')\n .option('--tenant <slug>', 'Install app on this tenant after creation')\n .action(\n (opts: {\n name: string;\n slug: string;\n redirectUri?: string[];\n logoutUri?: string[];\n corsOrigin?: string[];\n description?: string;\n tenant?: string;\n }) => {\n return seedAppCommand(opts);\n },\n );\n\n seed\n .command('user')\n .description('Create a new user in Logto and add to a tenant organization')\n .requiredOption('--email <email>', 'User email address')\n .requiredOption('--password <password>', 'User password')\n .requiredOption('--tenant <slug>', 'Tenant slug to add the user to')\n .option('--username <username>', 'Logto username (defaults to email prefix)')\n .option('--display-name <name>', 'Display name (defaults to username)')\n .option('--role <role>', 'Organization role to assign (default: TENANT_ADMIN)', 'TENANT_ADMIN')\n .action(\n (opts: {\n email: string;\n password: string;\n tenant: string;\n username?: string;\n displayName?: string;\n role?: string;\n }) => {\n return seedUserCommand(opts);\n },\n );\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport path from 'node:path';\nimport { upCommand } from './commands/up.js';\nimport { downCommand } from './commands/down.js';\nimport { statusCommand } from './commands/status.js';\nimport { logsCommand } from './commands/logs.js';\nimport { restartCommand } from './commands/restart.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { destroyCommand } from './commands/destroy.js';\nimport { initPlatform } from './commands/init.js';\nimport { registerSeedCommand } from './commands/seed.js';\nimport { getProjectDir } from './utils/config.js';\n\nconst pkg = JSON.parse(\n readFileSync(path.resolve(__dirname, '..', 'package.json'), 'utf-8'),\n);\n\nconst program = new Command();\n\nprogram\n .name('habeetat')\n .description('Habeetat Platform CLI — manage your platform instances')\n .version(pkg.version);\n\nprogram\n .command('up')\n .description('Start the platform')\n .action(upCommand);\n\nprogram\n .command('down')\n .description('Stop the platform')\n .action(downCommand);\n\nprogram\n .command('status')\n .description('Show platform service status')\n .action(statusCommand);\n\nprogram\n .command('logs [service]')\n .description('View service logs')\n .option('-f, --follow', 'Follow log output')\n .option('-n, --tail <lines>', 'Number of lines to show', parseInt)\n .action((service: string | undefined, options: { follow?: boolean; tail?: number }) => {\n return logsCommand(service, options);\n });\n\nprogram\n .command('restart [service]')\n .description('Restart services')\n .action(restartCommand);\n\nprogram\n .command('doctor')\n .description('Diagnose common issues')\n .action(doctorCommand);\n\nprogram\n .command('destroy')\n .description('Destroy the platform — remove all containers and volumes')\n .option('-f, --force', 'Skip confirmation prompt')\n .action((options: { force?: boolean }) => {\n return destroyCommand(options);\n });\n\nprogram\n .command('init')\n .description('Initialize platform (seed Logto apps, create admin user, setup database)')\n .action(() => {\n return initPlatform(getProjectDir());\n });\n\nregisterSeedCommand(program);\n\nprogram.parse();\n"]}
1
+ {"version":3,"sources":["../src/utils/logger.ts","../src/constants.ts","../src/utils/config.ts","../src/utils/docker.ts","../src/commands/init.ts","../src/commands/up.ts","../src/commands/down.ts","../src/commands/status.ts","../src/commands/logs.ts","../src/commands/restart.ts","../src/commands/doctor.ts","../src/commands/destroy.ts","../src/commands/seed.ts","../src/bin.ts"],"names":["chalk","path","fs","execaCommand","ora","execa","createInterface","loadEnv","program","readFileSync","Command"],"mappings":"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","file":"bin.js","sourcesContent":["import chalk from 'chalk';\n\nconst prefix = chalk.cyan('[habeetat]');\n\nexport const logger = {\n info: (msg: string) => console.log(`${prefix} ${msg}`),\n success: (msg: string) => console.log(`${prefix} ${chalk.green('✓')} ${msg}`),\n warn: (msg: string) => console.log(`${prefix} ${chalk.yellow('⚠')} ${msg}`),\n error: (msg: string) => console.error(`${prefix} ${chalk.red('✗')} ${msg}`),\n phase: (msg: string) => {\n console.log('');\n console.log(chalk.cyan('═'.repeat(56)));\n console.log(chalk.cyan(` ${msg}`));\n console.log(chalk.cyan('═'.repeat(56)));\n console.log('');\n },\n banner: () => {\n console.log('');\n console.log(chalk.cyan('╔══════════════════════════════════════════════╗'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('║ Habeetat Platform CLI ║'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('╚══════════════════════════════════════════════╝'));\n console.log('');\n },\n};\n","export const CONFIG_FILE = 'habeetat.json';\nexport const ENV_FILE = '.env';\nexport const COMPOSE_FILE = 'docker-compose.yml';\n\nexport const DOCKER_REGISTRY = 'docker.io/capriisland';\n\nexport const IMAGES = {\n backend: 'capriisland/habeetat-backend',\n launcher: 'capriisland/habeetat-launcher',\n orgManager: 'capriisland/habeetat-org-manager',\n platformManager: 'capriisland/habeetat-platform-manager',\n sampleCrm: 'capriisland/habeetat-sample-crm',\n logtoConfig: 'capriisland/habeetat-logto-config',\n} as const;\n\nexport const THIRD_PARTY_IMAGES = {\n postgres: 'postgres:15-alpine',\n logto: 'svhd/logto:1.33',\n nginx: 'nginx:1.25-alpine',\n certbot: 'certbot/certbot',\n} as const;\n\nexport const DEFAULT_PORTS = {\n http: 80,\n https: 443,\n hostNginx: 8080,\n} as const;\n\nexport const SERVICES = [\n 'logto-db',\n 'platform-db',\n 'logto-core',\n 'backend',\n 'launcher',\n 'organization-manager',\n 'platform-manager',\n 'sample-crm',\n 'nginx',\n] as const;\n\nexport type ServiceName = (typeof SERVICES)[number];\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_FILE } from '../constants.js';\nimport type { HabeetatConfig } from '../types.js';\n\nexport function findProjectRoot(startDir: string = process.cwd()): string | null {\n let dir = startDir;\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, CONFIG_FILE))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n return null;\n}\n\nexport function loadConfig(projectDir?: string): HabeetatConfig {\n const dir = projectDir || findProjectRoot();\n if (!dir) {\n throw new Error(\n `Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`,\n );\n }\n const configPath = path.join(dir, CONFIG_FILE);\n const raw = fs.readFileSync(configPath, 'utf-8');\n return JSON.parse(raw) as HabeetatConfig;\n}\n\nexport function saveConfig(config: HabeetatConfig, projectDir: string): void {\n const configPath = path.join(projectDir, CONFIG_FILE);\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function getProjectDir(): string {\n const dir = findProjectRoot();\n if (!dir) {\n throw new Error(\n `Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`,\n );\n }\n return dir;\n}\n","import { execaCommand } from 'execa';\nimport { logger } from './logger.js';\n\nexport async function checkDocker(): Promise<boolean> {\n try {\n const { stdout } = await execaCommand('docker --version');\n const match = stdout.match(/Docker version (\\d+)/);\n if (match && parseInt(match[1], 10) >= 20) {\n return true;\n }\n logger.error(`Docker >= 20.0 required. Found: ${stdout.trim()}`);\n return false;\n } catch {\n logger.error('Docker is not installed or not in PATH');\n logger.info('Install Docker: https://docs.docker.com/get-docker/');\n return false;\n }\n}\n\nexport async function checkDockerCompose(): Promise<boolean> {\n try {\n await execaCommand('docker compose version');\n return true;\n } catch {\n logger.error('Docker Compose V2 is not available');\n logger.info('Docker Compose V2 is included with Docker Desktop');\n return false;\n }\n}\n\nexport async function checkPrerequisites(): Promise<boolean> {\n const docker = await checkDocker();\n const compose = await checkDockerCompose();\n return docker && compose;\n}\n\nexport interface ComposeExecOptions {\n cwd: string;\n composeFile?: string;\n silent?: boolean;\n}\n\nexport async function composeUp(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} up -d`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeDown(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} down`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeDestroy(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} down -v --remove-orphans`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composePs(opts: ComposeExecOptions): Promise<string> {\n const file = opts.composeFile || 'docker-compose.yml';\n const { stdout } = await execaCommand(`docker compose -f ${file} ps`, {\n cwd: opts.cwd,\n });\n return stdout;\n}\n\nexport async function composeLogs(\n opts: ComposeExecOptions & { service?: string; follow?: boolean; tail?: number },\n): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n const parts = ['docker', 'compose', '-f', file, 'logs'];\n if (opts.follow) parts.push('-f');\n if (opts.tail) parts.push('--tail', String(opts.tail));\n if (opts.service) parts.push(opts.service);\n\n await execaCommand(parts.join(' '), {\n cwd: opts.cwd,\n stdio: 'inherit',\n });\n}\n\nexport async function composeRestart(\n opts: ComposeExecOptions & { service?: string },\n): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n const cmd = opts.service\n ? `docker compose -f ${file} restart ${opts.service}`\n : `docker compose -f ${file} restart`;\n\n await execaCommand(cmd, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeExec(\n opts: ComposeExecOptions & { service: string; command: string },\n): Promise<string> {\n const file = opts.composeFile || 'docker-compose.yml';\n const { stdout } = await execaCommand(\n `docker compose -f ${file} exec -T ${opts.service} ${opts.command}`,\n { cwd: opts.cwd },\n );\n return stdout;\n}\n\nexport async function dockerPull(image: string): Promise<void> {\n await execaCommand(`docker pull ${image}`, { stdio: 'inherit' });\n}\n","import ora from 'ora';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { execa, execaCommand } from 'execa';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { COMPOSE_FILE } from '../constants.js';\n\nconst INITIALIZED_FILE = '.initialized';\n\nexport function isInitialized(projectDir: string): boolean {\n return fs.existsSync(path.join(projectDir, INITIALIZED_FILE));\n}\n\nfunction markInitialized(projectDir: string): void {\n fs.writeFileSync(\n path.join(projectDir, INITIALIZED_FILE),\n JSON.stringify({ initializedAt: new Date().toISOString() }, null, 2) + '\\n',\n );\n}\n\nfunction loadEnv(projectDir: string): Record<string, string> {\n const envPath = path.join(projectDir, '.env');\n if (!fs.existsSync(envPath)) return {};\n const lines = fs.readFileSync(envPath, 'utf-8').split('\\n');\n const env: Record<string, string> = {};\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIdx = trimmed.indexOf('=');\n if (eqIdx === -1) continue;\n env[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);\n }\n return env;\n}\n\nasync function execCompose(projectDir: string, args: string): Promise<string> {\n const { stdout } = await execaCommand(\n `docker compose -f ${COMPOSE_FILE} ${args}`,\n { cwd: projectDir },\n );\n return stdout;\n}\n\nasync function waitForService(\n projectDir: string,\n service: string,\n checkCmd: string,\n timeoutSec: number,\n): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutSec * 1000) {\n try {\n await execCompose(projectDir, `exec -T ${service} ${checkCmd}`);\n return true;\n } catch {\n await new Promise((r) => setTimeout(r, 3000));\n }\n }\n return false;\n}\n\nasync function getContainerState(\n projectDir: string,\n service: string,\n): Promise<{ state: string; health: string } | null> {\n try {\n const { stdout } = await execaCommand(\n `docker compose -f ${COMPOSE_FILE} ps ${service} --format json`,\n { cwd: projectDir },\n );\n const lines = stdout.trim().split('\\n');\n for (const line of lines) {\n try {\n const info = JSON.parse(line);\n return { state: info.State || '', health: info.Health || '' };\n } catch { /* skip non-json lines */ }\n }\n } catch { /* container may not exist yet */ }\n return null;\n}\n\nasync function waitForDockerRunning(\n projectDir: string,\n service: string,\n timeoutSec: number,\n): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutSec * 1000) {\n const info = await getContainerState(projectDir, service);\n if (info && info.state === 'running') return true;\n await new Promise((r) => setTimeout(r, 3000));\n }\n return false;\n}\n\nasync function waitForDockerHealthy(\n projectDir: string,\n service: string,\n timeoutSec: number,\n): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutSec * 1000) {\n const info = await getContainerState(projectDir, service);\n if (info) {\n if (info.health === 'healthy') return true;\n if (info.state === 'running' && !info.health) return true;\n }\n await new Promise((r) => setTimeout(r, 5000));\n }\n return false;\n}\n\nfunction buildSeedLogtoAppsSql(env: Record<string, string>): string {\n const protocol = env.PROTOCOL || 'https';\n const domain = env.DOMAIN || 'localhost';\n const launcherUrl = env.LAUNCHER_URL || `${protocol}://launcher.${domain}`;\n const orgManagerUrl = env.ORG_MANAGER_URL || `${protocol}://organization-manager.${domain}`;\n const platformManagerUrl = env.PLATFORM_MANAGER_URL || `${protocol}://platform-manager.${domain}`;\n const sampleCrmUrl = env.SAMPLE_CRM_URL || `${protocol}://sample-crm.${domain}`;\n const apiResource = env.IAM_AUDIENCE || `${protocol}://api.${domain}/api`;\n const m2mAppId = 'nhp-m2m-config';\n const m2mAppSecret = env.LOGTO_M2M_APP_SECRET || '';\n\n return `BEGIN;\n\n-- API Resource\nINSERT INTO resources (tenant_id, id, name, indicator, is_default, access_token_ttl)\nVALUES ('default', 'nhp-backend-resource', 'NHP Backend API', '${apiResource}', false, 3600)\nON CONFLICT (id) DO UPDATE\nSET name = EXCLUDED.name, indicator = EXCLUDED.indicator, access_token_ttl = EXCLUDED.access_token_ttl;\n\n-- Scope for API Resource\nINSERT INTO scopes (tenant_id, id, resource_id, name, description)\nVALUES ('default', 'nhp-backend-scope', 'nhp-backend-resource', 'nhp:all', 'Full access to NHP backend API')\nON CONFLICT (id) DO UPDATE\nSET resource_id = EXCLUDED.resource_id, name = EXCLUDED.name, description = EXCLUDED.description;\n\n-- Launcher SPA\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', 'nhp-launcher', 'Habeetat Launcher', 'spa-secret-nhp-launcher', 'Main launcher application', 'SPA',\n jsonb_build_object('redirectUris', ARRAY['${launcherUrl}', '${launcherUrl}/callback'], 'postLogoutRedirectUris', ARRAY['${launcherUrl}']),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, type = EXCLUDED.type, oidc_client_metadata = EXCLUDED.oidc_client_metadata;\n\n-- Organization Manager SPA\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', 'nhp-org-manager', 'Organization Manager', 'spa-secret-nhp-org-manager', 'Organization management application', 'SPA',\n jsonb_build_object('redirectUris', ARRAY['${orgManagerUrl}', '${orgManagerUrl}/callback'], 'postLogoutRedirectUris', ARRAY['${orgManagerUrl}']),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, type = EXCLUDED.type, oidc_client_metadata = EXCLUDED.oidc_client_metadata;\n\n-- Platform Manager SPA\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', 'nhp-plat-mgr', 'Platform Manager', 'spa-secret-nhp-plat-mgr', 'Platform administration application', 'SPA',\n jsonb_build_object('redirectUris', ARRAY['${platformManagerUrl}', '${platformManagerUrl}/callback'], 'postLogoutRedirectUris', ARRAY['${platformManagerUrl}']),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, type = EXCLUDED.type, oidc_client_metadata = EXCLUDED.oidc_client_metadata;\n\n-- Sample CRM SPA\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', 'nhp-sample-crm', 'Sample CRM', 'spa-secret-nhp-sample-crm', 'Sample CRM application', 'SPA',\n jsonb_build_object('redirectUris', ARRAY['${sampleCrmUrl}', '${sampleCrmUrl}/callback'], 'postLogoutRedirectUris', ARRAY['${sampleCrmUrl}']),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, type = EXCLUDED.type, oidc_client_metadata = EXCLUDED.oidc_client_metadata;\n\n-- M2M Application for backend\nINSERT INTO applications (tenant_id, id, name, secret, description, type, oidc_client_metadata, custom_client_metadata, is_third_party)\nVALUES (\n 'default', '${m2mAppId}', 'NHP M2M Config', '${m2mAppSecret}', 'Machine-to-machine application for backend services', 'MachineToMachine',\n jsonb_build_object('redirectUris', ARRAY[]::text[], 'postLogoutRedirectUris', ARRAY[]::text[]),\n '{}'::jsonb, false\n) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, secret = EXCLUDED.secret, description = EXCLUDED.description, type = EXCLUDED.type;\n\n-- Assign Management API role to M2M app\nDO $$\nDECLARE\n v_role_id TEXT;\nBEGIN\n SELECT id INTO v_role_id FROM roles\n WHERE tenant_id = 'default' AND name = 'Logto Management API access' AND type = 'MachineToMachine'\n LIMIT 1;\n\n IF v_role_id IS NULL THEN\n v_role_id := 'role_m2m_mgmt_api';\n INSERT INTO roles (tenant_id, id, name, description, type)\n VALUES ('default', v_role_id, 'Logto Management API access', 'Access to Logto Management API', 'MachineToMachine');\n\n INSERT INTO roles_scopes (tenant_id, id, role_id, scope_id)\n SELECT 'default', 'rs_' || s.id, v_role_id, s.id\n FROM scopes s WHERE s.resource_id = 'management-api' AND s.tenant_id = 'default'\n ON CONFLICT DO NOTHING;\n END IF;\n\n INSERT INTO applications_roles (tenant_id, id, application_id, role_id)\n VALUES ('default', 'ar_m2m_${m2mAppId}', '${m2mAppId}', v_role_id)\n ON CONFLICT DO NOTHING;\nEND $$;\n\n-- Update admin-console redirect URIs\nUPDATE applications\nSET oidc_client_metadata = jsonb_build_object(\n 'redirectUris', ARRAY['${protocol}://iam-console.${domain}/callback'],\n 'postLogoutRedirectUris', ARRAY['${protocol}://iam-console.${domain}']\n)\nWHERE id = 'admin-console' AND tenant_id = 'admin';\n\nCOMMIT;`;\n}\n\nfunction buildInitPlatformSql(env: Record<string, string>): string {\n const protocol = env.PROTOCOL || 'https';\n const domain = env.DOMAIN || 'localhost';\n const adminEmail = env.PLATFORM_ADMIN_EMAIL || 'admin@habeetat.local';\n const orgName = env.ORGANIZATION_NAME || 'Default Organization';\n const orgSlug = orgName.toLowerCase().replace(/\\s+/g, '-').replace(/[^a-z0-9-]/g, '');\n\n return `\n-- Seed system applications\nINSERT INTO applications (id, slug, name, description, category, is_internal, is_system_app, is_hidden, auto_install, status, logto_app_id, created_at, updated_at)\nVALUES\n ('app_launcher', 'launcher', 'Habeetat Launcher', 'Main launcher and navigation hub', 'system', true, true, true, true, 'PUBLISHED', 'nhp-launcher', NOW(), NOW()),\n ('app_org_manager', 'organization-manager', 'Organization Manager', 'Manage organizations, users and roles', 'system', true, true, false, true, 'PUBLISHED', 'nhp-org-manager', NOW(), NOW()),\n ('app_plat_manager', 'platform-manager', 'Platform Manager', 'Platform administration and configuration', 'system', true, true, true, false, 'PUBLISHED', 'nhp-plat-mgr', NOW(), NOW()),\n ('app_sample_crm', 'sample-crm', 'Sample CRM', 'Sample CRM application for demonstration', 'demo', true, false, false, false, 'PUBLISHED', 'nhp-sample-crm', NOW(), NOW())\nON CONFLICT (slug) DO UPDATE SET\n name = EXCLUDED.name,\n description = EXCLUDED.description,\n logto_app_id = EXCLUDED.logto_app_id,\n is_system_app = EXCLUDED.is_system_app,\n is_hidden = EXCLUDED.is_hidden,\n auto_install = EXCLUDED.auto_install,\n status = EXCLUDED.status;\n\n-- Create initial versions for system apps\nINSERT INTO application_versions (id, app_id, version, manifest, status, created_at)\nVALUES\n ('ver_launcher_100', 'app_launcher', '1.0.0', jsonb_build_object('endpoints', jsonb_build_object('main', '${protocol}://launcher.${domain}')), 'ACTIVE', NOW()),\n ('ver_org_manager_100', 'app_org_manager', '1.0.0', jsonb_build_object('endpoints', jsonb_build_object('main', '${protocol}://organization-manager.${domain}')), 'ACTIVE', NOW()),\n ('ver_plat_manager_100', 'app_plat_manager', '1.0.0', jsonb_build_object('endpoints', jsonb_build_object('main', '${protocol}://platform-manager.${domain}')), 'ACTIVE', NOW()),\n ('ver_sample_crm_100', 'app_sample_crm', '1.0.0', jsonb_build_object('endpoints', jsonb_build_object('main', '${protocol}://sample-crm.${domain}')), 'ACTIVE', NOW())\nON CONFLICT (app_id, version) DO UPDATE SET manifest = EXCLUDED.manifest;\n\n-- Create default tenant\nINSERT INTO tenants (id, display_name, slug, status, created_at, updated_at)\nSELECT\n 'tenant_${orgSlug}',\n '${orgName}',\n '${orgSlug}',\n 'ACTIVE',\n NOW(),\n NOW()\nWHERE NOT EXISTS (\n SELECT 1 FROM tenants WHERE slug = '${orgSlug}'\n);\n\n-- Initialize tenant, admin user, roles, memberships, and app installations\nDO $$\nDECLARE\n v_tenant_id TEXT;\n v_user_id TEXT;\n v_admin_role_id TEXT;\nBEGIN\n SELECT id INTO v_tenant_id FROM tenants WHERE slug = '${orgSlug}' LIMIT 1;\n\n IF v_tenant_id IS NULL THEN\n RAISE NOTICE 'Tenant not found, skipping user setup';\n RETURN;\n END IF;\n\n SELECT id INTO v_user_id FROM users\n WHERE external_identity_id = 'usr_admin01'\n OR primary_email = '${adminEmail}'\n LIMIT 1;\n\n IF v_user_id IS NULL THEN\n v_user_id := 'usr_plat_admin01';\n INSERT INTO users (id, external_identity_id, primary_email, username, display_name, status, created_at, updated_at)\n VALUES (v_user_id, 'usr_admin01', '${adminEmail}', 'admin', 'Platform Admin', 'ACTIVE', NOW(), NOW());\n ELSE\n UPDATE users SET external_identity_id = 'usr_admin01'\n WHERE id = v_user_id AND external_identity_id IS NULL;\n END IF;\n\n SELECT id INTO v_admin_role_id FROM tenant_roles WHERE name = 'TENANT_ADMIN' LIMIT 1;\n\n IF v_admin_role_id IS NULL THEN\n v_admin_role_id := 'role_tenant_admin';\n INSERT INTO tenant_roles (id, name, description, created_at, updated_at)\n VALUES (v_admin_role_id, 'TENANT_ADMIN', 'Tenant Administrator', NOW(), NOW());\n END IF;\n\n INSERT INTO tenant_memberships (id, user_id, tenant_id, status, created_at, updated_at)\n SELECT 'tm_admin_${orgSlug}', v_user_id, v_tenant_id, 'ACTIVE', NOW(), NOW()\n WHERE NOT EXISTS (\n SELECT 1 FROM tenant_memberships WHERE user_id = v_user_id AND tenant_id = v_tenant_id\n );\n\n INSERT INTO tenant_membership_roles (id, membership_id, role_id, created_at)\n SELECT 'tmr_admin_${orgSlug}', 'tm_admin_${orgSlug}', v_admin_role_id, NOW()\n WHERE NOT EXISTS (\n SELECT 1 FROM tenant_membership_roles\n WHERE membership_id = 'tm_admin_${orgSlug}' AND role_id = v_admin_role_id\n );\nEND $$;\n\n-- Auto-install published non-hidden apps for the default tenant\nINSERT INTO tenant_application_installations (id, tenant_id, app_id, app_version_id, status, is_enabled, installed_at, updated_at)\nSELECT 'tai_${orgSlug}_' || a.slug, t.id, a.id, v.id, 'INSTALLED', true, NOW(), NOW()\nFROM tenants t\nJOIN applications a ON a.status = 'PUBLISHED' AND a.is_hidden = false\nJOIN application_versions v ON v.app_id = a.id AND v.version = '1.0.0'\nWHERE t.slug = '${orgSlug}'\nON CONFLICT (tenant_id, app_id) DO NOTHING;`;\n}\n\nexport async function initPlatform(projectDir: string): Promise<void> {\n const config = loadConfig(projectDir);\n const env = loadEnv(projectDir);\n const domain = config.platform.domain;\n\n // --- Phase 1: Wait for databases ---\n const dbSpinner = ora('Waiting for databases...').start();\n\n const logtoDbReady = await waitForService(\n projectDir, 'logto-db', 'pg_isready -U logto -d logto', 60,\n );\n if (!logtoDbReady) {\n dbSpinner.fail('logto-db did not become ready');\n throw new Error('logto-db timeout');\n }\n\n const platformDbReady = await waitForService(\n projectDir, 'platform-db',\n `pg_isready -U ${env.PLATFORM_DB_USER || 'habeetat'} -d ${env.PLATFORM_DB_NAME || 'habeetat_platform'}`,\n 60,\n );\n if (!platformDbReady) {\n dbSpinner.fail('platform-db did not become ready');\n throw new Error('platform-db timeout');\n }\n dbSpinner.succeed('Databases ready');\n\n // --- Phase 2: Wait for Logto to be healthy ---\n const logtoSpinner = ora('Waiting for Logto to be healthy (this may take up to 2 min)...').start();\n const logtoReady = await waitForService(\n projectDir, 'logto-core',\n 'wget -q --spider http://localhost:3001/oidc/.well-known/openid-configuration',\n 180,\n );\n if (!logtoReady) {\n logtoSpinner.fail('logto-core did not become healthy');\n throw new Error('logto-core timeout');\n }\n logtoSpinner.succeed('Logto is healthy');\n\n // --- Phase 3: Seed Logto applications (SQL) ---\n const logtoSeedSpinner = ora('Seeding Logto applications...').start();\n try {\n const sql = buildSeedLogtoAppsSql(env);\n await execaCommand(\n `docker compose -f ${COMPOSE_FILE} exec -T logto-db psql -U logto -d logto`,\n { cwd: projectDir, input: sql },\n );\n logtoSeedSpinner.succeed('Logto applications seeded');\n } catch (err) {\n logtoSeedSpinner.fail('Failed to seed Logto applications');\n logger.error(String(err));\n throw err;\n }\n\n // --- Phase 4: Bootstrap Logto users/orgs/roles (via Node container) ---\n const bootstrapSpinner = ora('Bootstrapping Logto users and organizations...').start();\n try {\n const orgName = env.ORGANIZATION_NAME || config.platform.organization || 'Default';\n const orgSlug = orgName.toLowerCase().replace(/\\s+/g, '-').replace(/[^a-z0-9-]/g, '');\n const adminEmail = env.PLATFORM_ADMIN_EMAIL || config.platform.adminEmail;\n const adminPassword = env.PLATFORM_ADMIN_PASSWORD || 'Habeetat_01';\n const adminUsername = adminEmail.split('@')[0];\n const logtoDbUrl = `postgres://${env.LOGTO_DB_USER || 'logto'}:${env.LOGTO_DB_PASSWORD || 'logto'}@logto-db:5432/${env.LOGTO_DB_NAME || 'logto'}`;\n\n const bootstrapScriptPath = path.join(projectDir, 'scripts', 'nhp-seed-logto-bootstrap.mjs');\n const hasLocalScript = fs.existsSync(bootstrapScriptPath);\n\n if (hasLocalScript) {\n await execa('docker', [\n 'run', '--rm', '--network', 'habeetat_habeetat-network',\n '-e', `NHP_LOGTO_DB_URL=${logtoDbUrl}`,\n '-e', `NHP_PLATFORM_ADMIN_USERNAME=${adminUsername}`,\n '-e', `NHP_PLATFORM_ADMIN_EMAIL=${adminEmail}`,\n '-e', `NHP_PLATFORM_ADMIN_PASSWORD=${adminPassword}`,\n '-e', `NHP_PLATFORM_ADMIN_DISPLAY_NAME=Platform Admin`,\n '-e', `NHP_DEFAULT_TENANT_NAME=${orgName}`,\n '-e', `NHP_DEFAULT_TENANT_SLUG=${orgSlug}`,\n '-v', `${bootstrapScriptPath}:/app/bootstrap.mjs:ro`,\n '-w', '/app',\n 'node:20-alpine',\n 'sh', '-c', 'npm init -y >/dev/null 2>&1 && npm install --no-package-lock pg hash-wasm nanoid 2>/dev/null && node bootstrap.mjs',\n ],\n { cwd: projectDir, stdio: 'pipe' },\n );\n bootstrapSpinner.succeed('Logto users and organizations bootstrapped');\n } else {\n bootstrapSpinner.warn('Bootstrap script not found — skipping Logto user/org setup');\n logger.info('You may need to create the admin user manually via the Logto admin console');\n }\n } catch (err) {\n bootstrapSpinner.fail('Logto bootstrap failed');\n logger.error(String(err));\n logger.info('You may need to create the admin user manually via the Logto admin console');\n }\n\n // --- Phase 5: Wait for backend container to be running ---\n const backendRunSpinner = ora('Waiting for backend container to start...').start();\n const backendRunning = await waitForDockerRunning(projectDir, 'backend', 90);\n if (!backendRunning) {\n backendRunSpinner.fail('Backend container did not start');\n throw new Error('backend container timeout');\n }\n backendRunSpinner.succeed('Backend container is running');\n\n // --- Phase 6: Run Prisma migrations (before health check — tables must exist first) ---\n const migrateSpinner = ora('Running database migrations...').start();\n try {\n await execCompose(projectDir, 'exec -T backend npx prisma migrate deploy');\n migrateSpinner.succeed('Database migrations completed');\n } catch (err) {\n migrateSpinner.fail('Migrations failed');\n logger.error(String(err));\n logger.info('Run manually: docker compose exec backend npx prisma migrate deploy');\n }\n\n // --- Phase 7: Run Prisma seed ---\n const seedSpinner = ora('Seeding platform database...').start();\n try {\n const orgName = env.ORGANIZATION_NAME || config.platform.organization || 'Default';\n const orgSlug = orgName.toLowerCase().replace(/\\s+/g, '-').replace(/[^a-z0-9-]/g, '');\n const adminEmail = env.PLATFORM_ADMIN_EMAIL || config.platform.adminEmail;\n\n await execa('docker', [\n 'compose', '-f', COMPOSE_FILE, 'exec', '-T',\n '-e', `NHP_PLATFORM_ADMIN_USER=${adminEmail.split('@')[0]}`,\n '-e', `NHP_PLATFORM_ADMIN_EMAIL=${adminEmail}`,\n '-e', `NHP_PLATFORM_ADMIN_DISPLAY_NAME=Platform Admin`,\n '-e', `NHP_DEFAULT_TENANT_NAME=${orgName}`,\n '-e', `NHP_DEFAULT_TENANT_SLUG=${orgSlug}`,\n 'backend', 'npx', 'tsx', 'prisma/seed.ts',\n ], { cwd: projectDir, stdio: 'pipe' });\n seedSpinner.succeed('Platform database seeded');\n } catch {\n seedSpinner.warn('Prisma seed skipped (may not be available in Docker image)');\n }\n\n // --- Phase 8: Wait for backend to become healthy (tables now exist) ---\n const backendSpinner = ora('Waiting for backend to be healthy...').start();\n const backendReady = await waitForDockerHealthy(\n projectDir, 'backend', 180,\n );\n if (!backendReady) {\n backendSpinner.fail('Backend did not become healthy');\n logger.info('Check logs: docker compose logs backend');\n } else {\n backendSpinner.succeed('Backend is healthy');\n }\n\n // --- Phase 9: Initialize platform SQL (system apps, tenant, admin) ---\n const platformSpinner = ora('Initializing platform data...').start();\n try {\n const sql = buildInitPlatformSql(env);\n await execaCommand(\n `docker compose -f ${COMPOSE_FILE} exec -T platform-db psql -U ${env.PLATFORM_DB_USER || 'habeetat'} -d ${env.PLATFORM_DB_NAME || 'habeetat_platform'}`,\n { cwd: projectDir, input: sql },\n );\n platformSpinner.succeed('Platform data initialized');\n } catch (err) {\n platformSpinner.fail('Platform initialization failed');\n logger.error(String(err));\n logger.info('You may need to initialize the platform manually after first login');\n }\n\n // Mark as initialized\n markInitialized(projectDir);\n\n console.log('');\n logger.info(`✓ Platform initialized for ${domain}`);\n logger.info(` Admin: ${env.PLATFORM_ADMIN_EMAIL || config.platform.adminEmail}`);\n logger.info(` Organization: ${env.ORGANIZATION_NAME || config.platform.organization}`);\n}\n","import ora from 'ora';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { composeUp, checkPrerequisites } from '../utils/docker.js';\nimport { isInitialized, initPlatform } from './init.js';\n\nexport async function upCommand(): Promise<void> {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n\n logger.info(`Starting Habeetat Platform (${config.platform.domain})...`);\n\n if (!(await checkPrerequisites())) {\n process.exit(1);\n }\n\n const freshInstall = !isInitialized(projectDir);\n const spinner = ora('Starting services...').start();\n\n try {\n await composeUp({ cwd: projectDir });\n spinner.succeed('All services started');\n } catch (err) {\n spinner.fail('Failed to start services');\n logger.error(String(err));\n process.exit(1);\n }\n\n if (freshInstall) {\n console.log('');\n logger.info('First run detected — initializing platform...');\n console.log('');\n try {\n await initPlatform(projectDir);\n } catch (err) {\n logger.error('Platform initialization failed');\n logger.error(String(err));\n logger.info('You can retry with: npx habeetat init');\n process.exit(1);\n }\n }\n\n const proto = config.platform.protocol;\n const domain = config.platform.domain;\n\n console.log('');\n logger.info('Platform URLs:');\n console.log(` Launcher: ${proto}://launcher.${domain}`);\n console.log(` Organization Manager: ${proto}://organization-manager.${domain}`);\n console.log(` Platform Manager: ${proto}://platform-manager.${domain}`);\n console.log(` Backend API: ${proto}://api.${domain}`);\n console.log(` Logto IAM: ${proto}://iam.${domain}`);\n console.log(` Logto Admin Console: ${proto}://iam-console.${domain}`);\n console.log('');\n logger.info('Run `habeetat status` to check service health');\n}\n","import ora from 'ora';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir } from '../utils/config.js';\nimport { composeDown } from '../utils/docker.js';\n\nexport async function downCommand(): Promise<void> {\n const projectDir = getProjectDir();\n const spinner = ora('Stopping services...').start();\n\n try {\n await composeDown({ cwd: projectDir });\n spinner.succeed('All services stopped');\n } catch (err) {\n spinner.fail('Failed to stop services');\n logger.error(String(err));\n process.exit(1);\n }\n}\n","import { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { composePs } from '../utils/docker.js';\n\nexport async function statusCommand(): Promise<void> {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n\n logger.info(`Habeetat Platform — ${config.platform.domain}`);\n logger.info(`Version: ${config.version}`);\n logger.info(`Image tag: ${config.docker.imageTag}`);\n console.log('');\n\n try {\n const output = await composePs({ cwd: projectDir });\n console.log(output);\n } catch (err) {\n logger.error('Could not get service status. Is the platform running?');\n logger.info('Run `habeetat up` to start the platform');\n process.exit(1);\n }\n}\n","import { logger } from '../utils/logger.js';\nimport { getProjectDir } from '../utils/config.js';\nimport { composeLogs } from '../utils/docker.js';\nimport { SERVICES } from '../constants.js';\n\nexport async function logsCommand(\n service?: string,\n options?: { follow?: boolean; tail?: number },\n): Promise<void> {\n const projectDir = getProjectDir();\n\n if (service && !(SERVICES as readonly string[]).includes(service)) {\n logger.error(`Unknown service: ${service}`);\n logger.info(`Available services: ${SERVICES.join(', ')}`);\n process.exit(1);\n }\n\n try {\n await composeLogs({\n cwd: projectDir,\n service,\n follow: options?.follow,\n tail: options?.tail,\n });\n } catch {\n // User interrupted with Ctrl+C — that's fine\n }\n}\n","import ora from 'ora';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir } from '../utils/config.js';\nimport { composeRestart } from '../utils/docker.js';\nimport { SERVICES } from '../constants.js';\n\nexport async function restartCommand(service?: string): Promise<void> {\n const projectDir = getProjectDir();\n\n if (service && !(SERVICES as readonly string[]).includes(service)) {\n logger.error(`Unknown service: ${service}`);\n logger.info(`Available services: ${SERVICES.join(', ')}`);\n process.exit(1);\n }\n\n const label = service || 'all services';\n const spinner = ora(`Restarting ${label}...`).start();\n\n try {\n await composeRestart({ cwd: projectDir, service });\n spinner.succeed(`Restarted ${label}`);\n } catch (err) {\n spinner.fail(`Failed to restart ${label}`);\n logger.error(String(err));\n process.exit(1);\n }\n}\n","import chalk from 'chalk';\nimport { logger } from '../utils/logger.js';\nimport { checkDocker, checkDockerCompose } from '../utils/docker.js';\nimport { findProjectRoot, loadConfig } from '../utils/config.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_FILE, COMPOSE_FILE, ENV_FILE } from '../constants.js';\n\nexport async function doctorCommand(): Promise<void> {\n logger.phase('Habeetat Doctor — Diagnostics');\n let issues = 0;\n\n // Check Docker\n const dockerOk = await checkDocker();\n console.log(` Docker: ${dockerOk ? chalk.green('✓ Installed') : chalk.red('✗ Not found')}`);\n if (!dockerOk) issues++;\n\n // Check Docker Compose\n const composeOk = await checkDockerCompose();\n console.log(` Docker Compose: ${composeOk ? chalk.green('✓ Available') : chalk.red('✗ Not found')}`);\n if (!composeOk) issues++;\n\n // Check project directory\n const projectDir = findProjectRoot();\n console.log(` Project dir: ${projectDir ? chalk.green(`✓ ${projectDir}`) : chalk.yellow('⚠ Not in a Habeetat project')}`);\n if (!projectDir) {\n issues++;\n console.log('');\n logger.info(`Run \\`npm create habeetat my-platform\\` to create a new project`);\n return;\n }\n\n // Check config file\n const configExists = fs.existsSync(path.join(projectDir, CONFIG_FILE));\n console.log(` ${CONFIG_FILE}: ${configExists ? chalk.green('✓ Found') : chalk.red('✗ Missing')}`);\n if (!configExists) issues++;\n\n // Check compose file\n const composeExists = fs.existsSync(path.join(projectDir, COMPOSE_FILE));\n console.log(` ${COMPOSE_FILE}: ${composeExists ? chalk.green('✓ Found') : chalk.red('✗ Missing')}`);\n if (!composeExists) issues++;\n\n // Check env file\n const envExists = fs.existsSync(path.join(projectDir, ENV_FILE));\n console.log(` ${ENV_FILE}: ${envExists ? chalk.green('✓ Found') : chalk.red('✗ Missing')}`);\n if (!envExists) issues++;\n\n // Check nginx config\n const nginxExists = fs.existsSync(path.join(projectDir, 'nginx', 'platform.conf'));\n console.log(` nginx/platform.conf: ${nginxExists ? chalk.green('✓ Found') : chalk.red('✗ Missing')}`);\n if (!nginxExists) issues++;\n\n // Load config and check images\n if (configExists) {\n try {\n const config = loadConfig(projectDir);\n console.log(` Version: ${chalk.cyan(config.version)}`);\n console.log(` Domain: ${chalk.cyan(config.platform.domain)}`);\n console.log(` Protocol: ${chalk.cyan(config.platform.protocol)}`);\n } catch (err) {\n console.log(` Config: ${chalk.red('✗ Invalid JSON')}`);\n issues++;\n }\n }\n\n console.log('');\n if (issues === 0) {\n logger.success('No issues found');\n } else {\n logger.warn(`${issues} issue(s) found`);\n }\n}\n","import ora from 'ora';\nimport { createInterface } from 'node:readline';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { composeDestroy } from '../utils/docker.js';\n\nasync function confirm(message: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(`${message} (y/N) `, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y');\n });\n });\n}\n\nexport async function destroyCommand(options: { force?: boolean }): Promise<void> {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n const domain = config.platform.domain;\n\n logger.warn(`This will permanently destroy the Habeetat Platform (${domain}):`);\n console.log(' - Stop and remove all containers');\n console.log(' - Delete all Docker volumes (databases, data)');\n console.log(' - Remove orphan containers');\n console.log('');\n\n if (!options.force) {\n const ok = await confirm('Are you sure you want to continue?');\n if (!ok) {\n logger.info('Aborted');\n return;\n }\n }\n\n const spinner = ora('Destroying platform...').start();\n\n try {\n await composeDestroy({ cwd: projectDir });\n spinner.succeed('Platform destroyed — all containers and volumes removed');\n console.log('');\n logger.info('To reinstall, run: npx habeetat up');\n } catch (err) {\n spinner.fail('Failed to destroy platform');\n logger.error(String(err));\n process.exit(1);\n }\n}\n","import ora from 'ora';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport chalk from 'chalk';\nimport { execa } from 'execa';\nimport type { Command } from 'commander';\nimport { logger } from '../utils/logger.js';\nimport { getProjectDir, loadConfig } from '../utils/config.js';\nimport { COMPOSE_FILE } from '../constants.js';\n\n// Path to the seed script bundled with the CLI package.\n// __dirname is dist/ at runtime; tsup copies scripts/ → dist/scripts/ during build.\nconst SEED_SCRIPT_PATH = path.resolve(__dirname, 'scripts/nhp-seed-dev.ts');\nconst SEED_SCRIPT_REMOTE = '/tmp/nhp-seed-dev.ts';\n\nfunction loadEnv(projectDir: string): Record<string, string> {\n const envPath = path.join(projectDir, '.env');\n if (!fs.existsSync(envPath)) return {};\n const lines = fs.readFileSync(envPath, 'utf-8').split('\\n');\n const env: Record<string, string> = {};\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIdx = trimmed.indexOf('=');\n if (eqIdx === -1) continue;\n env[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);\n }\n return env;\n}\n\nasync function runSeedScript(\n projectDir: string,\n command: string,\n args: string[],\n): Promise<Record<string, unknown>> {\n // Inject the script into the container via stdin so it works regardless\n // of whether the Docker image was built with or without scripts/.\n if (!fs.existsSync(SEED_SCRIPT_PATH)) {\n throw new Error(\n `Seed script not found at ${SEED_SCRIPT_PATH}. ` +\n `This is a bug — please reinstall @habeetat/cli.`,\n );\n }\n const scriptContent = fs.readFileSync(SEED_SCRIPT_PATH, 'utf-8');\n\n await execa(\n 'docker',\n ['compose', '-f', COMPOSE_FILE, 'exec', '-T', 'backend', 'sh', '-c',\n `cat > ${SEED_SCRIPT_REMOTE}`],\n { cwd: projectDir, input: scriptContent, stdio: 'pipe' },\n );\n\n const { stdout, stderr } = await execa(\n 'docker',\n [\n 'compose', '-f', COMPOSE_FILE, 'exec', '-T', 'backend',\n 'npx', 'tsx', SEED_SCRIPT_REMOTE,\n command,\n ...args,\n ],\n { cwd: projectDir, stdio: 'pipe' },\n );\n\n // Forward container stderr to our stderr for debugging\n if (stderr) process.stderr.write(stderr + '\\n');\n\n const jsonLine = stdout.trim().split('\\n').pop() ?? '';\n try {\n return JSON.parse(jsonLine) as Record<string, unknown>;\n } catch {\n throw new Error(`Script produced unexpected output: ${stdout}`);\n }\n}\n\nfunction printSdkConfig(\n config: { protocol: string; domain: string },\n env: Record<string, string>,\n parts: { tenant?: string; logtoAppId?: string; email?: string; password?: string },\n) {\n const protocol = config.protocol || 'https';\n const domain = config.domain;\n const iamUrl = env.LOGTO_EXTERNAL_ENDPOINT || `${protocol}://iam.${domain}`;\n const apiUrl = env.IAM_AUDIENCE\n ? env.IAM_AUDIENCE.replace(/\\/api$/, '')\n : `${protocol}://api.${domain}`;\n\n console.log('');\n console.log(chalk.cyan('═'.repeat(56)));\n console.log(chalk.cyan(' SDK Configuration'));\n console.log(chalk.cyan('═'.repeat(56)));\n console.log('');\n\n if (parts.logtoAppId) {\n console.log(chalk.bold(' Frontend SDK (@logto/react + @habeetat/sdk-frontend)'));\n console.log(chalk.dim(' ' + '─'.repeat(50)));\n console.log(` VITE_LOGTO_ENDPOINT=${chalk.green(iamUrl)}`);\n console.log(` VITE_LOGTO_APP_ID=${chalk.green(parts.logtoAppId)}`);\n console.log(` VITE_LOGTO_API_RESOURCE=${chalk.green(env.IAM_AUDIENCE || `${protocol}://api.${domain}/api`)}`);\n if (parts.tenant) {\n console.log(` VITE_APP_TENANT=${chalk.green(parts.tenant)}`);\n }\n console.log('');\n }\n\n if (parts.tenant) {\n console.log(chalk.bold(' Backend SDK (@habeetat/sdk-backend)'));\n console.log(chalk.dim(' ' + '─'.repeat(50)));\n console.log(` HABEETAT_ENDPOINT=${chalk.green(apiUrl)}`);\n console.log(` HABEETAT_TENANT_SLUG=${chalk.green(parts.tenant)}`);\n console.log('');\n }\n\n if (parts.email && parts.password) {\n console.log(chalk.bold(' Test credentials'));\n console.log(chalk.dim(' ' + '─'.repeat(50)));\n console.log(` Email: ${chalk.green(parts.email)}`);\n console.log(` Password: ${chalk.green(parts.password)}`);\n console.log(` IAM: ${chalk.green(iamUrl)}`);\n console.log('');\n }\n\n console.log(chalk.cyan('═'.repeat(56)));\n console.log('');\n}\n\n// ---------------------------------------------------------------------------\n// Slug validation\n// ---------------------------------------------------------------------------\nfunction validateSlug(slug: string, entity: string): void {\n if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(slug) && !/^[a-z0-9]$/.test(slug)) {\n logger.error(\n `Invalid ${entity} slug \"${slug}\": must be lowercase alphanumeric with hyphens (e.g. get-master)`,\n );\n process.exit(1);\n }\n}\n\n// ---------------------------------------------------------------------------\n// seed tenant\n// ---------------------------------------------------------------------------\nexport async function seedTenantCommand(options: {\n name: string;\n slug: string;\n description?: string;\n}) {\n validateSlug(options.slug, 'tenant');\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n const env = loadEnv(projectDir);\n\n const args = [\n '--name', options.name,\n '--slug', options.slug,\n ...(options.description ? ['--description', options.description] : []),\n ];\n\n const spinner = ora(`Creating tenant \"${options.slug}\"...`).start();\n let result: Record<string, unknown>;\n try {\n result = await runSeedScript(projectDir, 'create-tenant', args);\n spinner.succeed(`Tenant created: ${chalk.bold(result.slug)} (${result.displayName})`);\n } catch (err) {\n spinner.fail('Failed to create tenant');\n logger.error(String(err));\n process.exit(1);\n }\n\n logger.info(` ID: ${result.id}`);\n logger.info(` Logto Org ID: ${result.logtoOrganizationId}`);\n\n printSdkConfig(config.platform, env, { tenant: result.slug as string });\n}\n\n// ---------------------------------------------------------------------------\n// seed app\n// ---------------------------------------------------------------------------\nexport async function seedAppCommand(options: {\n name: string;\n slug: string;\n redirectUri?: string[];\n logoutUri?: string[];\n corsOrigin?: string[];\n description?: string;\n tenant?: string;\n}) {\n validateSlug(options.slug, 'app');\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n const env = loadEnv(projectDir);\n\n const args: string[] = [\n '--name', options.name,\n '--slug', options.slug,\n ...(options.description ? ['--description', options.description] : []),\n ...(options.tenant ? ['--tenant', options.tenant] : []),\n ...(options.redirectUri?.flatMap((u) => ['--redirect-uri', u]) ?? []),\n ...(options.logoutUri?.flatMap((u) => ['--logout-uri', u]) ?? []),\n ...(options.corsOrigin?.flatMap((o) => ['--cors-origin', o]) ?? []),\n ];\n\n const spinner = ora(`Creating app \"${options.slug}\"...`).start();\n let result: Record<string, unknown>;\n try {\n result = await runSeedScript(projectDir, 'create-app', args);\n spinner.succeed(`App created: ${chalk.bold(result.slug)} (Logto app: ${result.logtoAppId})`);\n } catch (err) {\n spinner.fail('Failed to create app');\n logger.error(String(err));\n process.exit(1);\n }\n\n logger.info(` ID: ${result.id}`);\n logger.info(` Logto App ID: ${result.logtoAppId}`);\n if (result.redirectUris && (result.redirectUris as string[]).length > 0) {\n logger.info(` Redirect URIs: ${(result.redirectUris as string[]).join(', ')}`);\n }\n if (result.tenantSlug) {\n logger.info(` Installed on: ${result.tenantSlug}`);\n }\n\n printSdkConfig(config.platform, env, {\n tenant: (result.tenantSlug as string) || options.tenant,\n logtoAppId: result.logtoAppId as string,\n });\n}\n\n// ---------------------------------------------------------------------------\n// seed user\n// ---------------------------------------------------------------------------\nexport async function seedUserCommand(options: {\n email: string;\n password: string;\n tenant: string;\n username?: string;\n displayName?: string;\n role?: string;\n}) {\n const projectDir = getProjectDir();\n const config = loadConfig(projectDir);\n const env = loadEnv(projectDir);\n\n const args: string[] = [\n '--email', options.email,\n '--password', options.password,\n '--tenant', options.tenant,\n ...(options.username ? ['--username', options.username] : []),\n ...(options.displayName ? ['--display-name', options.displayName] : []),\n ...(options.role ? ['--role', options.role] : []),\n ];\n\n const spinner = ora(`Creating user \"${options.email}\" in tenant \"${options.tenant}\"...`).start();\n let result: Record<string, unknown>;\n try {\n result = await runSeedScript(projectDir, 'create-user', args);\n spinner.succeed(`User created: ${chalk.bold(result.email)} (Logto ID: ${result.logtoUserId})`);\n } catch (err) {\n spinner.fail('Failed to create user');\n logger.error(String(err));\n process.exit(1);\n }\n\n logger.info(` Logto User ID: ${result.logtoUserId}`);\n logger.info(` Username: ${result.username}`);\n logger.info(` Tenant: ${result.tenantSlug}`);\n logger.info(` Role: ${result.role}${result.roleAssigned ? '' : ' (not assigned — role not found in Logto)'}`);\n if (result.note) logger.info(` Note: ${result.note}`);\n\n printSdkConfig(config.platform, env, {\n tenant: result.tenantSlug as string,\n email: result.email as string,\n password: result.password as string,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Command registration\n// ---------------------------------------------------------------------------\nexport function registerSeedCommand(program: Command) {\n const seed = program\n .command('seed')\n .description('Seed dev data — create tenants, apps and users for local development');\n\n seed\n .command('tenant')\n .description('Create a new tenant (Logto org + platform DB)')\n .requiredOption('--name <name>', 'Display name (e.g. \"Acme Corp\")')\n .requiredOption('--slug <slug>', 'Unique slug, lowercase alphanumeric + hyphens (e.g. acme)')\n .option('--description <desc>', 'Optional description')\n .action((opts: { name: string; slug: string; description?: string }) => {\n return seedTenantCommand(opts);\n });\n\n seed\n .command('app')\n .description('Create a new OIDC application (Logto SPA app + platform DB)')\n .requiredOption('--name <name>', 'App display name (e.g. \"My CRM\")')\n .requiredOption('--slug <slug>', 'Unique slug, lowercase alphanumeric + hyphens (e.g. my-crm)')\n .option('--redirect-uri <uri...>', 'OIDC redirect URI(s) (e.g. http://localhost:3000/callback)')\n .option('--logout-uri <uri...>', 'Post-logout redirect URI(s)')\n .option('--cors-origin <origin...>', 'CORS allowed origin(s)')\n .option('--description <desc>', 'Optional description')\n .option('--tenant <slug>', 'Install app on this tenant after creation')\n .action(\n (opts: {\n name: string;\n slug: string;\n redirectUri?: string[];\n logoutUri?: string[];\n corsOrigin?: string[];\n description?: string;\n tenant?: string;\n }) => {\n return seedAppCommand(opts);\n },\n );\n\n seed\n .command('user')\n .description('Create a new user in Logto and add to a tenant organization')\n .requiredOption('--email <email>', 'User email address')\n .requiredOption('--password <password>', 'User password')\n .requiredOption('--tenant <slug>', 'Tenant slug to add the user to')\n .option('--username <username>', 'Logto username (defaults to email prefix)')\n .option('--display-name <name>', 'Display name (defaults to username)')\n .option('--role <role>', 'Organization role to assign (default: TENANT_ADMIN)', 'TENANT_ADMIN')\n .action(\n (opts: {\n email: string;\n password: string;\n tenant: string;\n username?: string;\n displayName?: string;\n role?: string;\n }) => {\n return seedUserCommand(opts);\n },\n );\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport path from 'node:path';\nimport { upCommand } from './commands/up.js';\nimport { downCommand } from './commands/down.js';\nimport { statusCommand } from './commands/status.js';\nimport { logsCommand } from './commands/logs.js';\nimport { restartCommand } from './commands/restart.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { destroyCommand } from './commands/destroy.js';\nimport { initPlatform } from './commands/init.js';\nimport { registerSeedCommand } from './commands/seed.js';\nimport { getProjectDir } from './utils/config.js';\n\nconst pkg = JSON.parse(\n readFileSync(path.resolve(__dirname, '..', 'package.json'), 'utf-8'),\n);\n\nconst program = new Command();\n\nprogram\n .name('habeetat')\n .description('Habeetat Platform CLI — manage your platform instances')\n .version(pkg.version);\n\nprogram\n .command('up')\n .description('Start the platform')\n .action(upCommand);\n\nprogram\n .command('down')\n .description('Stop the platform')\n .action(downCommand);\n\nprogram\n .command('status')\n .description('Show platform service status')\n .action(statusCommand);\n\nprogram\n .command('logs [service]')\n .description('View service logs')\n .option('-f, --follow', 'Follow log output')\n .option('-n, --tail <lines>', 'Number of lines to show', parseInt)\n .action((service: string | undefined, options: { follow?: boolean; tail?: number }) => {\n return logsCommand(service, options);\n });\n\nprogram\n .command('restart [service]')\n .description('Restart services')\n .action(restartCommand);\n\nprogram\n .command('doctor')\n .description('Diagnose common issues')\n .action(doctorCommand);\n\nprogram\n .command('destroy')\n .description('Destroy the platform — remove all containers and volumes')\n .option('-f, --force', 'Skip confirmation prompt')\n .action((options: { force?: boolean }) => {\n return destroyCommand(options);\n });\n\nprogram\n .command('init')\n .description('Initialize platform (seed Logto apps, create admin user, setup database)')\n .action(() => {\n return initPlatform(getProjectDir());\n });\n\nregisterSeedCommand(program);\n\nprogram.parse();\n"]}
@@ -0,0 +1,499 @@
1
+ /**
2
+ * nhp-seed-dev.ts
3
+ *
4
+ * Standalone seed script for dev tooling — run inside the backend container:
5
+ * npx tsx scripts/nhp-seed-dev.ts <command> [flags]
6
+ *
7
+ * Commands:
8
+ * create-tenant --name <name> --slug <slug> [--description <desc>]
9
+ * create-app --name <name> --slug <slug> [--redirect-uri <uri>...] [--logout-uri <uri>...]
10
+ * [--cors-origin <origin>...] [--description <desc>] [--tenant <slug>]
11
+ * create-user --email <email> --password <pass> --tenant <slug>
12
+ * [--username <user>] [--display-name <name>] [--role <roleName>]
13
+ *
14
+ * Output: JSON on stdout. Errors go to stderr.
15
+ */
16
+
17
+ import { PrismaClient } from '@prisma/client';
18
+
19
+ const prisma = new PrismaClient();
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Simple arg parser: --key value or --key=value, repeated for arrays
23
+ // ---------------------------------------------------------------------------
24
+ function parseArgs(args: string[]): Record<string, string | string[]> {
25
+ const result: Record<string, string | string[]> = {};
26
+ let i = 0;
27
+ while (i < args.length) {
28
+ const arg = args[i];
29
+ if (arg.startsWith('--')) {
30
+ const eqIdx = arg.indexOf('=');
31
+ let key: string;
32
+ let value: string;
33
+ if (eqIdx !== -1) {
34
+ key = arg.slice(2, eqIdx);
35
+ value = arg.slice(eqIdx + 1);
36
+ i++;
37
+ } else {
38
+ key = arg.slice(2);
39
+ value = args[i + 1] ?? '';
40
+ i += 2;
41
+ }
42
+ const existing = result[key];
43
+ if (existing !== undefined) {
44
+ result[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
45
+ } else {
46
+ result[key] = value;
47
+ }
48
+ } else {
49
+ i++;
50
+ }
51
+ }
52
+ return result;
53
+ }
54
+
55
+ function asArray(v: string | string[] | undefined): string[] {
56
+ if (!v) return [];
57
+ return Array.isArray(v) ? v : [v];
58
+ }
59
+
60
+ function require(opts: Record<string, string | string[]>, key: string): string {
61
+ const v = opts[key];
62
+ if (!v || (typeof v !== 'string' && !Array.isArray(v))) {
63
+ throw new Error(`Missing required option: --${key}`);
64
+ }
65
+ return typeof v === 'string' ? v : v[0];
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Logto Management API client (mirrors LogtoAdminService, no NestJS DI)
70
+ // ---------------------------------------------------------------------------
71
+ class LogtoClient {
72
+ private readonly endpoint: string;
73
+ private readonly m2mAppId: string;
74
+ private readonly m2mAppSecret: string;
75
+ private readonly resourceIndicator: string;
76
+ private cachedToken: string | null = null;
77
+ private tokenExpiresAt = 0;
78
+
79
+ constructor() {
80
+ this.endpoint = process.env.LOGTO_ENDPOINT ?? '';
81
+ this.m2mAppId = process.env.LOGTO_M2M_APP_ID ?? '';
82
+ this.m2mAppSecret = process.env.LOGTO_M2M_APP_SECRET ?? '';
83
+ this.resourceIndicator =
84
+ process.env.LOGTO_MANAGEMENT_API_RESOURCE_INDICATOR ?? 'https://default.logto.app/api';
85
+
86
+ if (!this.endpoint || !this.m2mAppId || !this.m2mAppSecret) {
87
+ throw new Error(
88
+ 'Logto M2M credentials not configured. Ensure LOGTO_ENDPOINT, LOGTO_M2M_APP_ID and LOGTO_M2M_APP_SECRET are set.',
89
+ );
90
+ }
91
+ }
92
+
93
+ private async getToken(): Promise<string> {
94
+ if (this.cachedToken && Date.now() < this.tokenExpiresAt - 60_000) {
95
+ return this.cachedToken;
96
+ }
97
+ const credentials = Buffer.from(`${this.m2mAppId}:${this.m2mAppSecret}`).toString('base64');
98
+ const res = await fetch(`${this.endpoint}/oidc/token`, {
99
+ method: 'POST',
100
+ headers: {
101
+ 'Content-Type': 'application/x-www-form-urlencoded',
102
+ Authorization: `Basic ${credentials}`,
103
+ },
104
+ body: new URLSearchParams({
105
+ grant_type: 'client_credentials',
106
+ resource: this.resourceIndicator,
107
+ scope: 'all',
108
+ }),
109
+ });
110
+ if (!res.ok) throw new Error(`Logto token error: ${res.status} ${await res.text()}`);
111
+ const data = (await res.json()) as { access_token: string; expires_in: number };
112
+ this.cachedToken = data.access_token;
113
+ this.tokenExpiresAt = Date.now() + (data.expires_in ?? 3600) * 1000;
114
+ return this.cachedToken;
115
+ }
116
+
117
+ async request<T>(method: string, path: string, body?: unknown): Promise<T> {
118
+ const token = await this.getToken();
119
+ const res = await fetch(`${this.endpoint}/api${path}`, {
120
+ method,
121
+ headers: {
122
+ Authorization: `Bearer ${token}`,
123
+ ...(body ? { 'Content-Type': 'application/json' } : {}),
124
+ },
125
+ body: body ? JSON.stringify(body) : undefined,
126
+ });
127
+
128
+ if (res.status === 204) return null as T;
129
+
130
+ const text = await res.text();
131
+ if (!res.ok) {
132
+ throw new Error(`Logto API ${method} ${path} failed [${res.status}]: ${text}`);
133
+ }
134
+ if (!text) return null as T;
135
+ try {
136
+ return JSON.parse(text) as T;
137
+ } catch {
138
+ return null as T;
139
+ }
140
+ }
141
+ }
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // create-tenant
145
+ // ---------------------------------------------------------------------------
146
+ async function createTenant(opts: Record<string, string | string[]>) {
147
+ const name = require(opts, 'name');
148
+ const slug = require(opts, 'slug');
149
+ const description = (opts['description'] as string) || undefined;
150
+
151
+ process.stderr.write(`Creating tenant: ${slug} (${name})\n`);
152
+
153
+ const existing = await prisma.tenant.findUnique({ where: { slug } });
154
+ if (existing) throw new Error(`Tenant with slug "${slug}" already exists`);
155
+
156
+ const logto = new LogtoClient();
157
+ const logtoOrgId = `org_${slug.replace(/-/g, '_')}`;
158
+
159
+ process.stderr.write('Creating Logto organization...\n');
160
+ let logtoOrg: { id: string } | null = null;
161
+ try {
162
+ logtoOrg = await logto.request<{ id: string }>('POST', '/organizations', {
163
+ name,
164
+ description,
165
+ customData: { slug, type: 'tenant' },
166
+ });
167
+
168
+ // Logto may return null for 201 with just "Created" body — fetch by name
169
+ if (!logtoOrg) {
170
+ const orgs = await logto.request<Array<{ id: string; name: string }>>(
171
+ 'GET',
172
+ '/organizations',
173
+ );
174
+ logtoOrg = orgs.find((o) => o.name === name) ?? null;
175
+ }
176
+ if (!logtoOrg) throw new Error('Organization created but not retrievable');
177
+ } catch (err) {
178
+ throw new Error(`Failed to create Logto organization: ${(err as Error).message}`);
179
+ }
180
+
181
+ process.stderr.write(`Logto organization created: ${logtoOrg.id}\n`);
182
+
183
+ let tenant: { id: string; slug: string; displayName: string; logtoOrganizationId: string | null };
184
+ try {
185
+ tenant = await prisma.$transaction(async (tx) => {
186
+ const t = await tx.tenant.create({
187
+ data: {
188
+ slug,
189
+ displayName: name,
190
+ status: 'ACTIVE',
191
+ logtoOrganizationId: logtoOrg!.id,
192
+ ...(description ? { description } : {}),
193
+ },
194
+ });
195
+
196
+ // Auto-install default apps (launcher + organization-manager)
197
+ const defaultApps = await tx.application.findMany({
198
+ where: { slug: { in: ['launcher', 'organization-manager'] } },
199
+ include: {
200
+ versions: { where: { status: 'ACTIVE' }, orderBy: { createdAt: 'desc' }, take: 1 },
201
+ },
202
+ });
203
+
204
+ for (const app of defaultApps) {
205
+ if (app.versions.length > 0) {
206
+ await tx.tenantApplicationInstallation.create({
207
+ data: {
208
+ tenantId: t.id,
209
+ appId: app.id,
210
+ appVersionId: app.versions[0].id,
211
+ status: 'INSTALLED',
212
+ },
213
+ });
214
+ }
215
+ }
216
+
217
+ return t;
218
+ });
219
+ } catch (err) {
220
+ // Rollback Logto org
221
+ try {
222
+ await logto.request('DELETE', `/organizations/${logtoOrg.id}`);
223
+ } catch { /* ignore rollback error */ }
224
+ throw new Error(`Failed to create tenant in DB: ${(err as Error).message}`);
225
+ }
226
+
227
+ const result = {
228
+ id: tenant.id,
229
+ slug: tenant.slug,
230
+ displayName: tenant.displayName,
231
+ logtoOrganizationId: tenant.logtoOrganizationId,
232
+ };
233
+
234
+ process.stdout.write(JSON.stringify(result) + '\n');
235
+ }
236
+
237
+ // ---------------------------------------------------------------------------
238
+ // create-app
239
+ // ---------------------------------------------------------------------------
240
+ async function createApp(opts: Record<string, string | string[]>) {
241
+ const name = require(opts, 'name');
242
+ const slug = require(opts, 'slug');
243
+ const description = (opts['description'] as string) || undefined;
244
+ const tenantSlug = (opts['tenant'] as string) || undefined;
245
+ const redirectUris = asArray(opts['redirect-uri']);
246
+ const postLogoutRedirectUris = asArray(opts['logout-uri']);
247
+ const corsAllowedOrigins = asArray(opts['cors-origin']);
248
+
249
+ process.stderr.write(`Creating app: ${slug} (${name})\n`);
250
+
251
+ const existing = await prisma.application.findUnique({ where: { slug } });
252
+ if (existing) throw new Error(`Application with slug "${slug}" already exists`);
253
+
254
+ // Find the owner — use first available user (platform admin)
255
+ const owner = await prisma.user.findFirst({ orderBy: { createdAt: 'asc' } });
256
+ if (!owner) {
257
+ throw new Error('No users found in the platform DB. Run "habeetat init" first.');
258
+ }
259
+
260
+ const logto = new LogtoClient();
261
+
262
+ process.stderr.write('Creating Logto OIDC application...\n');
263
+ let logtoApp: { id: string; secret?: string } | null = null;
264
+ try {
265
+ logtoApp = await logto.request<{ id: string; secret?: string }>('POST', '/applications', {
266
+ name,
267
+ description: description ?? `Application: ${name}`,
268
+ type: 'SPA',
269
+ oidcClientMetadata: { redirectUris, postLogoutRedirectUris },
270
+ customClientMetadata: { corsAllowedOrigins },
271
+ isThirdParty: false,
272
+ });
273
+ if (!logtoApp) throw new Error('Logto application created but not retrievable');
274
+ } catch (err) {
275
+ throw new Error(`Failed to create Logto application: ${(err as Error).message}`);
276
+ }
277
+
278
+ process.stderr.write(`Logto OIDC app created: ${logtoApp.id}\n`);
279
+
280
+ let appId: string;
281
+ let versionId: string;
282
+ try {
283
+ const result = await prisma.$transaction(async (tx) => {
284
+ const app = await tx.application.create({
285
+ data: {
286
+ slug,
287
+ name,
288
+ description,
289
+ isInternal: true,
290
+ status: 'DRAFT',
291
+ ownerId: owner.id,
292
+ logtoAppId: logtoApp!.id,
293
+ redirectUris,
294
+ postLogoutRedirectUris,
295
+ corsAllowedOrigins,
296
+ },
297
+ });
298
+
299
+ // Always create an initial version so the app can be installed on tenants
300
+ const version = await tx.applicationVersion.create({
301
+ data: {
302
+ appId: app.id,
303
+ version: '1.0.0',
304
+ manifest: { name, slug, version: '1.0.0' },
305
+ status: 'ACTIVE',
306
+ },
307
+ });
308
+
309
+ return { app, version };
310
+ });
311
+ appId = result.app.id;
312
+ versionId = result.version.id;
313
+ } catch (err) {
314
+ // Rollback Logto app
315
+ try {
316
+ await logto.request('DELETE', `/applications/${logtoApp.id}`);
317
+ } catch { /* ignore */ }
318
+ throw new Error(`Failed to create application in DB: ${(err as Error).message}`);
319
+ }
320
+
321
+ // Optionally install on tenant
322
+ if (tenantSlug) {
323
+ process.stderr.write(`Installing app on tenant: ${tenantSlug}\n`);
324
+ const tenant = await prisma.tenant.findUnique({ where: { slug: tenantSlug } });
325
+ if (!tenant) {
326
+ process.stderr.write(`Warning: tenant "${tenantSlug}" not found — skipping installation\n`);
327
+ } else {
328
+ await prisma.tenantApplicationInstallation.upsert({
329
+ where: { tenantId_appId: { tenantId: tenant.id, appId } },
330
+ create: {
331
+ tenantId: tenant.id,
332
+ appId,
333
+ appVersionId: versionId,
334
+ status: 'INSTALLED',
335
+ },
336
+ update: { status: 'INSTALLED' },
337
+ });
338
+ }
339
+ }
340
+
341
+ const result = {
342
+ id: appId,
343
+ slug,
344
+ name,
345
+ logtoAppId: logtoApp.id,
346
+ redirectUris,
347
+ postLogoutRedirectUris,
348
+ corsAllowedOrigins,
349
+ tenantSlug: tenantSlug ?? null,
350
+ };
351
+
352
+ process.stdout.write(JSON.stringify(result) + '\n');
353
+ }
354
+
355
+ // ---------------------------------------------------------------------------
356
+ // create-user
357
+ // ---------------------------------------------------------------------------
358
+ async function createUser(opts: Record<string, string | string[]>) {
359
+ const email = require(opts, 'email');
360
+ const password = require(opts, 'password');
361
+ const tenantSlug = require(opts, 'tenant');
362
+ const username = (opts['username'] as string) || email.split('@')[0];
363
+ const displayName = (opts['display-name'] as string) || username;
364
+ const roleName = (opts['role'] as string) || 'TENANT_ADMIN';
365
+
366
+ process.stderr.write(`Creating user: ${email} in tenant: ${tenantSlug}\n`);
367
+
368
+ const tenant = await prisma.tenant.findUnique({ where: { slug: tenantSlug } });
369
+ if (!tenant) throw new Error(`Tenant "${tenantSlug}" not found`);
370
+ if (!tenant.logtoOrganizationId) {
371
+ throw new Error(`Tenant "${tenantSlug}" has no Logto organization ID`);
372
+ }
373
+
374
+ const logto = new LogtoClient();
375
+
376
+ // Check if user already exists
377
+ process.stderr.write('Checking if user already exists in Logto...\n');
378
+ const existingUsers = await logto.request<Array<{ id: string; primaryEmail?: string }>>(
379
+ 'GET',
380
+ `/users?search.primaryEmail=${encodeURIComponent(email)}`,
381
+ );
382
+ let logtoUserId: string;
383
+
384
+ if (existingUsers && existingUsers.find((u) => u.primaryEmail === email)) {
385
+ logtoUserId = existingUsers.find((u) => u.primaryEmail === email)!.id;
386
+ process.stderr.write(`User already exists in Logto: ${logtoUserId}\n`);
387
+ } else {
388
+ process.stderr.write('Creating user in Logto...\n');
389
+ const logtoUser = await logto.request<{ id: string } | null>('POST', '/users', {
390
+ primaryEmail: email,
391
+ password,
392
+ username,
393
+ name: displayName,
394
+ });
395
+
396
+ // Logto may return null for 201 with just "Created" — fetch by email
397
+ if (!logtoUser) {
398
+ const users = await logto.request<Array<{ id: string; primaryEmail?: string }>>(
399
+ 'GET',
400
+ `/users?search.primaryEmail=${encodeURIComponent(email)}`,
401
+ );
402
+ const found = users?.find((u) => u.primaryEmail === email);
403
+ if (!found) throw new Error('User created but not retrievable');
404
+ logtoUserId = found.id;
405
+ } else {
406
+ logtoUserId = logtoUser.id;
407
+ }
408
+ process.stderr.write(`Logto user created: ${logtoUserId}\n`);
409
+ }
410
+
411
+ // Add user to Logto organization
412
+ process.stderr.write(`Adding user to org: ${tenant.logtoOrganizationId}\n`);
413
+ try {
414
+ await logto.request('POST', `/organizations/${tenant.logtoOrganizationId}/users`, {
415
+ userIds: [logtoUserId],
416
+ });
417
+ } catch (err) {
418
+ const msg = (err as Error).message;
419
+ // Ignore "already member" type errors
420
+ if (!msg.includes('already') && !msg.includes('conflict') && !msg.includes('409')) {
421
+ throw new Error(`Failed to add user to organization: ${msg}`);
422
+ }
423
+ }
424
+
425
+ // Assign role in Logto organization
426
+ let roleAssigned = false;
427
+ try {
428
+ const orgRoles = await logto.request<Array<{ id: string; name: string }>>(
429
+ 'GET',
430
+ '/organization-roles',
431
+ );
432
+ const matchingRole = orgRoles?.find((r) => r.name === roleName);
433
+ if (matchingRole) {
434
+ await logto.request(
435
+ 'POST',
436
+ `/organizations/${tenant.logtoOrganizationId}/users/${logtoUserId}/roles`,
437
+ { organizationRoleIds: [matchingRole.id] },
438
+ );
439
+ roleAssigned = true;
440
+ process.stderr.write(`Role "${roleName}" assigned\n`);
441
+ } else {
442
+ process.stderr.write(
443
+ `Warning: organization role "${roleName}" not found in Logto — skipping role assignment\n`,
444
+ );
445
+ }
446
+ } catch (err) {
447
+ process.stderr.write(
448
+ `Warning: could not assign role "${roleName}": ${(err as Error).message}\n`,
449
+ );
450
+ }
451
+
452
+ // Note: the user record in platform DB is created automatically on first login
453
+ // via IdentityService.enrichUserContext (JWT-based auto-sync)
454
+
455
+ const result = {
456
+ logtoUserId,
457
+ email,
458
+ username,
459
+ displayName,
460
+ password,
461
+ tenantSlug,
462
+ role: roleName,
463
+ roleAssigned,
464
+ note: 'User will be synced to platform DB on first login',
465
+ };
466
+
467
+ process.stdout.write(JSON.stringify(result) + '\n');
468
+ }
469
+
470
+ // ---------------------------------------------------------------------------
471
+ // Entry point
472
+ // ---------------------------------------------------------------------------
473
+ async function main() {
474
+ const [, , command, ...rest] = process.argv;
475
+ const opts = parseArgs(rest);
476
+
477
+ switch (command) {
478
+ case 'create-tenant':
479
+ await createTenant(opts);
480
+ break;
481
+ case 'create-app':
482
+ await createApp(opts);
483
+ break;
484
+ case 'create-user':
485
+ await createUser(opts);
486
+ break;
487
+ default:
488
+ throw new Error(
489
+ `Unknown command: "${command}". Valid commands: create-tenant, create-app, create-user`,
490
+ );
491
+ }
492
+ }
493
+
494
+ main()
495
+ .catch((err: Error) => {
496
+ process.stderr.write(`\nError: ${err.message}\n`);
497
+ process.exit(1);
498
+ })
499
+ .finally(() => prisma.$disconnect());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@habeetat/cli",
3
- "version": "0.1.0-dev.20260324202418.70eccf7",
3
+ "version": "0.1.0-dev.20260324204704.66fdba5",
4
4
  "description": "Habeetat Platform CLI — manage your platform instances",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -16,7 +16,8 @@
16
16
  }
17
17
  },
18
18
  "files": [
19
- "dist"
19
+ "dist",
20
+ "scripts"
20
21
  ],
21
22
  "scripts": {
22
23
  "build": "tsup",