opsidian 0.1.0 → 0.1.1

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/opsidian.mjs +102 -65
  2. package/package.json +1 -1
package/dist/opsidian.mjs CHANGED
@@ -8059,7 +8059,7 @@ var require_thread_stream = __commonJS({
8059
8059
  var { version } = require_package();
8060
8060
  var { EventEmitter } = __require("events");
8061
8061
  var { Worker } = __require("worker_threads");
8062
- var { join: join4 } = __require("path");
8062
+ var { join: join5 } = __require("path");
8063
8063
  var { pathToFileURL } = __require("url");
8064
8064
  var { wait } = require_wait();
8065
8065
  var {
@@ -8110,7 +8110,7 @@ var require_thread_stream = __commonJS({
8110
8110
  function createWorker(stream, opts) {
8111
8111
  const { filename, workerData } = opts;
8112
8112
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
8113
- const toExecute = bundlerOverrides["thread-stream-worker"] || join4(__dirname, "lib", "worker.js");
8113
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join5(__dirname, "lib", "worker.js");
8114
8114
  const worker = new Worker(toExecute, {
8115
8115
  ...opts.workerOpts,
8116
8116
  name: opts.workerOpts?.name || "thread-stream",
@@ -8578,7 +8578,7 @@ var require_transport = __commonJS({
8578
8578
  var { createRequire } = __require("module");
8579
8579
  var { existsSync: existsSync4 } = __require("node:fs");
8580
8580
  var getCallers = require_caller();
8581
- var { join: join4, isAbsolute, sep } = __require("node:path");
8581
+ var { join: join5, isAbsolute, sep } = __require("node:path");
8582
8582
  var { fileURLToPath: fileURLToPath2 } = __require("node:url");
8583
8583
  var sleep = require_atomic_sleep();
8584
8584
  var onExit = require_on_exit_leak_free();
@@ -8733,7 +8733,7 @@ var require_transport = __commonJS({
8733
8733
  throw new Error("only one of target or targets can be specified");
8734
8734
  }
8735
8735
  if (targets) {
8736
- target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
8736
+ target = bundlerOverrides["pino-worker"] || join5(__dirname, "worker.js");
8737
8737
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
8738
8738
  return {
8739
8739
  ...dest,
@@ -8754,7 +8754,7 @@ var require_transport = __commonJS({
8754
8754
  const pipelinesHaveLevel = options.pipelines.some((p) => p.some((t) => t.level != null));
8755
8755
  usesMultistream = options.targets.length + options.pipelines.length > 1 || targetsHaveLevel || pipelinesHaveLevel;
8756
8756
  } else if (pipeline) {
8757
- target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
8757
+ target = bundlerOverrides["pino-worker"] || join5(__dirname, "worker.js");
8758
8758
  options.pipelines = [pipeline.map((dest) => {
8759
8759
  return {
8760
8760
  ...dest,
@@ -8781,7 +8781,7 @@ var require_transport = __commonJS({
8781
8781
  return origin;
8782
8782
  }
8783
8783
  if (origin === "pino/file") {
8784
- return join4(__dirname, "..", "file.js");
8784
+ return join5(__dirname, "..", "file.js");
8785
8785
  }
8786
8786
  let fixTarget2;
8787
8787
  for (const filePath of callers) {
@@ -9761,7 +9761,7 @@ var require_safe_stable_stringify = __commonJS({
9761
9761
  return circularValue;
9762
9762
  }
9763
9763
  let res = "";
9764
- let join4 = ",";
9764
+ let join5 = ",";
9765
9765
  const originalIndentation = indentation;
9766
9766
  if (Array.isArray(value)) {
9767
9767
  if (value.length === 0) {
@@ -9775,7 +9775,7 @@ var require_safe_stable_stringify = __commonJS({
9775
9775
  indentation += spacer;
9776
9776
  res += `
9777
9777
  ${indentation}`;
9778
- join4 = `,
9778
+ join5 = `,
9779
9779
  ${indentation}`;
9780
9780
  }
9781
9781
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -9783,13 +9783,13 @@ ${indentation}`;
9783
9783
  for (; i < maximumValuesToStringify - 1; i++) {
9784
9784
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
9785
9785
  res += tmp2 !== void 0 ? tmp2 : "null";
9786
- res += join4;
9786
+ res += join5;
9787
9787
  }
9788
9788
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
9789
9789
  res += tmp !== void 0 ? tmp : "null";
9790
9790
  if (value.length - 1 > maximumBreadth) {
9791
9791
  const removedKeys = value.length - maximumBreadth - 1;
9792
- res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
9792
+ res += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
9793
9793
  }
9794
9794
  if (spacer !== "") {
9795
9795
  res += `
@@ -9810,7 +9810,7 @@ ${originalIndentation}`;
9810
9810
  let separator = "";
9811
9811
  if (spacer !== "") {
9812
9812
  indentation += spacer;
9813
- join4 = `,
9813
+ join5 = `,
9814
9814
  ${indentation}`;
9815
9815
  whitespace = " ";
9816
9816
  }
@@ -9824,13 +9824,13 @@ ${indentation}`;
9824
9824
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
9825
9825
  if (tmp !== void 0) {
9826
9826
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
9827
- separator = join4;
9827
+ separator = join5;
9828
9828
  }
9829
9829
  }
9830
9830
  if (keyLength > maximumBreadth) {
9831
9831
  const removedKeys = keyLength - maximumBreadth;
9832
9832
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
9833
- separator = join4;
9833
+ separator = join5;
9834
9834
  }
9835
9835
  if (spacer !== "" && separator.length > 1) {
9836
9836
  res = `
@@ -9871,7 +9871,7 @@ ${originalIndentation}`;
9871
9871
  }
9872
9872
  const originalIndentation = indentation;
9873
9873
  let res = "";
9874
- let join4 = ",";
9874
+ let join5 = ",";
9875
9875
  if (Array.isArray(value)) {
9876
9876
  if (value.length === 0) {
9877
9877
  return "[]";
@@ -9884,7 +9884,7 @@ ${originalIndentation}`;
9884
9884
  indentation += spacer;
9885
9885
  res += `
9886
9886
  ${indentation}`;
9887
- join4 = `,
9887
+ join5 = `,
9888
9888
  ${indentation}`;
9889
9889
  }
9890
9890
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -9892,13 +9892,13 @@ ${indentation}`;
9892
9892
  for (; i < maximumValuesToStringify - 1; i++) {
9893
9893
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
9894
9894
  res += tmp2 !== void 0 ? tmp2 : "null";
9895
- res += join4;
9895
+ res += join5;
9896
9896
  }
9897
9897
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
9898
9898
  res += tmp !== void 0 ? tmp : "null";
9899
9899
  if (value.length - 1 > maximumBreadth) {
9900
9900
  const removedKeys = value.length - maximumBreadth - 1;
9901
- res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
9901
+ res += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
9902
9902
  }
9903
9903
  if (spacer !== "") {
9904
9904
  res += `
@@ -9911,7 +9911,7 @@ ${originalIndentation}`;
9911
9911
  let whitespace = "";
9912
9912
  if (spacer !== "") {
9913
9913
  indentation += spacer;
9914
- join4 = `,
9914
+ join5 = `,
9915
9915
  ${indentation}`;
9916
9916
  whitespace = " ";
9917
9917
  }
@@ -9920,7 +9920,7 @@ ${indentation}`;
9920
9920
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
9921
9921
  if (tmp !== void 0) {
9922
9922
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
9923
- separator = join4;
9923
+ separator = join5;
9924
9924
  }
9925
9925
  }
9926
9926
  if (spacer !== "" && separator.length > 1) {
@@ -9978,20 +9978,20 @@ ${originalIndentation}`;
9978
9978
  indentation += spacer;
9979
9979
  let res2 = `
9980
9980
  ${indentation}`;
9981
- const join5 = `,
9981
+ const join6 = `,
9982
9982
  ${indentation}`;
9983
9983
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
9984
9984
  let i = 0;
9985
9985
  for (; i < maximumValuesToStringify - 1; i++) {
9986
9986
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
9987
9987
  res2 += tmp2 !== void 0 ? tmp2 : "null";
9988
- res2 += join5;
9988
+ res2 += join6;
9989
9989
  }
9990
9990
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
9991
9991
  res2 += tmp !== void 0 ? tmp : "null";
9992
9992
  if (value.length - 1 > maximumBreadth) {
9993
9993
  const removedKeys = value.length - maximumBreadth - 1;
9994
- res2 += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
9994
+ res2 += `${join6}"... ${getItemCount(removedKeys)} not stringified"`;
9995
9995
  }
9996
9996
  res2 += `
9997
9997
  ${originalIndentation}`;
@@ -10007,16 +10007,16 @@ ${originalIndentation}`;
10007
10007
  return '"[Object]"';
10008
10008
  }
10009
10009
  indentation += spacer;
10010
- const join4 = `,
10010
+ const join5 = `,
10011
10011
  ${indentation}`;
10012
10012
  let res = "";
10013
10013
  let separator = "";
10014
10014
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
10015
10015
  if (isTypedArrayWithEntries(value)) {
10016
- res += stringifyTypedArray(value, join4, maximumBreadth);
10016
+ res += stringifyTypedArray(value, join5, maximumBreadth);
10017
10017
  keys = keys.slice(value.length);
10018
10018
  maximumPropertiesToStringify -= value.length;
10019
- separator = join4;
10019
+ separator = join5;
10020
10020
  }
10021
10021
  if (deterministic) {
10022
10022
  keys = sort(keys, comparator);
@@ -10027,13 +10027,13 @@ ${indentation}`;
10027
10027
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
10028
10028
  if (tmp !== void 0) {
10029
10029
  res += `${separator}${strEscape(key2)}: ${tmp}`;
10030
- separator = join4;
10030
+ separator = join5;
10031
10031
  }
10032
10032
  }
10033
10033
  if (keyLength > maximumBreadth) {
10034
10034
  const removedKeys = keyLength - maximumBreadth;
10035
10035
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
10036
- separator = join4;
10036
+ separator = join5;
10037
10037
  }
10038
10038
  if (separator !== "") {
10039
10039
  res = `
@@ -38284,7 +38284,7 @@ ${body}`);
38284
38284
  import { spawn } from "node:child_process";
38285
38285
  import { existsSync as existsSync3 } from "node:fs";
38286
38286
  import { copyFile as copyFile2, mkdir as mkdir4, readFile as readFile3, rm as rm3 } from "node:fs/promises";
38287
- import { dirname as dirname3, resolve } from "node:path";
38287
+ import { dirname as dirname3, join as join4, resolve } from "node:path";
38288
38288
  import { fileURLToPath } from "node:url";
38289
38289
 
38290
38290
  // src/host.ts
@@ -40460,6 +40460,20 @@ function place(home = process.env.OPSIDIAN_HOME || join2(homedir(), ".opsidian")
40460
40460
  };
40461
40461
  }
40462
40462
  var DEFAULT_PORT = 4810;
40463
+ var BOOLEAN = /* @__PURE__ */ new Set(["follow", "f", "delete-data", "help", "h", "version", "v"]);
40464
+ function parseArgs(argv) {
40465
+ const flags2 = /* @__PURE__ */ new Map();
40466
+ const words2 = [];
40467
+ for (let position = 0; position < argv.length; position++) {
40468
+ const word = argv[position];
40469
+ const match = word.match(/^--?([a-z][a-z-]*)(?:=(.*))?$/);
40470
+ if (!match) words2.push(word);
40471
+ else if (match[2] !== void 0) flags2.set(match[1], match[2]);
40472
+ else if (BOOLEAN.has(match[1])) flags2.set(match[1], "");
40473
+ else flags2.set(match[1], argv[++position] ?? "");
40474
+ }
40475
+ return { flags: flags2, words: words2 };
40476
+ }
40463
40477
  async function readConfig(where2) {
40464
40478
  try {
40465
40479
  return JSON.parse(await readFile2(where2.config, "utf8"));
@@ -40605,8 +40619,16 @@ var Launchd = class {
40605
40619
  await writeFile3(this.file, launchdPlist(this.where));
40606
40620
  await run("launchctl", ["bootout", `${this.target}/${LABEL}`]).catch(() => {
40607
40621
  });
40622
+ for (let tries = 0; tries < 50 && await this.loaded(); tries++)
40623
+ await new Promise((done) => setTimeout(done, 100));
40608
40624
  await run("launchctl", ["bootstrap", this.target, this.file]);
40609
40625
  }
40626
+ async loaded() {
40627
+ return run("launchctl", ["print", `${this.target}/${LABEL}`]).then(
40628
+ () => true,
40629
+ () => false
40630
+ );
40631
+ }
40610
40632
  async remove() {
40611
40633
  await run("launchctl", ["bootout", `${this.target}/${LABEL}`]).catch(() => {
40612
40634
  });
@@ -40689,24 +40711,27 @@ function service(where2) {
40689
40711
  }
40690
40712
 
40691
40713
  // src/cli.ts
40692
- var VERSION = "0.1.0";
40714
+ var VERSION = "0.1.1";
40693
40715
  var me = process.env.npm_lifecycle_event === "start" ? "pnpm" : process.env.npm_command === "exec" ? "npx opsidian" : "opsidian";
40694
- var BOOLEAN = /* @__PURE__ */ new Set(["follow", "f", "delete-data", "help", "h", "version", "v"]);
40695
- var flags = /* @__PURE__ */ new Map();
40696
- var words = [];
40697
- var argv = process.argv.slice(2);
40698
- for (let position = 0; position < argv.length; position++) {
40699
- const word = argv[position];
40700
- const flag = word.match(/^--?([a-z-]+)$/)?.[1];
40701
- if (!flag) words.push(word);
40702
- else if (BOOLEAN.has(flag)) flags.set(flag, "");
40703
- else flags.set(flag, argv[++position] ?? "");
40704
- }
40716
+ var { flags, words } = parseArgs(process.argv.slice(2));
40705
40717
  var where = place();
40706
40718
  var when = (time) => new Date(time).toLocaleString();
40707
40719
  var fail = (text) => {
40708
40720
  throw new Error(text);
40709
40721
  };
40722
+ var whole = (name, fallback, low, high) => {
40723
+ const given = flags.get(name);
40724
+ if (given === void 0) return fallback;
40725
+ const value = Number(given);
40726
+ if (!Number.isInteger(value) || value < low || value > high)
40727
+ fail(`--${name} takes a whole number from ${low} to ${high}.`);
40728
+ return value;
40729
+ };
40730
+ var backupFrom = (folder, before) => ({
40731
+ folder: resolve(folder),
40732
+ keep: whole("keep", before?.keep ?? 14, 1, 1e3),
40733
+ hour: whole("hour", before?.hour ?? 3, 0, 23)
40734
+ });
40710
40735
  var HELP = `Opsidian ${VERSION}: a host for your notebooks, so every device syncs through it.
40711
40736
 
40712
40737
  ${me} host start Run the host in the background, now and after restarts
@@ -40753,10 +40778,14 @@ async function withHost(work) {
40753
40778
  }
40754
40779
  async function deviceAddress() {
40755
40780
  if (process.env.OPSIDIAN_ADDRESS) return process.env.OPSIDIAN_ADDRESS;
40781
+ if (existsSync3("/.dockerenv"))
40782
+ fail(
40783
+ "Inside Docker the host cannot see the address devices reach it at.\nRun the container with -e OPSIDIAN_ADDRESS=100.x.y.z:4810 (the server\u2019s Tailscale address)."
40784
+ );
40756
40785
  const config = await readConfig(where);
40757
40786
  return reachableAt({
40758
40787
  address: flags.get("address") ?? config?.address ?? "0.0.0.0",
40759
- port: Number(flags.get("port") ?? config?.port ?? DEFAULT_PORT)
40788
+ port: whole("port", config?.port ?? DEFAULT_PORT, 1, 65535)
40760
40789
  });
40761
40790
  }
40762
40791
  async function lastLines(count) {
@@ -40771,17 +40800,19 @@ function backupLine(config) {
40771
40800
  async function start() {
40772
40801
  const manager = needService();
40773
40802
  const before = await readConfig(where);
40774
- const port = Number(flags.get("port") ?? before?.port ?? DEFAULT_PORT);
40775
- if (!Number.isInteger(port) || port < 1 || port > 65535) fail("--port takes a number.");
40803
+ const port = whole("port", before?.port ?? DEFAULT_PORT, 1, 65535);
40776
40804
  let address = flags.get("address");
40805
+ let manual = address !== void 0 || before?.manual === true;
40777
40806
  let note;
40778
40807
  if (address === "all") {
40779
40808
  address = "0.0.0.0";
40780
40809
  note = "The host listens on every address. It has no sign-in of its own: make sure a firewall keeps it off the open internet.";
40781
40810
  } else if (!address) {
40782
40811
  const found = addresses();
40783
- if (before && found.some((each) => each.ip === before.address)) address = before.address;
40812
+ if (manual && before && (before.address === "0.0.0.0" || found.some((each) => each.ip === before.address)))
40813
+ address = before.address;
40784
40814
  else {
40815
+ manual = false;
40785
40816
  const chosen = chooseAddress(found, process.platform);
40786
40817
  if ("error" in chosen) return fail(chosen.error);
40787
40818
  address = chosen.ip;
@@ -40789,15 +40820,18 @@ async function start() {
40789
40820
  }
40790
40821
  }
40791
40822
  const config = { ...before, port, address };
40823
+ if (manual) config.manual = true;
40824
+ else delete config.manual;
40792
40825
  const folder = flags.get("backup");
40793
- if (folder)
40794
- config.backup = {
40795
- folder: resolve(folder),
40796
- keep: Number(flags.get("keep") ?? before?.backup?.keep ?? 14),
40797
- hour: Number(flags.get("hour") ?? before?.backup?.hour ?? 3)
40798
- };
40826
+ if (folder) config.backup = backupFrom(folder, before?.backup);
40827
+ else if (flags.has("keep") || flags.has("hour"))
40828
+ config.backup = backupFrom(
40829
+ before?.backup?.folder ?? fail("--keep and --hour go with --backup FOLDER."),
40830
+ before?.backup
40831
+ );
40799
40832
  const reach = reachableAt(config);
40800
- if (!(await manager.state()).running && await answers(reach))
40833
+ const moving = !(await manager.state()).running || before?.port !== port || before.address !== address;
40834
+ if (moving && await answers(reach))
40801
40835
  fail(
40802
40836
  `Another Opsidian host is already using port ${port} here, perhaps the Opsidian app.
40803
40837
  Turn hosting off there, or start this one with --port ${port + 1}.`
@@ -40900,11 +40934,7 @@ async function backup() {
40900
40934
  }
40901
40935
  let target = config?.backup;
40902
40936
  if (what !== "now") {
40903
- target = {
40904
- folder: resolve(what),
40905
- keep: Number(flags.get("keep") ?? target?.keep ?? 14),
40906
- hour: Number(flags.get("hour") ?? target?.hour ?? 3)
40907
- };
40937
+ target = backupFrom(what, target);
40908
40938
  if (config) {
40909
40939
  await writeConfig(where, { ...config, backup: target });
40910
40940
  console.log(`Backing up: ${backupLine({ ...config, backup: target })}.`);
@@ -40918,25 +40948,32 @@ async function restore() {
40918
40948
  const config = await readConfig(where);
40919
40949
  const name = words.at(-1);
40920
40950
  const folder = words.length > 1 ? resolve(words[0]) : config?.backup?.folder;
40921
- if (!name || !folder) fail(`Say which: ${me} host restore BACKUP, or restore FOLDER BACKUP`);
40922
- const manager = service(where);
40923
- const running = !("missing" in manager) && (await manager.state()).running;
40924
- if (running) await manager.remove();
40951
+ if (!name || !folder)
40952
+ return fail(`Say which: ${me} host restore BACKUP, or restore FOLDER BACKUP`);
40953
+ const data = flags.get("data") ?? where.data;
40954
+ const found = service(where);
40955
+ const manager = "missing" in found ? void 0 : found;
40956
+ const managed = (await manager?.state())?.running === true;
40957
+ const port = config?.port ?? DEFAULT_PORT;
40958
+ const live = [`127.0.0.1:${port}`, ...config ? [reachableAt(config)] : []];
40959
+ if (!managed && (await Promise.all(live.map(answers))).some(Boolean))
40960
+ fail("The host is running. Stop it first (Ctrl+C, or docker stop), then restore.");
40961
+ if (managed) await manager.remove();
40925
40962
  try {
40926
- if (existsSync3(`${where.data}/host.sqlite`)) {
40927
- const keep = (config?.backup?.keep ?? 14) + 1;
40963
+ if (existsSync3(join4(data, "host.sqlite"))) {
40964
+ const keep = (await listBackups(folder)).length + 1;
40928
40965
  const safety = await withHost((host) => host.backup(folder, keep));
40929
40966
  console.log(`Backed up what the host held first, as ${safety.name}.`);
40930
40967
  }
40931
- await restoreBackup(flags.get("data") ?? where.data, folder, name);
40968
+ await restoreBackup(data, folder, name);
40932
40969
  console.log("Restored. Devices catch up by themselves.");
40933
40970
  } finally {
40934
- if (running) await manager.install();
40971
+ if (managed) await manager.install();
40935
40972
  }
40936
40973
  }
40937
40974
  async function runHere() {
40938
40975
  const config = await readConfig(where);
40939
- const port = Number(flags.get("port") ?? config?.port ?? DEFAULT_PORT);
40976
+ const port = whole("port", config?.port ?? DEFAULT_PORT, 1, 65535);
40940
40977
  const address = flags.get("address") ?? config?.address ?? "0.0.0.0";
40941
40978
  const data = flags.get("data") ?? where.data;
40942
40979
  const host = new Host({ dataDir: data });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opsidian",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Host your own Opsidian notebooks: every device syncs through it.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "homepage": "https://ferran.sh/opsidian",