@zalkera/cli 0.26.0 → 0.28.0

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/dist/main.js +171 -135
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -700,17 +700,25 @@ var ZalkeraApi = class _ZalkeraApi {
700
700
  return this.request("GET", `/api/partner/site-preset/presets/${encodeURIComponent(code2)}/source-url`);
701
701
  }
702
702
  /**
703
- * 버전 이력(최신순). B2「현재 사이트 내려받기」와 롤백이 여기서 대상을 고른다.
703
+ * 버전 이력 **전량**(최신순). B2「현재 사이트 내려받기」와 롤백이 여기서 대상을 고른다.
704
704
  *
705
- * @param limit **최근 몇 개만** 받을지. 없으면 전량이다.
705
+ * 🔴 **상한을 못 받는다.** 방향 판정(memo191)이 「이 내용이 원장에 처음 나타난 번호」를 세는데,
706
+ * 잘린 페이지로 세면 앞부분이 안 보여 그 번호가 **거짓**이 된다. 그리고 그 거짓은 화면에서
707
+ * 「서버가 더 최신」 같은 단정적인 낱말로 나온다. 상한이 필요한 자리는 [listRecentRevisions] 다 —
708
+ * 한 메서드에 선택 인자로 두면 잘린 목록이 원장 자리로 흘러들어도 타입이 안 막는다.
709
+ */
710
+ listRevisions() {
711
+ return this.request("GET", "/api/partner/site-upload/revisions");
712
+ }
713
+ /**
714
+ * **최근 [limit] 건만.** 목록을 보여 주는 자리용이다 — 원장 판정에 쓰면 안 된다([listRevisions]).
706
715
  *
707
716
  * ⚠ **판은 발행할 때마다 늘고 줄지 않는다.** 몇 개면 되는 소비자가 전량을 받으면 그 비용이 원장
708
717
  * 크기에 비례해 영원히 자란다 — 반영 확인 폴링이 그 자리다(판 1,000개 테넌트에서 매 폴마다
709
718
  * 전량). 구 서버는 이 파라미터를 **조용히 무시**하고 전량을 준다 — 동작은 종전과 같다.
710
719
  */
