@ours.network/messenger-server 1.0.31-nightly.10 → 1.0.31-nightly.11

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.
@@ -38,7 +38,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
38
38
  var define_MESSENGER_BUILD_INFO_default;
39
39
  var init_define_MESSENGER_BUILD_INFO = __esm({
40
40
  "<define:__MESSENGER_BUILD_INFO__>"() {
41
- define_MESSENGER_BUILD_INFO_default = { name: "@ours.network/messenger-server", version: "1.0.31-nightly.10", sha: "8439d0b521650da63b97749c8bd7ebd48826ef05", dirty: true };
41
+ define_MESSENGER_BUILD_INFO_default = { name: "@ours.network/messenger-server", version: "1.0.31-nightly.11", sha: "0b84916c7fa85aa89cc5fcc004fb6b7cd79a26cd", dirty: true };
42
42
  }
43
43
  });
44
44
 
@@ -10,7 +10,7 @@ import {
10
10
  publicEngineError,
11
11
  publicInternalError,
12
12
  reportFailure
13
- } from "./chunk-O34PQ4M6.js";
13
+ } from "./chunk-Y5H3QIV5.js";
14
14
 
15
15
  // node_modules/bn.js/lib/bn.js
16
16
  var require_bn = __commonJS({
@@ -2990,7 +2990,7 @@ var require_reporter = __commonJS({
2990
2990
  if (state.obj !== null)
2991
2991
  state.obj[key] = value;
2992
2992
  };
2993
- Reporter.prototype.path = function path() {
2993
+ Reporter.prototype.path = function path2() {
2994
2994
  return this._reporterState.path.join("/");
2995
2995
  };
2996
2996
  Reporter.prototype.enterObject = function enterObject() {
@@ -3031,8 +3031,8 @@ var require_reporter = __commonJS({
3031
3031
  errors: state.errors
3032
3032
  };
3033
3033
  };
3034
- function ReporterError(path, msg) {
3035
- this.path = path;
3034
+ function ReporterError(path2, msg) {
3035
+ this.path = path2;
3036
3036
  this.rethrow(msg);
3037
3037
  }
3038
3038
  inherits(ReporterError, Error);
@@ -3144,7 +3144,7 @@ var require_buffer = __commonJS({
3144
3144
  const isCompatible = typeof data === "object" && data.constructor.name === "EncoderBuffer" && typeof data.length === "number" && typeof data.join === "function";
3145
3145
  return isCompatible;
3146
3146
  };
3147
- EncoderBuffer.prototype.join = function join5(out, offset) {
3147
+ EncoderBuffer.prototype.join = function join6(out, offset) {
3148
3148
  if (!out)
3149
3149
  out = Buffer2.alloc(this.length);
3150
3150
  if (!offset)
@@ -11676,7 +11676,7 @@ var MessengerNotificationProducer = class {
11676
11676
  };
11677
11677
 
11678
11678
  // src/server.ts
11679
- import { existsSync as existsSync2 } from "node:fs";
11679
+ import { existsSync as existsSync3 } from "node:fs";
11680
11680
  import { readFile, realpath, stat } from "node:fs/promises";
11681
11681
  import { createServer } from "node:http";
11682
11682
  import { dirname as dirname5, extname, isAbsolute as isAbsolute2, relative, resolve as resolve2, sep } from "node:path";
@@ -11686,6 +11686,44 @@ import { Worker } from "node:worker_threads";
11686
11686
  // src/api.ts
11687
11687
  init_define_MESSENGER_BUILD_INFO();
11688
11688
 
11689
+ // src/workspace-profile.ts
11690
+ init_define_MESSENGER_BUILD_INFO();
11691
+ import { existsSync as existsSync2, lstatSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
11692
+ import { join as join2 } from "node:path";
11693
+ import { randomUUID } from "node:crypto";
11694
+ function profileName(value) {
11695
+ if (typeof value !== "string" || !value.trim() || value.length > 100 || /[\x00-\x1f\x7f]/.test(value)) throw Error("Name and Surname require printable text");
11696
+ return value.trim();
11697
+ }
11698
+ function path(dir, cid) {
11699
+ if (!/^[a-f0-9]{64}$/i.test(cid)) throw Error("Invalid identity");
11700
+ return join2(dir, "human-" + cid.toLowerCase() + ".json");
11701
+ }
11702
+ function readHumanProfile(dir, cid) {
11703
+ if (!/^[a-f0-9]{64}$/i.test(cid)) return;
11704
+ const file = path(dir, cid);
11705
+ if (!existsSync2(file)) return;
11706
+ const stat2 = lstatSync(file);
11707
+ if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.nlink !== 1 || stat2.uid !== process.getuid?.() || (stat2.mode & 63) !== 0) throw Error("Private profile path required");
11708
+ const row = JSON.parse(readFileSync2(file, "utf8"));
11709
+ return { name: profileName(row.name), surname: profileName(row.surname) };
11710
+ }
11711
+ function writeHumanProfile(dir, cid, value) {
11712
+ const row = { name: profileName(value.name), surname: profileName(value.surname) };
11713
+ mkdirSync2(dir, { recursive: true, mode: 448 });
11714
+ const directory = lstatSync(dir);
11715
+ if (!directory.isDirectory() || directory.isSymbolicLink() || directory.uid !== process.getuid?.() || (directory.mode & 63) !== 0) throw Error("Private profile directory required");
11716
+ const file = path(dir, cid);
11717
+ if (existsSync2(file)) {
11718
+ const stat2 = lstatSync(file);
11719
+ if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.nlink !== 1 || stat2.uid !== process.getuid?.() || (stat2.mode & 63) !== 0) throw Error("Private profile path required");
11720
+ }
11721
+ const temporary = file + "." + randomUUID();
11722
+ writeFileSync2(temporary, JSON.stringify(row) + "\n", { mode: 384, flag: "wx" });
11723
+ renameSync2(temporary, file);
11724
+ return row;
11725
+ }
11726
+
11689
11727
  // src/conversation.ts
11690
11728
  init_define_MESSENGER_BUILD_INFO();
11691
11729
 
@@ -11956,8 +11994,8 @@ function toSse(event, identity) {
11956
11994
  // src/command-invocations.ts
11957
11995
  init_define_MESSENGER_BUILD_INFO();
11958
11996
  import { createHash as createHash2 } from "node:crypto";
11959
- import { chmodSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
11960
- import { dirname as dirname2, join as join2 } from "node:path";
11997
+ import { chmodSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "node:fs";
11998
+ import { dirname as dirname2, join as join3 } from "node:path";
11961
11999
  var MAX_INVOCATIONS = 4096;
11962
12000
  var InvocationConflictError = class extends Error {
11963
12001
  };
@@ -11984,10 +12022,10 @@ var CommandInvocationStore = class _CommandInvocationStore {
11984
12022
  }
11985
12023
  static open(stateDir, identityCid, capacity = MAX_INVOCATIONS) {
11986
12024
  if (!Number.isInteger(capacity) || capacity < 1) throw new Error("invocation capacity must be a positive integer");
11987
- const file = join2(stateDir, `typed-commands-${createHash2("sha256").update(identityCid).digest("hex").slice(0, 24)}.json`);
12025
+ const file = join3(stateDir, `typed-commands-${createHash2("sha256").update(identityCid).digest("hex").slice(0, 24)}.json`);
11988
12026
  let state = { version: 1, records: {} };
11989
12027
  try {
11990
- const parsed = JSON.parse(readFileSync2(file, "utf8"));
12028
+ const parsed = JSON.parse(readFileSync3(file, "utf8"));
11991
12029
  if (!parsed || typeof parsed !== "object" || parsed.version !== 1 || !parsed.records || typeof parsed.records !== "object" || !Object.values(parsed.records).every(validRecord)) {
11992
12030
  throw new Error("invalid typed command invocation state");
11993
12031
  }
@@ -12035,11 +12073,11 @@ var CommandInvocationStore = class _CommandInvocationStore {
12035
12073
  return record;
12036
12074
  }
12037
12075
  save() {
12038
- mkdirSync2(dirname2(this.file), { recursive: true, mode: 448 });
12076
+ mkdirSync3(dirname2(this.file), { recursive: true, mode: 448 });
12039
12077
  const temp = `${this.file}.${process.pid}.tmp`;
12040
- writeFileSync2(temp, JSON.stringify(this.state), { mode: 384 });
12078
+ writeFileSync3(temp, JSON.stringify(this.state), { mode: 384 });
12041
12079
  chmodSync(temp, 384);
12042
- renameSync2(temp, this.file);
12080
+ renameSync3(temp, this.file);
12043
12081
  }
12044
12082
  };
12045
12083
  function statusFor(delivery, wireId) {
@@ -20977,7 +21015,47 @@ var ROUTES = {
20977
21015
  // ---- identity / profile --------------------------------------------------
20978
21016
  // The old browser surface called the read half `getProfileName`; the name is a
20979
21017
  // field on this result.
20980
- "GET /api/identity": async ({ client }) => publicIdentity(await client.currentIdentity()),
21018
+ "GET /api/identity": async ({ client, deps }) => ({ ...publicIdentity(await client.currentIdentity()), humanProfile: readHumanProfile(deps.config.stateDir, deps.identityCid) }),
21019
+ "POST /api/identity/profile": async ({ client, deps, body }) => {
21020
+ const identity = await client.currentIdentity();
21021
+ if (!identity.isRoot || identity.temporary) throw bad("Human profile requires the root identity");
21022
+ return writeHumanProfile(deps.config.stateDir, deps.identityCid, { name: profileName(body.name), surname: profileName(body.surname) });
21023
+ },
21024
+ // First-party setup operation: daemon signs the command using this bound root.
21025
+ "GET /api/workspace/enrollment-identity": async ({ client }) => {
21026
+ const identity = await client.currentIdentity();
21027
+ if (!identity.isRoot || identity.temporary) throw bad("Workspace proof requires the bound Human root");
21028
+ return { cid: identity.cid };
21029
+ },
21030
+ "POST /api/workspace/enroll": async ({ client, deps, body }) => {
21031
+ const identity = await client.currentIdentity();
21032
+ if (!identity.isRoot || identity.temporary) throw bad("Workspace proof requires the bound Human root");
21033
+ const serverCid = str(body, "serverCid").toUpperCase();
21034
+ if (!/^[A-F0-9]{64}$/.test(serverCid) || !/^[A-Za-z0-9_-]{43}$/.test(str(body, "hostWorkspaceId"))) throw bad("Invalid workspace proof");
21035
+ const challenge = body.challenge;
21036
+ if (!challenge || !["nonce", "workspaceId", "accountId"].every((k3) => typeof challenge[k3] === "string" && /^[A-Za-z0-9_-]{43}$/.test(String(challenge[k3]))) || !Number.isFinite(challenge.expiresAt) || Number(challenge.expiresAt) <= Date.now() || Number(challenge.expiresAt) > Date.now() + 16 * 6e4) throw bad("Workspace challenge expired or invalid");
21037
+ let humanProfile;
21038
+ try {
21039
+ humanProfile = { name: profileName(body.name), surname: profileName(body.surname) };
21040
+ } catch {
21041
+ throw bad("Name and Surname require printable text up to 100 characters");
21042
+ }
21043
+ const invitation = str(body, "invitation");
21044
+ if (invitation.length > 8192) throw bad("Workspace invitation too large");
21045
+ writeHumanProfile(deps.config.stateDir, deps.identityCid, humanProfile);
21046
+ const peer = await client.addContact({ invite: invitation });
21047
+ if (peer.cid.toUpperCase() !== serverCid) throw bad("Enrollment server identity mismatch");
21048
+ const contactDeadline = Date.now() + 1e4;
21049
+ while (!(await client.listContacts()).contacts.some((contact) => contact.container_id.toUpperCase() === serverCid)) {
21050
+ if (Date.now() >= contactDeadline) throw bad("Enrollment contact is not ready; obtain a fresh setup payload before retrying");
21051
+ await new Promise((resolve3) => setTimeout(resolve3, 100));
21052
+ }
21053
+ const argumentsValue = { type: "ours.app.bind-workspace.v1", accountId: String(challenge.accountId), workspaceId: String(challenge.workspaceId), nonce: String(challenge.nonce), hostWorkspaceId: String(body.hostWorkspaceId) };
21054
+ const outcome = await client.sendCommand({ contact: serverCid, command: "bind-workspace", arguments: argumentsValue });
21055
+ if (!("sent" in outcome) || !outcome.sent) throw bad("Workspace proof was not sent");
21056
+ const invite = await client.generateInvite({ mode: "public" });
21057
+ return { submitted: true, rootCid: identity.cid, ownerInvite: invite.blob };
21058
+ },
20981
21059
  "GET /api/identities": async ({ client }) => client.listIdentities(),
20982
21060
  "POST /api/identity/bio": async ({ client, body }) => {
20983
21061
  const bio = body.bio;
@@ -21991,11 +22069,11 @@ async function G(e2 = {}) {
21991
22069
  init_define_MESSENGER_BUILD_INFO();
21992
22070
  import { randomBytes } from "node:crypto";
21993
22071
  import * as fs from "node:fs";
21994
- import { isAbsolute, join as join3, resolve, dirname as dirname3 } from "node:path";
22072
+ import { isAbsolute, join as join4, resolve, dirname as dirname3 } from "node:path";
21995
22073
  import { spawnSync } from "node:child_process";
21996
- function stateExists(path) {
22074
+ function stateExists(path2) {
21997
22075
  try {
21998
- fs.lstatSync(path);
22076
+ fs.lstatSync(path2);
21999
22077
  return true;
22000
22078
  } catch (error) {
22001
22079
  if (error.code === "ENOENT") return false;
@@ -22007,13 +22085,13 @@ var OwnerSession = class _OwnerSession {
22007
22085
  constructor(stateDir, selection) {
22008
22086
  this.stateDir = stateDir;
22009
22087
  this.selection = selection;
22010
- this.path = join3(stateDir, "owner-session.json");
22088
+ this.path = join4(stateDir, "owner-session.json");
22011
22089
  }
22012
22090
  record;
22013
22091
  path;
22014
22092
  lockFd;
22015
22093
  static async open(stateDir, selection, attach) {
22016
- const saved = stateDir && stateExists(join3(stateDir, "owner-session.json"));
22094
+ const saved = stateDir && stateExists(join4(stateDir, "owner-session.json"));
22017
22095
  if (!selection || process.platform !== "linux") {
22018
22096
  if (saved) throw new ConfigurationError("Saved messenger ownership requires its qualified V1 activation and original selection");
22019
22097
  return void 0;
@@ -22106,23 +22184,23 @@ var OwnerSession = class _OwnerSession {
22106
22184
  }
22107
22185
  }
22108
22186
  activate() {
22109
- for (let path2 = this.stateDir; ; path2 = dirname3(path2)) {
22187
+ for (let path3 = this.stateDir; ; path3 = dirname3(path3)) {
22110
22188
  let st3;
22111
22189
  try {
22112
- st3 = fs.lstatSync(path2);
22190
+ st3 = fs.lstatSync(path3);
22113
22191
  } catch (error) {
22114
22192
  if (error.code !== "ENOENT") throw error;
22115
22193
  }
22116
22194
  if (st3 && (!st3.isDirectory() || st3.isSymbolicLink() || st3.uid !== 0 && st3.uid !== process.getuid() || (st3.mode & 18) !== 0 && !(st3.uid === 0 && (st3.mode & 512) !== 0))) {
22117
22195
  throw new ConfigurationError("Messenger ownership state requires safe private directory ancestry");
22118
22196
  }
22119
- if (path2 === dirname3(path2)) break;
22197
+ if (path3 === dirname3(path3)) break;
22120
22198
  }
22121
22199
  fs.mkdirSync(this.stateDir, { recursive: true, mode: 448 });
22122
22200
  this.privateStat(this.stateDir, true);
22123
- const path = join3(this.stateDir, "owner-session.lock");
22124
- this.lockFd = fs.openSync(path, fs.constants.O_CREAT | fs.constants.O_RDWR | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK, 384);
22125
- const st2 = this.privateStat(path);
22201
+ const path2 = join4(this.stateDir, "owner-session.lock");
22202
+ this.lockFd = fs.openSync(path2, fs.constants.O_CREAT | fs.constants.O_RDWR | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK, 384);
22203
+ const st2 = this.privateStat(path2);
22126
22204
  const opened = fs.fstatSync(this.lockFd);
22127
22205
  if (st2.dev !== opened.dev || st2.ino !== opened.ino) throw new Error("Messenger activation file changed");
22128
22206
  const acquired = spawnSync("flock", ["-n", "3"], {
@@ -22133,8 +22211,8 @@ var OwnerSession = class _OwnerSession {
22133
22211
  throw new ConfigurationError(acquired.status === 1 ? "Messenger application state is already active" : "Messenger state locking is unavailable on this runtime");
22134
22212
  }
22135
22213
  }
22136
- privateStat(path, directory = false) {
22137
- const st2 = fs.lstatSync(path);
22214
+ privateStat(path2, directory = false) {
22215
+ const st2 = fs.lstatSync(path2);
22138
22216
  if ((directory ? !st2.isDirectory() : !st2.isFile()) || st2.isSymbolicLink() || st2.uid !== process.getuid() || (st2.mode & 4095) !== (directory ? 448 : 384)) {
22139
22217
  throw new ConfigurationError("Messenger owner state must be private, regular and owned by this user");
22140
22218
  }
@@ -22285,9 +22363,9 @@ async function bindIdentity(runtime, cfg) {
22285
22363
  // src/push.ts
22286
22364
  init_define_MESSENGER_BUILD_INFO();
22287
22365
  var import_web_push = __toESM(require_src2(), 1);
22288
- import { createHash as createHash3, randomUUID, timingSafeEqual } from "node:crypto";
22289
- import { chmodSync as chmodSync2, lstatSync as lstatSync3, mkdirSync as mkdirSync5, readFileSync as readFileSync4, renameSync as renameSync4, writeFileSync as writeFileSync5 } from "node:fs";
22290
- import { dirname as dirname4, join as join4 } from "node:path";
22366
+ import { createHash as createHash3, randomUUID as randomUUID2, timingSafeEqual } from "node:crypto";
22367
+ import { chmodSync as chmodSync2, lstatSync as lstatSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync5, writeFileSync as writeFileSync6 } from "node:fs";
22368
+ import { dirname as dirname4, join as join5 } from "node:path";
22291
22369
  var MAX_BINDINGS = 32;
22292
22370
  var MAX_ENDPOINT_LENGTH = 2048;
22293
22371
  var MAX_LABEL_LENGTH = 160;
@@ -22483,15 +22561,15 @@ var PushStore = class _PushStore {
22483
22561
  const env = typeof identityCidOrEnv === "string" ? envOrDependencies : identityCidOrEnv;
22484
22562
  const deps = typeof identityCidOrEnv === "string" ? dependencies : envOrDependencies;
22485
22563
  if (!nonEmpty3(identityCid, 512)) throw new Error("push identity CID must be a non-empty bounded string");
22486
- const file = join4(stateDir, "push.json");
22487
- mkdirSync5(dirname4(file), { recursive: true, mode: 448 });
22564
+ const file = join5(stateDir, "push.json");
22565
+ mkdirSync6(dirname4(file), { recursive: true, mode: 448 });
22488
22566
  let parsed;
22489
22567
  try {
22490
- const stat2 = lstatSync3(file);
22568
+ const stat2 = lstatSync4(file);
22491
22569
  if (!stat2.isFile() || stat2.isSymbolicLink()) throw preservedStateError(file, "not a safe regular file");
22492
22570
  let value;
22493
22571
  try {
22494
- value = JSON.parse(readFileSync4(file, "utf8"));
22572
+ value = JSON.parse(readFileSync5(file, "utf8"));
22495
22573
  } catch (error) {
22496
22574
  throw preservedStateError(file, `corrupt or unreadable (${error instanceof Error ? error.message : String(error)})`);
22497
22575
  }
@@ -22569,7 +22647,7 @@ var PushStore = class _PushStore {
22569
22647
  [identityCid]: {
22570
22648
  ...newIdentityState(),
22571
22649
  bindings: (parsed?.subscriptions ?? []).map((row) => ({
22572
- bindingId: randomUUID(),
22650
+ bindingId: randomUUID2(),
22573
22651
  endpoint: row.endpoint,
22574
22652
  keys: row.keys,
22575
22653
  createdAt: row.createdAt,
@@ -22590,9 +22668,9 @@ var PushStore = class _PushStore {
22590
22668
  }
22591
22669
  persist() {
22592
22670
  const tmp = `${this.file}.tmp`;
22593
- writeFileSync5(tmp, JSON.stringify(this.state, null, 2), { mode: 384 });
22671
+ writeFileSync6(tmp, JSON.stringify(this.state, null, 2), { mode: 384 });
22594
22672
  chmodSync2(tmp, 384);
22595
- renameSync4(tmp, this.file);
22673
+ renameSync5(tmp, this.file);
22596
22674
  chmodSync2(this.file, 384);
22597
22675
  }
22598
22676
  get publicKey() {
@@ -22641,7 +22719,7 @@ var PushStore = class _PushStore {
22641
22719
  const preview = input.preview === void 0 ? previous?.preview ?? "full" : previewMode(input.preview);
22642
22720
  if (!previous && owner.bindings.length >= MAX_BINDINGS) throw new Error(`push subscription limit is ${MAX_BINDINGS}`);
22643
22721
  const createdAt = previous?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
22644
- const bindingId = previous?.bindingId ?? randomUUID();
22722
+ const bindingId = previous?.bindingId ?? randomUUID2();
22645
22723
  const record = {
22646
22724
  bindingId,
22647
22725
  endpoint,
@@ -22951,7 +23029,7 @@ var PushStore = class _PushStore {
22951
23029
  }
22952
23030
  /** Compatibility for tests/old callers; durable production delivery uses jobs. */
22953
23031
  async send(event) {
22954
- const wire = `compat-${randomUUID()}`;
23032
+ const wire = `compat-${randomUUID2()}`;
22955
23033
  this.enqueueJob({ wireId: wire, kind: event.kind, contactId: event.contact_id });
22956
23034
  const id = `${this.identityCid}:${wire}:${event.kind}`;
22957
23035
  this.claimJob(id);
@@ -23120,7 +23198,7 @@ function liveFrame(event) {
23120
23198
  return JSON.stringify({ type: "event", event: { v: 1, ...event } });
23121
23199
  }
23122
23200
  function attachPresenceServer(server, registry, options) {
23123
- const path = options.path ?? "/api/presence";
23201
+ const path2 = options.path ?? "/api/presence";
23124
23202
  const pingIntervalMs = options.pingIntervalMs ?? 3e4;
23125
23203
  const authTimeoutMs = options.authTimeoutMs ?? 5e3;
23126
23204
  const wss = new import_websocket_server.default({ noServer: true, maxPayload: 8 * 1024 });
@@ -23130,7 +23208,7 @@ function attachPresenceServer(server, registry, options) {
23130
23208
  pathname = new URL(request.url ?? "/", "http://localhost").pathname;
23131
23209
  } catch {
23132
23210
  }
23133
- if (pathname !== path || options.allowedOrigin && request.headers.origin !== options.allowedOrigin) {
23211
+ if (pathname !== path2 || options.allowedOrigin && request.headers.origin !== options.allowedOrigin) {
23134
23212
  socket.destroy();
23135
23213
  return;
23136
23214
  }
@@ -23288,8 +23366,8 @@ async function redirectStaleEntryAsset(req, res, appDir, pathname, basePath = "/
23288
23366
  return false;
23289
23367
  }
23290
23368
  }
23291
- async function readContainedFile(root, path) {
23292
- const [canonicalRoot, canonicalPath] = await Promise.all([realpath(root), realpath(path)]);
23369
+ async function readContainedFile(root, path2) {
23370
+ const [canonicalRoot, canonicalPath] = await Promise.all([realpath(root), realpath(path2)]);
23293
23371
  const fromRoot = relative(canonicalRoot, canonicalPath);
23294
23372
  if (fromRoot === "" || fromRoot === ".." || fromRoot.startsWith(`..${sep}`) || isAbsolute2(fromRoot) || !(await stat(canonicalPath)).isFile()) {
23295
23373
  throw new Error("static asset is not a contained regular file");
@@ -23585,7 +23663,7 @@ async function start(cfg, buildInfo, dependencies = DEFAULT_START_DEPENDENCIES)
23585
23663
  resolve2(moduleDir, "../dist/web"),
23586
23664
  resolve2(moduleDir, "web")
23587
23665
  ];
23588
- const appDir = process.env.OURS_MESSENGER_WEB_DIR ?? appCandidates.find((candidate) => existsSync2(resolve2(candidate, "index.html")) && existsSync2(resolve2(candidate, "assets"))) ?? resolve2(moduleDir, "__messenger_web_not_built__");
23666
+ const appDir = process.env.OURS_MESSENGER_WEB_DIR ?? appCandidates.find((candidate) => existsSync3(resolve2(candidate, "index.html")) && existsSync3(resolve2(candidate, "assets"))) ?? resolve2(moduleDir, "__messenger_web_not_built__");
23589
23667
  http = createServer((req, res) => {
23590
23668
  const pathname = new URL(req.url ?? "/", "http://localhost").pathname;
23591
23669
  let serving;
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  normalizeBasePath,
8
8
  operatorError,
9
9
  reportFailure
10
- } from "./chunks/chunk-O34PQ4M6.js";
10
+ } from "./chunks/chunk-Y5H3QIV5.js";
11
11
 
12
12
  // src/cli.ts
13
13
  init_define_MESSENGER_BUILD_INFO();
@@ -131,7 +131,7 @@ async function main() {
131
131
  }
132
132
  if (process.argv.length !== 3) throw new ConfigurationError("serve does not accept command-line options");
133
133
  const cfg = loadConfig();
134
- const { start } = await import("./chunks/server-Q2BQSKMJ.js");
134
+ const { start } = await import("./chunks/server-T57VZPJ5.js");
135
135
  const handle = await start(cfg, BUILD_INFO);
136
136
  let closing = false;
137
137
  const shutdown = (signal) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/messenger-server",
3
- "version": "1.0.31-nightly.10",
3
+ "version": "1.0.31-nightly.11",
4
4
  "description": "Self-hosted Messenger REST/SSE backend for one identity on a shared Ours daemon.",
5
5
  "type": "module",
6
6
  "license": "FSL-1.1-Apache-2.0",