@ours.network/messenger-server 1.0.31-nightly.12 → 1.0.31-nightly.14
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/README.md
CHANGED
|
@@ -409,3 +409,7 @@ The older mock walkthrough and its browser tests describe an earlier design stag
|
|
|
409
409
|
### Dedicated notification service
|
|
410
410
|
|
|
411
411
|
Set `OURS_NOTIFICATIONS_ORIGIN` and a Messenger-scoped `OURS_NOTIFICATIONS_PRODUCER_TOKEN` to forward incoming messages/files to [ours-notifications](https://github.com/adapt-toolkit/ours-notifications). Both settings must be provided together. The canonical watcher durably queues notifications even without a local push binding, freezes projected content before its first HTTP attempt, and retries the same payload after outages/restarts. Keep the Messenger state directory across restarts. When configured, new events use the dedicated service; legacy pending push jobs may finish. Existing standalone push endpoints remain for compatibility.
|
|
412
|
+
|
|
413
|
+
Workspace enrollment supports optional `preserveProfile: true` on its protected POST endpoint. This skips human profile creation/replacement (including an absent profile); root checks and the signed binding command remain mandatory. The protected enrollment-identity response advertises `preserveProfile: true` so clients can fail closed against older servers. Omitted/false keeps fresh-host account profile setup.
|
|
414
|
+
|
|
415
|
+
Messenger may run as the Human root or as a permanent identity under it. For the latter, the enrollment-identity response also carries `rootCid`, the root the daemon describes for the bound identity; `POST /api/identity/profile` accepts both. Only a Messenger bound to the root itself signs the workspace binding on `POST /api/workspace/enroll`; for an identity under the root the caller obtains that signature from the root outside Messenger.
|
|
@@ -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.
|
|
41
|
+
define_MESSENGER_BUILD_INFO_default = { name: "@ours.network/messenger-server", version: "1.0.31-nightly.14", sha: "472ad12fdb461e51398c29e8e224d12caca9a43e", 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-
|
|
13
|
+
} from "./chunk-XNYNQSPB.js";
|
|
14
14
|
|
|
15
15
|
// node_modules/bn.js/lib/bn.js
|
|
16
16
|
var require_bn = __commonJS({
|
|
@@ -20622,6 +20622,15 @@ function inlineBase64(body) {
|
|
|
20622
20622
|
}
|
|
20623
20623
|
return value;
|
|
20624
20624
|
}
|
|
20625
|
+
function humanIdentity(value) {
|
|
20626
|
+
if (value === null || typeof value !== "object") return void 0;
|
|
20627
|
+
const identity = value;
|
|
20628
|
+
if (identity.temporary !== false || typeof identity.cid !== "string") return void 0;
|
|
20629
|
+
if (identity.isRoot === true) return {};
|
|
20630
|
+
const rootCid = identity.rootCid;
|
|
20631
|
+
if (identity.isRoot !== false || identity.described !== true || typeof identity.roleId !== "string" || !identity.roleId || typeof rootCid !== "string" || !/^[a-f0-9]{64}$/i.test(rootCid) || rootCid.toLowerCase() === identity.cid.toLowerCase()) return void 0;
|
|
20632
|
+
return { rootCid };
|
|
20633
|
+
}
|
|
20625
20634
|
function publicIdentity(value) {
|
|
20626
20635
|
if (value === null || typeof value !== "object") return {};
|
|
20627
20636
|
const identity = value;
|
|
@@ -21017,16 +21026,18 @@ var ROUTES = {
|
|
|
21017
21026
|
// field on this result.
|
|
21018
21027
|
"GET /api/identity": async ({ client, deps }) => ({ ...publicIdentity(await client.currentIdentity()), humanProfile: readHumanProfile(deps.config.stateDir, deps.identityCid) }),
|
|
21019
21028
|
"POST /api/identity/profile": async ({ client, deps, body }) => {
|
|
21020
|
-
|
|
21021
|
-
if (!identity.isRoot || identity.temporary) throw bad("Human profile requires the root identity");
|
|
21029
|
+
if (!humanIdentity(await client.currentIdentity())) throw bad("Human profile requires the Human root or a permanent identity under it");
|
|
21022
21030
|
return writeHumanProfile(deps.config.stateDir, deps.identityCid, { name: profileName(body.name), surname: profileName(body.surname) });
|
|
21023
21031
|
},
|
|
21024
|
-
//
|
|
21032
|
+
// Who the person is on this host. A Messenger that runs as the Human root can sign the workspace proof
|
|
21033
|
+
// itself; one that runs as the person's own identity under that root names the root the daemon describes
|
|
21034
|
+
// for it, and the proof is then signed by that root outside Messenger.
|
|
21025
21035
|
"GET /api/workspace/enrollment-identity": async ({ client }) => {
|
|
21026
|
-
const identity = await client.currentIdentity();
|
|
21027
|
-
if (!
|
|
21028
|
-
return { cid: identity.cid };
|
|
21036
|
+
const identity = await client.currentIdentity(), human = humanIdentity(identity);
|
|
21037
|
+
if (!human) throw bad("Workspace proof requires the bound Human root or a permanent identity under it");
|
|
21038
|
+
return human.rootCid === void 0 ? { cid: identity.cid, preserveProfile: true } : { cid: identity.cid, rootCid: human.rootCid, preserveProfile: true };
|
|
21029
21039
|
},
|
|
21040
|
+
// First-party setup operation: daemon signs the command using this bound root.
|
|
21030
21041
|
"POST /api/workspace/enroll": async ({ client, deps, body }) => {
|
|
21031
21042
|
const identity = await client.currentIdentity();
|
|
21032
21043
|
if (!identity.isRoot || identity.temporary) throw bad("Workspace proof requires the bound Human root");
|
|
@@ -21034,15 +21045,16 @@ var ROUTES = {
|
|
|
21034
21045
|
if (!/^[A-F0-9]{64}$/.test(serverCid) || !/^[A-Za-z0-9_-]{43}$/.test(str(body, "hostWorkspaceId"))) throw bad("Invalid workspace proof");
|
|
21035
21046
|
const challenge = body.challenge;
|
|
21036
21047
|
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");
|
|
21048
|
+
const preserveProfile = optBool(body, "preserveProfile") === true;
|
|
21037
21049
|
let humanProfile;
|
|
21038
|
-
try {
|
|
21050
|
+
if (!preserveProfile) try {
|
|
21039
21051
|
humanProfile = { name: profileName(body.name), surname: profileName(body.surname) };
|
|
21040
21052
|
} catch {
|
|
21041
21053
|
throw bad("Name and Surname require printable text up to 100 characters");
|
|
21042
21054
|
}
|
|
21043
21055
|
const invitation = str(body, "invitation");
|
|
21044
21056
|
if (invitation.length > 8192) throw bad("Workspace invitation too large");
|
|
21045
|
-
writeHumanProfile(deps.config.stateDir, deps.identityCid, humanProfile);
|
|
21057
|
+
if (humanProfile) writeHumanProfile(deps.config.stateDir, deps.identityCid, humanProfile);
|
|
21046
21058
|
const peer = await client.addContact({ invite: invitation });
|
|
21047
21059
|
if (peer.cid.toUpperCase() !== serverCid) throw bad("Enrollment server identity mismatch");
|
|
21048
21060
|
const contactDeadline = Date.now() + 1e4;
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
normalizeBasePath,
|
|
8
8
|
operatorError,
|
|
9
9
|
reportFailure
|
|
10
|
-
} from "./chunks/chunk-
|
|
10
|
+
} from "./chunks/chunk-XNYNQSPB.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-
|
|
134
|
+
const { start } = await import("./chunks/server-ML4SVL44.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.
|
|
3
|
+
"version": "1.0.31-nightly.14",
|
|
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",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
34
34
|
"test:startup": "node --import tsx tests/startup-readiness.test.mjs",
|
|
35
35
|
"test:runtime-catalog-candidate": "node --import tsx tests/runtime-command-catalog-reopen-e2e.test.mjs",
|
|
36
|
-
"test:offline": "for f in tests/notification-producer.test.mjs tests/base-path.test.mjs tests/build-epoch.test.mjs tests/owner-session.test.mjs tests/v1-runtime.test.mjs tests/typed-commands-core.test.mjs tests/shared-daemon-contract.test.mjs tests/room-envelope-matrix.test.mjs tests/bundle-smoke.test.mjs tests/build-metadata.test.mjs tests/production-security.test.mjs tests/conversation-page.test.mjs tests/media-response.test.mjs tests/html-preview-transform.test.mjs tests/html-preview-response.test.mjs tests/push-store.test.mjs tests/push-store-hardening.test.mjs tests/push-delivery.test.mjs tests/push-queue-saturation.test.mjs tests/events.test.mjs tests/watch-cursor.test.mjs tests/watch-reconcile.test.mjs tests/introduction-send-guard.test.mjs tests/sse-e2e.test.mjs tests/presence.test.mjs tests/static-hosting.test.mjs tests/room-preview.test.mjs; do echo \"# $f\"; node --import tsx \"$f\" || exit 1; done",
|
|
36
|
+
"test:offline": "for f in tests/workspace-profile-preservation.test.mjs tests/notification-producer.test.mjs tests/base-path.test.mjs tests/build-epoch.test.mjs tests/owner-session.test.mjs tests/v1-runtime.test.mjs tests/typed-commands-core.test.mjs tests/shared-daemon-contract.test.mjs tests/room-envelope-matrix.test.mjs tests/bundle-smoke.test.mjs tests/build-metadata.test.mjs tests/production-security.test.mjs tests/conversation-page.test.mjs tests/media-response.test.mjs tests/html-preview-transform.test.mjs tests/html-preview-response.test.mjs tests/push-store.test.mjs tests/push-store-hardening.test.mjs tests/push-delivery.test.mjs tests/push-queue-saturation.test.mjs tests/events.test.mjs tests/watch-cursor.test.mjs tests/watch-reconcile.test.mjs tests/introduction-send-guard.test.mjs tests/sse-e2e.test.mjs tests/presence.test.mjs tests/static-hosting.test.mjs tests/room-preview.test.mjs; do echo \"# $f\"; node --import tsx \"$f\" || exit 1; done",
|
|
37
37
|
"test:loopback": "for f in tests/shared-daemon-e2e.test.mjs tests/typed-command-loopback-e2e.test.mjs tests/introduction-send.test.mjs tests/rest-e2e.test.mjs; do echo \"# $f\"; node --import tsx \"$f\" || exit 1; done",
|
|
38
38
|
"test": "npm run build && npm run test:startup && npm run test:offline && npm run test:loopback"
|
|
39
39
|
},
|