711
- listRevisions(limit) {
712
- const path = "/api/partner/site-upload/revisions";
713
- return this.request("GET", limit == null ? path : `${path}?limit=${limit}`);
720
+ listRecentRevisions(limit) {
721
+ return this.request("GET", `/api/partner/site-upload/revisions?limit=${limit}`);
714
722
  }
715
723
  /** 소스 tar.gz 다운로드 URL **+ sha256**(TENANT_ADMIN+). 소스 소유의 실물이고, 해시가 그 약속의 검산이다. */
716
724
  sourceUrl(revisionNo) {
@@ -1911,6 +1919,14 @@ function serializeSyncLedger(ledger) {
1911
1919
 
1912
1920
  // ../core/dist/localMark.js
1913
1921
  import { join as join9 } from "node:path";
1922
+
1923
+ // ../core/dist/sourceVersion.js
1924
+ var VERSION_DIGEST_PATTERN = /^[0-9a-f]{64}$/;
1925
+ function isVersionDigest(value) {
1926
+ return typeof value === "string" && VERSION_DIGEST_PATTERN.test(value);
1927
+ }
1928
+
1929
+ // ../core/dist/localMark.js
1914
1930
  var SOURCE_MARK_PATH = ".zalkera/source.json";
1915
1931
  var TENANT_CODE = /^[a-z0-9][a-z0-9-]{0,62}$/;
1916
1932
  var MAX_REVISION_NO = 2147483647;
@@ -1943,7 +1959,14 @@ function parseSourceMark(text) {
1943
1959
  return null;
1944
1960
  if (typeof o.fetchedAt !== "string")
1945
1961
  return null;
1946
- return { format: 1, tenant: o.tenant, revisionNo: o.revisionNo, sha256: o.sha256, fetchedAt: o.fetchedAt };
1962
+ return {
1963
+ format: 1,
1964
+ tenant: o.tenant,
1965
+ revisionNo: o.revisionNo,
1966
+ sha256: o.sha256,
1967
+ fetchedAt: o.fetchedAt,
1968
+ ...baselineFields(o)
1969
+ };
1947
1970
  }
1948
1971
  if (o.format === 2 && o.origin === "published") {
1949
1972
  if (typeof o.revisionNo !== "number" || !Number.isInteger(o.revisionNo))
@@ -1955,7 +1978,8 @@ function parseSourceMark(text) {
1955
1978
  origin: "published",
1956
1979
  tenant: o.tenant,
1957
1980
  revisionNo: o.revisionNo,
1958
- publishedAt: o.publishedAt
1981
+ publishedAt: o.publishedAt,
1982
+ ...baselineFields(o)
1959
1983
  };
1960
1984
  }
1961
1985
  if (o.format === 2 && o.origin === "linked") {
@@ -1965,6 +1989,16 @@ function parseSourceMark(text) {
1965
1989
  }
1966
1990
  return null;
1967
1991
  }
1992
+ function baselineFields(o) {
1993
+ const out = {};
1994
+ if (isVersionDigest(o.folderVersion))
1995
+ out.folderVersion = o.folderVersion;
1996
+ if (isVersionDigest(o.serverVersion))
1997
+ out.serverVersion = o.serverVersion;
1998
+ if (typeof o.tool === "string" && o.tool.length > 0 && o.tool.length <= 64)
1999
+ out.tool = o.tool;
2000
+ return out;
2001
+ }
1968
2002
  async function writeSourceMarkTo(root, mark) {
1969
2003
  return writeMarkText(root, buildSourceMark(mark));
1970
2004
  }
@@ -2155,6 +2189,126 @@ var MAX_RAW_BYTES = 300 * 1024 * 1024;
2155
2189
 
2156
2190
  // ../core/dist/publish.js
2157
2191
  init_errors();
2192
+
2193
+ // ../core/dist/serverNormalization.js
2194
+ var EXCLUDED_PREFIXES2 = [".git/", "node_modules/", ".github/workflows/"];
2195
+ var SECRET_FILE_NAMES = /* @__PURE__ */ new Set([
2196
+ "authorized_keys",
2197
+ "known_hosts",
2198
+ "netrc",
2199
+ "htpasswd",
2200
+ "shadow",
2201
+ "credentials",
2202
+ "credentials.json",
2203
+ "credentials.yml",
2204
+ "credentials.yaml",
2205
+ "secrets.json",
2206
+ "secrets.yml",
2207
+ "secrets.yaml",
2208
+ "database.yml",
2209
+ "database.yaml",
2210
+ "wp-config.php"
2211
+ ]);
2212
+ var SECRET_BASE_NAMES = /* @__PURE__ */ new Set([
2213
+ "id_rsa",
2214
+ "id_dsa",
2215
+ "id_ecdsa",
2216
+ "id_ed25519",
2217
+ "id_ecdsa_sk",
2218
+ "id_ed25519_sk"
2219
+ ]);
2220
+ var SECRET_EXTENSIONS = /* @__PURE__ */ new Set([
2221
+ "pem",
2222
+ "key",
2223
+ "p12",
2224
+ "pfx",
2225
+ "jks",
2226
+ "keystore",
2227
+ "kdbx",
2228
+ "ppk",
2229
+ "ovpn",
2230
+ "env",
2231
+ "tfstate",
2232
+ "tfvars",
2233
+ "gpg",
2234
+ "pgp"
2235
+ ]);
2236
+ var ENV_KEEP_SUFFIXES = [".example", ".sample", ".template"];
2237
+ var SERVER_NORMALIZATION_SETS = {
2238
+ prefixes: EXCLUDED_PREFIXES2,
2239
+ secretFileNames: [...SECRET_FILE_NAMES],
2240
+ secretBaseNames: [...SECRET_BASE_NAMES],
2241
+ secretExtensions: [...SECRET_EXTENSIONS],
2242
+ envKeepSuffixes: ENV_KEEP_SUFFIXES
2243
+ };
2244
+
2245
+ // ../core/dist/workdir.js
2246
+ init_errors();
2247
+ import { createReadStream as createReadStream2 } from "node:fs";
2248
+ import { createHash as createHash5 } from "node:crypto";
2249
+ import { lstat as lstat3, readdir as readdir3 } from "node:fs/promises";
2250
+ import { join as join11, sep as sep4 } from "node:path";
2251
+ async function hashWorkdir(root, options = {}) {
2252
+ const manifest = {};
2253
+ const cap = Math.min(options.maxEntries ?? MAX_ENTRIES, MAX_ENTRIES);
2254
+ let seen = 0;
2255
+ async function walk(dir, prefix) {
2256
+ const entries = await readdir3(dir, { withFileTypes: true }).catch((error) => {
2257
+ if (error?.code === "ENOENT")
2258
+ return [];
2259
+ throw error;
2260
+ });
2261
+ for (const item of entries) {
2262
+ const relative5 = prefix === "" ? item.name : `${prefix}/${item.name}`;
2263
+ if (isExcludedEntry(relative5))
2264
+ continue;
2265
+ if (item.isSymbolicLink())
2266
+ continue;
2267
+ if (item.isDirectory()) {
2268
+ await walk(join11(dir, item.name), relative5);
2269
+ continue;
2270
+ }
2271
+ if (!item.isFile())
2272
+ continue;
2273
+ seen += 1;
2274
+ if (seen > cap) {
2275
+ throw new DevtoolsError("LOCAL_TOO_LARGE", `\uC774 \uD3F4\uB354\uC758 \uD30C\uC77C\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4(${cap}\uAC1C \uCD08\uACFC).`, "\uC0AC\uC774\uD2B8 \uD3F4\uB354\uAC00 \uC544\uB2CC \uACF3\uC744 \uAC00\uB9AC\uD0A4\uACE0 \uC788\uC9C0 \uC54A\uC740\uC9C0 \uD655\uC778\uD574 \uC8FC\uC138\uC694.");
2276
+ }
2277
+ manifest[relative5] = { sha256: await hashFile(join11(dir, item.name)) };
2278
+ }
2279
+ }
2280
+ await walk(root, "");
2281
+ return manifest;
2282
+ }
2283
+ async function hashFile(path) {
2284
+ const hash = createHash5("sha256");
2285
+ for await (const chunk of createReadStream2(path))
2286
+ hash.update(chunk);
2287
+ return hash.digest("hex");
2288
+ }
2289
+ async function resolveExisting(root, path) {
2290
+ if (path === "" || path.includes("\0"))
2291
+ return null;
2292
+ const segments = path.split("/").filter((s) => s !== "");
2293
+ if (segments.length === 0)
2294
+ return null;
2295
+ if (segments.some((s) => s === "." || s === ".." || s.includes(sep4)))
2296
+ return null;
2297
+ let current = root;
2298
+ for (const part of segments) {
2299
+ const next = join11(current, part);
2300
+ const info = await lstat3(next).catch(() => null);
2301
+ if (!info || info.isSymbolicLink())
2302
+ return null;
2303
+ current = next;
2304
+ }
2305
+ return current;
2306
+ }
2307
+
2308
+ // ../core/dist/folderVersion.js
2309
+ var TEMPLATE_SCAN_MAX_BYTES = 256 * 1024;
2310
+
2311
+ // ../core/dist/publish.js
2158
2312
  var MAX_ARCHIVE_BYTES = 100 * 1024 * 1024;
2159
2313
  var TRANSFER_TIMEOUT_MS = 15 * 60 * 1e3;
2160
2314
 
@@ -2216,7 +2370,7 @@ async function startDevServerWithEnv(options, storefrontKey, envName) {
2216
2370
  }
2217
2371
 
2218
2372
  // ../core/dist/fetchSource.js
2219
- import { createHash as createHash5 } from "node:crypto";
2373
+ import { createHash as createHash6 } from "node:crypto";
2220
2374
  init_errors();
2221
2375
 
2222
2376
  // ../core/dist/fetchTarget.js
@@ -2297,11 +2451,11 @@ async function fetchVerifiedSourceTar(options) {
2297
2451
  if (!source.sha256) {
2298
2452
  throw new DevtoolsError("SERVER_REJECTED", "\uC11C\uBC84\uAC00 \uBB34\uACB0\uC131 \uD574\uC2DC\uB97C \uC8FC\uC9C0 \uC54A\uC544 \uC18C\uC2A4\uB97C \uAC80\uC99D\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "\uC798\uCEE4\uB77C\uC5D0 \uBB38\uC758\uD574 \uC8FC\uC138\uC694. \uAC80\uC99D \uC5C6\uC774 \uC9C4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
2299
2453
  }
2300
- const actual = createHash5("sha256").update(buffer).digest("hex");
2454
+ const actual = createHash6("sha256").update(buffer).digest("hex");
2301
2455
  if (actual !== source.sha256) {
2302
2456
  throw new DevtoolsError("SERVER_REJECTED", "\uBC1B\uC740 \uC18C\uC2A4\uAC00 \uC6D0\uBCF8\uACFC \uB2E4\uB985\uB2C8\uB2E4(\uBB34\uACB0\uC131 \uD655\uC778 \uC2E4\uD328).", "\uB124\uD2B8\uC6CC\uD06C \uBB38\uC81C\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.");
2303
2457
  }
2304
- return { revisionNo, buffer, sha256: source.sha256 };
2458
+ return { revisionNo, buffer, sha256: source.sha256, versionDigest: source.versionDigest ?? null };
2305
2459
  }
2306
2460
 
2307
2461
  // ../core/dist/unzip.js
@@ -2323,7 +2477,7 @@ init_notice();
2323
2477
  // ../core/dist/npmChoice.js
2324
2478
  import { execFileSync } from "node:child_process";
2325
2479
  import { existsSync as existsSync7, realpathSync } from "node:fs";
2326
- import { delimiter as delimiter2, isAbsolute as isAbsolute2, join as join11, normalize as normalize3, sep as sep4 } from "node:path";
2480
+ import { delimiter as delimiter2, isAbsolute as isAbsolute2, join as join12, normalize as normalize3, sep as sep5 } from "node:path";
2327
2481
  var MIN_SYSTEM_NPM_MAJOR = 9;
2328
2482
  function majorOf(version2) {
2329
2483
  const m = /^(\d+)\./.exec((version2 ?? "").trim());
@@ -2386,7 +2540,7 @@ function npmArgvOf(choice, nodePath) {
2386
2540
  return null;
2387
2541
  }
2388
2542
  }
2389
- var PATH_OPS = { join: join11, isAbsolute: isAbsolute2, normalize: normalize3, sep: sep4 };
2543
+ var PATH_OPS = { join: join12, isAbsolute: isAbsolute2, normalize: normalize3, sep: sep5 };
2390
2544
  function probeSystemNpm(nodePath, excludeUnder = [], env = process.env) {
2391
2545
  const entries = (env.PATH ?? "").split(delimiter2);
2392
2546
  for (const step of systemNpmSearchSteps(entries, PATH_OPS, excludeUnder)) {
@@ -2465,12 +2619,12 @@ var UPGRADE_NOTICE_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2465
2619
 
2466
2620
  // ../core/dist/tokenPath.js
2467
2621
  import { homedir as homedir2 } from "node:os";
2468
- import { isAbsolute as isAbsolute3, join as join12, resolve as resolve5, sep as sep5 } from "node:path";
2622
+ import { isAbsolute as isAbsolute3, join as join13, resolve as resolve5, sep as sep6 } from "node:path";
2469
2623
  function tokenPath(env = process.env, home = homedir2()) {
2470
- const fallback = join12(home, ".config");
2624
+ const fallback = join13(home, ".config");
2471
2625
  const base = env.XDG_CONFIG_HOME;
2472
- const inside = base !== void 0 && isAbsolute3(base) && (resolve5(base) === resolve5(home) || resolve5(base).startsWith(resolve5(home) + sep5));
2473
- return join12(inside ? resolve5(base) : fallback, "zalkera", "auth.json");
2626
+ const inside = base !== void 0 && isAbsolute3(base) && (resolve5(base) === resolve5(home) || resolve5(base).startsWith(resolve5(home) + sep6));
2627
+ return join13(inside ? resolve5(base) : fallback, "zalkera", "auth.json");
2474
2628
  }
2475
2629
 
2476
2630
  // ../core/dist/index.js
@@ -2514,124 +2668,6 @@ init_notice();
2514
2668
  // ../core/dist/sidebarPlan.js
2515
2669
  init_notice();
2516
2670
 
2517
- // ../core/dist/serverNormalization.js
2518
- var EXCLUDED_PREFIXES2 = [".git/", "node_modules/", ".github/workflows/"];
2519
- var SECRET_FILE_NAMES = /* @__PURE__ */ new Set([
2520
- "authorized_keys",
2521
- "known_hosts",
2522
- "netrc",
2523
- "htpasswd",
2524
- "shadow",
2525
- "credentials",
2526
- "credentials.json",
2527
- "credentials.yml",
2528
- "credentials.yaml",
2529
- "secrets.json",
2530
- "secrets.yml",
2531
- "secrets.yaml",
2532
- "database.yml",
2533
- "database.yaml",
2534
- "wp-config.php"
2535
- ]);
2536
- var SECRET_BASE_NAMES = /* @__PURE__ */ new Set([
2537
- "id_rsa",
2538
- "id_dsa",
2539
- "id_ecdsa",
2540
- "id_ed25519",
2541
- "id_ecdsa_sk",
2542
- "id_ed25519_sk"
2543
- ]);
2544
- var SECRET_EXTENSIONS = /* @__PURE__ */ new Set([
2545
- "pem",
2546
- "key",
2547
- "p12",
2548
- "pfx",
2549
- "jks",
2550
- "keystore",
2551
- "kdbx",
2552
- "ppk",
2553
- "ovpn",
2554
- "env",
2555
- "tfstate",
2556
- "tfvars",
2557
- "gpg",
2558
- "pgp"
2559
- ]);
2560
- var ENV_KEEP_SUFFIXES = [".example", ".sample", ".template"];
2561
- var SERVER_NORMALIZATION_SETS = {
2562
- prefixes: EXCLUDED_PREFIXES2,
2563
- secretFileNames: [...SECRET_FILE_NAMES],
2564
- secretBaseNames: [...SECRET_BASE_NAMES],
2565
- secretExtensions: [...SECRET_EXTENSIONS],
2566
- envKeepSuffixes: ENV_KEEP_SUFFIXES
2567
- };
2568
-
2569
- // ../core/dist/workdir.js
2570
- init_errors();
2571
- import { createReadStream as createReadStream2 } from "node:fs";
2572
- import { createHash as createHash6 } from "node:crypto";
2573
- import { lstat as lstat3, readdir as readdir3 } from "node:fs/promises";
2574
- import { join as join13, sep as sep6 } from "node:path";
2575
- async function hashWorkdir(root, options = {}) {
2576
- const manifest = {};
2577
- const cap = Math.min(options.maxEntries ?? MAX_ENTRIES, MAX_ENTRIES);
2578
- let seen = 0;
2579
- async function walk(dir, prefix) {
2580
- const entries = await readdir3(dir, { withFileTypes: true }).catch((error) => {
2581
- if (error?.code === "ENOENT")
2582
- return [];
2583
- throw error;
2584
- });
2585
- for (const item of entries) {
2586
- const relative5 = prefix === "" ? item.name : `${prefix}/${item.name}`;
2587
- if (isExcludedEntry(relative5))
2588
- continue;
2589
- if (item.isSymbolicLink())
2590
- continue;
2591
- if (item.isDirectory()) {
2592
- await walk(join13(dir, item.name), relative5);
2593
- continue;
2594
- }
2595
- if (!item.isFile())
2596
- continue;
2597
- seen += 1;
2598
- if (seen > cap) {
2599
- throw new DevtoolsError("LOCAL_TOO_LARGE", `\uC774 \uD3F4\uB354\uC758 \uD30C\uC77C\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4(${cap}\uAC1C \uCD08\uACFC).`, "\uC0AC\uC774\uD2B8 \uD3F4\uB354\uAC00 \uC544\uB2CC \uACF3\uC744 \uAC00\uB9AC\uD0A4\uACE0 \uC788\uC9C0 \uC54A\uC740\uC9C0 \uD655\uC778\uD574 \uC8FC\uC138\uC694.");
2600
- }
2601
- manifest[relative5] = { sha256: await hashFile(join13(dir, item.name)) };
2602
- }
2603
- }
2604
- await walk(root, "");
2605
- return manifest;
2606
- }
2607
- async function hashFile(path) {
2608
- const hash = createHash6("sha256");
2609
- for await (const chunk of createReadStream2(path))
2610
- hash.update(chunk);
2611
- return hash.digest("hex");
2612
- }
2613
- async function resolveExisting(root, path) {
2614
- if (path === "" || path.includes("\0"))
2615
- return null;
2616
- const segments = path.split("/").filter((s) => s !== "");
2617
- if (segments.length === 0)
2618
- return null;
2619
- if (segments.some((s) => s === "." || s === ".." || s.includes(sep6)))
2620
- return null;
2621
- let current = root;
2622
- for (const part of segments) {
2623
- const next = join13(current, part);
2624
- const info = await lstat3(next).catch(() => null);
2625
- if (!info || info.isSymbolicLink())
2626
- return null;
2627
- current = next;
2628
- }
2629
- return current;
2630
- }
2631
-
2632
- // ../core/dist/folderVersion.js
2633
- var TEMPLATE_SCAN_MAX_BYTES = 256 * 1024;
2634
-
2635
2671
  // ../core/dist/pullPlan.js
2636
2672
  function planPull(input) {
2637
2673
  const { incoming, ledger, local } = input;
@@ -3903,7 +3939,7 @@ async function main(argv) {
3903
3939
  case "status": {
3904
3940
  const context = await openContext(common);
3905
3941
  const draft = await context.api.draftFiles().catch(() => null);
3906
- const active = await context.api.listRevisions(20).then((rows) => rows.find((r) => r.isActive)?.revisionNo ?? null).catch(() => null);
3942
+ const active = await context.api.listRecentRevisions(20).then((rows) => rows.find((r) => r.isActive)?.revisionNo ?? null).catch(() => null);
3907
3943
  const ledger = await readLedger(context.folder);
3908
3944
  const status = syncStatus({
3909
3945
  ledger,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zalkera/cli",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "잘커라 사이트 소스를 터미널에서 받고·올리고·발행합니다. 편집기 없이, 스크립트에서도.",
5
5
  "license": "MIT",
6
6
  "type": "module",