chiwaa 0.1.13 → 0.1.14

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.
Files changed (2) hide show
  1. package/bin/chiwaa.js +60 -23
  2. package/package.json +1 -1
package/bin/chiwaa.js CHANGED
@@ -124,32 +124,65 @@ async function login(args) {
124
124
  console.log(c.green("✓"), `${me.data.user} 계정으로 로그인했습니다.`);
125
125
  return;
126
126
  }
127
- const s = await api("POST", "/api/v1/login", { auth: false });
128
- if (s.status !== 200) fail(s.data.error || "로그인을 시작하지 못했습니다.");
129
- console.log(`브라우저에서 아래 주소를 열고 코드를 확인한 뒤 ${c.bold("승인")}을 눌러 주세요.\n`);
130
- console.log(` ${c.cyan(s.data.verify_url)}`);
131
- console.log(` 코드: ${c.bold(s.data.user_code)}\n`);
132
- if (!args["no-browser"]) openBrowser(s.data.verify_url);
133
- const until = Date.now() + s.data.expires_in * 1000;
127
+ // 앞서 시작한 로그인이 아직 살아 있으면 새 코드를 만들지 않고 이어서 기다린다(AI 도구가 대기 중에 명령을 끊는 경우)
128
+ if (await resumePendingLogin()) return;
129
+ let s = readJSON(PENDING_FILE);
130
+ const resumed = !!s;
131
+ if (!s) {
132
+ const r = await api("POST", "/api/v1/login", { auth: false });
133
+ if (r.status !== 200) fail(r.data.error || "로그인을 시작하지 못했습니다.");
134
+ s = { ...r.data, until: Date.now() + r.data.expires_in * 1000 };
135
+ fs.mkdirSync(CONF_DIR, { recursive: true });
136
+ fs.writeFileSync(PENDING_FILE, JSON.stringify(s), { mode: 0o600 });
137
+ }
138
+ console.log(`브라우저에서 아래 주소를 열고 코드를 확인한 뒤 ${c.bold("승인")}을 눌러 주세요.${resumed ? c.dim(" (앞서 연 로그인을 이어서 기다립니다)") : ""}\n`);
139
+ console.log(` ${c.cyan(s.verify_url)}`);
140
+ console.log(` 코드: ${c.bold(s.user_code)}\n`);
141
+ console.log(c.dim(`승인할 때까지 이 명령이 기다립니다(최대 ${Math.ceil((s.until - Date.now()) / 60000)}분). 중간에 끊겼으면 같은 명령을 다시 실행하면 이어집니다 — 다시 승인할 필요 없음.`));
142
+ if (!args["no-browser"] && !resumed) openBrowser(s.verify_url);
134
143
  process.stdout.write(c.dim("승인을 기다리는 중…"));
135
- while (Date.now() < until) {
136
- await new Promise((r) => setTimeout(r, (s.data.interval || 3) * 1000));
137
- const p = await api("POST", "/api/v1/login/poll", { auth: false, body: { device_code: s.data.device_code } });
138
- if (p.status === 200 && p.data.token) {
139
- saveToken(p.data.token);
140
- process.stdout.write("\n");
141
- console.log(c.green("✓"), `${p.data.user} 계정으로 로그인했습니다.`);
142
- return;
143
- }
144
- if (p.status !== 202) {
145
- process.stdout.write("\n");
146
- fail(p.data.error || "로그인하지 못했습니다.");
147
- }
144
+ while (Date.now() < s.until) {
145
+ await new Promise((r) => setTimeout(r, (s.interval || 3) * 1000));
146
+ const done = await pollLogin(s);
147
+ if (done === "wait") continue;
148
+ process.stdout.write("\n");
149
+ if (done) return console.log(c.green("✓"), `${done} 계정으로 로그인했습니다.`);
150
+ fail("로그인하지 못했습니다. 다시 `chiwaa login` 해 주세요.");
148
151
  }
152
+ fs.rmSync(PENDING_FILE, { force: true });
149
153
  process.stdout.write("\n");
150
154
  fail("시간이 지났습니다. 다시 `chiwaa login` 해 주세요.");
151
155
  }
152
156
 
