tabahan
This commit is contained in:
68
find-port.ts
Normal file
68
find-port.ts
Normal file
@@ -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<number>();
|
||||||
|
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;
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
"@types/lodash": "^4.17.15",
|
"@types/lodash": "^4.17.15",
|
||||||
"add": "^2.0.6",
|
"add": "^2.0.6",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"compress-pdf": "^0.5.2",
|
|
||||||
"elysia": "^1.2.12",
|
"elysia": "^1.2.12",
|
||||||
"embla-carousel-autoplay": "^8.5.2",
|
"embla-carousel-autoplay": "^8.5.2",
|
||||||
"embla-carousel-react": "^7.1.0",
|
"embla-carousel-react": "^7.1.0",
|
||||||
"framer-motion": "^12.4.1",
|
"framer-motion": "^12.4.1",
|
||||||
|
"get-port": "^7.1.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"motion": "^12.4.1",
|
"motion": "^12.4.1",
|
||||||
"next": "15.1.6",
|
"next": "15.1.6",
|
||||||
@@ -33,8 +33,6 @@
|
|||||||
"prisma": "^6.3.1",
|
"prisma": "^6.3.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-multi-carousel": "^2.8.5",
|
|
||||||
"react-scroll-motion": "^0.3.5",
|
|
||||||
"readdirp": "^4.1.1",
|
"readdirp": "^4.1.1",
|
||||||
"swr": "^2.3.2",
|
"swr": "^2.3.2",
|
||||||
"valtio": "^2.1.3"
|
"valtio": "^2.1.3"
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { Center, Container, Stack, Text } from "@mantine/core";
|
import { Center, Container, Stack, Text } from "@mantine/core";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import FlipOnScroll from "./FlipScroll";
|
|
||||||
|
const name = process.env.NEXT_PUBLIC_NAME;
|
||||||
|
|
||||||
function Content5() {
|
function Content5() {
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack ref={ref}>
|
<Stack ref={ref}>
|
||||||
|
ini name
|
||||||
|
{name && <Text>{name}</Text>}
|
||||||
<Container w={{ base: "100%", md: "80%" }} p={"xl"} h={720}>
|
<Container w={{ base: "100%", md: "80%" }} p={"xl"} h={720}>
|
||||||
<Center>
|
<Center>
|
||||||
<Text fz={"3.4rem"}>CONTENT 5</Text>
|
<Text fz={"3.4rem"}>CONTENT 5</Text>
|
||||||
</Center>
|
</Center>
|
||||||
<FlipOnScroll />
|
|
||||||
</Container>
|
</Container>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
53
src/lib/EnvStringParse.ts
Normal file
53
src/lib/EnvStringParse.ts
Normal file
@@ -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<string, string> containing parsed environment variables.
|
||||||
|
*/
|
||||||
|
static parse(envString: string, env: Record<string, string | undefined> = process.env): Record<string, string> {
|
||||||
|
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<string, string>
|
||||||
|
const envObj: Record<string, string> = {};
|
||||||
|
for (const { key, value } of envVars) {
|
||||||
|
envObj[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return envObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EnvStringParser;
|
||||||
7
unknown/Library/Preferences/nextjs-nodejs/config.json
Normal file
7
unknown/Library/Preferences/nextjs-nodejs/config.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"telemetry": {
|
||||||
|
"notifiedAt": "1739668984025",
|
||||||
|
"anonymousId": "da4db3546c4d6315299db5f269034c4669decd44840966bd3dc435bc184f5d61",
|
||||||
|
"salt": "f26f15c27a3239f30152845755757b47"
|
||||||
|
}
|
||||||
|
}
|
||||||
75
xcoba.ts
75
xcoba.ts
@@ -1,11 +1,68 @@
|
|||||||
import path from 'path';
|
import { spawn } from 'bun'
|
||||||
import fs from 'fs';
|
|
||||||
import { compress } from 'compress-pdf';
|
|
||||||
|
|
||||||
(async () => {
|
async function proc(params?: {
|
||||||
const pdf = path.resolve("/Users/bip/Downloads", 'komoditas.pdf');
|
env?: Record<string, string | undefined>
|
||||||
const buffer = await compress(pdf);
|
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');
|
if (!cmd) {
|
||||||
await fs.promises.writeFile(compressedPdf, buffer);
|
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<Uint8Array>) {
|
||||||
|
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<Uint8Array>) {
|
||||||
|
const text = decoder.decode(chunk)
|
||||||
|
std.stderr += text
|
||||||
|
params?.onStdErr?.(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(timeOut)
|
||||||
|
if (!child.killed) {
|
||||||
|
child.kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(std)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default proc
|
||||||
104
xcoba2.ts
Normal file
104
xcoba2.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import { spawn } from 'bun';
|
||||||
|
|
||||||
|
async function proc(params?: {
|
||||||
|
env?: Record<string, string | undefined>;
|
||||||
|
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<Uint8Array>): Promise<string> {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user