diff --git a/bun.lockb b/bun.lockb index c555ee57..8971ddf4 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/find-port.ts b/find-port.ts new file mode 100644 index 00000000..887273b3 --- /dev/null +++ b/find-port.ts @@ -0,0 +1,68 @@ +import getPort, { portNumbers } from 'get-port'; + +/** + * Mencari port yang tersedia dalam rentang tertentu. + * @param params - Parameter opsional untuk mencari port. + * @param params.count - Jumlah port yang dibutuhkan (default: 1). + * @param params.portStart - Awal rentang port (default: 3000). + * @param params.portEnd - Akhir rentang port (default: 6000). + * @param params.exclude - Daftar port yang harus dikecualikan. + * @returns Array port yang tersedia atau null jika tidak ada port yang cukup. + */ +async function findPort(params?: { count?: number, portStart?: number, portEnd?: number, exclude?: number[] }) { + const { count = 1, portStart = 3000, portEnd = 6000, exclude = [] } = params || {}; + + // Gabungkan port yang dikecualikan + const listPort = [...exclude]; // Hapus .flat() karena tidak diperlukan + const usedPorts = Array.from(new Set(listPort)) as number[]; + + // Validasi input + if (count <= 0) { + throw new Error('Count harus lebih besar dari 0'); + } + if (count > (portEnd - portStart + 1)) { + throw new Error(`Count tidak boleh lebih besar dari range port (${portEnd - portStart + 1})`); + } + if (portStart >= portEnd) { + throw new Error('portStart harus lebih kecil dari portEnd'); + } + if (portStart < 0 || portEnd > 65535) { + throw new Error('Port harus berada dalam rentang 0-65535'); + } + + // Optimasi pencarian port + const availablePorts = new Set(); + const portRange = portNumbers(portStart, portEnd); + const usedPortsSet = new Set(usedPorts); + + for (const port of portRange) { + if (availablePorts.size >= count) break; + + // Skip jika port sudah digunakan + if (usedPortsSet.has(port)) continue; + + try { + const availablePort = await getPort({ + port, + exclude: [...usedPorts, ...Array.from(availablePorts)], + }); + + // Pastikan port yang diperiksa berada dalam rentang yang ditentukan + if (availablePort === port && availablePort >= portStart && availablePort <= portEnd) { + availablePorts.add(port); + } + } catch (error) { + console.warn(`Gagal memeriksa port ${port}:`, error); + continue; // Lanjutkan ke port berikutnya + } + } + + // Jika tidak cukup port yang tersedia, lempar error + if (availablePorts.size < count) { + throw new Error('Tidak cukup port yang tersedia dalam rentang yang diberikan'); + } + + return Array.from(availablePorts); +} + +export default findPort; diff --git a/package.json b/package.json index f2c08e20..e65cce6e 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,11 @@ "@types/lodash": "^4.17.15", "add": "^2.0.6", "animate.css": "^4.1.1", - "compress-pdf": "^0.5.2", "elysia": "^1.2.12", "embla-carousel-autoplay": "^8.5.2", "embla-carousel-react": "^7.1.0", "framer-motion": "^12.4.1", + "get-port": "^7.1.0", "lodash": "^4.17.21", "motion": "^12.4.1", "next": "15.1.6", @@ -33,8 +33,6 @@ "prisma": "^6.3.1", "react": "^19.0.0", "react-dom": "^19.0.0", - "react-multi-carousel": "^2.8.5", - "react-scroll-motion": "^0.3.5", "readdirp": "^4.1.1", "swr": "^2.3.2", "valtio": "^2.1.3" diff --git a/src/com/main-page/content-5/index.tsx b/src/com/main-page/content-5/index.tsx index 3d166384..5587052b 100644 --- a/src/com/main-page/content-5/index.tsx +++ b/src/com/main-page/content-5/index.tsx @@ -1,18 +1,21 @@ "use client"; import { Center, Container, Stack, Text } from "@mantine/core"; import { useRef } from "react"; -import FlipOnScroll from "./FlipScroll"; + +const name = process.env.NEXT_PUBLIC_NAME; function Content5() { const ref = useRef(null); return ( + ini name + {name && {name}}
CONTENT 5
- +
); diff --git a/src/lib/EnvStringParse.ts b/src/lib/EnvStringParse.ts new file mode 100644 index 00000000..f7bec7fc --- /dev/null +++ b/src/lib/EnvStringParse.ts @@ -0,0 +1,53 @@ +type EnvVariable = { key: string; value: string }; + +class EnvStringParser { + /** + * Parses an environment string into a key-value object. + * @param envString - The environment string to parse. + * @param env - Optional custom environment variables (defaults to `process.env` in Node.js). + * @returns A Record containing parsed environment variables. + */ + static parse(envString: string, env: Record = process.env): Record { + const envVars: EnvVariable[] = []; + // Split the string into lines + const lines = envString.split(/\r?\n/); // Handle both \n and \r\n line endings + + for (const line of lines) { + const trimmedLine = line.trim(); + // Skip comments and empty lines + if (!trimmedLine || trimmedLine.startsWith("#")) continue; + + // Match key-value pairs with support for quoted values + const match = trimmedLine.match(/^([\w.-]+)=(?:"([^"]*)"|'([^']*)'|([^#\s]*))/); + if (!match) { + console.warn(`Skipping invalid line: ${trimmedLine}`); + continue; + } + + const key = match[1]; + let value = match[2] || match[3] || match[4] || ""; // Handle double quotes, single quotes, or unquoted values + + // Resolve environment variable placeholders like ${VAR_NAME} + value = value.replace(/\$\{(\w+)\}/g, (_, varName) => { + if (env[varName]) { + return env[varName]!; + } else { + console.warn(`Environment variable ${varName} is not defined`); + return ""; + } + }); + + envVars.push({ key, value }); + } + + // Convert array of EnvVariable objects into a Record + const envObj: Record = {}; + for (const { key, value } of envVars) { + envObj[key] = value; + } + + return envObj; + } +} + +export default EnvStringParser; \ No newline at end of file diff --git a/unknown/Library/Preferences/nextjs-nodejs/config.json b/unknown/Library/Preferences/nextjs-nodejs/config.json new file mode 100644 index 00000000..1b0837d0 --- /dev/null +++ b/unknown/Library/Preferences/nextjs-nodejs/config.json @@ -0,0 +1,7 @@ +{ + "telemetry": { + "notifiedAt": "1739668984025", + "anonymousId": "da4db3546c4d6315299db5f269034c4669decd44840966bd3dc435bc184f5d61", + "salt": "f26f15c27a3239f30152845755757b47" + } +} \ No newline at end of file diff --git a/xcoba.ts b/xcoba.ts index ccb480e0..3e52e3e3 100644 --- a/xcoba.ts +++ b/xcoba.ts @@ -1,11 +1,68 @@ -import path from 'path'; -import fs from 'fs'; -import { compress } from 'compress-pdf'; +import { spawn } from 'bun' -(async () => { - const pdf = path.resolve("/Users/bip/Downloads", 'komoditas.pdf'); - const buffer = await compress(pdf); +async function proc(params?: { + env?: Record + cmd?: string + cwd?: string + timeout?: number + onStdOut?: (chunk: string) => void + onStdErr?: (chunk: string) => void +}) { + const { env = {}, cmd, cwd = "./", timeout = 30000 } = params || {} + return new Promise(async (resolve, reject) => { + const std = { + stdout: "", + stderr: "", + } - const compressedPdf = path.resolve(__dirname, 'compressed_pdf.pdf'); - await fs.promises.writeFile(compressedPdf, buffer); -})(); \ No newline at end of file + if (!cmd) { + reject(new Error("cmd is required")) + return + } + + const decoder = new TextDecoder() + const child = spawn(["/bin/bash", "-c", cmd], { + cwd, + env: { + PATH: process.env.PATH, + ...env + }, + }) + + const timeOut = setTimeout(() => { + child.kill() + clearTimeout(timeOut) + reject("timeout") + }, timeout) + + const resOut = new Response(child.stdout) + const resErr = new Response(child.stderr) + + if (resOut && resOut.body) { + for await (const chunk of resOut.body as unknown as AsyncIterable) { + const text = decoder.decode(chunk) + std.stdout += text + if (params?.onStdOut) { + params.onStdOut(text) + } + } + } + + if (resErr && resErr.body) { + for await (const chunk of resErr.body as unknown as AsyncIterable) { + const text = decoder.decode(chunk) + std.stderr += text + params?.onStdErr?.(text) + } + } + + clearTimeout(timeOut) + if (!child.killed) { + child.kill() + } + + resolve(std) + }) +} + +export default proc \ No newline at end of file diff --git a/xcoba2.ts b/xcoba2.ts new file mode 100644 index 00000000..526397ef --- /dev/null +++ b/xcoba2.ts @@ -0,0 +1,104 @@ +import { spawn } from 'bun'; + +async function proc(params?: { + env?: Record; + cmd?: string; + cwd?: string; + timeout?: number; + exitCode?: number; + onStdOut?: (chunk: string) => void; + onStdErr?: (chunk: string) => void; + onStdio?: (chunk: string) => void; +}) { + const { env = {}, cmd, cwd = "./", timeout = 600000 } = params || {}; + return new Promise(async (resolve, reject) => { + if (!cmd || typeof cmd !== "string") { + return reject(new Error("Invalid or missing command")); + } + + const std = { + stdout: "", + stderr: "", + stdio: "", + }; + + try { + // Spawn the child process + const child = spawn(cmd.split(" "), { + cwd, + env: { + PATH: process.env.PATH, + ...env, + }, + }); + + // Set a timeout to kill the process if it takes too long + const timeOut = setTimeout(() => { + try { + child.kill(); + } catch (err) { + console.warn("Failed to kill child process:", err); + } + reject(new Error("Process timed out")); + }, timeout); + + // Read stdout and stderr as text + const [stdout, stderr] = await Promise.all([ + readStream(child.stdout), + child.stderr ? readStream(child.stderr) : undefined, + ]); + + // Handle stdout + std.stdout = stdout; + std.stdio += stdout; + if (params?.onStdOut) { + params.onStdOut(stdout.trim()); + } + if (params?.onStdio) { + params.onStdio(stdout.trim()); + } + + // Handle stderr + std.stderr = stderr ?? ""; + std.stdio += stderr; + if (params?.onStdErr) { + params.onStdErr((stderr ?? "").trim()); + } + if (params?.onStdio) { + params.onStdio((stderr ?? "").trim()); + } + + clearTimeout(timeOut); + resolve(std); + } catch (err) { + reject(err); + } + }); +} + +async function readStream(stream: ReadableStream): Promise { + const reader = stream.getReader(); + const decoder = new TextDecoder(); + let result = ''; + let done = false; + + while (!done) { + const { value, done: streamDone } = await reader.read(); + done = streamDone; + if (value) { + result += decoder.decode(value, { stream: true }); + } + } + result += decoder.decode(); // flush any remaining data + return result.trim(); +} + +export default proc; + +proc({ + cmd: "bun run build", + cwd: "./", + onStdio: (text) => { + console.log(text.trim()); + } +}) \ No newline at end of file