157
+ // 로그인 승인을 한 번 확인한다: 계정 이름(성공) · "wait"(아직) · null(끝남, 대기 파일 지움)
158
+ const PENDING_FILE = path.join(CONF_DIR, "login-pending.json");
159
+ async function pollLogin(s) {
160
+ const p = await api("POST", "/api/v1/login/poll", { auth: false, body: { device_code: s.device_code } });
161
+ if (p.status === 202) return "wait";
162
+ fs.rmSync(PENDING_FILE, { force: true });
163
+ if (p.status === 200 && p.data.token) {
164
+ saveToken(p.data.token);
165
+ return p.data.user || "내";
166
+ }
167
+ return null;
168
+ }
169
+
170
+ // 승인은 했는데 기다리던 명령이 끊긴 경우: 다음 명령에서 승인 결과를 받아 로그인을 마친다
171
+ async function resumePendingLogin() {
172
+ const s = readJSON(PENDING_FILE);
173
+ if (!s || token()) return false;
174
+ if (!(s.until > Date.now())) {
175
+ fs.rmSync(PENDING_FILE, { force: true });
176
+ return false;
177
+ }
178
+ const done = await pollLogin(s);
179
+ if (done && done !== "wait") {
180
+ console.log(c.green("✓"), `앞서 승인한 로그인을 이어받았습니다(${done} 계정).`);
181
+ return true;
182
+ }
183
+ return false;
184
+ }
185
+
153
186
  // ---------- tar.gz (의존성 없이 직접 만든다) ----------
154
187
  function tarHeader(name, size, mode, type, mtime) {
155
188
  const b = Buffer.alloc(512);
@@ -475,7 +508,7 @@ async function deploy(args) {
475
508
  const dir = path.resolve(args._[1] || ".");
476
509
  if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) fail(`폴더가 없습니다: ${dir}`);
477
510
  if (!token()) {
478
- if (!TTY) fail("로그인이 필요합니다. 먼저 아래 명령으로 로그인하고(브라우저에서 승인), 같은 배포 명령을 다시 실행하세요.\n\n npx chiwaa login\n\n (자동화·AI 도구에서는 환경변수 CHIWAA_TOKEN 으로도 됩니다)");
511
+ if (!TTY) fail("로그인이 필요합니다. 먼저 아래 명령으로 로그인하고(브라우저에서 승인), 같은 배포 명령을 다시 실행하세요.\n\n npx chiwaa login\n\n (login 은 승인할 때까지 기다리는 명령입니다. 끊겼으면 다시 실행하면 같은 승인을 이어서 기다립니다. 자동화에서는 환경변수 CHIWAA_TOKEN 으로도 됩니다)");
479
512
  await login(args);
480
513
  }
481
514
  const site = await resolveSite(dir, args);
@@ -569,7 +602,7 @@ function snippet(table, read, write) {
569
602
  <button type="submit">보내기</button>
570
603
  </form>
571
604
 
572
- <!-- 글 목록 보기(읽기 권한이 public 일 때) -->
605
+ ${read === "public" ? `<!-- 글 목록 보기 -->
573
606
  <ul id="${table}-list"></ul>
574
607
  <script>
575
608
  chiwaa.table("${table}").list({ limit: 20 }).then(function (items) {
@@ -582,7 +615,10 @@ function snippet(table, read, write) {
582
615
  });
583
616
  </script>
584
617
 
585
- <!-- 스크립트로 직접:
618
+ ` : `<!-- 읽기가 「나만」이라 받은 글을 사이트에 보여 주지 않습니다(목록을 붙이지 마세요).
619
+ 받은 글 보기: chiwaa.kr → 내 사이트 → 이 사이트 「자세히」 → 「DB」 → ${table} 줄의 「데이터 보기」, 또는 npx chiwaa db rows ${table} -->
620
+
621
+ `}<!-- 스크립트로 직접:
586
622
  chiwaa.table("${table}").add({ 제목, 내용, _pw }) 글쓰기(_pw 를 넣으면 그 비밀번호로 수정·삭제 가능)
587
623
  chiwaa.table("${table}").list({ limit: 20, before: 마지막id }) 목록(최신순, 다음 쪽은 before)
588
624
  chiwaa.table("${table}").get(id) 글 하나(상세 화면)
@@ -1019,6 +1055,7 @@ async function main() {
1019
1055
  if (args.help || !cmd || cmd === "help") return console.log(HELP);
1020
1056
  const cmds = { deploy, login, list, ls: list, versions, rollback, db, files, domains, domain: domains, stats, env, logs, lock, unlock, open, usage, agent, whoami, logout };
1021
1057
  if (!cmds[cmd]) fail(`모르는 명령입니다: ${cmd}\n\n${HELP}`);
1058
+ if (cmd !== "login" && cmd !== "logout") await resumePendingLogin();
1022
1059
  await cmds[cmd](args);
1023
1060
  }
1024
1061
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chiwaa",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "chiwaa.kr 에 사이트를 터미널에서 바로 올리는 도구",
5
5
  "bin": {
6
6
  "chiwaa": "bin/chiwaa.js"