ryugi-artifacts 1.11.0 → 1.12.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.
package/dist/server.cjs CHANGED
@@ -1563,14 +1563,14 @@ var require_canvas = __commonJS({
1563
1563
 
1564
1564
  // src/server/main.ts
1565
1565
  var import_node_child_process2 = require("node:child_process");
1566
- var import_node_fs20 = __toESM(require("node:fs"), 1);
1566
+ var import_node_fs22 = __toESM(require("node:fs"), 1);
1567
1567
  var import_node_os = __toESM(require("node:os"), 1);
1568
- var import_node_path18 = __toESM(require("node:path"), 1);
1568
+ var import_node_path19 = __toESM(require("node:path"), 1);
1569
1569
 
1570
1570
  // src/server/app.ts
1571
- var import_node_fs18 = __toESM(require("node:fs"), 1);
1571
+ var import_node_fs20 = __toESM(require("node:fs"), 1);
1572
1572
  var import_node_http = __toESM(require("node:http"), 1);
1573
- var import_node_path17 = __toESM(require("node:path"), 1);
1573
+ var import_node_path18 = __toESM(require("node:path"), 1);
1574
1574
 
1575
1575
  // src/shared/types.ts
1576
1576
  var ARTIFACT_TYPES = ["artboard", "document", "html"];
@@ -15642,19 +15642,19 @@ var ElementDOMSlot = class _ElementDOMSlot extends DOMSlot {
15642
15642
  }
15643
15643
  };
15644
15644
  function indexPath(root, child) {
15645
- const path19 = [];
15645
+ const path20 = [];
15646
15646
  let node = child;
15647
15647
  for (; node !== root && node !== null; node = node.parentNode) {
15648
15648
  let i6 = 0;
15649
15649
  for (let sibling = node.previousSibling; sibling !== null; sibling = sibling.previousSibling) {
15650
15650
  i6++;
15651
15651
  }
15652
- path19.push(i6);
15652
+ path20.push(i6);
15653
15653
  }
15654
15654
  if (!(node === root)) {
15655
15655
  formatDevErrorMessage(`indexPath: root is not a parent of child`);
15656
15656
  }
15657
- return path19.reverse();
15657
+ return path20.reverse();
15658
15658
  }
15659
15659
  // @__NO_SIDE_EFFECTS__
15660
15660
  function readLexicalVersion() {
@@ -30434,9 +30434,9 @@ function getActiveElementDeep(root) {
30434
30434
  function getComposedEventTarget(event) {
30435
30435
  const target = event.target;
30436
30436
  if (target !== null && isHTMLElement(target) && target.shadowRoot !== null && typeof event.composedPath === "function") {
30437
- const path19 = event.composedPath();
30438
- if (path19.length > 0) {
30439
- return path19[0];
30437
+ const path20 = event.composedPath();
30438
+ if (path20.length > 0) {
30439
+ return path20[0];
30440
30440
  }
30441
30441
  }
30442
30442
  return target;
@@ -40532,10 +40532,10 @@ function _loadWasmModule(sync, filepath, src, imports2) {
40532
40532
  var buf = null;
40533
40533
  var isNode2 = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
40534
40534
  if (filepath && isNode2) {
40535
- var fs23 = null;
40536
- var path19 = null;
40535
+ var fs25 = null;
40536
+ var path20 = null;
40537
40537
  return new Promise((resolve, reject) => {
40538
- fs23.readFile(path19.resolve(__dirname, filepath), (error, buffer) => {
40538
+ fs25.readFile(path20.resolve(__dirname, filepath), (error, buffer) => {
40539
40539
  if (error != null) {
40540
40540
  reject(error);
40541
40541
  } else {
@@ -41838,10 +41838,10 @@ var LoroDoc = class _LoroDoc {
41838
41838
  * @param {string} path
41839
41839
  * @returns {Value | Container | undefined}
41840
41840
  */
41841
- getByPath(path19) {
41841
+ getByPath(path20) {
41842
41842
  try {
41843
41843
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
41844
- const ptr0 = passStringToWasm0(path19, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
41844
+ const ptr0 = passStringToWasm0(path20, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
41845
41845
  const len0 = WASM_VECTOR_LEN;
41846
41846
  wasm.lorodoc_getByPath(retptr, this.__wbg_ptr, ptr0, len0);
41847
41847
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
@@ -84952,15 +84952,18 @@ function isCloudRecord(value) {
84952
84952
  function normalize(raw) {
84953
84953
  const config = defaults();
84954
84954
  if (typeof raw !== "object" || raw === null) return config;
84955
+ const { autoPublish } = raw;
84956
+ if (typeof autoPublish === "boolean") config.autoPublish = autoPublish;
84955
84957
  const artifacts = raw.artifacts;
84956
84958
  if (typeof artifacts !== "object" || artifacts === null) return config;
84957
84959
  for (const [key2, value] of Object.entries(artifacts)) {
84958
84960
  if (typeof value !== "object" || value === null) continue;
84959
- const { visibility, cloud } = value;
84961
+ const { visibility, cloud, autoPublish: autoPublish2 } = value;
84960
84962
  if (visibility !== void 0 && !isVisibility(visibility)) continue;
84961
84963
  const entry = {};
84962
84964
  if (visibility) entry.visibility = visibility;
84963
84965
  if (isCloudRecord(cloud)) entry.cloud = { id: cloud.id, url: cloud.url, publishedAt: cloud.publishedAt, visibility: cloud.visibility };
84966
+ if (autoPublish2 === false) entry.autoPublish = false;
84964
84967
  config.artifacts[key2] = entry;
84965
84968
  }
84966
84969
  return config;
@@ -85003,10 +85006,20 @@ function updateArtifactConfig(file, key2, patch) {
85003
85006
  if (patch.visibility) entry.visibility = patch.visibility;
85004
85007
  if (patch.cloud === null) delete entry.cloud;
85005
85008
  else if (patch.cloud) entry.cloud = patch.cloud;
85009
+ if (patch.autoPublish === null) delete entry.autoPublish;
85010
+ else if (patch.autoPublish === false) entry.autoPublish = false;
85006
85011
  config.artifacts[key2] = entry;
85007
85012
  writeJsonAtomic(file, config);
85008
85013
  return entry;
85009
85014
  }
85015
+ function setProjectAutoPublish(file, value) {
85016
+ const { config, warning } = readConfig(file);
85017
+ if (warning) throw new Error(warning);
85018
+ if (value === null) delete config.autoPublish;
85019
+ else config.autoPublish = value;
85020
+ import_node_fs12.default.mkdirSync(import_node_path12.default.dirname(file), { recursive: true });
85021
+ writeJsonAtomic(file, config);
85022
+ }
85010
85023
 
85011
85024
  // src/server/avatars.ts
85012
85025
  var import_node_crypto3 = require("node:crypto");
@@ -85133,7 +85146,7 @@ function callbackPage(result) {
85133
85146
  const body = result.ok ? `<p class="status">${CIRCLE_CHECK}\u5DF2\u8FDE\u63A5 Ryugi Cloud</p>
85134
85147
  <h1>\u5DF2\u767B\u5F55<em>${escapeHtml(result.login)}</em></h1>
85135
85148
  <p class="lead">\u8FD9\u53F0\u7535\u8111\u4E0A\u7684 Ryugi \u73B0\u5728\u53EF\u4EE5\u53D1\u5E03 artifact \u4E86\u3002</p>
85136
- <ul class="rows">${row("\u5728 Ryugi \u9875\u9762\u91CC\u53D1\u5E03\u7684\uFF1F", "\u56DE\u5230 Ryugi\uFF0C\u5206\u4EAB\u9762\u677F\u4F1A\u81EA\u52A8\u5237\u65B0\u3002")}${row("\u8BA9 agent \u53D1\u5E03\u7684\uFF1F", "\u8BA9\u5B83\u518D\u8FD0\u884C\u4E00\u6B21\u53D1\u5E03\u547D\u4EE4\u3002")}</ul>` : `<p class="status">${CIRCLE_ALERT}\u672A\u8FDE\u63A5</p>
85149
+ <ul class="rows">${row("\u5728 Ryugi \u9875\u9762\u91CC\u53D1\u5E03\u7684\uFF1F", "\u56DE\u5230 Ryugi\uFF0C\u5206\u4EAB\u9762\u677F\u4F1A\u81EA\u52A8\u5237\u65B0\u3002")}${row("\u8BA9 agent \u53D1\u5E03\u7684\uFF1F", "\u8BA9\u5B83\u518D\u8FD0\u884C\u4E00\u6B21\u53D1\u5E03\u547D\u4EE4\u3002")}${result.autoPublish ? row("\u81EA\u52A8\u53D1\u5E03\u5DF2\u6253\u5F00", "agent \u6BCF\u8F6E\u7ED3\u675F\u540E\uFF0C\u6539\u8FC7\u7684 artifact \u4F1A\u4EE5\u79C1\u5BC6\u65B9\u5F0F\u540C\u6B65\u5230 Ryugi Cloud\u3002\u5173\u95ED\uFF1A\u8FD0\u884C <code>ryugi-artifacts config --auto-publish off</code>\u3002") : ""}</ul>` : `<p class="status">${CIRCLE_ALERT}\u672A\u8FDE\u63A5</p>
85137
85150
  <h1>\u767B\u5F55\u6CA1\u6709\u5B8C\u6210</h1>
85138
85151
  <p class="lead">${escapeHtml(result.detail)}</p>
85139
85152
  <ul class="rows">${row("\u91CD\u65B0\u767B\u5F55", "\u56DE\u5230 Ryugi\uFF0C\u5728\u5206\u4EAB\u9762\u677F\u91CC\u518D\u70B9\u4E00\u6B21\u300C\u767B\u5F55\u300D\u3002")}</ul>`;
@@ -85259,12 +85272,39 @@ function withCloudRuntime(type, files) {
85259
85272
  );
85260
85273
  }
85261
85274
 
85275
+ // src/server/settings.ts
85276
+ var import_node_fs16 = __toESM(require("node:fs"), 1);
85277
+ var import_node_path16 = __toESM(require("node:path"), 1);
85278
+ var settingsFileFor = (credentialsFile2) => import_node_path16.default.join(import_node_path16.default.dirname(credentialsFile2), "config.json");
85279
+ function readSettings(file) {
85280
+ try {
85281
+ const raw = JSON.parse(import_node_fs16.default.readFileSync(file, "utf8"));
85282
+ return typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
85283
+ } catch {
85284
+ return {};
85285
+ }
85286
+ }
85287
+ function readGlobalAutoPublish(file) {
85288
+ const value = readSettings(file).autoPublish;
85289
+ return typeof value === "boolean" ? value : void 0;
85290
+ }
85291
+ function writeGlobalAutoPublish(file, value) {
85292
+ import_node_fs16.default.mkdirSync(import_node_path16.default.dirname(file), { recursive: true, mode: 448 });
85293
+ writeJsonAtomic(file, { ...readSettings(file), autoPublish: value });
85294
+ }
85295
+ function defaultGlobalAutoPublish(file) {
85296
+ if (readGlobalAutoPublish(file) === void 0) writeGlobalAutoPublish(file, true);
85297
+ }
85298
+ function autoPublishEnabled({ globalFile, projectFile }) {
85299
+ return readConfig(projectFile).config.autoPublish ?? readGlobalAutoPublish(globalFile) ?? false;
85300
+ }
85301
+
85262
85302
  // src/server/cloud.ts
85263
85303
  var LOGIN_STATE_TTL_MS = 10 * 60 * 1e3;
85264
85304
  var UPLOAD_CONCURRENCY = 6;
85265
85305
  var MAX_JSON_BODY = 4096;
85266
85306
  var CLOUD_ID = /^[A-Za-z0-9_-]{1,64}$/;
85267
- var ROUTE = /^\/api\/cloud\/(status|login|logout|artifacts|publish|visibility)(?:\/([^/]+)(?:\/([^/]+))?)?$/;
85307
+ var ROUTE = /^\/api\/cloud\/(status|login|logout|artifacts|publish|visibility|auto-publish)(?:\/([^/]+)(?:\/([^/]+))?)?$/;
85268
85308
  var SignedOut = class extends Error {
85269
85309
  };
85270
85310
  var CloudRefused = class extends Error {
@@ -85274,6 +85314,15 @@ var CloudRefused = class extends Error {
85274
85314
  }
85275
85315
  status;
85276
85316
  };
85317
+ var CloudCopyGone = class extends Error {
85318
+ };
85319
+ var CreateRefused = class extends CloudRefused {
85320
+ constructor(detail) {
85321
+ super(502, `cloud refused (403): ${detail}`);
85322
+ this.detail = detail;
85323
+ }
85324
+ detail;
85325
+ };
85277
85326
  async function readJsonBody(req) {
85278
85327
  const chunks = [];
85279
85328
  let size = 0;
@@ -85298,7 +85347,13 @@ async function errorMessage(res) {
85298
85347
  }
85299
85348
  }
85300
85349
  function createCloudRoutes(options) {
85301
- const { origin, credentialsFile: credentialsFile2, configFile } = options;
85350
+ const { origin, credentialsFile: credentialsFile2, configFile, project } = options;
85351
+ const settingsFile = settingsFileFor(credentialsFile2);
85352
+ const autoPublishState = () => ({
85353
+ global: readGlobalAutoPublish(settingsFile) ?? null,
85354
+ project: readConfig(configFile).config.autoPublish ?? null,
85355
+ enabled: !!readCredentials(credentialsFile2, origin) && autoPublishEnabled({ globalFile: settingsFile, projectFile: configFile })
85356
+ });
85302
85357
  const pendingStates = /* @__PURE__ */ new Map();
85303
85358
  const loginUrl = () => {
85304
85359
  const now = Date.now();
@@ -85309,7 +85364,7 @@ function createCloudRoutes(options) {
85309
85364
  const challenge = import_node_crypto4.default.createHash("sha256").update(verifier).digest("base64url");
85310
85365
  return `${origin}/auth/cli?port=${options.port()}&state=${state}&challenge=${challenge}`;
85311
85366
  };
85312
- const cloudFetch = async (method, path19, body) => {
85367
+ const cloudFetch = async (method, path20, body) => {
85313
85368
  const credentials = readCredentials(credentialsFile2, origin);
85314
85369
  if (!credentials) throw new SignedOut();
85315
85370
  const headers = { Authorization: `Bearer ${credentials.token}` };
@@ -85323,7 +85378,7 @@ function createCloudRoutes(options) {
85323
85378
  }
85324
85379
  let res;
85325
85380
  try {
85326
- res = await fetch(`${origin}${path19}`, { method, headers, body: payload });
85381
+ res = await fetch(`${origin}${path20}`, { method, headers, body: payload });
85327
85382
  } catch (err) {
85328
85383
  throw new CloudRefused(502, `could not reach ${origin}: ${err.message}`);
85329
85384
  }
@@ -85335,7 +85390,18 @@ function createCloudRoutes(options) {
85335
85390
  return res;
85336
85391
  };
85337
85392
  const artifactEntry = (key2) => readConfig(configFile).config.artifacts[key2] ?? {};
85338
- const publish = async (ref, requested) => {
85393
+ const locks = /* @__PURE__ */ new Map();
85394
+ const serialized = (key2, task) => {
85395
+ const run2 = (locks.get(key2) ?? Promise.resolve()).then(task, task);
85396
+ const tail = run2.catch(() => void 0);
85397
+ locks.set(key2, tail);
85398
+ void tail.then(() => {
85399
+ if (locks.get(key2) === tail) locks.delete(key2);
85400
+ });
85401
+ return run2;
85402
+ };
85403
+ const keyOfCloudId = (cloudId) => Object.entries(readConfig(configFile).config.artifacts).find(([, entry]) => entry.cloud?.id === cloudId)?.[0] ?? `cloud:${cloudId}`;
85404
+ const publish = async (ref, requested, { recreate = true } = {}) => {
85339
85405
  const inspected = await options.inspect(ref);
85340
85406
  if (!inspected) throw new CloudRefused(404, `${ref.type}/${ref.id} not found`);
85341
85407
  if (inspected.reasons.length > 0 || !inspected.payload) return { status: 409, body: { error: "fix these before publishing", reasons: inspected.reasons } };
@@ -85349,10 +85415,11 @@ function createCloudRoutes(options) {
85349
85415
  const entry = artifactEntry(key2);
85350
85416
  const hashed = files.map((file) => ({ ...file, hash: import_node_crypto4.default.createHash("sha256").update(file.data).digest("hex") }));
85351
85417
  const byHash = new Map(hashed.map((file) => [file.hash, file.data]));
85352
- const manifest = hashed.map(({ path: path19, hash }) => ({ path: path19, hash }));
85353
- const version = (visibility) => ({ title: inspected.title, payload: inspected.payload, files: manifest, ...visibility ? { visibility } : {} });
85418
+ const manifest = hashed.map(({ path: path20, hash }) => ({ path: path20, hash }));
85419
+ const version = (visibility) => ({ title: inspected.title, payload: inspected.payload, files: manifest, project, ...visibility ? { visibility } : {} });
85354
85420
  const create3 = async () => {
85355
- const res2 = await cloudFetch("POST", "/api/artifacts", { type: ref.type, visibility: requested ?? entry.visibility ?? "private" });
85421
+ const res2 = await cloudFetch("POST", "/api/artifacts", { type: ref.type, visibility: requested ?? entry.visibility ?? "private", project });
85422
+ if (res2.status === 403) throw new CreateRefused(await errorMessage(res2));
85356
85423
  const created = await (await expectOk(res2)).json();
85357
85424
  updateArtifactConfig(configFile, key2, {
85358
85425
  visibility: created.visibility,
@@ -85380,7 +85447,10 @@ function createCloudRoutes(options) {
85380
85447
  return cloudFetch("POST", `/api/artifacts/${id2}/versions`, version(visibility));
85381
85448
  };
85382
85449
  let res = entry.cloud ? await commit(entry.cloud.id, requested) : await commit(await create3(), void 0);
85383
- if (res.status === 404 && entry.cloud) res = await commit(await create3(), void 0);
85450
+ if (res.status === 404 && entry.cloud) {
85451
+ if (!recreate) throw new CloudCopyGone();
85452
+ res = await commit(await create3(), void 0);
85453
+ }
85384
85454
  const published = await (await expectOk(res)).json();
85385
85455
  updateArtifactConfig(configFile, key2, {
85386
85456
  visibility: published.visibility,
@@ -85414,7 +85484,29 @@ function createCloudRoutes(options) {
85414
85484
  const res = await cloudFetch("DELETE", `/api/artifacts/${cloudId}`);
85415
85485
  if (res.status !== 404) await expectOk(res);
85416
85486
  for (const [key2, entry] of Object.entries(readConfig(configFile).config.artifacts)) {
85417
- if (entry.cloud?.id === cloudId) updateArtifactConfig(configFile, key2, { cloud: null });
85487
+ if (entry.cloud?.id === cloudId) updateArtifactConfig(configFile, key2, { cloud: null, autoPublish: false });
85488
+ }
85489
+ };
85490
+ const autoPublish = (key2) => serialized(key2, () => autoPublishNow(key2));
85491
+ const autoPublishNow = async (key2) => {
85492
+ const ref = artifactKeyOf(key2);
85493
+ if (!ref) return { kind: "gone" };
85494
+ const entry = artifactEntry(key2);
85495
+ if (entry.autoPublish === false) return { kind: "opted-out" };
85496
+ try {
85497
+ const result = await publish(ref, void 0, { recreate: false });
85498
+ if (result.status !== 200) return { kind: "not-ready" };
85499
+ return { kind: "published", created: result.body.id !== entry.cloud?.id };
85500
+ } catch (err) {
85501
+ if (err instanceof CloudCopyGone) {
85502
+ updateArtifactConfig(configFile, key2, { cloud: null, autoPublish: false });
85503
+ return { kind: "opted-out" };
85504
+ }
85505
+ if (err instanceof SignedOut) return { kind: "signed-out" };
85506
+ if (err instanceof CreateRefused) return { kind: "cannot-create", message: err.detail };
85507
+ if (err instanceof CloudRefused && err.status === 404) return { kind: "gone" };
85508
+ if (err instanceof CloudRefused && err.status === 413) return { kind: "not-ready" };
85509
+ return { kind: "failed", message: err.message };
85418
85510
  }
85419
85511
  };
85420
85512
  const route = async (req, res, match) => {
@@ -85424,7 +85516,7 @@ function createCloudRoutes(options) {
85424
85516
  if (action === "status" && method === "GET" && !first) {
85425
85517
  const credentials = readCredentials(credentialsFile2, origin);
85426
85518
  const { config, warning } = readConfig(configFile);
85427
- sendJson(res, 200, { signedIn: !!credentials, login: credentials?.login ?? null, origin, artifacts: config.artifacts, warning: warning ?? null });
85519
+ sendJson(res, 200, { signedIn: !!credentials, login: credentials?.login ?? null, origin, artifacts: config.artifacts, autoPublish: autoPublishState(), warning: warning ?? null });
85428
85520
  return;
85429
85521
  }
85430
85522
  if (action === "login" && method === "POST" && !first) {
@@ -85448,20 +85540,30 @@ function createCloudRoutes(options) {
85448
85540
  }
85449
85541
  if (action === "artifacts" && method === "DELETE" && first && !second) {
85450
85542
  if (!CLOUD_ID.test(first)) throw new CloudRefused(400, "not a cloud artifact id");
85451
- await deleteCloud(first);
85543
+ await serialized(keyOfCloudId(first), () => deleteCloud(first));
85452
85544
  sendJson(res, 200, { deleted: first });
85453
85545
  return;
85454
85546
  }
85455
85547
  if (action === "publish" && ref && method === "POST") {
85456
85548
  const body = await readJsonBody(req);
85457
85549
  if (body?.visibility !== void 0 && !isVisibility(body.visibility)) throw new CloudRefused(400, 'visibility must be "public" or "private"');
85458
- const result = await publish(ref, body?.visibility);
85550
+ const key2 = `${ref.type}/${ref.id}`;
85551
+ const requested = body?.visibility;
85552
+ const result = await serialized(key2, async () => {
85553
+ const published = await publish(ref, requested);
85554
+ if (published.status === 200) updateArtifactConfig(configFile, key2, { autoPublish: null });
85555
+ return published;
85556
+ });
85459
85557
  sendJson(res, result.status, result.body);
85460
85558
  return;
85461
85559
  }
85462
85560
  if (action === "publish" && ref && method === "DELETE") {
85463
- const entry = artifactEntry(`${ref.type}/${ref.id}`);
85464
- if (entry.cloud) await deleteCloud(entry.cloud.id);
85561
+ const key2 = `${ref.type}/${ref.id}`;
85562
+ await serialized(key2, async () => {
85563
+ const entry = artifactEntry(key2);
85564
+ if (entry.cloud) await deleteCloud(entry.cloud.id);
85565
+ updateArtifactConfig(configFile, key2, { autoPublish: false });
85566
+ });
85465
85567
  sendJson(res, 200, { unpublished: `${ref.type}/${ref.id}` });
85466
85568
  return;
85467
85569
  }
@@ -85472,6 +85574,15 @@ function createCloudRoutes(options) {
85472
85574
  sendJson(res, 200, await setVisibility(ref, visibility));
85473
85575
  return;
85474
85576
  }
85577
+ if (action === "auto-publish" && method === "POST" && !first) {
85578
+ const body = await readJsonBody(req);
85579
+ const value = body?.value;
85580
+ if (body?.scope === "global" && typeof value === "boolean") writeGlobalAutoPublish(settingsFile, value);
85581
+ else if (body?.scope === "project" && (typeof value === "boolean" || value === null)) setProjectAutoPublish(configFile, value);
85582
+ else throw new CloudRefused(400, 'send {"scope":"global","value":true|false} or {"scope":"project","value":true|false|null}');
85583
+ sendJson(res, 200, autoPublishState());
85584
+ return;
85585
+ }
85475
85586
  send(res, 404, "Not found");
85476
85587
  };
85477
85588
  return {
@@ -85506,9 +85617,13 @@ function createCloudRoutes(options) {
85506
85617
  return;
85507
85618
  }
85508
85619
  writeCredentials(credentialsFile2, { origin, token: issued.token, login: issued.login });
85509
- page(200, { ok: true, login: issued.login });
85620
+ defaultGlobalAutoPublish(settingsFile);
85621
+ page(200, { ok: true, login: issued.login, autoPublish: autoPublishState().enabled });
85510
85622
  },
85511
85623
  match: (pathname) => ROUTE.exec(pathname),
85624
+ autoPublish,
85625
+ autoPublishEnabled: () => autoPublishState().enabled,
85626
+ token: () => readCredentials(credentialsFile2, origin)?.token ?? null,
85512
85627
  async handle(req, res, match) {
85513
85628
  try {
85514
85629
  await route(req, res, match);
@@ -85528,7 +85643,7 @@ function createCloudRoutes(options) {
85528
85643
 
85529
85644
  // src/server/comment-names.ts
85530
85645
  var import_node_child_process = require("node:child_process");
85531
- var import_node_fs16 = __toESM(require("node:fs"), 1);
85646
+ var import_node_fs17 = __toESM(require("node:fs"), 1);
85532
85647
 
85533
85648
  // src/server/agent.ts
85534
85649
  var NAMES = {
@@ -85609,7 +85724,7 @@ function commentNames({ agentFile, projectDir, cloud }) {
85609
85724
  },
85610
85725
  agent: () => {
85611
85726
  try {
85612
- return detectAgent(JSON.parse(import_node_fs16.default.readFileSync(agentFile, "utf8")));
85727
+ return detectAgent(JSON.parse(import_node_fs17.default.readFileSync(agentFile, "utf8")));
85613
85728
  } catch {
85614
85729
  return void 0;
85615
85730
  }
@@ -85636,26 +85751,117 @@ function viewerPage(template, page) {
85636
85751
  </head>`);
85637
85752
  }
85638
85753
 
85754
+ // src/server/auto-publish.ts
85755
+ var import_node_crypto5 = __toESM(require("node:crypto"), 1);
85756
+ var import_node_fs18 = __toESM(require("node:fs"), 1);
85757
+ var SIGNED_OUT_MESSAGE = "auto-publish paused: the Ryugi Cloud sign-in expired";
85758
+ function isNotice(value) {
85759
+ if (typeof value !== "object" || value === null) return false;
85760
+ const { id: id2, kind, message } = value;
85761
+ return typeof id2 === "string" && (kind === "signed-out" || kind === "cap") && typeof message === "string";
85762
+ }
85763
+ function readAutoPublishState(file) {
85764
+ let raw = {};
85765
+ try {
85766
+ const parsed = JSON.parse(import_node_fs18.default.readFileSync(file, "utf8"));
85767
+ if (typeof parsed === "object" && parsed !== null) raw = parsed;
85768
+ } catch {
85769
+ }
85770
+ const dirty = Array.isArray(raw.dirty) ? raw.dirty.filter((key2) => typeof key2 === "string") : [];
85771
+ const paused = raw.paused;
85772
+ return {
85773
+ dirty,
85774
+ notice: isNotice(raw.notice) ? raw.notice : null,
85775
+ paused: paused && (typeof paused.token === "string" || paused.token === null) ? { token: paused.token } : null
85776
+ };
85777
+ }
85778
+ function createAutoPublisher(options) {
85779
+ const saved = readAutoPublishState(options.stateFile);
85780
+ const dirty = new Set(saved.dirty);
85781
+ let notice = saved.notice;
85782
+ let paused = saved.paused;
85783
+ const remarked = /* @__PURE__ */ new Set();
85784
+ const save = () => writeJsonAtomic(options.stateFile, { dirty: [...dirty], notice, paused });
85785
+ const raise = (kind, message) => {
85786
+ if (notice?.kind !== kind) notice = { id: import_node_crypto5.default.randomUUID(), kind, message };
85787
+ };
85788
+ const run2 = async () => {
85789
+ if (!options.enabled() || dirty.size === 0) return;
85790
+ const token = options.token();
85791
+ if (paused && paused.token === token) return;
85792
+ if (paused) {
85793
+ paused = null;
85794
+ if (notice?.kind === "signed-out") notice = null;
85795
+ }
85796
+ for (const key2 of [...dirty]) {
85797
+ remarked.delete(key2);
85798
+ const outcome = await options.publish(key2);
85799
+ if (outcome.kind === "signed-out") {
85800
+ paused = { token };
85801
+ raise("signed-out", SIGNED_OUT_MESSAGE);
85802
+ break;
85803
+ }
85804
+ if (outcome.kind === "published") {
85805
+ if (!remarked.has(key2)) dirty.delete(key2);
85806
+ if (outcome.created && notice?.kind === "cap") notice = null;
85807
+ } else if (outcome.kind === "opted-out" || outcome.kind === "gone") {
85808
+ dirty.delete(key2);
85809
+ } else if (outcome.kind === "cannot-create") {
85810
+ raise("cap", outcome.message);
85811
+ }
85812
+ }
85813
+ save();
85814
+ };
85815
+ let running = null;
85816
+ let queued = null;
85817
+ const flush = () => {
85818
+ if (!running) {
85819
+ running = run2().catch((err) => console.error(JSON.stringify({ type: "auto-publish-error", error: err.message }))).finally(() => {
85820
+ running = null;
85821
+ });
85822
+ return running;
85823
+ }
85824
+ queued ??= running.then(() => {
85825
+ queued = null;
85826
+ return flush();
85827
+ });
85828
+ return queued;
85829
+ };
85830
+ return {
85831
+ changed(key2) {
85832
+ if (!options.enabled()) return;
85833
+ dirty.add(key2);
85834
+ remarked.add(key2);
85835
+ save();
85836
+ },
85837
+ removed(key2) {
85838
+ if (!dirty.delete(key2)) return;
85839
+ save();
85840
+ },
85841
+ flush
85842
+ };
85843
+ }
85844
+
85639
85845
  // src/server/watch.ts
85640
- var import_node_fs17 = __toESM(require("node:fs"), 1);
85641
- var import_node_path16 = __toESM(require("node:path"), 1);
85642
- var toPosix = (file) => file.split(import_node_path16.default.sep).join("/");
85846
+ var import_node_fs19 = __toESM(require("node:fs"), 1);
85847
+ var import_node_path17 = __toESM(require("node:path"), 1);
85848
+ var toPosix = (file) => file.split(import_node_path17.default.sep).join("/");
85643
85849
  var ignored = (file) => file === ".state" || file.startsWith(".state/");
85644
85850
  function snapshot(root, dir = root, out = /* @__PURE__ */ new Map()) {
85645
85851
  let entries2;
85646
85852
  try {
85647
- entries2 = import_node_fs17.default.readdirSync(dir, { withFileTypes: true });
85853
+ entries2 = import_node_fs19.default.readdirSync(dir, { withFileTypes: true });
85648
85854
  } catch {
85649
85855
  return out;
85650
85856
  }
85651
85857
  for (const entry of entries2) {
85652
- const full = import_node_path16.default.join(dir, entry.name);
85653
- const rel = toPosix(import_node_path16.default.relative(root, full));
85858
+ const full = import_node_path17.default.join(dir, entry.name);
85859
+ const rel = toPosix(import_node_path17.default.relative(root, full));
85654
85860
  if (ignored(rel)) continue;
85655
85861
  if (entry.isDirectory()) snapshot(root, full, out);
85656
85862
  else {
85657
85863
  try {
85658
- out.set(rel, import_node_fs17.default.statSync(full).mtimeMs);
85864
+ out.set(rel, import_node_fs19.default.statSync(full).mtimeMs);
85659
85865
  } catch {
85660
85866
  }
85661
85867
  }
@@ -85688,7 +85894,7 @@ function watchTree(root, onChange, debounceMs = 120, backupPollMs = 1e3) {
85688
85894
  }, debounceMs);
85689
85895
  };
85690
85896
  try {
85691
- const watcher = import_node_fs17.default.watch(root, { recursive: true }, (_event, filename) => {
85897
+ const watcher = import_node_fs19.default.watch(root, { recursive: true }, (_event, filename) => {
85692
85898
  if (filename) queue([toPosix(filename.toString())]);
85693
85899
  });
85694
85900
  watcher.on("error", () => {
@@ -85713,7 +85919,7 @@ function watchTree(root, onChange, debounceMs = 120, backupPollMs = 1e3) {
85713
85919
  }
85714
85920
 
85715
85921
  // src/server/ws.ts
85716
- var import_node_crypto5 = __toESM(require("node:crypto"), 1);
85922
+ var import_node_crypto6 = __toESM(require("node:crypto"), 1);
85717
85923
  var WS_MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
85718
85924
  var OPCODE_TEXT = 1;
85719
85925
  var OPCODE_CLOSE = 8;
@@ -85721,7 +85927,7 @@ var OPCODE_PING = 9;
85721
85927
  var OPCODE_PONG = 10;
85722
85928
  var MAX_CLIENT_FRAME = 8 * 1024 * 1024;
85723
85929
  function acceptKey(clientKey) {
85724
- return import_node_crypto5.default.createHash("sha1").update(clientKey + WS_MAGIC).digest("base64");
85930
+ return import_node_crypto6.default.createHash("sha1").update(clientKey + WS_MAGIC).digest("base64");
85725
85931
  }
85726
85932
  function encodeFrame(opcode, payload) {
85727
85933
  const len = payload.length;
@@ -85840,17 +86046,17 @@ function titleOf(payload, ref) {
85840
86046
  return payload.canvas?.title || ref.id;
85841
86047
  }
85842
86048
  async function startArtifactsServer(options) {
85843
- const root = import_node_path17.default.resolve(options.root);
85844
- const viewerDir = import_node_path17.default.resolve(options.viewerDir);
85845
- const runtimeDir = options.runtimeDir ? import_node_path17.default.resolve(options.runtimeDir) : null;
85846
- const stateDir = import_node_path17.default.join(root, ".state");
85847
- import_node_fs18.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
85848
- import_node_fs18.default.writeFileSync(import_node_path17.default.join(stateDir, ".gitignore"), "*\n");
86049
+ const root = import_node_path18.default.resolve(options.root);
86050
+ const viewerDir = import_node_path18.default.resolve(options.viewerDir);
86051
+ const runtimeDir = options.runtimeDir ? import_node_path18.default.resolve(options.runtimeDir) : null;
86052
+ const stateDir = import_node_path18.default.join(root, ".state");
86053
+ import_node_fs20.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
86054
+ import_node_fs20.default.writeFileSync(import_node_path18.default.join(stateDir, ".gitignore"), "*\n");
85849
86055
  if (options.configFile) ensureConfig(options.configFile);
85850
- const portFile = import_node_path17.default.join(stateDir, ".last-port");
85851
- const tokenFile = import_node_path17.default.join(stateDir, ".last-token");
86056
+ const portFile = import_node_path18.default.join(stateDir, ".last-port");
86057
+ const tokenFile = import_node_path18.default.join(stateDir, ".last-token");
85852
86058
  const token = readPersisted(tokenFile) || randomToken();
85853
- import_node_fs18.default.writeFileSync(tokenFile, `${token}
86059
+ import_node_fs20.default.writeFileSync(tokenFile, `${token}
85854
86060
  `, { mode: 384 });
85855
86061
  const contentToken = randomToken();
85856
86062
  const runtimeWarnings = /* @__PURE__ */ new Map();
@@ -85871,7 +86077,7 @@ async function startArtifactsServer(options) {
85871
86077
  for (const socket of clients) socket.write(frame);
85872
86078
  };
85873
86079
  const avatars = createAvatars(options.fetch);
85874
- const names = commentNames({ agentFile: import_node_path17.default.join(stateDir, "agent"), projectDir: import_node_path17.default.resolve(root, "../.."), cloud: options.cloud });
86080
+ const names = commentNames({ agentFile: import_node_path18.default.join(stateDir, "agent"), projectDir: import_node_path18.default.resolve(root, "../.."), cloud: options.cloud });
85875
86081
  const documents = createDocumentRegistry({
85876
86082
  root,
85877
86083
  stateDir,
@@ -85909,7 +86115,8 @@ async function startArtifactsServer(options) {
85909
86115
  }
85910
86116
  return { dir, title, reasons, payload: published };
85911
86117
  };
85912
- const cloud = options.cloud && options.configFile ? createCloudRoutes({ ...options.cloud, configFile: options.configFile, port: () => port, inspect }) : null;
86118
+ const cloud = options.cloud && options.configFile ? createCloudRoutes({ ...options.cloud, configFile: options.configFile, project: import_node_path18.default.basename(import_node_path18.default.resolve(root, "../..")), port: () => port, inspect }) : null;
86119
+ const autoPublisher = cloud ? createAutoPublisher({ stateFile: import_node_path18.default.join(stateDir, "auto-publish.json"), enabled: cloud.autoPublishEnabled, token: cloud.token, publish: cloud.autoPublish }) : null;
85913
86120
  const sameOrigin = (req) => {
85914
86121
  const origin2 = req.headers.origin;
85915
86122
  const host = req.headers.host ?? "";
@@ -85987,7 +86194,7 @@ async function startArtifactsServer(options) {
85987
86194
  };
85988
86195
  const blockIdsOf = async (id2, dir) => {
85989
86196
  await (await documents.open(id2))?.flush();
85990
- const state = parseDocument2(import_node_fs18.default.readFileSync(import_node_path17.default.join(dir, "doc.xml"), "utf8"));
86197
+ const state = parseDocument2(import_node_fs20.default.readFileSync(import_node_path18.default.join(dir, "doc.xml"), "utf8"));
85991
86198
  return new Set(state.root.children.flatMap((block) => block.$?.blockId ? [block.$.blockId] : []));
85992
86199
  };
85993
86200
  const serveAgentComments = async (req, res, id2) => {
@@ -86067,7 +86274,7 @@ async function startArtifactsServer(options) {
86067
86274
  sendFile(res, target, headers);
86068
86275
  return;
86069
86276
  }
86070
- import_node_fs18.default.readFile(target, "utf8", (err, source) => {
86277
+ import_node_fs20.default.readFile(target, "utf8", (err, source) => {
86071
86278
  if (err) send(res, 404, "Not found");
86072
86279
  else {
86073
86280
  const uiRuntimeUrl = runtimeDir ? `${contentPrefix}runtime/ryugi-ui.js` : void 0;
@@ -86092,7 +86299,7 @@ async function startArtifactsServer(options) {
86092
86299
  title: titleOf(readArtifact(entry.dir, entry), entry),
86093
86300
  updatedAt: latestMtime(entry.dir)
86094
86301
  }));
86095
- sendJson(res, 200, { project: import_node_path17.default.basename(import_node_path17.default.dirname(import_node_path17.default.dirname(root))), artifacts: summaries, warnings });
86302
+ sendJson(res, 200, { project: import_node_path18.default.basename(import_node_path18.default.dirname(import_node_path18.default.dirname(root))), artifacts: summaries, warnings });
86096
86303
  };
86097
86304
  function onClientText(socket, text2) {
86098
86305
  let message;
@@ -86152,7 +86359,7 @@ async function startArtifactsServer(options) {
86152
86359
  return;
86153
86360
  }
86154
86361
  if (pathname === "/robots.txt") {
86155
- sendFile(res, import_node_path17.default.join(viewerDir, "robots.txt"));
86362
+ sendFile(res, import_node_path18.default.join(viewerDir, "robots.txt"));
86156
86363
  return;
86157
86364
  }
86158
86365
  if (pathname.startsWith("/c/")) {
@@ -86201,6 +86408,19 @@ async function startArtifactsServer(options) {
86201
86408
  }
86202
86409
  return;
86203
86410
  }
86411
+ if (pathname === "/api/cloud/flush") {
86412
+ if (req.method !== "POST" || key2 === null || !safeEqual(key2, token)) {
86413
+ send(res, 403, "Forbidden: agent calls need ?key=");
86414
+ return;
86415
+ }
86416
+ if (!autoPublisher) sendJson(res, 404, { error: "cloud publishing is not configured" });
86417
+ else if (url2.searchParams.get("wait") === "1") void autoPublisher.flush().then(() => sendJson(res, 200, { flushed: true }));
86418
+ else {
86419
+ void autoPublisher.flush();
86420
+ sendJson(res, 202, { queued: true });
86421
+ }
86422
+ return;
86423
+ }
86204
86424
  const cloudMatch = cloud?.match(pathname);
86205
86425
  if (cloud && cloudMatch) {
86206
86426
  if (req.method !== "GET" && !(key2 !== null && safeEqual(key2, token)) && !sameOrigin(req)) {
@@ -86236,7 +86456,7 @@ async function startArtifactsServer(options) {
86236
86456
  if (SHELL_ROUTE.test(pathname) || PREVIEW_ROUTE.test(pathname) || pathname === "/index.html") {
86237
86457
  const ref = artifactKeyOf(pathname.replace(/^\/(?:preview\/)?/, "").replace(/\/$/, ""));
86238
86458
  const dir = ref && resolveArtifactDir(root, ref.type, ref.id);
86239
- const project = import_node_path17.default.basename(import_node_path17.default.dirname(import_node_path17.default.dirname(root)));
86459
+ const project = import_node_path18.default.basename(import_node_path18.default.dirname(import_node_path18.default.dirname(root)));
86240
86460
  const title = ref ? dir ? titleOf(readArtifact(dir, ref), ref) : ref.id : `${project} \xB7 Artifacts`;
86241
86461
  const description = ref ? `\u5728 ${project} \u9879\u76EE\u4E2D\u67E5\u770B ${title}\uFF0C\u8FD9\u662F\u4E00\u4E2A ${ref.type === "artboard" ? "Artboard" : ref.type === "document" ? "Document" : "HTML"} Artifact\u3002` : `\u6D4F\u89C8 ${project} \u9879\u76EE\u7684\u5168\u90E8 Artboard\u3001Document \u548C HTML Artifact\uFF0C\u9884\u89C8\u771F\u5B9E\u5185\u5BB9\uFF0C\u6309\u7C7B\u578B\u3001\u540D\u79F0\u548C\u66F4\u65B0\u65F6\u95F4\u67E5\u627E\u4F5C\u54C1\u3002`;
86242
86462
  const canonical = `http://${urlHostForHttp(options.urlHost)}:${port}/${ref ? `${ref.type}/${ref.id}` : ""}`;
@@ -86245,7 +86465,7 @@ async function startArtifactsServer(options) {
86245
86465
  "Content-Security-Policy": PREVIEW_ROUTE.test(pathname) ? VIEWER_CSP.replace("frame-ancestors 'none'", "frame-ancestors 'self'") : VIEWER_CSP
86246
86466
  };
86247
86467
  if (key2 !== null) headers["Set-Cookie"] = `${cookieName}=${token}; HttpOnly; SameSite=Strict; Path=/`;
86248
- void import_node_fs18.default.promises.readFile(import_node_path17.default.join(viewerDir, "index.html"), "utf8").then((template) => send(res, 200, viewerPage(template, { title, description, url: canonical }), headers)).catch((err) => send(res, err.code === "ENOENT" ? 404 : 500, "Viewer unavailable"));
86468
+ void import_node_fs20.default.promises.readFile(import_node_path18.default.join(viewerDir, "index.html"), "utf8").then((template) => send(res, 200, viewerPage(template, { title, description, url: canonical }), headers)).catch((err) => send(res, err.code === "ENOENT" ? 404 : 500, "Viewer unavailable"));
86249
86469
  return;
86250
86470
  }
86251
86471
  const target = resolveInside(viewerDir, pathname.slice(1));
@@ -86292,7 +86512,7 @@ async function startArtifactsServer(options) {
86292
86512
  port = await listen(server, options.host, 0);
86293
86513
  }
86294
86514
  cookieName = `ryugi_artifacts_${port}`;
86295
- import_node_fs18.default.writeFileSync(portFile, `${port}
86515
+ import_node_fs20.default.writeFileSync(portFile, `${port}
86296
86516
  `, { mode: 384 });
86297
86517
  const origin = `http://${urlHostForHttp(options.urlHost)}:${port}`;
86298
86518
  const url = `${origin}/?key=${token}`;
@@ -86318,7 +86538,7 @@ async function startArtifactsServer(options) {
86318
86538
  initialChanges.push({ ref: entry, payload, files: [] });
86319
86539
  if (entry.type === "document") void documents.open(entry.id);
86320
86540
  }
86321
- writeJsonAtomic(import_node_path17.default.join(stateDir, "server-info"), { type: "server-started", url, port, root });
86541
+ writeJsonAtomic(import_node_path18.default.join(stateDir, "server-info"), { type: "server-started", url, port, root });
86322
86542
  const watcher = watchTree(
86323
86543
  root,
86324
86544
  (files) => {
@@ -86336,6 +86556,7 @@ async function startArtifactsServer(options) {
86336
86556
  const dir = resolveArtifactDir(root, ref.type, ref.id);
86337
86557
  if (!dir) {
86338
86558
  signatures.delete(key2);
86559
+ autoPublisher?.removed(key2);
86339
86560
  const frame2 = textFrame(JSON.stringify({ type: "change", artifact: key2, files: changed }));
86340
86561
  for (const socket of clients) socket.write(frame2);
86341
86562
  continue;
@@ -86343,6 +86564,7 @@ async function startArtifactsServer(options) {
86343
86564
  if (ref.type === "document" && (changed.includes("doc.xml") || changed.length === 0)) documents.fileChanged(ref.id);
86344
86565
  if (ref.type === "document" && changed.includes("comments.json")) documents.commentsChanged(ref.id);
86345
86566
  if (signatures.get(key2) === artifactSignature(dir)) continue;
86567
+ autoPublisher?.changed(key2);
86346
86568
  runtimeWarnings.delete(key2);
86347
86569
  const payload = refreshState(ref, dir);
86348
86570
  const frame = textFrame(JSON.stringify({ type: "change", artifact: key2, files: changed }));
@@ -86376,7 +86598,7 @@ async function startArtifactsServer(options) {
86376
86598
  }
86377
86599
 
86378
86600
  // src/server/lifecycle.ts
86379
- var import_node_fs19 = __toESM(require("node:fs"), 1);
86601
+ var import_node_fs21 = __toESM(require("node:fs"), 1);
86380
86602
  var DEFAULT_IDLE_TIMEOUT_MS = 4 * 60 * 60 * 1e3;
86381
86603
  var DEFAULT_LIFECYCLE_CHECK_MS = 60 * 1e3;
86382
86604
  var SERVER_ID_ARG = "--artifacts-server-id=";
@@ -86408,7 +86630,7 @@ function parseEnv(env, argv = []) {
86408
86630
  function readOwners(file) {
86409
86631
  let text2;
86410
86632
  try {
86411
- text2 = import_node_fs19.default.readFileSync(file, "utf8");
86633
+ text2 = import_node_fs21.default.readFileSync(file, "utf8");
86412
86634
  } catch {
86413
86635
  return [];
86414
86636
  }
@@ -86473,15 +86695,15 @@ function openReady(payload) {
86473
86695
  // src/server/main.ts
86474
86696
  async function main() {
86475
86697
  const config = parseEnv(process.env, process.argv.slice(2));
86476
- const root = import_node_path18.default.resolve(config.root);
86477
- const stateDir = import_node_path18.default.join(root, ".state");
86698
+ const root = import_node_path19.default.resolve(config.root);
86699
+ const stateDir = import_node_path19.default.join(root, ".state");
86478
86700
  const server = await startArtifactsServer({
86479
86701
  root,
86480
- viewerDir: import_node_path18.default.join(__dirname, "viewer"),
86481
- runtimeDir: import_node_path18.default.join(__dirname, "runtime"),
86702
+ viewerDir: import_node_path19.default.join(__dirname, "viewer"),
86703
+ runtimeDir: import_node_path19.default.join(__dirname, "runtime"),
86482
86704
  host: config.host,
86483
86705
  urlHost: config.urlHost,
86484
- configFile: import_node_path18.default.join(import_node_path18.default.dirname(root), "config.json"),
86706
+ configFile: import_node_path19.default.join(import_node_path19.default.dirname(root), "config.json"),
86485
86707
  cloud: { origin: config.cloudOrigin, credentialsFile: credentialsFile(process.env, process.platform, import_node_os.default.homedir()) }
86486
86708
  });
86487
86709
  let lastActivity = Date.now();
@@ -86510,12 +86732,12 @@ async function main() {
86510
86732
  if (stopping) return;
86511
86733
  stopping = true;
86512
86734
  console.log(JSON.stringify({ type: "server-stopped", reason }));
86513
- import_node_fs20.default.rmSync(import_node_path18.default.join(stateDir, "server-info"), { force: true });
86514
- writeJsonAtomic(import_node_path18.default.join(stateDir, "server-stopped"), { reason, timestamp: Date.now() });
86735
+ import_node_fs22.default.rmSync(import_node_path19.default.join(stateDir, "server-info"), { force: true });
86736
+ writeJsonAtomic(import_node_path19.default.join(stateDir, "server-stopped"), { reason, timestamp: Date.now() });
86515
86737
  await server.close();
86516
86738
  process.exit(0);
86517
86739
  };
86518
- const ownersFile = import_node_path18.default.join(stateDir, "owners");
86740
+ const ownersFile = import_node_path19.default.join(stateDir, "owners");
86519
86741
  const timer = setInterval(() => {
86520
86742
  const owners = readOwners(ownersFile);
86521
86743
  const reason = shutdownReason({
@@ -86529,7 +86751,7 @@ async function main() {
86529
86751
  timer.unref();
86530
86752
  process.on("SIGTERM", () => void shutdown("SIGTERM"));
86531
86753
  process.on("SIGINT", () => void shutdown("SIGINT"));
86532
- import_node_fs20.default.rmSync(import_node_path18.default.join(stateDir, "server-stopped"), { force: true });
86754
+ import_node_fs22.default.rmSync(import_node_path19.default.join(stateDir, "server-stopped"), { force: true });
86533
86755
  console.log(JSON.stringify({ type: "server-started", url: server.url, port: server.port, root }));
86534
86756
  }
86535
86757
  main().catch((err) => {