chiwaa 0.1.7 → 0.1.9
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/README.md +1 -0
- package/bin/chiwaa.js +70 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ npx chiwaa deploy
|
|
|
23
23
|
| `chiwaa stats` | 방문자 통계(오늘·최근 7일·많이 본 페이지·들어온 곳) |
|
|
24
24
|
| `chiwaa deploy --preview` | 운영 주소는 두고 `이름--preview.chiwaa.com` 에 미리보기 |
|
|
25
25
|
| `chiwaa env` · `env set 이름` · `env rm 이름` | 서버 함수(`api/*.js`) 비밀값 — 값은 화면에 안 보이게 입력 |
|
|
26
|
+
| `chiwaa logs` | 서버 함수 기록(오류·console.log) |
|
|
26
27
|
| `chiwaa lock` / `unlock` | 사이트 비밀번호 잠금(공개 전 나만 보기) |
|
|
27
28
|
| `chiwaa open` · `usage` | 관리 화면 열기 · 이번 달 사용량 |
|
|
28
29
|
| `chiwaa agent` | AI 도구용 안내(AGENTS.md·CLAUDE.md) 만들기 — 처음 deploy 때 자동 |
|
package/bin/chiwaa.js
CHANGED
|
@@ -92,7 +92,7 @@ function parseArgs(argv) {
|
|
|
92
92
|
if (a.startsWith("--")) {
|
|
93
93
|
const [k, v] = a.slice(2).split("=", 2);
|
|
94
94
|
if (v !== undefined) out[k] = v;
|
|
95
|
-
else if (["name", "token", "dir", "read", "write", "page", "days"].includes(k) && argv[i + 1] && !argv[i + 1].startsWith("-")) out[k] = argv[++i];
|
|
95
|
+
else if (["name", "token", "dir", "read", "write", "page", "days", "lines"].includes(k) && argv[i + 1] && !argv[i + 1].startsWith("-")) out[k] = argv[++i];
|
|
96
96
|
else out[k] = true;
|
|
97
97
|
} else if (a === "-y") out.yes = true;
|
|
98
98
|
else if (a === "-h") out.help = true;
|
|
@@ -326,6 +326,7 @@ function agentSection(name) {
|
|
|
326
326
|
- 글 저장(문의·방명록·게시판)은 사이트 DB: \`npx chiwaa db on\` → \`npx chiwaa db create <표> --read public|owner --write public|owner\`.
|
|
327
327
|
- 문의·신청서처럼 개인정보가 든 표는 반드시 \`--read owner\`. 사이트에서 안 읽힌다고 public 으로 바꾸지 않는다.
|
|
328
328
|
- 방문자 글은 화면에 \`textContent\` 로만 넣는다. 비밀번호는 \`<input type="password">\` 로 받는다.
|
|
329
|
+
- 사진 첨부(게시판·후기)는 \`npx chiwaa files on\` 뒤 폼에 \`<input type="file" name="사진">\`, 주인 사진은 \`npx chiwaa files put 사진.jpg\`.
|
|
329
330
|
- 로그인 토큰(~/.chiwaa/config.json, CHIWAA_TOKEN)은 출력하거나 파일·저장소에 적지 않는다.
|
|
330
331
|
- 자세한 규칙·예시: https://chiwaa.kr/llms.txt — 처음 작업하거나 헷갈리면 먼저 읽는다.
|
|
331
332
|
${AGENT_END}`;
|
|
@@ -670,6 +671,26 @@ async function stats(args) {
|
|
|
670
671
|
if (!s.total.views) console.log(c.dim("\n 아직 집계된 방문이 없습니다."));
|
|
671
672
|
}
|
|
672
673
|
|
|
674
|
+
// ---------- logs (서버 함수 기록) ----------
|
|
675
|
+
async function logs(args) {
|
|
676
|
+
const name = await siteName(args);
|
|
677
|
+
const n = Math.min(Math.max(parseInt(args.lines, 10) || 30, 1), 500);
|
|
678
|
+
const r = await api("GET", `/api/v1/sites/${encodeURIComponent(name)}/logs?lines=${n}${args.preview ? "&preview=1" : ""}`);
|
|
679
|
+
if (r.status !== 200) fail(r.data.error || "기록을 받지 못했습니다.");
|
|
680
|
+
const d = r.data;
|
|
681
|
+
console.log(c.bold(`${d.site} 서버 함수 기록`), c.dim(`(최근 ${n}건 · 1분쯤 늦을 수 있음)`));
|
|
682
|
+
if (d.functions.length) console.log(c.dim(` 함수: ${d.functions.map((f) => "/api/" + f).join(" ")}`));
|
|
683
|
+
if (!d.entries.length) return console.log(c.dim(" 아직 기록이 없습니다. 오류가 나거나 console.log 를 쓰면 여기에 남습니다."));
|
|
684
|
+
for (const e of d.entries) {
|
|
685
|
+
const when = new Date(e.t);
|
|
686
|
+
const p2 = (x) => String(x).padStart(2, "0");
|
|
687
|
+
const t = isNaN(when) ? e.t : `${p2(when.getMonth() + 1)}-${p2(when.getDate())} ${p2(when.getHours())}:${p2(when.getMinutes())}:${p2(when.getSeconds())}`;
|
|
688
|
+
const st = e.status >= 500 ? c.red(String(e.status)) : String(e.status);
|
|
689
|
+
console.log(`${c.dim(t)} /api/${e.fn} ${st}${e.ms != null ? c.dim(` ${e.ms}ms`) : ""}${e.error ? " " + c.red(e.error) : ""}`);
|
|
690
|
+
for (const l of e.logs || []) console.log(` ${l}`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
673
694
|
// ---------- env (서버 함수 비밀값) ----------
|
|
674
695
|
async function env(args) {
|
|
675
696
|
const sub = args._[1] || "ls";
|
|
@@ -704,6 +725,51 @@ async function env(args) {
|
|
|
704
725
|
fail(`모르는 env 명령입니다: ${sub}\n 쓸 수 있는 것: ls · set · rm`);
|
|
705
726
|
}
|
|
706
727
|
|
|
728
|
+
// ---------- files (사진) ----------
|
|
729
|
+
// 지우기는 CLI 로 열지 않는다(웹 화면에서만, DB 와 같은 원칙)
|
|
730
|
+
const mbKo = (b) => (b >= 1048576 ? `${(b / 1048576).toFixed(1)}MB` : `${Math.ceil(b / 1024)}KB`);
|
|
731
|
+
async function files(args) {
|
|
732
|
+
const sub = args._[1] || "ls";
|
|
733
|
+
const name = await siteName(args);
|
|
734
|
+
const base = `/api/v1/sites/${encodeURIComponent(name)}/files`;
|
|
735
|
+
if (sub === "ls") {
|
|
736
|
+
const page = Math.max(parseInt(args.page, 10) || 1, 1);
|
|
737
|
+
const r = await api("GET", `${base}?page=${page}`);
|
|
738
|
+
if (r.status !== 200) fail(r.data.error || "사진 목록을 받지 못했습니다.");
|
|
739
|
+
const d = r.data;
|
|
740
|
+
const cap = d.limit_mb >= 1024 ? `${d.limit_mb / 1024}GB` : `${d.limit_mb}MB`;
|
|
741
|
+
console.log(c.bold(`${name}.chiwaa.com 사진`), c.dim(`· ${d.total}장 · ${mbKo(d.bytes)} / ${cap} · 방문자 사진 올리기 ${d.visitors ? "켜짐" : "꺼짐"}`));
|
|
742
|
+
for (const it of d.items || [])
|
|
743
|
+
console.log(` ${it.id} ${c.dim(`${it.width}×${it.height} ${mbKo(it.bytes)} · ${it.pinned ? "내가 올림" : it.record_id ? `글 #${it.record_id}` : "글에 안 쓰임(24시간 뒤 지움)"}`)} ${d.site}${it.url}`);
|
|
744
|
+
if (!(d.items || []).length) console.log(c.dim(" 없음. 올리기: npx chiwaa files put 사진.jpg · 방문자 올리기 켜기: npx chiwaa files on"));
|
|
745
|
+
if (d.total > page * d.per_page) console.log(c.dim(`다음 쪽: npx chiwaa files ls --page ${page + 1}`));
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
if (sub === "on" || sub === "off") {
|
|
749
|
+
const r = await api("POST", `${base}/${sub}`);
|
|
750
|
+
if (r.status !== 200) fail(r.data.error || "바꾸지 못했습니다.");
|
|
751
|
+
return console.log(c.green("✓"), r.data.message);
|
|
752
|
+
}
|
|
753
|
+
if (sub === "put") {
|
|
754
|
+
const paths = args._.slice(2);
|
|
755
|
+
if (!paths.length) fail("올릴 사진 파일을 적어 주세요. 예: npx chiwaa files put 상품1.jpg 상품2.jpg");
|
|
756
|
+
for (const f of paths) {
|
|
757
|
+
let buf;
|
|
758
|
+
try {
|
|
759
|
+
buf = fs.readFileSync(f);
|
|
760
|
+
} catch {
|
|
761
|
+
fail(`파일을 읽지 못했습니다: ${f}`);
|
|
762
|
+
}
|
|
763
|
+
const r = await api("POST", base, { body: buf, headers: { "Content-Type": "application/octet-stream" } });
|
|
764
|
+
if (r.status !== 201) fail(`${f}: ${r.data.error || "올리지 못했습니다."}`);
|
|
765
|
+
console.log(c.green("✓"), `${f} → ${c.cyan(r.data.full_url)}`, c.dim(`(${r.data.width}×${r.data.height} ${mbKo(r.data.bytes)}, 작은 그림 ${r.data.thumb})`));
|
|
766
|
+
}
|
|
767
|
+
return console.log(c.dim("\n이 주소를 그대로 <img src> 에 쓰면 됩니다. 브라우저에 맞춰 AVIF·WebP 로 나갑니다."));
|
|
768
|
+
}
|
|
769
|
+
fail(`모르는 files 명령입니다: ${sub}
|
|
770
|
+
쓸 수 있는 것: ls · put · on · off (지우기는 chiwaa.kr 사이트 화면 「DB」에서)`);
|
|
771
|
+
}
|
|
772
|
+
|
|
707
773
|
// ---------- lock / unlock / open / usage ----------
|
|
708
774
|
function readSecret(prompt) {
|
|
709
775
|
if (!process.stdin.isTTY) {
|
|
@@ -804,6 +870,8 @@ const HELP = `chiwaa ${VERSION} — chiwaa.kr 에 사이트를 바로 올립니
|
|
|
804
870
|
chiwaa domains add <도메인> 도메인 붙이기(x-y.net 도메인은 바로, 다른 곳 도메인은 넣을 DNS 레코드 안내)
|
|
805
871
|
chiwaa domains check 연결됐는지 확인 · domains remove -y 로 연결 끊기
|
|
806
872
|
chiwaa stats 방문자 통계(오늘·최근 7일, 많이 본 페이지, 들어온 곳) --days 30
|
|
873
|
+
chiwaa files 사진 목록·용량 · files put 사진.jpg(주인 사진 올리기) · files on|off(방문자 사진 올리기)
|
|
874
|
+
chiwaa logs 서버 함수 기록(오류·console.log) --lines 100, --preview
|
|
807
875
|
chiwaa env 서버 함수 비밀값 목록 · env set 이름(값은 안 보이게 입력) · env rm 이름
|
|
808
876
|
chiwaa lock / unlock 사이트 비밀번호 잠금(아이디 chiwaa) / 풀기 — 공개 전 나만 보기
|
|
809
877
|
chiwaa open 관리 화면 열기 (--site 는 사이트 열기)
|
|
@@ -821,7 +889,7 @@ async function main() {
|
|
|
821
889
|
const cmd = args._[0];
|
|
822
890
|
if (args.version) return console.log(VERSION);
|
|
823
891
|
if (args.help || !cmd || cmd === "help") return console.log(HELP);
|
|
824
|
-
const cmds = { deploy, login, list, ls: list, versions, rollback, db, domains, domain: domains, stats, env, lock, unlock, open, usage, agent, whoami, logout };
|
|
892
|
+
const cmds = { deploy, login, list, ls: list, versions, rollback, db, files, domains, domain: domains, stats, env, logs, lock, unlock, open, usage, agent, whoami, logout };
|
|
825
893
|
if (!cmds[cmd]) fail(`모르는 명령입니다: ${cmd}\n\n${HELP}`);
|
|
826
894
|
await cmds[cmd](args);
|
|
827
895
|
}
|