openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
372 lines (371 loc) • 13.2 kB
JavaScript
import { t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js";
import { Ar as validateSessionMemberRemoveParams, Ir as validateSessionVisibilitySetParams, jr as validateSessionMembersListParams, kr as validateSessionMemberAddParams } from "./src-BiL5aQto.js";
import { d as errorShape } from "./error-codes-Bo8q2D1o.js";
import "./session-accessor-YsytfDtG.js";
import { d as patchSessionEntryCore } from "./session-accessor.sqlite-entry-CWk3jL7s.js";
import { h as runExclusiveSessionLifecycleMutation } from "./session-lifecycle-admission-CS8v45tk.js";
import { h as listProfiles } from "./user-profiles-4AB7AmiH.js";
import { n as loadCombinedSessionStoreForGatewayCore } from "./combined-store-gateway-DGm4nZAJ.js";
import { d as removeSessionMember, l as listSessionMembers, s as addSessionMember } from "./sessions-9nxpeTwt.js";
import { h as gatewayClientSessionCreator } from "./operator-role-policy-wsr1DeJv.js";
import { n as resolveRequestedSessionAgentId } from "./session-request-agent-CCRSEGCB.js";
import { D as invalidateSessionSharingSnapshot, L as isSessionVisibilityAllowed, O as allowedSessionVisibilities, P as canManageSessionSharing, R as resolveSessionSharingRole, V as resolveSessionVisibility, z as resolveSessionSharingTarget } from "./session-sharing-B7MI8hNo.js";
import { t as assertValidParams } from "./validation-pzrlzFvo.js";
import { n as emitSessionsChanged } from "./session-change-event-DzmH4zlz.js";
import { n as getGatewayLocalUserIngress } from "./local-user-ingress-o2_EOOV8.js";
//#region src/gateway/server-methods/sessions-sharing.ts
function runExclusiveSharingMutation(target, run) {
return runExclusiveSessionLifecycleMutation({
scope: target.storePath,
identities: [
target.canonicalKey,
target.storeKey,
...target.storeKeys,
target.entry.sessionId
],
run
});
}
const UNKNOWN_SHARING_ACTOR_STORAGE_REF = "actor-evidence:unknown";
const UNATTRIBUTED_SHARING_ACTOR_STORAGE_REF = "actor-evidence:unattributed";
const LEGACY_SYNTHETIC_SHARING_ACTOR_STORAGE_REFS = /* @__PURE__ */ new Set(["local-operator", "operator.admin"]);
function actorIdentity(client) {
const principal = gatewayClientSessionCreator(client);
if (principal) return {
state: "present",
actor: principal
};
return getGatewayLocalUserIngress(client)?.facts.invoker?.state === "unknown" ? { state: "unknown" } : { state: "absent" };
}
function sharingActorStorageRef(facts) {
return facts.state === "present" ? facts.actor.id : facts.state === "unknown" ? UNKNOWN_SHARING_ACTOR_STORAGE_REF : UNATTRIBUTED_SHARING_ACTOR_STORAGE_REF;
}
function projectSessionMemberEvidence(member) {
const common = {
identityId: member.identityId,
addedAt: member.addedAt
};
if (member.addedBy === UNKNOWN_SHARING_ACTOR_STORAGE_REF) return {
...common,
addedByState: "unknown"
};
if (member.addedBy === UNATTRIBUTED_SHARING_ACTOR_STORAGE_REF || LEGACY_SYNTHETIC_SHARING_ACTOR_STORAGE_REFS.has(member.addedBy)) return common;
return {
...common,
addedBy: member.addedBy
};
}
function projectLegacySessionMember(member) {
if (!member.addedBy) return null;
return {
identityId: member.identityId,
addedBy: member.addedBy,
addedAt: member.addedAt
};
}
function requireManageableTarget(params) {
const requestedAgent = resolveRequestedSessionAgentId(params.cfg, params.sessionKey, params.agentId);
if (!requestedAgent.ok) {
params.respond(false, void 0, requestedAgent.error);
return null;
}
const target = resolveSessionSharingTarget({
cfg: params.cfg,
sessionKey: params.sessionKey,
agentId: requestedAgent.agentId
});
if (!target) {
params.respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `unknown session: ${params.sessionKey}`));
return null;
}
const role = resolveSessionSharingRole({
client: params.client,
cfg: params.cfg,
target
});
if (!canManageSessionSharing(role)) {
params.respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session owner or operator.admin required", { details: {
code: "SESSION_SHARING_MANAGER_REQUIRED",
sessionKey: target.canonicalKey
} }));
return null;
}
return {
target,
role
};
}
function requireCurrentManagedTarget(params) {
const current = resolveSessionSharingTarget({
cfg: params.cfg,
sessionKey: params.authorized.canonicalKey,
agentId: params.authorized.agentId
});
if (!current || current.entry.sessionId !== params.authorized.entry.sessionId) throw new Error("session changed before sharing mutation");
const role = resolveSessionSharingRole({
client: params.client,
cfg: params.cfg,
target: current
});
if (!canManageSessionSharing(role)) throw new Error("session ownership changed before sharing mutation");
return current;
}
function knownSessionIdentities(params) {
const identities = /* @__PURE__ */ new Map();
const remember = (identity) => {
if (!identity?.id) return;
const current = identities.get(identity.id);
identities.set(identity.id, {
type: identity.type,
id: identity.id,
...identity.label ?? current?.label ? { label: identity.label ?? current?.label } : {}
});
};
if (params.actor.state === "present") remember(params.actor.actor);
for (const entry of Object.values(loadCombinedSessionStoreForGatewayCore(params.cfg).store)) remember(entry.createdActor ?? null);
for (const profile of listProfiles()) remember({
type: "human",
id: profile.id,
...profile.displayName ? { label: profile.displayName } : {}
});
return [...identities.values()].toSorted((left, right) => (left.label ?? left.id).localeCompare(right.label ?? right.id) || left.id.localeCompare(right.id));
}
function publishSharingChange(params) {
invalidateSessionSharingSnapshot(params.event.sessionKey);
const eventOptions = { sessionKeys: [params.event.sessionKey] };
if (params.actor.state === "present") {
const event = {
...params.event,
actor: params.actor.actor
};
params.context.broadcast("session.sharing", event, eventOptions);
} else {
const event = {
...params.event,
...params.actor.state === "unknown" ? { actorState: "unknown" } : {}
};
params.context.broadcast("session.sharing.evidence", event, eventOptions);
}
emitSessionsChanged(params.context, {
reason: "sharing",
sessionKey: params.event.sessionKey,
agentId: params.agentId
});
emitSessionsChanged(params.context, { reason: "sharing" });
}
function createSessionMembersListHandler(method) {
const evidenceAware = method === "session.members.listEvidence";
return async ({ params, respond, client, context }) => {
if (!assertValidParams(params, validateSessionMembersListParams, method, respond)) return;
const cfg = context.getRuntimeConfig();
const managed = requireManageableTarget({
cfg,
client,
sessionKey: params.sessionKey,
agentId: params.agentId,
respond
});
if (!managed) return;
const target = managed.target;
const actor = actorIdentity(client);
const evidenceMembers = listSessionMembers({
agentId: target.agentId,
sessionKey: target.storeKey,
storePath: target.storePath
}).map(projectSessionMemberEvidence);
const members = evidenceAware ? evidenceMembers : evidenceMembers.map(projectLegacySessionMember);
if (!evidenceAware && members.some((member) => member === null)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session membership includes actor evidence this client cannot represent", { details: {
code: "SESSION_MEMBER_ACTOR_EVIDENCE_UNSUPPORTED",
recommendedMethod: "session.members.listEvidence"
} }));
return;
}
const projectedMembers = members.filter((member) => member !== null);
const identities = knownSessionIdentities({
cfg,
actor
});
for (const member of projectedMembers) if (!identities.some((identity) => identity.id === member.identityId)) identities.push({
type: "human",
id: member.identityId
});
identities.sort((left, right) => (left.label ?? left.id).localeCompare(right.label ?? right.id) || left.id.localeCompare(right.id));
const owner = target.entry.createdActor?.id ? target.entry.createdActor : void 0;
respond(true, {
sessionKey: target.canonicalKey,
...owner ? { owner: { ...owner } } : {},
members: projectedMembers,
identities,
role: managed.role,
allowedVisibilities: allowedSessionVisibilities(cfg)
}, void 0);
};
}
const sessionSharingHandlers = {
"session.visibility.set": async ({ params, respond, client, context }) => {
if (!assertValidParams(params, validateSessionVisibilitySetParams, "session.visibility.set", respond)) return;
const cfg = context.getRuntimeConfig();
const managed = requireManageableTarget({
cfg,
client,
sessionKey: params.sessionKey,
agentId: params.agentId,
respond
});
if (!managed) return;
const visibility = params.visibility;
if (!isSessionVisibilityAllowed(cfg, visibility)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session visibility is disabled: ${visibility}`, { details: {
code: "SESSION_VISIBILITY_DISABLED",
visibility
} }));
return;
}
await runExclusiveSharingMutation(managed.target, async () => {
const current = requireCurrentManagedTarget({
cfg,
client,
authorized: managed.target
});
if (resolveSessionVisibility(current.entry) === visibility) return;
const scope = {
agentId: current.agentId,
sessionKey: current.canonicalKey,
storePath: current.storePath
};
let sessionChanged = false;
await patchSessionEntryCore(scope, (entry) => {
if (entry.sessionId !== current.entry.sessionId) {
sessionChanged = true;
return null;
}
return { visibility };
});
if (sessionChanged) throw new Error("session changed before sharing mutation");
const now = Date.now();
const actor = actorIdentity(client);
publishSharingChange({
context,
agentId: current.agentId,
actor,
event: {
action: "visibility",
sessionKey: current.canonicalKey,
agentId: current.agentId,
visibility,
ts: now
}
});
});
respond(true, {
ok: true,
sessionKey: managed.target.canonicalKey,
visibility
}, void 0);
},
"session.members.list": createSessionMembersListHandler("session.members.list"),
"session.members.listEvidence": createSessionMembersListHandler("session.members.listEvidence"),
"session.members.add": async ({ params, respond, client, context }) => {
if (!assertValidParams(params, validateSessionMemberAddParams, "session.members.add", respond)) return;
const cfg = context.getRuntimeConfig();
const managed = requireManageableTarget({
cfg,
client,
sessionKey: params.sessionKey,
agentId: params.agentId,
respond
});
if (!managed) return;
const actor = actorIdentity(client);
if (!knownSessionIdentities({
cfg,
actor
}).some((identity) => identity.id === params.identityId)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unknown identity"));
return;
}
await runExclusiveSharingMutation(managed.target, async () => {
const current = requireCurrentManagedTarget({
cfg,
client,
authorized: managed.target
});
const scope = {
agentId: current.agentId,
sessionKey: current.storeKey,
storePath: current.storePath
};
const now = Date.now();
if (!addSessionMember(scope, {
identityId: params.identityId,
addedBy: sharingActorStorageRef(actor),
addedAt: now,
expectedSessionId: current.entry.sessionId
}).inserted) return;
publishSharingChange({
context,
agentId: current.agentId,
actor,
event: {
action: "member-added",
sessionKey: current.canonicalKey,
agentId: current.agentId,
identityId: params.identityId,
ts: now
}
});
});
respond(true, {
ok: true,
sessionKey: managed.target.canonicalKey,
identityId: params.identityId
}, void 0);
},
"session.members.remove": async ({ params, respond, client, context }) => {
if (!assertValidParams(params, validateSessionMemberRemoveParams, "session.members.remove", respond)) return;
const cfg = context.getRuntimeConfig();
const managed = requireManageableTarget({
cfg,
client,
sessionKey: params.sessionKey,
agentId: params.agentId,
respond
});
if (!managed) return;
await runExclusiveSharingMutation(managed.target, async () => {
const current = requireCurrentManagedTarget({
cfg,
client,
authorized: managed.target
});
const scope = {
agentId: current.agentId,
sessionKey: current.storeKey,
storePath: current.storePath
};
if (!removeSessionMember(scope, params.identityId, void 0, current.entry.sessionId)) return;
const now = Date.now();
const actor = actorIdentity(client);
publishSharingChange({
context,
agentId: current.agentId,
actor,
event: {
action: "member-removed",
sessionKey: current.canonicalKey,
agentId: current.agentId,
identityId: params.identityId,
ts: now
}
});
});
respond(true, {
ok: true,
sessionKey: managed.target.canonicalKey,
identityId: params.identityId
}, void 0);
}
};
//#endregion
export { sessionSharingHandlers };