runlot 0.1.0-rc.21 → 0.1.0-rc.22

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/index.js +48 -186
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -5609,7 +5609,7 @@ var Client = class {
5609
5609
  *
5610
5610
  * **데이터베이스가 없으면 409 `database_required`** 다 — 가입자 표가
5611
5611
  * 프로젝트 DB 안이라 부여만 세우면 워커가 뜨는 순간 표가 없다. 부르는 쪽은
5612
- * 그 코드를 잡아 `runlot pg create` 안내한다.
5612
+ * 그 코드를 잡아 `"database": true` 선언을 안내한다 — 배포는 순서로 이 코드를 안 본다.
5613
5613
  */
5614
5614
  grantAuth(org, name) {
5615
5615
  return this.json("POST", `${this.projectPath(org, name)}/auth`);
@@ -6444,30 +6444,6 @@ function saveCredentialsFor(apiUrl, creds) {
6444
6444
  function projectConfigPath(dir) {
6445
6445
  return join2(resolve2(dir), "runlot.json");
6446
6446
  }
6447
- function recordStorageBinding(dir) {
6448
- const path = projectConfigPath(dir);
6449
- const cfg = loadProjectConfig(dir);
6450
- if (cfg.storage === true) return false;
6451
- cfg.storage = true;
6452
- writeFileSync(path, JSON.stringify(cfg, null, 2) + "\n");
6453
- return true;
6454
- }
6455
- function recordAuthBinding(dir) {
6456
- const path = projectConfigPath(dir);
6457
- const cfg = loadProjectConfig(dir);
6458
- if (cfg.auth === true) return false;
6459
- cfg.auth = true;
6460
- writeFileSync(path, JSON.stringify(cfg, null, 2) + "\n");
6461
- return true;
6462
- }
6463
- function recordDatabaseBinding(dir) {
6464
- const path = projectConfigPath(dir);
6465
- const cfg = loadProjectConfig(dir);
6466
- if (cfg.database === true) return false;
6467
- cfg.database = true;
6468
- writeFileSync(path, JSON.stringify(cfg, null, 2) + "\n");
6469
- return true;
6470
- }
6471
6447
  function loadProjectConfig(dir) {
6472
6448
  const path = projectConfigPath(dir);
6473
6449
  let raw;
@@ -7077,17 +7053,6 @@ function formatBytes(n) {
7077
7053
  }
7078
7054
  async function storageCommand(sub, rest, deps) {
7079
7055
  switch (sub) {
7080
- case "create":
7081
- case "grant": {
7082
- const dir = rest[0] ?? ".";
7083
- const { org, project } = deps.target(dir);
7084
- const st = await deps.client().grantStorage(org, project);
7085
- if (deps.record(dir)) console.log(`runlot.json \uC5D0 "storage": true \uB97C \uAE30\uB85D\uD588\uC2B5\uB2C8\uB2E4`);
7086
- console.log(
7087
- `${org}/${project} \uC758 \uC2A4\uD1A0\uB9AC\uC9C0\uAC00 \uC900\uBE44\uB410\uC2B5\uB2C8\uB2E4. Worker \uC5D0\uC11C\uB294 env.storage \uB85C \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4 (\uC0C1\uD55C ${formatBytes(st.quotaBytes)}).`
7088
- );
7089
- return 0;
7090
- }
7091
7056
  case "status":
7092
7057
  case void 0: {
7093
7058
  const { org, project } = deps.target(rest[0] ?? ".");
@@ -7097,7 +7062,9 @@ async function storageCommand(sub, rest, deps) {
7097
7062
  return 0;
7098
7063
  }
7099
7064
  if (!st.granted) {
7100
- console.log(`${org}/${project} \uC5D0\uB294 \uC2A4\uD1A0\uB9AC\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \`runlot storage create\` \uB85C \uCF24 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`);
7065
+ console.log(
7066
+ `${org}/${project} \uC5D0\uB294 \uC2A4\uD1A0\uB9AC\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. runlot.json \uC5D0 "storage": true \uB97C \uC801\uACE0 \uBC30\uD3EC\uD558\uBA74 \uCF1C\uC9D1\uB2C8\uB2E4.`
7067
+ );
7101
7068
  return 0;
7102
7069
  }
7103
7070
  console.log(`${org}/${project} ${formatBytes(st.usedBytes)} / ${formatBytes(st.quotaBytes)} ${st.prefix}`);
@@ -7413,7 +7380,7 @@ function describeSettings(s) {
7413
7380
  function describeAuth(org, project, st) {
7414
7381
  const out = [org + "/" + project];
7415
7382
  if (!st.granted) {
7416
- out.push(" \uB85C\uADF8\uC778 \uAEBC\uC9D0", " `runlot auth create` \uB85C \uCF24 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
7383
+ out.push(" \uB85C\uADF8\uC778 \uAEBC\uC9D0", ' runlot.json \uC5D0 "auth": true \uB97C \uC801\uACE0 \uBC30\uD3EC\uD558\uBA74 \uCF1C\uC9D1\uB2C8\uB2E4.');
7417
7384
  return out;
7418
7385
  }
7419
7386
  out.push(" \uB85C\uADF8\uC778 \uCF1C\uC9D0");
@@ -7448,33 +7415,6 @@ function describeAuth(org, project, st) {
7448
7415
  }
7449
7416
  async function authCommand(sub, rest, deps) {
7450
7417
  switch (sub) {
7451
- case "create":
7452
- case "grant": {
7453
- const dir = rest[0] ?? ".";
7454
- const { org, project } = deps.target(dir);
7455
- let st;
7456
- try {
7457
- st = await deps.client().grantAuth(org, project);
7458
- } catch (err) {
7459
- if (err instanceof ApiError && err.code === "database_required") {
7460
- throw new Error(
7461
- `${org}/${project} \uC5D0\uB294 \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uAC00\uC785\uC790 \uD14C\uC774\uBE14\uC774 \uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uC548\uC5D0 \uC788\uC73C\uBBC0\uB85C \uB85C\uADF8\uC778\uC740 \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uAC00 \uC788\uC5B4\uC57C \uCF24 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \`runlot pg create\` \uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uAC70\uB098 \`runlot add pg auth\` \uB85C \uD55C \uBC88\uC5D0 \uCF1C\uC138\uC694.`
7462
- );
7463
- }
7464
- throw err;
7465
- }
7466
- if (deps.record(dir)) console.log(`runlot.json \uC5D0 "auth": true \uB97C \uAE30\uB85D\uD588\uC2B5\uB2C8\uB2E4`);
7467
- console.log(
7468
- `${org}/${project} \uC758 \uB85C\uADF8\uC778\uC774 \uC900\uBE44\uB410\uC2B5\uB2C8\uB2E4. Worker \uC5D0\uC11C\uB294 env.auth.user(request) \uB85C \uC77D\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`
7469
- );
7470
- console.log("\uB85C\uADF8\uC778 \uD654\uBA74\uC740 /__runlot/auth/sign-in \uC785\uB2C8\uB2E4.");
7471
- if (st.providers.length === 0) {
7472
- console.log(
7473
- "\uC18C\uC15C \uB85C\uADF8\uC778\uC744 \uC4F0\uB824\uBA74 `runlot auth provider set github --client-id <id>` \uCC98\uB7FC \uB4F1\uB85D\uD558\uC138\uC694."
7474
- );
7475
- }
7476
- return 0;
7477
- }
7478
7418
  case "status":
7479
7419
  case void 0: {
7480
7420
  const { org, project } = deps.target(rest[0] ?? ".");
@@ -7511,7 +7451,7 @@ async function authCommand(sub, rest, deps) {
7511
7451
  }
7512
7452
  default:
7513
7453
  throw new Error(
7514
- `\uBAA8\uB974\uB294 auth \uD558\uC704 \uBA85\uB839\uC785\uB2C8\uB2E4: ${sub ?? "(\uC5C6\uC74C)"} \u2014 create | status | provider | set | delete \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4. \uB2E4\uB978 \uB514\uB809\uD1A0\uB9AC\uB97C \uBCF4\uB824\uBA74 \`runlot auth status <dir>\` \uCC98\uB7FC \uB4A4\uC5D0 \uC801\uC73C\uC138\uC694.`
7454
+ `\uBAA8\uB974\uB294 auth \uD558\uC704 \uBA85\uB839\uC785\uB2C8\uB2E4: ${sub ?? "(\uC5C6\uC74C)"} \u2014 status | provider | set | delete \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4. \uB2E4\uB978 \uB514\uB809\uD1A0\uB9AC\uB97C \uBCF4\uB824\uBA74 \`runlot auth status <dir>\` \uCC98\uB7FC \uB4A4\uC5D0 \uC801\uC73C\uC138\uC694.`
7515
7455
  );
7516
7456
  }
7517
7457
  }
@@ -7597,45 +7537,6 @@ async function providerCommand(sub, rest, deps) {
7597
7537
  }
7598
7538
  }
7599
7539
 
7600
- // src/add.ts
7601
- var ADD_NAMES = ["pg", "auth", "storage"];
7602
- var ORDER = ADD_NAMES;
7603
- var BINDING = {
7604
- pg: "env.db",
7605
- auth: "env.auth",
7606
- storage: "env.storage"
7607
- };
7608
- function parseAdd(args) {
7609
- const picked = /* @__PURE__ */ new Set();
7610
- let i = 0;
7611
- while (i < args.length && ADD_NAMES.includes(args[i])) {
7612
- picked.add(args[i]);
7613
- i++;
7614
- }
7615
- const rest = args.slice(i);
7616
- if (picked.size === 0) {
7617
- if (rest.length === 0) {
7618
- throw new Error(`\uC0AC\uC6A9\uBC95: runlot add <${ADD_NAMES.join("|")}>... [dir] (\uD558\uB098 \uC774\uC0C1 \uC9C0\uC815\uD569\uB2C8\uB2E4)`);
7619
- }
7620
- throw new Error(`\uBAA8\uB974\uB294 \uC774\uB984\uC785\uB2C8\uB2E4: ${rest[0]} \u2014 ${ADD_NAMES.join(" | ")} \uC911\uC5D0\uC11C \uACE0\uB974\uC138\uC694`);
7621
- }
7622
- if (rest.length > 1) {
7623
- throw new Error(`\uBAA8\uB974\uB294 \uC774\uB984\uC785\uB2C8\uB2E4: ${rest[0]} \u2014 ${ADD_NAMES.join(" | ")} \uC911\uC5D0\uC11C \uACE0\uB974\uC138\uC694`);
7624
- }
7625
- return { names: ORDER.filter((n) => picked.has(n)), dir: rest[0] ?? "." };
7626
- }
7627
- async function addCommand(args, deps) {
7628
- const { names, dir } = parseAdd(args);
7629
- const plan = [...names];
7630
- if (plan.includes("auth") && !plan.includes("pg") && !await deps.hasDatabase(dir)) {
7631
- plan.unshift("pg");
7632
- deps.log("\uB85C\uADF8\uC778\uC740 \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uAC00 \uC788\uC5B4\uC57C \uCF24 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB3C4 \uD568\uAED8 \uCF2D\uB2C8\uB2E4.");
7633
- }
7634
- for (const name of plan) await deps.create(name, dir);
7635
- deps.log(`${plan.map((n) => BINDING[n]).join(" \xB7 ")} \uB97C \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4`);
7636
- return 0;
7637
- }
7638
-
7639
7540
  // src/pg.ts
7640
7541
  import { readFileSync as readFileSync4 } from "node:fs";
7641
7542
  import { join as join3 } from "node:path";
@@ -8235,7 +8136,6 @@ var ALL_GROUPS = [
8235
8136
  "pg",
8236
8137
  "storage",
8237
8138
  "auth",
8238
- "add",
8239
8139
  "access",
8240
8140
  "secret",
8241
8141
  "domain",
@@ -8256,7 +8156,6 @@ var PROJECT_GROUPS = [
8256
8156
  "pg",
8257
8157
  "storage",
8258
8158
  "auth",
8259
- "add",
8260
8159
  "access",
8261
8160
  "secret",
8262
8161
  "domain",
@@ -8270,7 +8169,7 @@ var PROJECT_GROUPS = [
8270
8169
  "repo"
8271
8170
  ];
8272
8171
  var USAGE_HEAD = "runlot \u2014 \uC571 \uBC30\uD3EC\uC640 PostgreSQL \uAD00\uB9AC\uB97C \uC704\uD55C CLI";
8273
- var CLI_VERSION = true ? "0.1.0-rc.21 (aefe0bd)" : "dev";
8172
+ var CLI_VERSION = true ? "0.1.0-rc.22 (45e8e51)" : "dev";
8274
8173
  var USAGE_BODY = [
8275
8174
  { text: " runlot login \uBE0C\uB77C\uC6B0\uC800\uB85C \uB85C\uADF8\uC778\uD569\uB2C8\uB2E4 (GitHub \uB4F1)" },
8276
8175
  { text: " runlot login <\uC774\uB984> \uB85C\uCEEC \uAC1C\uBC1C\uC6A9 \uB85C\uADF8\uC778 (\uAC1C\uBC1C \uC11C\uBC84\uC5D0\uC11C\uB9CC)" },
@@ -8279,13 +8178,11 @@ var USAGE_BODY = [
8279
8178
  { text: " runlot org list \uCC38\uC5EC \uC911\uC778 \uC870\uC9C1 \uBAA9\uB85D", groups: ["org"] },
8280
8179
  { text: " runlot project create <name> \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4ED\uB2C8\uB2E4 (--org \uD544\uC694)", groups: ["project"] },
8281
8180
  { text: " runlot project list \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D (--org \uD544\uC694)", groups: ["project"] },
8282
- { text: " runlot add <pg|auth|storage>\u2026 [dir] \uD544\uC694\uD55C \uAE30\uB2A5\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4 (\uC5EC\uB7EC \uAC1C\uB97C \uD55C \uBC88\uC5D0)", groups: ["add"] },
8283
8181
  { text: " runlot deploy [dir] \uBC88\uB4E4\uC744 \uB9CC\uB4E4\uC5B4 \uBC30\uD3EC\uD569\uB2C8\uB2E4", groups: ["deploy"] },
8284
8182
  { text: " runlot versions [dir] \uBC30\uD3EC \uC774\uB825", groups: ["versions"] },
8285
8183
  { text: " runlot rollback <version> [dir] \uC774\uC804 \uBC84\uC804\uC73C\uB85C \uB418\uB3CC\uB9BD\uB2C8\uB2E4", groups: ["rollback"] },
8286
8184
  { text: "" },
8287
- { text: " runlot pg create [dir] \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB97C \uB9CC\uB4E4\uACE0 \uC811\uC18D \uC815\uBCF4\uB97C \uBCF4\uC5EC \uC90D\uB2C8\uB2E4", groups: ["pg"] },
8288
- { text: " runlot pg bind [dir] runlot.json \uC5D0 \uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uC0AC\uC6A9\uC744 \uAE30\uB85D\uD569\uB2C8\uB2E4", groups: ["pg"] },
8185
+ { text: " runlot pg connect [dir] \uC811\uC18D \uC815\uBCF4\uB97C \uBCF4\uC5EC \uC90D\uB2C8\uB2E4 (\uBE44\uBC00\uBC88\uD638 \uD3EC\uD568)", groups: ["pg"] },
8289
8186
  { text: " runlot pg execute [dir] SQL \uC744 \uC2E4\uD589\uD569\uB2C8\uB2E4 (-c <sql> \uB610\uB294 -f <\uD30C\uC77C>)", groups: ["pg"] },
8290
8187
  { text: " runlot pg migrate [dir] migrations/NNNN_*.sql \uC744 \uC801\uC6A9\uD569\uB2C8\uB2E4", groups: ["pg"] },
8291
8188
  { text: " runlot pg shell [dir] [-- ...] psql \uB85C \uC811\uC18D\uD569\uB2C8\uB2E4 (-- \uB4A4\uB294 psql \uC5D0 \uADF8\uB300\uB85C \uC804\uB2EC)", groups: ["pg"] },
@@ -8302,11 +8199,9 @@ var USAGE_BODY = [
8302
8199
  { text: " runlot port-forward [dir] \uB85C\uADF8\uC778 \uC138\uC158\uC73C\uB85C \uC778\uC99D\uD558\uACE0 \uB85C\uCEEC \uD3EC\uD2B8\uB97C \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uC5D0 \uC5F0\uACB0\uD569\uB2C8\uB2E4", groups: ["port-forward"] },
8303
8200
  { text: " (--port 15432, --listen 127.0.0.1, Ctrl-C \uB85C \uC885\uB8CC)", groups: ["port-forward"] },
8304
8201
  { text: "" },
8305
- { text: " runlot storage create [dir] \uD30C\uC77C \uC800\uC7A5\uC18C\uB97C \uCD94\uAC00\uD569\uB2C8\uB2E4 (\uC6CC\uCEE4\uC5D0\uC11C env.storage\uB85C \uC0AC\uC6A9)", groups: ["storage"] },
8306
8202
  { text: " runlot storage [status] [dir] \uC800\uC7A5 \uC6A9\uB7C9\uACFC \uC0AC\uC6A9 \uD55C\uB3C4 (--json\uC73C\uB85C \uC6D0\uBCF8 \uCD9C\uB825)", groups: ["storage"] },
8307
8203
  { text: " runlot storage delete [dir] \uC2A4\uD1A0\uB9AC\uC9C0\uB97C \uD574\uC81C\uD569\uB2C8\uB2E4 (admin)", groups: ["storage"] },
8308
8204
  { text: "", groups: ["storage"] },
8309
- { text: " runlot auth create [dir] \uC571\uC5D0 \uC778\uC99D \uAE30\uB2A5\uC744 \uCD94\uAC00\uD569\uB2C8\uB2E4 (\uC6CC\uCEE4\uC5D0\uC11C env.auth\uB85C \uC0AC\uC6A9)", groups: ["auth"] },
8310
8205
  { text: " runlot auth [status] [dir] \uC124\uC815\xB7\uD504\uB85C\uBC14\uC774\uB354\xB7\uCF5C\uBC31 URL (--json \uC73C\uB85C \uC6D0\uBCF8 \uCD9C\uB825)", groups: ["auth"] },
8311
8206
  { text: " runlot auth provider set <p> \uC18C\uC15C \uB85C\uADF8\uC778\uC744 \uB4F1\uB85D\uD569\uB2C8\uB2E4 (--client-id, --client-secret, admin)", groups: ["auth"] },
8312
8207
  { text: " runlot auth provider rm <p> \uC18C\uC15C \uB85C\uADF8\uC778 \uC81C\uACF5\uC790 \uC124\uC815\uC744 \uC0AD\uC81C\uD569\uB2C8\uB2E4 (admin)", groups: ["auth"] },
@@ -8427,7 +8322,7 @@ var USAGE2 = [
8427
8322
  ""
8428
8323
  ].join("\n");
8429
8324
  var HELP_GROUPS = new Set(ALL_GROUPS);
8430
- var GROUPS_NEEDING_SUB = /* @__PURE__ */ new Set(["pg", "secret", "domain", "dns", "domains", "add"]);
8325
+ var GROUPS_NEEDING_SUB = /* @__PURE__ */ new Set(["pg", "secret", "domain", "dns", "domains"]);
8431
8326
  function groupUsage(group) {
8432
8327
  const has = (l) => l.groups?.includes(group) === true;
8433
8328
  const options = USAGE_OPTIONS.filter(has).map((l) => l.text);
@@ -8584,37 +8479,44 @@ async function portForwardCommand(rest, flags) {
8584
8479
  );
8585
8480
  return done;
8586
8481
  }
8587
- async function createDatabaseAt(dir, flags) {
8588
- const { org, project } = targetOf(dir, flags);
8589
- const { connect } = await client(flags).createDatabase(org, project);
8590
- if (recordDatabaseBinding(dir)) console.log(`runlot.json \uC5D0 "database": true \uB97C \uAE30\uB85D\uD588\uC2B5\uB2C8\uB2E4`);
8591
- console.log(`${org}/${project} \uC758 \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uAC00 \uC900\uBE44\uB410\uC2B5\uB2C8\uB2E4. Worker \uC5D0\uC11C\uB294 env.db \uB85C \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`);
8592
- console.log(connectionUrl(connect));
8593
- console.log("\uC774 \uC811\uC18D \uBB38\uC790\uC5F4\uC5D0\uB294 \uBE44\uBC00\uBC88\uD638\uAC00 \uB4E4\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. \uACF5\uAC1C\uB41C \uACF3\uC5D0 \uBD99\uC5EC \uB123\uC9C0 \uB9C8\uC138\uC694.");
8482
+ async function provision(c, org, project, cfg) {
8483
+ const out = [];
8484
+ if (cfg.database || cfg.auth) {
8485
+ const { db } = await c.getDatabase(org, project);
8486
+ if (!db) {
8487
+ await c.createDatabase(org, project);
8488
+ out.push(
8489
+ cfg.database ? `\uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB97C \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4. \uC6CC\uCEE4\uC5D0\uC11C\uB294 env.db, \uC811\uC18D \uC815\uBCF4\uB294 \`runlot pg connect\` \uC785\uB2C8\uB2E4.` : `\uB85C\uADF8\uC778\uC740 \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uAC00 \uC788\uC5B4\uC57C \uD574\uC11C \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB3C4 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4 (env.db).`
8490
+ );
8491
+ }
8492
+ }
8493
+ if (cfg.auth) {
8494
+ const st = await c.getAuth(org, project);
8495
+ if (!st.granted) {
8496
+ await c.grantAuth(org, project);
8497
+ out.push("\uB85C\uADF8\uC778\uC744 \uCF30\uC2B5\uB2C8\uB2E4. \uC6CC\uCEE4\uC5D0\uC11C\uB294 env.auth.user(request), \uD654\uBA74\uC740 /__runlot/auth/sign-in \uC785\uB2C8\uB2E4.");
8498
+ }
8499
+ }
8500
+ if (cfg.storage) {
8501
+ const st = await c.getStorage(org, project);
8502
+ if (!st.granted) {
8503
+ await c.grantStorage(org, project);
8504
+ out.push("\uD30C\uC77C \uC800\uC7A5\uC18C\uB97C \uCF30\uC2B5\uB2C8\uB2E4. \uC6CC\uCEE4\uC5D0\uC11C\uB294 env.storage \uC785\uB2C8\uB2E4.");
8505
+ }
8506
+ }
8507
+ return out;
8594
8508
  }
8595
8509
  async function pgCommand(sub, rest, flags, passthrough) {
8596
8510
  const dir = rest[0] ?? ".";
8597
8511
  switch (sub) {
8598
- case "create":
8599
- await createDatabaseAt(dir, flags);
8600
- return 0;
8601
- // 바인딩 기록만 다시 쓴다. 체크아웃을 새로 받았거나 runlot.json 을 손으로
8602
- // 고치다 지운 경우가 이 명령의 자리다.
8603
- case "bind": {
8604
- const cfg = loadProjectConfig(dir);
8605
- if (rest.length > 1) {
8606
- throw new Error(bindRefusal(rest[1]));
8607
- }
8608
- if (flags.project !== void 0 && flags.project !== cfg.name) {
8609
- throw new Error(bindRefusal(flags.project));
8610
- }
8512
+ // 접속 정보. 만드는 명령은 없다 — `runlot.json` 의 `"database": true` 를
8513
+ // `runlot deploy` 가 읽어 만든다 (docs/provisioning.md). 첫 판의 `pg create`
8514
+ // 가 찍던 접속 문자열을 이 명령이 찍는다.
8515
+ case "connect": {
8611
8516
  const { org, project } = targetOf(dir, flags);
8612
- const { db } = await client(flags).getDatabase(org, project);
8613
- if (!db) {
8614
- throw new Error(`${org}/${project} \uC5D0 \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 \`runlot pg create\` \uB97C \uC2E4\uD589\uD558\uC138\uC694.`);
8615
- }
8616
- if (recordDatabaseBinding(dir)) console.log(`runlot.json \uC5D0 "database": true \uB97C \uAE30\uB85D\uD588\uC2B5\uB2C8\uB2E4`);
8617
- else console.log(`runlot.json \uC5D0 \uC774\uBBF8 \uAE30\uB85D\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4`);
8517
+ const info = await connectInfoOf(client(flags), org, project);
8518
+ console.log(connectionUrl(info));
8519
+ console.log("\uC774 \uC811\uC18D \uBB38\uC790\uC5F4\uC5D0\uB294 \uBE44\uBC00\uBC88\uD638\uAC00 \uB4E4\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. \uACF5\uAC1C\uB41C \uACF3\uC5D0 \uBD99\uC5EC \uB123\uC9C0 \uB9C8\uC138\uC694.");
8618
8520
  return 0;
8619
8521
  }
8620
8522
  case "execute": {
@@ -8935,9 +8837,6 @@ async function usageCommand(rest, flags) {
8935
8837
  console.log(formatUsage(usage, storage));
8936
8838
  return 0;
8937
8839
  }
8938
- function bindRefusal(target) {
8939
- return `${target} \uC5D0\uB294 \uC5F0\uACB0\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uD55C \uD504\uB85C\uC81D\uD2B8 = \uD55C \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB77C\uC11C \uB2E4\uB978 \uD504\uB85C\uC81D\uD2B8\uC758 \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB294 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \`runlot pg bind\` \uB294 \uC774 \uB514\uB809\uD1A0\uB9AC\uC758 \uD504\uB85C\uC81D\uD2B8\uC5D0\uB9CC \uAE30\uB85D\uC744 \uB0A8\uAE41\uB2C8\uB2E4.`;
8940
- }
8941
8840
  function authDeps(flags) {
8942
8841
  return {
8943
8842
  target: (dir) => targetOf(dir, flags),
@@ -8947,29 +8846,9 @@ function authDeps(flags) {
8947
8846
  ask: askLine,
8948
8847
  interactive: process.stdin.isTTY === true,
8949
8848
  clientId: flags.clientId,
8950
- clientSecret: flags.clientSecret,
8951
- record: recordAuthBinding
8849
+ clientSecret: flags.clientSecret
8952
8850
  };
8953
8851
  }
8954
- async function createBinding(name, dir, flags) {
8955
- switch (name) {
8956
- case "pg":
8957
- await createDatabaseAt(dir, flags);
8958
- return;
8959
- case "auth":
8960
- await authCommand("create", [dir], authDeps(flags));
8961
- return;
8962
- case "storage":
8963
- await storageCommand("create", [dir], {
8964
- target: (dir2) => targetOf(dir2, flags),
8965
- client: () => client(flags),
8966
- json: false,
8967
- confirm: (question) => confirmYes(question, confirmOpts(flags)),
8968
- record: recordStorageBinding
8969
- });
8970
- return;
8971
- }
8972
- }
8973
8852
  function repoDeps(flags) {
8974
8853
  return {
8975
8854
  client: () => client(flags),
@@ -9156,14 +9035,7 @@ async function main(argv) {
9156
9035
  await createProjectWithHint(c, org, project);
9157
9036
  console.log(`\uD504\uB85C\uC81D\uD2B8 ${org}/${project} \uC744(\uB97C) \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4`);
9158
9037
  }
9159
- if (cfg.database) {
9160
- const { db } = await c.getDatabase(org, project);
9161
- if (!db) {
9162
- console.error(
9163
- `\uACBD\uACE0: runlot.json \uC5D0\uB294 \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB97C \uC4F4\uB2E4\uACE0 \uB418\uC5B4 \uC788\uC9C0\uB9CC ${org}/${project} \uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4. \`runlot pg create\` \uB97C \uC2E4\uD589\uD558\uC138\uC694. \uC774 \uBC30\uD3EC\uC5D0\uC11C\uB294 env.db \uB97C \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
9164
- );
9165
- }
9166
- }
9038
+ for (const line of await provision(c, org, project, cfg)) console.log(line);
9167
9039
  console.log(`\uC62C\uB9AC\uB294 \uC911\u2026 (${(built.bundle.length / 1024).toFixed(1)} KiB)`);
9168
9040
  const d = await c.deploy(org, project, built.bundle);
9169
9041
  console.log("\uBC30\uD3EC\uD558\uB294 \uC911\u2026");
@@ -9206,8 +9078,7 @@ async function main(argv) {
9206
9078
  target: (dir) => targetOf(dir, flags),
9207
9079
  client: () => client(flags),
9208
9080
  json: flags.json === true,
9209
- confirm: (question) => confirmYes(question, confirmOpts(flags)),
9210
- record: recordStorageBinding
9081
+ confirm: (question) => confirmYes(question, confirmOpts(flags))
9211
9082
  });
9212
9083
  // 자체 Git 호스팅 (docs/git-hosting.md §12.1, §19). `repo` 는 프로젝트
9213
9084
  // 명령이다 — 저장소는 프로젝트의 것이라 대상을 `pg` 와 같은 규칙으로 읽는다.
@@ -9225,18 +9096,6 @@ async function main(argv) {
9225
9096
  // (docs/auth.md §1).
9226
9097
  case "auth":
9227
9098
  return authCommand(rest[0], rest.slice(1), authDeps(flags));
9228
- // 회차 5 — 랜딩의 `runlot add pg auth storage` 한 줄. 각각의 create 를
9229
- // 그대로 부른다.
9230
- case "add":
9231
- return addCommand(rest, {
9232
- create: (name, dir) => createBinding(name, dir, flags),
9233
- hasDatabase: async (dir) => {
9234
- const { org, project } = targetOf(dir, flags);
9235
- const { db } = await client(flags).getDatabase(org, project);
9236
- return db === true;
9237
- },
9238
- log: (line) => console.log(line)
9239
- });
9240
9099
  case "logs":
9241
9100
  return logsCommand(rest, flags);
9242
9101
  case "secret":
@@ -9303,3 +9162,6 @@ main(process.argv.slice(2)).then(
9303
9162
  process.exit(1);
9304
9163
  }
9305
9164
  );
9165
+ export {
9166
+ provision
9167
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runlot",
3
- "version": "0.1.0-rc.21",
3
+ "version": "0.1.0-rc.22",
4
4
  "description": "runlot CLI — 앱 배포와 PostgreSQL 관리",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,9 +25,9 @@
25
25
  "@types/pg": "^8.23.1",
26
26
  "typescript": "^5.7.2",
27
27
  "pg": "^8.23.0",
28
- "@runlot/config": "0.1.0-rc.21",
29
- "@runlot/api": "0.1.0-rc.21",
30
- "@runlot/pg": "0.1.0-rc.21"
28
+ "@runlot/config": "0.1.0-rc.22",
29
+ "@runlot/api": "0.1.0-rc.22",
30
+ "@runlot/pg": "0.1.0-rc.22"
31
31
  },
32
32
  "engines": {
33
33
  "node": ">=20"