ryugi-artifacts 1.32.0 → 1.33.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
@@ -5171,9 +5171,9 @@ var require_websocket_server = __commonJS({
5171
5171
 
5172
5172
  // src/server/main.ts
5173
5173
  var import_node_child_process2 = require("node:child_process");
5174
- var import_node_fs26 = __toESM(require("node:fs"), 1);
5175
- var import_node_os = __toESM(require("node:os"), 1);
5176
- var import_node_path22 = __toESM(require("node:path"), 1);
5174
+ var import_node_fs27 = __toESM(require("node:fs"), 1);
5175
+ var import_node_os2 = __toESM(require("node:os"), 1);
5176
+ var import_node_path23 = __toESM(require("node:path"), 1);
5177
5177
 
5178
5178
  // src/server/app.ts
5179
5179
  var import_node_fs24 = __toESM(require("node:fs"), 1);
@@ -19688,19 +19688,19 @@ var ElementDOMSlot = class _ElementDOMSlot extends DOMSlot {
19688
19688
  }
19689
19689
  };
19690
19690
  function indexPath(root, child) {
19691
- const path23 = [];
19691
+ const path24 = [];
19692
19692
  let node = child;
19693
19693
  for (; node !== root && node !== null; node = node.parentNode) {
19694
19694
  let i6 = 0;
19695
19695
  for (let sibling = node.previousSibling; sibling !== null; sibling = sibling.previousSibling) {
19696
19696
  i6++;
19697
19697
  }
19698
- path23.push(i6);
19698
+ path24.push(i6);
19699
19699
  }
19700
19700
  if (!(node === root)) {
19701
19701
  formatDevErrorMessage(`indexPath: root is not a parent of child`);
19702
19702
  }
19703
- return path23.reverse();
19703
+ return path24.reverse();
19704
19704
  }
19705
19705
  // @__NO_SIDE_EFFECTS__
19706
19706
  function readLexicalVersion() {
@@ -34480,9 +34480,9 @@ function getActiveElementDeep(root) {
34480
34480
  function getComposedEventTarget(event) {
34481
34481
  const target = event.target;
34482
34482
  if (target !== null && isHTMLElement(target) && target.shadowRoot !== null && typeof event.composedPath === "function") {
34483
- const path23 = event.composedPath();
34484
- if (path23.length > 0) {
34485
- return path23[0];
34483
+ const path24 = event.composedPath();
34484
+ if (path24.length > 0) {
34485
+ return path24[0];
34486
34486
  }
34487
34487
  }
34488
34488
  return target;
@@ -44578,10 +44578,10 @@ function _loadWasmModule(sync, filepath, src, imports2) {
44578
44578
  var buf = null;
44579
44579
  var isNode2 = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
44580
44580
  if (filepath && isNode2) {
44581
- var fs29 = null;
44582
- var path23 = null;
44581
+ var fs30 = null;
44582
+ var path24 = null;
44583
44583
  return new Promise((resolve, reject) => {
44584
- fs29.readFile(path23.resolve(__dirname, filepath), (error, buffer) => {
44584
+ fs30.readFile(path24.resolve(__dirname, filepath), (error, buffer) => {
44585
44585
  if (error != null) {
44586
44586
  reject(error);
44587
44587
  } else {
@@ -45884,10 +45884,10 @@ var LoroDoc = class _LoroDoc {
45884
45884
  * @param {string} path
45885
45885
  * @returns {Value | Container | undefined}
45886
45886
  */
45887
- getByPath(path23) {
45887
+ getByPath(path24) {
45888
45888
  try {
45889
45889
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
45890
- const ptr0 = passStringToWasm0(path23, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
45890
+ const ptr0 = passStringToWasm0(path24, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
45891
45891
  const len0 = WASM_VECTOR_LEN;
45892
45892
  wasm.lorodoc_getByPath(retptr, this.__wbg_ptr, ptr0, len0);
45893
45893
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
@@ -90150,7 +90150,7 @@ function createCloudRoutes(options) {
90150
90150
  const challenge = import_node_crypto8.default.createHash("sha256").update(verifier).digest("base64url");
90151
90151
  return `${origin}/auth/cli?port=${options.port()}&state=${state}&challenge=${challenge}`;
90152
90152
  };
90153
- const cloudFetch = async (method, path23, body) => {
90153
+ const cloudFetch = async (method, path24, body) => {
90154
90154
  const credentials = readCredentials(credentialsFile2, origin);
90155
90155
  if (!credentials) throw new SignedOut();
90156
90156
  const headers = { Authorization: `Bearer ${credentials.token}` };
@@ -90164,7 +90164,7 @@ function createCloudRoutes(options) {
90164
90164
  }
90165
90165
  let res;
90166
90166
  try {
90167
- res = await fetch(`${origin}${path23}`, { method, headers, body: payload });
90167
+ res = await fetch(`${origin}${path24}`, { method, headers, body: payload });
90168
90168
  } catch (err) {
90169
90169
  throw new CloudRefused(502, `could not reach ${origin}: ${err.message}`);
90170
90170
  }
@@ -90221,7 +90221,7 @@ function createCloudRoutes(options) {
90221
90221
  }
90222
90222
  const sha = (data) => import_node_crypto8.default.createHash("sha256").update(data).digest("hex");
90223
90223
  const hashed = withCloudRuntime(ref.type, packed).map((file) => ({ ...file, hash: sha(file.data) }));
90224
- const content = { title: inspected.title, payload: inspected.payload, files: hashed.map(({ path: path23, hash }) => ({ path: path23, hash })) };
90224
+ const content = { title: inspected.title, payload: inspected.payload, files: hashed.map(({ path: path24, hash }) => ({ path: path24, hash })) };
90225
90225
  const fingerprint = sha(JSON.stringify({ title: inspected.title, payload: fingerprintPayload(inspected.payload), files: packed.map((file) => ({ path: file.path, hash: sha(file.data) })) }));
90226
90226
  return { ready: true, hashed, content, fingerprint };
90227
90227
  };
@@ -90921,7 +90921,12 @@ async function startArtifactsServer(options) {
90921
90921
  selections.clearAll();
90922
90922
  const changeListeners = [];
90923
90923
  const activityListeners = [];
90924
- const touch = () => activityListeners.forEach((listener) => listener());
90924
+ const startedAt = Date.now();
90925
+ let lastActivity = startedAt;
90926
+ const touch = () => {
90927
+ lastActivity = Date.now();
90928
+ activityListeners.forEach((listener) => listener());
90929
+ };
90925
90930
  let port = 0;
90926
90931
  let cookieName = "";
90927
90932
  let relay = null;
@@ -91289,9 +91294,14 @@ async function startArtifactsServer(options) {
91289
91294
  for (const socket of clients) socket.write(frame);
91290
91295
  }
91291
91296
  const handleRequest = (req, res) => {
91292
- touch();
91293
91297
  res.setHeader("X-Robots-Tag", "noindex, nofollow");
91294
91298
  const url2 = new URL(req.url ?? "/", "http://artifacts.local");
91299
+ if (url2.pathname === "/api/status") {
91300
+ if (!isAuthorized(req, url2.searchParams.get("key"))) send(res, 403, "Forbidden: agent calls need ?key=");
91301
+ else sendJson(res, 200, { pid: process.pid, startedAt, lastActivity, clients: clients.size });
91302
+ return;
91303
+ }
91304
+ touch();
91295
91305
  let pathname;
91296
91306
  try {
91297
91307
  pathname = decodeURIComponent(url2.pathname);
@@ -91800,22 +91810,76 @@ function openReady(payload) {
91800
91810
  return pageBoards.filter(([id2]) => ready(id2)).length >= 2;
91801
91811
  }
91802
91812
 
91813
+ // src/server/registry.ts
91814
+ var import_node_crypto11 = __toESM(require("node:crypto"), 1);
91815
+ var import_node_fs26 = __toESM(require("node:fs"), 1);
91816
+ var import_node_os = __toESM(require("node:os"), 1);
91817
+ var import_node_path22 = __toESM(require("node:path"), 1);
91818
+ function registryDir(env = process.env, platform = process.platform, uid = process.getuid?.() ?? -1, tmpdir = import_node_os.default.tmpdir()) {
91819
+ if (env.RYUGI_RUNTIME_DIR) return import_node_path22.default.join(env.RYUGI_RUNTIME_DIR, "servers");
91820
+ if (platform === "win32") return import_node_path22.default.join(tmpdir, "ryugi", "servers");
91821
+ return `/tmp/ryugi-${uid}/servers`;
91822
+ }
91823
+ var fileFor = (dir, project) => import_node_path22.default.join(dir, `${import_node_crypto11.default.createHash("sha256").update(project).digest("hex").slice(0, 16)}.json`);
91824
+ function verifyDir(dir) {
91825
+ if (process.platform === "win32") return;
91826
+ for (const target of [import_node_path22.default.dirname(dir), dir]) {
91827
+ const stat = import_node_fs26.default.lstatSync(target);
91828
+ if (!stat.isDirectory() || stat.uid !== process.getuid() || stat.mode & 18) throw new Error(`Unsafe registry directory: ${target}`);
91829
+ }
91830
+ }
91831
+ function ensureDir(dir) {
91832
+ import_node_fs26.default.mkdirSync(dir, { recursive: true, mode: 448 });
91833
+ verifyDir(dir);
91834
+ }
91835
+ function writeEntry(dir, entry) {
91836
+ ensureDir(dir);
91837
+ const file = fileFor(dir, entry.project);
91838
+ const tmp = `${file}.${process.pid}.tmp`;
91839
+ import_node_fs26.default.writeFileSync(tmp, `${JSON.stringify(entry)}
91840
+ `, { mode: 384 });
91841
+ import_node_fs26.default.renameSync(tmp, file);
91842
+ }
91843
+ function readEntry(file) {
91844
+ try {
91845
+ const value = JSON.parse(import_node_fs26.default.readFileSync(file, "utf8"));
91846
+ if (typeof value.project !== "string" || typeof value.root !== "string" || typeof value.serverId !== "string") return null;
91847
+ if (!Number.isInteger(value.pid) || !Number.isFinite(value.startedAt)) return null;
91848
+ if (value.root !== import_node_path22.default.join(value.project, ".ryugi", "artifacts")) return null;
91849
+ return value;
91850
+ } catch {
91851
+ return null;
91852
+ }
91853
+ }
91854
+ function removeEntry(dir, entry) {
91855
+ const file = fileFor(dir, entry.project);
91856
+ if (readEntry(file)?.serverId === entry.serverId) import_node_fs26.default.rmSync(file, { force: true });
91857
+ }
91858
+ function touchEntry(dir, entry) {
91859
+ const file = fileFor(dir, entry.project);
91860
+ const current = readEntry(file);
91861
+ if (!current) return writeEntry(dir, entry);
91862
+ if (current.serverId !== entry.serverId) return;
91863
+ const now = /* @__PURE__ */ new Date();
91864
+ import_node_fs26.default.utimesSync(file, now, now);
91865
+ }
91866
+
91803
91867
  // package.json
91804
- var version = "1.32.0";
91868
+ var version = "1.33.0";
91805
91869
 
91806
91870
  // src/server/main.ts
91807
91871
  async function main() {
91808
91872
  const config = parseEnv(process.env, process.argv.slice(2));
91809
- const root = import_node_path22.default.resolve(config.root);
91810
- const stateDir = import_node_path22.default.join(root, ".state");
91873
+ const root = import_node_path23.default.resolve(config.root);
91874
+ const stateDir = import_node_path23.default.join(root, ".state");
91811
91875
  const server = await startArtifactsServer({
91812
91876
  root,
91813
- viewerDir: import_node_path22.default.join(__dirname, "viewer"),
91814
- runtimeDir: import_node_path22.default.join(__dirname, "runtime"),
91877
+ viewerDir: import_node_path23.default.join(__dirname, "viewer"),
91878
+ runtimeDir: import_node_path23.default.join(__dirname, "runtime"),
91815
91879
  host: config.host,
91816
91880
  urlHost: config.urlHost,
91817
- configFile: import_node_path22.default.join(import_node_path22.default.dirname(root), "config.json"),
91818
- cloud: { origin: config.cloudOrigin, credentialsFile: credentialsFile(process.env, process.platform, import_node_os.default.homedir()) },
91881
+ configFile: import_node_path23.default.join(import_node_path23.default.dirname(root), "config.json"),
91882
+ cloud: { origin: config.cloudOrigin, credentialsFile: credentialsFile(process.env, process.platform, import_node_os2.default.homedir()) },
91819
91883
  relay: { url: `${config.cloudOrigin.replace(/^http/, "ws")}/api/relay/host`, version }
91820
91884
  });
91821
91885
  let lastActivity = Date.now();
@@ -91839,17 +91903,26 @@ async function main() {
91839
91903
  if (launcher) (0, import_node_child_process2.execFile)(launcher.bin, launcher.args, () => {
91840
91904
  });
91841
91905
  });
91906
+ const registry2 = registryDir();
91907
+ const entry = config.serverId ? { project: import_node_path23.default.dirname(import_node_path23.default.dirname(root)), root, pid: process.pid, serverId: config.serverId, startedAt: Date.now() } : null;
91908
+ const quietly = (fn5) => {
91909
+ try {
91910
+ fn5();
91911
+ } catch {
91912
+ }
91913
+ };
91842
91914
  let stopping = false;
91843
91915
  const shutdown = async (reason) => {
91844
91916
  if (stopping) return;
91845
91917
  stopping = true;
91846
91918
  console.log(JSON.stringify({ type: "server-stopped", reason }));
91847
- import_node_fs26.default.rmSync(import_node_path22.default.join(stateDir, "server-info"), { force: true });
91848
- writeJsonAtomic(import_node_path22.default.join(stateDir, "server-stopped"), { reason, timestamp: Date.now() });
91919
+ import_node_fs27.default.rmSync(import_node_path23.default.join(stateDir, "server-info"), { force: true });
91920
+ writeJsonAtomic(import_node_path23.default.join(stateDir, "server-stopped"), { reason, timestamp: Date.now() });
91921
+ if (entry) quietly(() => removeEntry(registry2, entry));
91849
91922
  await server.close();
91850
91923
  process.exit(0);
91851
91924
  };
91852
- const ownersFile = import_node_path22.default.join(stateDir, "owners");
91925
+ const ownersFile = import_node_path23.default.join(stateDir, "owners");
91853
91926
  const timer = setInterval(() => {
91854
91927
  const owners = readOwners(ownersFile);
91855
91928
  const reason = shutdownReason({
@@ -91859,11 +91932,14 @@ async function main() {
91859
91932
  ownersAlive: owners.length === 0 || liveOwners(owners, processAlive).length > 0
91860
91933
  });
91861
91934
  if (reason) void shutdown(reason);
91935
+ else if (entry) quietly(() => touchEntry(registry2, entry));
91862
91936
  }, config.lifecycleCheckMs);
91863
91937
  timer.unref();
91864
91938
  process.on("SIGTERM", () => void shutdown("SIGTERM"));
91865
91939
  process.on("SIGINT", () => void shutdown("SIGINT"));
91866
- import_node_fs26.default.rmSync(import_node_path22.default.join(stateDir, "server-stopped"), { force: true });
91940
+ process.on("SIGHUP", () => void shutdown("SIGHUP"));
91941
+ import_node_fs27.default.rmSync(import_node_path23.default.join(stateDir, "server-stopped"), { force: true });
91942
+ if (entry) quietly(() => writeEntry(registry2, entry));
91867
91943
  console.log(JSON.stringify({ type: "server-started", url: server.url, port: server.port, root }));
91868
91944
  }
91869
91945
  main().catch((err) => {
@@ -1 +1 @@
1
- import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{n as t,t as n}from"./jsx-runtime-CldxteV5.js";import{T as r,o as i,w as a}from"./RailSwitch-B8Aht-FG.js";import{t as o}from"./index.js";import s from"./CloudDocument-DBhwAPZX.js";import{DocumentView as c,t as l}from"./DocumentPage-p78IN0UO.js";var u=e(t(),1),d=`1.32.0`,f=e=>/^(\d+)\.(\d+)\./.exec(e??``)?.slice(1,3).join(`.`)??null;function p(e,t){let n=f(e);return n!==null&&n===f(t)}var m=(e,t)=>a.t(`document.versionReason`,{host:t??a.t(`document.unknownVersion`),viewer:e}),h=n();function g({id:e,state:t,contentBase:n,liveContentBase:a,comments:f}){let{transport:g,presence:_}=l(e,a??n??``),v=_?.online??!1;i(e,{online:_?.online??null});let[y,b]=(0,u.useState)(!1);(0,u.useEffect)(()=>{v&&b(!0)},[v]);let x=t&&n?(0,h.jsx)(s,{id:e,state:t,contentBase:n,comments:f,offline:_!==null&&!v}):null;if(!g||!(y||v))return x??(0,h.jsx)(o,{children:r(_===null?`common.connecting`:`document.notPublished`)});let S=v&&p(d,_?.version??null),C=v&&!S?m(d,_?.version??null):null;return(0,h.jsx)(c,{id:e,transport:g,live:v,cloud:{online:v,canEdit:S,reason:C},fallback:x})}export{g as default};
1
+ import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{n as t,t as n}from"./jsx-runtime-CldxteV5.js";import{T as r,o as i,w as a}from"./RailSwitch-B8Aht-FG.js";import{t as o}from"./index.js";import s from"./CloudDocument-DBhwAPZX.js";import{DocumentView as c,t as l}from"./DocumentPage-p78IN0UO.js";var u=e(t(),1),d=`1.33.0`,f=e=>/^(\d+)\.(\d+)\./.exec(e??``)?.slice(1,3).join(`.`)??null;function p(e,t){let n=f(e);return n!==null&&n===f(t)}var m=(e,t)=>a.t(`document.versionReason`,{host:t??a.t(`document.unknownVersion`),viewer:e}),h=n();function g({id:e,state:t,contentBase:n,liveContentBase:a,comments:f}){let{transport:g,presence:_}=l(e,a??n??``),v=_?.online??!1;i(e,{online:_?.online??null});let[y,b]=(0,u.useState)(!1);(0,u.useEffect)(()=>{v&&b(!0)},[v]);let x=t&&n?(0,h.jsx)(s,{id:e,state:t,contentBase:n,comments:f,offline:_!==null&&!v}):null;if(!g||!(y||v))return x??(0,h.jsx)(o,{children:r(_===null?`common.connecting`:`document.notPublished`)});let S=v&&p(d,_?.version??null),C=v&&!S?m(d,_?.version??null):null;return(0,h.jsx)(c,{id:e,transport:g,live:v,cloud:{online:v,canEdit:S,reason:C},fallback:x})}export{g as default};