@axiom-lattice/gateway 4.1.5 → 4.1.6
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/index.js +338 -91
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +337 -90
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1512,7 +1512,7 @@ function extractFailureReason(task) {
|
|
|
1512
1512
|
return extractText2(task.status.message.parts);
|
|
1513
1513
|
}
|
|
1514
1514
|
function observationEventKey(task, result, failureReason) {
|
|
1515
|
-
const digest = (0,
|
|
1515
|
+
const digest = (0, import_node_crypto19.createHash)("sha256").update(JSON.stringify({
|
|
1516
1516
|
state: task.status.state,
|
|
1517
1517
|
timestamp: task.status.timestamp,
|
|
1518
1518
|
message: task.status.message,
|
|
@@ -1522,7 +1522,7 @@ function observationEventKey(task, result, failureReason) {
|
|
|
1522
1522
|
return `a2a-status-observation:${task.id}:${digest}`;
|
|
1523
1523
|
}
|
|
1524
1524
|
function snapshotEventKey(task) {
|
|
1525
|
-
const digest = (0,
|
|
1525
|
+
const digest = (0, import_node_crypto19.createHash)("sha256").update(JSON.stringify(task)).digest("hex");
|
|
1526
1526
|
return `a2a-task-snapshot:${task.id}:${digest}`;
|
|
1527
1527
|
}
|
|
1528
1528
|
function isGovernedObservation(state) {
|
|
@@ -1534,11 +1534,11 @@ function isA2ATaskSnapshot(value) {
|
|
|
1534
1534
|
function snapshotSequence(value) {
|
|
1535
1535
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
1536
1536
|
}
|
|
1537
|
-
var
|
|
1537
|
+
var import_node_crypto19, import_node_util, TASK_STATUS_TO_A2A_STATE, TITLE_MAX_LENGTH, A2ATaskScopeConflictError, A2ATaskStoreAdapter;
|
|
1538
1538
|
var init_A2ATaskStoreAdapter = __esm({
|
|
1539
1539
|
"src/services/a2a/A2ATaskStoreAdapter.ts"() {
|
|
1540
1540
|
"use strict";
|
|
1541
|
-
|
|
1541
|
+
import_node_crypto19 = require("crypto");
|
|
1542
1542
|
import_node_util = require("util");
|
|
1543
1543
|
TASK_STATUS_TO_A2A_STATE = {
|
|
1544
1544
|
pending: "submitted",
|
|
@@ -3313,7 +3313,7 @@ var import_static = __toESM(require("@fastify/static"));
|
|
|
3313
3313
|
var import_path = __toESM(require("path"));
|
|
3314
3314
|
|
|
3315
3315
|
// src/routes/index.ts
|
|
3316
|
-
var
|
|
3316
|
+
var import_node_crypto18 = require("crypto");
|
|
3317
3317
|
var import_protocols24 = require("@axiom-lattice/protocols");
|
|
3318
3318
|
|
|
3319
3319
|
// src/controllers/assistant.ts
|
|
@@ -8485,6 +8485,113 @@ var import_uuid3 = require("uuid");
|
|
|
8485
8485
|
init_mime();
|
|
8486
8486
|
init_workspace_file_service();
|
|
8487
8487
|
init_path_containment();
|
|
8488
|
+
|
|
8489
|
+
// src/services/collaboration/RoomCoordinatorProvisioner.ts
|
|
8490
|
+
var ROOM_COORDINATOR_KEY = "room-coordinator";
|
|
8491
|
+
var RoomCoordinatorProvisioner = class {
|
|
8492
|
+
/** Creates a provisioner over the tenant-scoped assistant store operations. */
|
|
8493
|
+
constructor(deps) {
|
|
8494
|
+
this.deps = deps;
|
|
8495
|
+
}
|
|
8496
|
+
/**
|
|
8497
|
+
* Ensures the Room Coordinator assistant exists, reusing an existing record
|
|
8498
|
+
* and reconciling concurrent create races by rereading the winner.
|
|
8499
|
+
*
|
|
8500
|
+
* @param tenantId Tenant to provision the coordinator for.
|
|
8501
|
+
* @returns The persisted Room Coordinator assistant.
|
|
8502
|
+
*/
|
|
8503
|
+
async ensure(tenantId) {
|
|
8504
|
+
const existing = await this.deps.getAssistantById(tenantId, ROOM_COORDINATOR_KEY);
|
|
8505
|
+
if (existing) return existing;
|
|
8506
|
+
try {
|
|
8507
|
+
return await this.deps.createAssistant(tenantId, ROOM_COORDINATOR_KEY, {
|
|
8508
|
+
name: "Room Coordinator",
|
|
8509
|
+
description: "Coordinates project room conversations and organizes room work.",
|
|
8510
|
+
graphDefinition: {}
|
|
8511
|
+
});
|
|
8512
|
+
} catch (error) {
|
|
8513
|
+
const winner = await this.deps.getAssistantById(tenantId, ROOM_COORDINATOR_KEY);
|
|
8514
|
+
if (winner) return winner;
|
|
8515
|
+
throw error;
|
|
8516
|
+
}
|
|
8517
|
+
}
|
|
8518
|
+
};
|
|
8519
|
+
|
|
8520
|
+
// src/services/collaboration/WorkspacePublicRoomService.ts
|
|
8521
|
+
var import_node_crypto = require("crypto");
|
|
8522
|
+
var import_node_crypto2 = require("crypto");
|
|
8523
|
+
var WORKSPACE_PUBLIC_ROOM_PROJECT_PREFIX = "workspace_public_";
|
|
8524
|
+
var PUBLIC_ROOM_PROJECT_NAME = "General";
|
|
8525
|
+
var PUBLIC_ROOM_PROJECT_DESCRIPTION = "Public room for everyone in the workspace";
|
|
8526
|
+
function workspacePublicRoomProjectId(tenantId, workspaceId) {
|
|
8527
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update([tenantId, workspaceId].join(":")).digest("hex");
|
|
8528
|
+
return `${WORKSPACE_PUBLIC_ROOM_PROJECT_PREFIX}${hash}`;
|
|
8529
|
+
}
|
|
8530
|
+
var WorkspacePublicRoomService = class {
|
|
8531
|
+
/** Creates the service from explicitly injected stores and provisioners. */
|
|
8532
|
+
constructor(deps) {
|
|
8533
|
+
this.deps = deps;
|
|
8534
|
+
this.idFactory = deps.idFactory ?? import_node_crypto2.randomUUID;
|
|
8535
|
+
}
|
|
8536
|
+
/**
|
|
8537
|
+
* Returns the workspace's public room project and room, creating them on first call.
|
|
8538
|
+
*
|
|
8539
|
+
* @param tenantId Tenant owning the workspace.
|
|
8540
|
+
* @param workspaceId Workspace hosting the public room.
|
|
8541
|
+
* @returns The ensured project and room.
|
|
8542
|
+
*/
|
|
8543
|
+
async ensure(tenantId, workspaceId) {
|
|
8544
|
+
const projectId = workspacePublicRoomProjectId(tenantId, workspaceId);
|
|
8545
|
+
const project = await this.ensureProject(tenantId, workspaceId, projectId);
|
|
8546
|
+
const room = await this.deps.ensureMainRoom({
|
|
8547
|
+
id: this.idFactory(),
|
|
8548
|
+
tenantId,
|
|
8549
|
+
workspaceId,
|
|
8550
|
+
projectId,
|
|
8551
|
+
name: project.name
|
|
8552
|
+
});
|
|
8553
|
+
await this.ensureCoordinatorBot(tenantId, workspaceId, projectId, room.id);
|
|
8554
|
+
return { project, room };
|
|
8555
|
+
}
|
|
8556
|
+
async ensureProject(tenantId, workspaceId, projectId) {
|
|
8557
|
+
const existing = await this.deps.getProjectById(tenantId, projectId);
|
|
8558
|
+
if (existing && existing.kind === "public") return existing;
|
|
8559
|
+
try {
|
|
8560
|
+
return await this.deps.createProject(tenantId, workspaceId, projectId, {
|
|
8561
|
+
name: PUBLIC_ROOM_PROJECT_NAME,
|
|
8562
|
+
description: PUBLIC_ROOM_PROJECT_DESCRIPTION,
|
|
8563
|
+
kind: "public"
|
|
8564
|
+
});
|
|
8565
|
+
} catch (error) {
|
|
8566
|
+
const winner = await this.deps.getProjectById(tenantId, projectId);
|
|
8567
|
+
if (winner && winner.kind === "public") return winner;
|
|
8568
|
+
throw Object.assign(new Error("Workspace public room project could not be ensured"), { cause: error });
|
|
8569
|
+
}
|
|
8570
|
+
}
|
|
8571
|
+
async ensureCoordinatorBot(tenantId, workspaceId, projectId, roomId) {
|
|
8572
|
+
const coordinator = await this.deps.ensureCoordinator(tenantId);
|
|
8573
|
+
const existing = await this.deps.findBotByAssistant(tenantId, projectId, coordinator.id);
|
|
8574
|
+
if (existing && existing.status !== "removed") return;
|
|
8575
|
+
const saved = await this.deps.saveBot({
|
|
8576
|
+
id: this.idFactory(),
|
|
8577
|
+
tenantId,
|
|
8578
|
+
workspaceId,
|
|
8579
|
+
projectId,
|
|
8580
|
+
roomId,
|
|
8581
|
+
assistantId: coordinator.id,
|
|
8582
|
+
role: "coordinator",
|
|
8583
|
+
title: coordinator.name,
|
|
8584
|
+
mentionName: ROOM_COORDINATOR_KEY,
|
|
8585
|
+
status: "active",
|
|
8586
|
+
roomThreadId: this.idFactory()
|
|
8587
|
+
});
|
|
8588
|
+
if (saved.kind === "coordinator_conflict" || saved.kind === "mention_conflict") {
|
|
8589
|
+
throw new Error(`Workspace public room coordinator bot could not be ensured: ${saved.kind}`);
|
|
8590
|
+
}
|
|
8591
|
+
}
|
|
8592
|
+
};
|
|
8593
|
+
|
|
8594
|
+
// src/controllers/workspace.ts
|
|
8488
8595
|
var MAX_ZIP_ENTRIES = 1e4;
|
|
8489
8596
|
var MAX_ZIP_FILE_SIZE = 100 * 1024 * 1024;
|
|
8490
8597
|
var MAX_ZIP_TOTAL_SIZE = 512 * 1024 * 1024;
|
|
@@ -8619,6 +8726,21 @@ var WorkspaceController = class {
|
|
|
8619
8726
|
this.projectCollaboration = projectCollaboration;
|
|
8620
8727
|
this.workspaceStore = (0, import_core24.getStoreLattice)("default", "workspace").store;
|
|
8621
8728
|
this.projectStore = (0, import_core24.getStoreLattice)("default", "project").store;
|
|
8729
|
+
const roomStore = (0, import_core24.getStoreLattice)("default", "projectRoom").store;
|
|
8730
|
+
const botMembershipStore = (0, import_core24.getStoreLattice)("default", "projectBotMembership").store;
|
|
8731
|
+
const assistantStore = (0, import_core24.getStoreLattice)("default", "assistant").store;
|
|
8732
|
+
const coordinatorProvisioner = new RoomCoordinatorProvisioner({
|
|
8733
|
+
getAssistantById: assistantStore.getAssistantById.bind(assistantStore),
|
|
8734
|
+
createAssistant: assistantStore.createAssistant.bind(assistantStore)
|
|
8735
|
+
});
|
|
8736
|
+
this.publicRoom = new WorkspacePublicRoomService({
|
|
8737
|
+
getProjectById: this.projectStore.getProjectById.bind(this.projectStore),
|
|
8738
|
+
createProject: this.projectStore.createProject.bind(this.projectStore),
|
|
8739
|
+
ensureMainRoom: roomStore.ensureMainRoom.bind(roomStore),
|
|
8740
|
+
findBotByAssistant: botMembershipStore.findByAssistant.bind(botMembershipStore),
|
|
8741
|
+
saveBot: botMembershipStore.save.bind(botMembershipStore),
|
|
8742
|
+
ensureCoordinator: (tenantId) => coordinatorProvisioner.ensure(tenantId)
|
|
8743
|
+
});
|
|
8622
8744
|
}
|
|
8623
8745
|
getTenantId(request) {
|
|
8624
8746
|
const userTenantId = request.user?.tenantId;
|
|
@@ -8692,6 +8814,7 @@ var WorkspaceController = class {
|
|
|
8692
8814
|
const { workspaceId } = request.params;
|
|
8693
8815
|
const kindFilter = request.query.kind;
|
|
8694
8816
|
await this.ensureTrainingProject(tenantId, workspaceId);
|
|
8817
|
+
await this.publicRoom.ensure(tenantId, workspaceId);
|
|
8695
8818
|
const projects = kindFilter ? await this.projectStore.getProjectsByWorkspace(tenantId, workspaceId, {
|
|
8696
8819
|
kind: kindFilter
|
|
8697
8820
|
}) : await this.projectStore.getProjectsByWorkspace(tenantId, workspaceId);
|
|
@@ -8735,6 +8858,12 @@ var WorkspaceController = class {
|
|
|
8735
8858
|
message: CAPABILITY_BUNDLE_CONFIG_MESSAGE
|
|
8736
8859
|
});
|
|
8737
8860
|
}
|
|
8861
|
+
if (data.kind === "public") {
|
|
8862
|
+
return reply.status(409).send({
|
|
8863
|
+
success: false,
|
|
8864
|
+
error: "The public room project is managed automatically"
|
|
8865
|
+
});
|
|
8866
|
+
}
|
|
8738
8867
|
if (user?.id && this.projectCollaboration) {
|
|
8739
8868
|
try {
|
|
8740
8869
|
const authorized = await this.projectCollaboration.authorizeCreator({ tenantId, userId: user.id });
|
|
@@ -8810,6 +8939,21 @@ var WorkspaceController = class {
|
|
|
8810
8939
|
message: CAPABILITY_BUNDLE_CONFIG_MESSAGE
|
|
8811
8940
|
});
|
|
8812
8941
|
}
|
|
8942
|
+
if (updates.kind !== void 0) {
|
|
8943
|
+
const existingProject = await this.projectStore.getProjectById(tenantId, projectId);
|
|
8944
|
+
if (existingProject && updates.kind === "public") {
|
|
8945
|
+
return reply.status(409).send({
|
|
8946
|
+
success: false,
|
|
8947
|
+
error: "kind public is reserved for the workspace public room"
|
|
8948
|
+
});
|
|
8949
|
+
}
|
|
8950
|
+
if (existingProject?.kind === "public") {
|
|
8951
|
+
return reply.status(409).send({
|
|
8952
|
+
success: false,
|
|
8953
|
+
error: "The public room project classification cannot be changed"
|
|
8954
|
+
});
|
|
8955
|
+
}
|
|
8956
|
+
}
|
|
8813
8957
|
const project = await this.projectStore.updateProject(
|
|
8814
8958
|
tenantId,
|
|
8815
8959
|
projectId,
|
|
@@ -8840,6 +8984,12 @@ var WorkspaceController = class {
|
|
|
8840
8984
|
});
|
|
8841
8985
|
}
|
|
8842
8986
|
}
|
|
8987
|
+
if (project.kind === "public") {
|
|
8988
|
+
return reply.status(409).send({
|
|
8989
|
+
success: false,
|
|
8990
|
+
error: "The public room project cannot be deleted"
|
|
8991
|
+
});
|
|
8992
|
+
}
|
|
8843
8993
|
const deleted = await this.projectStore.deleteProject(tenantId, projectId);
|
|
8844
8994
|
if (!deleted) {
|
|
8845
8995
|
return reply.status(404).send({ success: false, error: "Project not found" });
|
|
@@ -11595,7 +11745,7 @@ function registerTenantRoutes(app2) {
|
|
|
11595
11745
|
// src/controllers/auth.ts
|
|
11596
11746
|
var import_core35 = require("@axiom-lattice/core");
|
|
11597
11747
|
var import_uuid8 = require("uuid");
|
|
11598
|
-
var
|
|
11748
|
+
var import_node_crypto3 = require("crypto");
|
|
11599
11749
|
var defaultAuthConfig = {
|
|
11600
11750
|
autoApproveUsers: true,
|
|
11601
11751
|
allowTenantRegistration: true,
|
|
@@ -11950,7 +12100,7 @@ var AuthController = class {
|
|
|
11950
12100
|
function resolveConsoleTokenSecret(_authRequired) {
|
|
11951
12101
|
const configured = process.env.AUTH_TOKEN_SECRET || process.env.JWT_SECRET;
|
|
11952
12102
|
if (configured) return configured;
|
|
11953
|
-
devSessionSecret ?? (devSessionSecret = (0,
|
|
12103
|
+
devSessionSecret ?? (devSessionSecret = (0, import_node_crypto3.randomBytes)(32).toString("hex"));
|
|
11954
12104
|
console.warn(
|
|
11955
12105
|
"[auth] AUTH_TOKEN_SECRET/JWT_SECRET is not set; using an in-process generated signing secret (sessions are invalidated on restart). Set AUTH_TOKEN_SECRET for production."
|
|
11956
12106
|
);
|
|
@@ -11959,7 +12109,7 @@ function resolveConsoleTokenSecret(_authRequired) {
|
|
|
11959
12109
|
var devSessionSecret;
|
|
11960
12110
|
function createConsoleSessionToken(payload, secret) {
|
|
11961
12111
|
const encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
11962
|
-
const signature = (0,
|
|
12112
|
+
const signature = (0, import_node_crypto3.createHmac)("sha256", secret).update(encodedPayload).digest("base64url");
|
|
11963
12113
|
return `${encodedPayload}.${signature}`;
|
|
11964
12114
|
}
|
|
11965
12115
|
function isConsoleSessionPayload(value) {
|
|
@@ -11986,8 +12136,8 @@ function verifySignedConsoleSession(authHeader, secret) {
|
|
|
11986
12136
|
try {
|
|
11987
12137
|
const actualSignature = Buffer.from(encodedSignature, "base64url");
|
|
11988
12138
|
if (actualSignature.toString("base64url") !== encodedSignature) return void 0;
|
|
11989
|
-
const expectedSignature = (0,
|
|
11990
|
-
if (actualSignature.length !== expectedSignature.length || !(0,
|
|
12139
|
+
const expectedSignature = (0, import_node_crypto3.createHmac)("sha256", secret).update(encodedPayload).digest();
|
|
12140
|
+
if (actualSignature.length !== expectedSignature.length || !(0, import_node_crypto3.timingSafeEqual)(actualSignature, expectedSignature)) {
|
|
11991
12141
|
return void 0;
|
|
11992
12142
|
}
|
|
11993
12143
|
const payload = JSON.parse(
|
|
@@ -13568,7 +13718,7 @@ async function getLocalA2ATemplates(_request, reply) {
|
|
|
13568
13718
|
}
|
|
13569
13719
|
|
|
13570
13720
|
// src/routes/a2a-test-connection.ts
|
|
13571
|
-
var
|
|
13721
|
+
var import_node_crypto4 = require("crypto");
|
|
13572
13722
|
function describeTestConnectionError(error, agentCardUrl) {
|
|
13573
13723
|
if (!(error instanceof Error)) {
|
|
13574
13724
|
return `Failed to fetch agent card from ${agentCardUrl}: ${String(error)}`;
|
|
@@ -13608,7 +13758,7 @@ async function ensureLocalRuntimeForConnectionTest(localRuntime, agentCardUrl) {
|
|
|
13608
13758
|
return { error: portValidation.error };
|
|
13609
13759
|
}
|
|
13610
13760
|
const state = await localA2AService.startProvider(
|
|
13611
|
-
`test-${(0,
|
|
13761
|
+
`test-${(0, import_node_crypto4.randomUUID)()}`,
|
|
13612
13762
|
testRuntime
|
|
13613
13763
|
);
|
|
13614
13764
|
if (state.status === "running") return { runtimeId: state.runtimeId };
|
|
@@ -13686,7 +13836,7 @@ var import_protocols10 = require("@axiom-lattice/protocols");
|
|
|
13686
13836
|
var import_core42 = require("@axiom-lattice/core");
|
|
13687
13837
|
|
|
13688
13838
|
// src/services/collaboration/ProjectAccessService.ts
|
|
13689
|
-
var
|
|
13839
|
+
var import_node_crypto5 = require("crypto");
|
|
13690
13840
|
var ProjectCollaborationError = class extends Error {
|
|
13691
13841
|
/** Creates a project collaboration error. */
|
|
13692
13842
|
constructor(code, statusCode, message) {
|
|
@@ -13712,7 +13862,7 @@ var ProjectAccessService = class {
|
|
|
13712
13862
|
/** Creates a project access service from explicitly injected stores. */
|
|
13713
13863
|
constructor(deps) {
|
|
13714
13864
|
this.deps = deps;
|
|
13715
|
-
this.idFactory = deps.idFactory ??
|
|
13865
|
+
this.idFactory = deps.idFactory ?? import_node_crypto5.randomUUID;
|
|
13716
13866
|
}
|
|
13717
13867
|
/** Returns the project and active membership when the user has the requested capability. */
|
|
13718
13868
|
async requireProjectAccess(input) {
|
|
@@ -13720,6 +13870,9 @@ var ProjectAccessService = class {
|
|
|
13720
13870
|
if (!project) {
|
|
13721
13871
|
throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
13722
13872
|
}
|
|
13873
|
+
if (project.kind === "public") {
|
|
13874
|
+
return this.requirePublicProjectAccess(project, input);
|
|
13875
|
+
}
|
|
13723
13876
|
const membership = await this.deps.membershipStore.findByUser(
|
|
13724
13877
|
input.tenantId,
|
|
13725
13878
|
input.projectId,
|
|
@@ -13764,10 +13917,13 @@ var ProjectAccessService = class {
|
|
|
13764
13917
|
this.requireCapability(racedMembership, input.capability);
|
|
13765
13918
|
return { project, membership: racedMembership };
|
|
13766
13919
|
}
|
|
13767
|
-
/** Authorizes
|
|
13920
|
+
/** Authorizes an already-existing membership, or any tenant member for public rooms; never mutates persistence. */
|
|
13768
13921
|
async requireExistingProjectAccess(input) {
|
|
13769
13922
|
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
13770
13923
|
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
13924
|
+
if (project.kind === "public") {
|
|
13925
|
+
return this.requireExistingPublicProjectAccess(project, input);
|
|
13926
|
+
}
|
|
13771
13927
|
const membership = await this.deps.membershipStore.findByUser(
|
|
13772
13928
|
input.tenantId,
|
|
13773
13929
|
input.projectId,
|
|
@@ -13777,6 +13933,87 @@ var ProjectAccessService = class {
|
|
|
13777
13933
|
this.requireCapability(membership, input.capability);
|
|
13778
13934
|
return { project, membership };
|
|
13779
13935
|
}
|
|
13936
|
+
/** Authorizes roster visibility: read for public rooms, manage elsewhere. */
|
|
13937
|
+
async requireRosterAccess(input) {
|
|
13938
|
+
const project = await this.deps.projectStore.getProjectById(input.tenantId, input.projectId);
|
|
13939
|
+
if (!project) throw new ProjectCollaborationError("PROJECT_NOT_FOUND", 404, "Project not found");
|
|
13940
|
+
return this.requireProjectAccess({
|
|
13941
|
+
...input,
|
|
13942
|
+
capability: project.kind === "public" ? "read" : "manage"
|
|
13943
|
+
});
|
|
13944
|
+
}
|
|
13945
|
+
async requirePublicProjectAccess(project, input) {
|
|
13946
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
13947
|
+
input.tenantId,
|
|
13948
|
+
input.projectId,
|
|
13949
|
+
input.userId
|
|
13950
|
+
);
|
|
13951
|
+
if (membership?.status === "active") {
|
|
13952
|
+
this.requireCapability(membership, input.capability);
|
|
13953
|
+
return { project, membership };
|
|
13954
|
+
}
|
|
13955
|
+
const materialized = await this.materializePublicMembership(input);
|
|
13956
|
+
this.requireCapability(materialized, input.capability);
|
|
13957
|
+
return { project, membership: materialized };
|
|
13958
|
+
}
|
|
13959
|
+
async requireExistingPublicProjectAccess(project, input) {
|
|
13960
|
+
const membership = await this.deps.membershipStore.findByUser(
|
|
13961
|
+
input.tenantId,
|
|
13962
|
+
input.projectId,
|
|
13963
|
+
input.userId
|
|
13964
|
+
);
|
|
13965
|
+
if (membership?.status === "active") {
|
|
13966
|
+
this.requireCapability(membership, input.capability);
|
|
13967
|
+
return { project, membership };
|
|
13968
|
+
}
|
|
13969
|
+
if (membership) this.accessDenied();
|
|
13970
|
+
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
13971
|
+
if (!tenantLink) this.accessDenied();
|
|
13972
|
+
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
13973
|
+
const synthetic = {
|
|
13974
|
+
id: `public:${input.userId}`,
|
|
13975
|
+
tenantId: input.tenantId,
|
|
13976
|
+
projectId: input.projectId,
|
|
13977
|
+
userId: input.userId,
|
|
13978
|
+
role,
|
|
13979
|
+
status: "active",
|
|
13980
|
+
joinedAt: project.createdAt,
|
|
13981
|
+
updatedAt: project.updatedAt
|
|
13982
|
+
};
|
|
13983
|
+
this.requireCapability(synthetic, input.capability);
|
|
13984
|
+
return { project, membership: synthetic };
|
|
13985
|
+
}
|
|
13986
|
+
async materializePublicMembership(input) {
|
|
13987
|
+
const tenantLink = await this.deps.userTenantLinkStore.getLink(input.userId, input.tenantId);
|
|
13988
|
+
if (!tenantLink) this.accessDenied();
|
|
13989
|
+
const existing = await this.deps.membershipStore.findByUser(
|
|
13990
|
+
input.tenantId,
|
|
13991
|
+
input.projectId,
|
|
13992
|
+
input.userId
|
|
13993
|
+
);
|
|
13994
|
+
if (existing) this.accessDenied();
|
|
13995
|
+
const role = tenantLink.role === "owner" || tenantLink.role === "admin" ? "admin" : "member";
|
|
13996
|
+
try {
|
|
13997
|
+
return await this.deps.membershipStore.create({
|
|
13998
|
+
id: this.idFactory(),
|
|
13999
|
+
tenantId: input.tenantId,
|
|
14000
|
+
projectId: input.projectId,
|
|
14001
|
+
userId: input.userId,
|
|
14002
|
+
role,
|
|
14003
|
+
status: "active"
|
|
14004
|
+
});
|
|
14005
|
+
} catch (error) {
|
|
14006
|
+
if (isProjectMembershipConflict(error)) {
|
|
14007
|
+
const raced = await this.deps.membershipStore.findByUser(
|
|
14008
|
+
input.tenantId,
|
|
14009
|
+
input.projectId,
|
|
14010
|
+
input.userId
|
|
14011
|
+
);
|
|
14012
|
+
if (raced?.status === "active") return raced;
|
|
14013
|
+
}
|
|
14014
|
+
throw error;
|
|
14015
|
+
}
|
|
14016
|
+
}
|
|
13780
14017
|
requireCapability(membership, capability2) {
|
|
13781
14018
|
if (!allowedRoles[capability2].has(membership.role)) this.accessDenied();
|
|
13782
14019
|
}
|
|
@@ -14992,7 +15229,7 @@ function invalidRequest(reply, statusCode) {
|
|
|
14992
15229
|
var import_zod6 = require("zod");
|
|
14993
15230
|
|
|
14994
15231
|
// src/services/agent-web-app/AgentWebAppRuntimeService.ts
|
|
14995
|
-
var
|
|
15232
|
+
var import_node_crypto6 = require("crypto");
|
|
14996
15233
|
var import_protocols11 = require("@axiom-lattice/protocols");
|
|
14997
15234
|
init_task_file_refs();
|
|
14998
15235
|
function isRecord2(value) {
|
|
@@ -15116,10 +15353,10 @@ ${formatFileRefsSection(refs)}` : input.content;
|
|
|
15116
15353
|
const runtime = await this.resolveOwnedRuntime(webAppId, userId, threadId, selection);
|
|
15117
15354
|
this.requireNamedFeature(runtime.webApp.features.attachments, "Attachments are disabled");
|
|
15118
15355
|
if (!this.deps.saveProjectFile || !this.deps.attachmentRefs) this.fail("INTERNAL_ERROR", 500, "Attachment service is unavailable");
|
|
15119
|
-
const userDigest = (0,
|
|
15120
|
-
const contentDigest = (0,
|
|
15356
|
+
const userDigest = (0, import_node_crypto6.createHash)("sha256").update(userId, "utf8").digest("hex");
|
|
15357
|
+
const contentDigest = (0, import_node_crypto6.createHash)("sha256").update(file.bytes).digest("hex");
|
|
15121
15358
|
const displayName = file.name;
|
|
15122
|
-
const physicalName = `${(0,
|
|
15359
|
+
const physicalName = `${(0, import_node_crypto6.randomUUID)()}-${sanitizePhysicalFilename(file.name)}`;
|
|
15123
15360
|
const saved = await this.deps.saveProjectFile({
|
|
15124
15361
|
tenantId: runtime.webApp.tenantId,
|
|
15125
15362
|
workspaceId: runtime.project.workspaceId,
|
|
@@ -15271,7 +15508,7 @@ ${formatFileRefsSection(refs)}` : input.content;
|
|
|
15271
15508
|
const thread = await this.deps.threadStore.createThread(
|
|
15272
15509
|
runtime.webApp.tenantId,
|
|
15273
15510
|
runtime.webApp.assistantId,
|
|
15274
|
-
(0,
|
|
15511
|
+
(0, import_node_crypto6.randomUUID)(),
|
|
15275
15512
|
{ metadata: this.metadata(runtime, userId, normalizeLabel(rawLabel)) }
|
|
15276
15513
|
);
|
|
15277
15514
|
return toRuntimeThread(thread);
|
|
@@ -15323,7 +15560,7 @@ function implicitThreadId(runtime, userId) {
|
|
|
15323
15560
|
userId,
|
|
15324
15561
|
runtime.project.id
|
|
15325
15562
|
]);
|
|
15326
|
-
const bytes = (0,
|
|
15563
|
+
const bytes = (0, import_node_crypto6.createHash)("sha256").update(canonicalTuple, "utf8").digest().subarray(0, 16);
|
|
15327
15564
|
bytes[6] = bytes[6] & 15 | 128;
|
|
15328
15565
|
bytes[8] = bytes[8] & 63 | 128;
|
|
15329
15566
|
const hex = bytes.toString("hex");
|
|
@@ -15588,7 +15825,7 @@ function isMultipartRequestError(error) {
|
|
|
15588
15825
|
}
|
|
15589
15826
|
|
|
15590
15827
|
// src/services/agent-web-app/AgentWebAppAttachmentRef.ts
|
|
15591
|
-
var
|
|
15828
|
+
var import_node_crypto7 = require("crypto");
|
|
15592
15829
|
var TTL_MS = 15 * 6e4;
|
|
15593
15830
|
function resolveAgentWebAppAttachmentSecret(consoleSecret) {
|
|
15594
15831
|
return process.env.WEB_APP_ATTACHMENT_SECRET || process.env.AUTH_TOKEN_SECRET || process.env.JWT_SECRET || consoleSecret;
|
|
@@ -15597,7 +15834,7 @@ var AgentWebAppAttachmentRefService = class {
|
|
|
15597
15834
|
constructor(secret, now = Date.now) {
|
|
15598
15835
|
this.now = now;
|
|
15599
15836
|
if (!secret) throw new Error("Attachment signing secret is required");
|
|
15600
|
-
this.key = (0,
|
|
15837
|
+
this.key = (0, import_node_crypto7.createHash)("sha256").update(secret, "utf8").digest();
|
|
15601
15838
|
}
|
|
15602
15839
|
sign(input) {
|
|
15603
15840
|
const payload = {
|
|
@@ -15612,8 +15849,8 @@ var AgentWebAppAttachmentRefService = class {
|
|
|
15612
15849
|
contentDigest: input.contentDigest,
|
|
15613
15850
|
exp: this.now() + TTL_MS
|
|
15614
15851
|
};
|
|
15615
|
-
const iv = (0,
|
|
15616
|
-
const cipher = (0,
|
|
15852
|
+
const iv = (0, import_node_crypto7.randomBytes)(12);
|
|
15853
|
+
const cipher = (0, import_node_crypto7.createCipheriv)("aes-256-gcm", this.key, iv);
|
|
15617
15854
|
const ciphertext = Buffer.concat([
|
|
15618
15855
|
cipher.update(JSON.stringify(payload), "utf8"),
|
|
15619
15856
|
cipher.final()
|
|
@@ -15628,7 +15865,7 @@ var AgentWebAppAttachmentRefService = class {
|
|
|
15628
15865
|
const iv = decodeCanonical(encodedIv, 12);
|
|
15629
15866
|
const ciphertext = decodeCanonical(encodedCiphertext);
|
|
15630
15867
|
const tag = decodeCanonical(encodedTag, 16);
|
|
15631
|
-
const decipher = (0,
|
|
15868
|
+
const decipher = (0, import_node_crypto7.createDecipheriv)("aes-256-gcm", this.key, iv);
|
|
15632
15869
|
decipher.setAuthTag(tag);
|
|
15633
15870
|
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
15634
15871
|
const value = JSON.parse(plaintext.toString("utf8"));
|
|
@@ -15659,7 +15896,7 @@ function decodeCanonical(value, expectedBytes) {
|
|
|
15659
15896
|
return decoded;
|
|
15660
15897
|
}
|
|
15661
15898
|
function digestUser(userId) {
|
|
15662
|
-
return (0,
|
|
15899
|
+
return (0, import_node_crypto7.createHash)("sha256").update(userId, "utf8").digest("hex");
|
|
15663
15900
|
}
|
|
15664
15901
|
function isAttachmentPayload(value) {
|
|
15665
15902
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
@@ -16023,12 +16260,12 @@ function registerCapabilityBundleRoutes(app2, controller) {
|
|
|
16023
16260
|
}
|
|
16024
16261
|
|
|
16025
16262
|
// src/services/collaboration/ProjectRoomService.ts
|
|
16026
|
-
var
|
|
16263
|
+
var import_node_crypto8 = require("crypto");
|
|
16027
16264
|
var ProjectRoomService = class {
|
|
16028
16265
|
/** Creates a project room service from explicitly injected collaborators. */
|
|
16029
16266
|
constructor(deps) {
|
|
16030
16267
|
this.deps = deps;
|
|
16031
|
-
this.idFactory = deps.idFactory ??
|
|
16268
|
+
this.idFactory = deps.idFactory ?? import_node_crypto8.randomUUID;
|
|
16032
16269
|
}
|
|
16033
16270
|
/** Authorizes read access and atomically ensures the project's main room. */
|
|
16034
16271
|
async ensureMainRoom(input) {
|
|
@@ -16047,7 +16284,7 @@ var ProjectRoomService = class {
|
|
|
16047
16284
|
};
|
|
16048
16285
|
|
|
16049
16286
|
// src/services/collaboration/ProjectMembershipService.ts
|
|
16050
|
-
var
|
|
16287
|
+
var import_node_crypto9 = require("crypto");
|
|
16051
16288
|
var ProjectMembershipServiceError = class extends Error {
|
|
16052
16289
|
constructor(code, statusCode, message) {
|
|
16053
16290
|
super(message);
|
|
@@ -16063,11 +16300,13 @@ function isMembershipConflict(error) {
|
|
|
16063
16300
|
var ProjectMembershipService = class {
|
|
16064
16301
|
constructor(deps) {
|
|
16065
16302
|
this.deps = deps;
|
|
16066
|
-
this.idFactory = deps.idFactory ??
|
|
16303
|
+
this.idFactory = deps.idFactory ?? import_node_crypto9.randomUUID;
|
|
16067
16304
|
this.mutationMutex = deps.projectMutationMutex ?? import_core41.projectMutationMutex;
|
|
16068
16305
|
}
|
|
16069
16306
|
async list(actor2) {
|
|
16070
|
-
await this.
|
|
16307
|
+
await this.deps.accessService.requireRosterAccess(actor2);
|
|
16308
|
+
const membership = await this.deps.membershipStore.findByUser(actor2.tenantId, actor2.projectId, actor2.userId);
|
|
16309
|
+
if (!membership || membership.status !== "active") this.accessDenied();
|
|
16071
16310
|
return this.deps.membershipStore.list(actor2.tenantId, actor2.projectId);
|
|
16072
16311
|
}
|
|
16073
16312
|
async add(actor2, input) {
|
|
@@ -16187,7 +16426,7 @@ var ProjectMembershipService = class {
|
|
|
16187
16426
|
};
|
|
16188
16427
|
|
|
16189
16428
|
// src/services/collaboration/ProjectRosterService.ts
|
|
16190
|
-
var
|
|
16429
|
+
var import_node_crypto10 = require("crypto");
|
|
16191
16430
|
var ProjectRosterServiceError = class extends Error {
|
|
16192
16431
|
/** Creates a stable roster service error. */
|
|
16193
16432
|
constructor(code, statusCode, message) {
|
|
@@ -16204,7 +16443,7 @@ var ProjectRosterService = class {
|
|
|
16204
16443
|
/** Creates a roster service from explicitly injected collaborators. */
|
|
16205
16444
|
constructor(deps) {
|
|
16206
16445
|
this.deps = deps;
|
|
16207
|
-
this.idFactory = deps.idFactory ??
|
|
16446
|
+
this.idFactory = deps.idFactory ?? import_node_crypto10.randomUUID;
|
|
16208
16447
|
this.mutationMutex = deps.projectMutationMutex ?? import_core41.projectMutationMutex;
|
|
16209
16448
|
}
|
|
16210
16449
|
/** Lists all bot memberships visible to a project reader. */
|
|
@@ -16424,7 +16663,7 @@ var ProjectRosterService = class {
|
|
|
16424
16663
|
};
|
|
16425
16664
|
|
|
16426
16665
|
// src/services/collaboration/RoomMessageService.ts
|
|
16427
|
-
var
|
|
16666
|
+
var import_node_crypto11 = require("crypto");
|
|
16428
16667
|
|
|
16429
16668
|
// src/services/collaboration/ProjectBotMembershipSnapshot.ts
|
|
16430
16669
|
var import_protocols13 = require("@axiom-lattice/protocols");
|
|
@@ -16513,7 +16752,7 @@ var RoomMessageService = class {
|
|
|
16513
16752
|
constructor(deps, options = {}) {
|
|
16514
16753
|
this.deps = deps;
|
|
16515
16754
|
this.idempotentOutcomes = /* @__PURE__ */ new Map();
|
|
16516
|
-
this.idFactory = deps.idFactory ??
|
|
16755
|
+
this.idFactory = deps.idFactory ?? import_node_crypto11.randomUUID;
|
|
16517
16756
|
const limit = options.idempotentOutcomeLimit ?? 1e3;
|
|
16518
16757
|
if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError("idempotentOutcomeLimit must be a positive safe integer");
|
|
16519
16758
|
this.idempotentOutcomeLimit = limit;
|
|
@@ -16694,7 +16933,7 @@ var RoomMessageService = class {
|
|
|
16694
16933
|
let idempotencyKey;
|
|
16695
16934
|
if (value.requestIdempotencyKey !== void 0) {
|
|
16696
16935
|
if (typeof value.requestIdempotencyKey !== "string" || !/^[\x21-\x7e]{1,200}$/.test(value.requestIdempotencyKey.trim())) throw new RoomMessageServiceError("INVALID_MESSAGE", 400, "Invalid idempotency key");
|
|
16697
|
-
idempotencyKey = `room-human:${actor2.userId}:${(0,
|
|
16936
|
+
idempotencyKey = `room-human:${actor2.userId}:${(0, import_node_crypto11.createHash)("sha256").update(value.requestIdempotencyKey.trim(), "utf8").digest("hex")}`;
|
|
16698
16937
|
}
|
|
16699
16938
|
return { text, mentions, botIds, ...value.replyToMessageId === void 0 ? {} : { replyToMessageId: value.replyToMessageId }, ...idempotencyKey === void 0 ? {} : { idempotencyKey } };
|
|
16700
16939
|
}
|
|
@@ -16751,7 +16990,7 @@ function cloneRoomMessage(message) {
|
|
|
16751
16990
|
};
|
|
16752
16991
|
}
|
|
16753
16992
|
function fingerprintRequest(input) {
|
|
16754
|
-
return (0,
|
|
16993
|
+
return (0, import_node_crypto11.createHash)("sha256").update(JSON.stringify({
|
|
16755
16994
|
text: input.text,
|
|
16756
16995
|
mentions: input.mentions,
|
|
16757
16996
|
replyToMessageId: input.replyToMessageId ?? null
|
|
@@ -16920,42 +17159,9 @@ async function execute(reply, operation) {
|
|
|
16920
17159
|
}
|
|
16921
17160
|
|
|
16922
17161
|
// src/routes/cospace.ts
|
|
16923
|
-
var
|
|
17162
|
+
var import_node_crypto12 = require("crypto");
|
|
16924
17163
|
var import_zod12 = require("zod");
|
|
16925
17164
|
var import_core44 = require("@axiom-lattice/core");
|
|
16926
|
-
|
|
16927
|
-
// src/services/collaboration/RoomCoordinatorProvisioner.ts
|
|
16928
|
-
var ROOM_COORDINATOR_KEY = "room-coordinator";
|
|
16929
|
-
var RoomCoordinatorProvisioner = class {
|
|
16930
|
-
/** Creates a provisioner over the tenant-scoped assistant store operations. */
|
|
16931
|
-
constructor(deps) {
|
|
16932
|
-
this.deps = deps;
|
|
16933
|
-
}
|
|
16934
|
-
/**
|
|
16935
|
-
* Ensures the Room Coordinator assistant exists, reusing an existing record
|
|
16936
|
-
* and reconciling concurrent create races by rereading the winner.
|
|
16937
|
-
*
|
|
16938
|
-
* @param tenantId Tenant to provision the coordinator for.
|
|
16939
|
-
* @returns The persisted Room Coordinator assistant.
|
|
16940
|
-
*/
|
|
16941
|
-
async ensure(tenantId) {
|
|
16942
|
-
const existing = await this.deps.getAssistantById(tenantId, ROOM_COORDINATOR_KEY);
|
|
16943
|
-
if (existing) return existing;
|
|
16944
|
-
try {
|
|
16945
|
-
return await this.deps.createAssistant(tenantId, ROOM_COORDINATOR_KEY, {
|
|
16946
|
-
name: "Room Coordinator",
|
|
16947
|
-
description: "Coordinates project room conversations and organizes room work.",
|
|
16948
|
-
graphDefinition: {}
|
|
16949
|
-
});
|
|
16950
|
-
} catch (error) {
|
|
16951
|
-
const winner = await this.deps.getAssistantById(tenantId, ROOM_COORDINATOR_KEY);
|
|
16952
|
-
if (winner) return winner;
|
|
16953
|
-
throw error;
|
|
16954
|
-
}
|
|
16955
|
-
}
|
|
16956
|
-
};
|
|
16957
|
-
|
|
16958
|
-
// src/routes/cospace.ts
|
|
16959
17165
|
var CoSpaceAuthError = class extends Error {
|
|
16960
17166
|
constructor() {
|
|
16961
17167
|
super(...arguments);
|
|
@@ -16971,7 +17177,7 @@ function getActor2(request) {
|
|
|
16971
17177
|
return { tenantId: user.tenantId, userId: user.id };
|
|
16972
17178
|
}
|
|
16973
17179
|
function registerCoSpaceRoutes(app2, deps) {
|
|
16974
|
-
const idFactory = deps.idFactory ?? (() => (0,
|
|
17180
|
+
const idFactory = deps.idFactory ?? (() => (0, import_node_crypto12.randomUUID)());
|
|
16975
17181
|
app2.get(
|
|
16976
17182
|
"/api/workspaces/:workspaceId/rooms",
|
|
16977
17183
|
async (request, reply) => {
|
|
@@ -16996,6 +17202,7 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
16996
17202
|
);
|
|
16997
17203
|
const accessibleProjects = [];
|
|
16998
17204
|
for (const project of allProjects) {
|
|
17205
|
+
if (project.kind === "public") continue;
|
|
16999
17206
|
const membership = await deps.membershipStore.findByUser(
|
|
17000
17207
|
actor2.tenantId,
|
|
17001
17208
|
project.id,
|
|
@@ -17049,6 +17256,34 @@ function registerCoSpaceRoutes(app2, deps) {
|
|
|
17049
17256
|
const bTime = b.lastMessage?.createdAt?.getTime() ?? 0;
|
|
17050
17257
|
return bTime - aTime;
|
|
17051
17258
|
});
|
|
17259
|
+
const publicRoom = await deps.publicRoom.ensure(actor2.tenantId, params.workspaceId);
|
|
17260
|
+
if (publicRoom) {
|
|
17261
|
+
const publicMessages = await deps.messageStore.list({
|
|
17262
|
+
tenantId: actor2.tenantId,
|
|
17263
|
+
roomId: publicRoom.room.id,
|
|
17264
|
+
limit: 1
|
|
17265
|
+
});
|
|
17266
|
+
const publicMemberships = await deps.membershipStore.list(
|
|
17267
|
+
actor2.tenantId,
|
|
17268
|
+
publicRoom.project.id
|
|
17269
|
+
);
|
|
17270
|
+
const publicParticipantNames = [];
|
|
17271
|
+
for (const m of publicMemberships) {
|
|
17272
|
+
if (m.status !== "active") continue;
|
|
17273
|
+
const user = await deps.userStore.getUserById(m.userId);
|
|
17274
|
+
if (user) {
|
|
17275
|
+
publicParticipantNames.push(user.name);
|
|
17276
|
+
}
|
|
17277
|
+
}
|
|
17278
|
+
rooms.unshift({
|
|
17279
|
+
project: publicRoom.project,
|
|
17280
|
+
room: publicRoom.room,
|
|
17281
|
+
lastMessage: publicMessages[0],
|
|
17282
|
+
participantCount: publicMemberships.filter((m) => m.status === "active").length,
|
|
17283
|
+
participantNames: publicParticipantNames,
|
|
17284
|
+
isPublic: true
|
|
17285
|
+
});
|
|
17286
|
+
}
|
|
17052
17287
|
return { data: { rooms } };
|
|
17053
17288
|
});
|
|
17054
17289
|
}
|
|
@@ -17805,7 +18040,7 @@ function exactValues(value, required, optional = []) {
|
|
|
17805
18040
|
}
|
|
17806
18041
|
|
|
17807
18042
|
// src/services/collaboration/CoordinatorWakeNotifier.ts
|
|
17808
|
-
var
|
|
18043
|
+
var import_node_crypto13 = require("crypto");
|
|
17809
18044
|
var import_core45 = require("@axiom-lattice/core");
|
|
17810
18045
|
var import_protocols15 = require("@axiom-lattice/protocols");
|
|
17811
18046
|
var SYNTHETIC_WAKE_AUTHOR = "coordinator-wake";
|
|
@@ -17820,7 +18055,7 @@ var CoordinatorWakeNotifier = class {
|
|
|
17820
18055
|
this.accepted = /* @__PURE__ */ new Set();
|
|
17821
18056
|
this.maxPending = deps.maxPending ?? 1024;
|
|
17822
18057
|
if (!Number.isSafeInteger(this.maxPending) || this.maxPending < 1) throw new RangeError("maxPending must be a positive safe integer");
|
|
17823
|
-
this.idFactory = deps.idFactory ??
|
|
18058
|
+
this.idFactory = deps.idFactory ?? import_node_crypto13.randomUUID;
|
|
17824
18059
|
}
|
|
17825
18060
|
/** Admits one notification without awaiting any store or dispatch operation. */
|
|
17826
18061
|
handle(value) {
|
|
@@ -18683,7 +18918,7 @@ function validRecoveryRow(row, task, thread) {
|
|
|
18683
18918
|
}
|
|
18684
18919
|
|
|
18685
18920
|
// src/services/collaboration/ProjectTaskObserver.ts
|
|
18686
|
-
var
|
|
18921
|
+
var import_node_crypto14 = require("crypto");
|
|
18687
18922
|
var import_core47 = require("@axiom-lattice/core");
|
|
18688
18923
|
var SYSTEM_ACTOR2 = "system";
|
|
18689
18924
|
var TERMINAL_ACTIONS = ["completed", "failed", "interrupted", "cancelled"];
|
|
@@ -19220,7 +19455,7 @@ var ProjectTaskObserver = class {
|
|
|
19220
19455
|
action: "activity",
|
|
19221
19456
|
summary: "Project task recovery warning",
|
|
19222
19457
|
detail: { type: "project_task_recovery_warning", phase, message },
|
|
19223
|
-
eventKey: `project-task-recovery-warning:${task.id}:${phase}:${(0,
|
|
19458
|
+
eventKey: `project-task-recovery-warning:${task.id}:${phase}:${(0, import_node_crypto14.createHash)("sha256").update(message).digest("hex")}`
|
|
19224
19459
|
});
|
|
19225
19460
|
}
|
|
19226
19461
|
async safeWarning(task, phase, error) {
|
|
@@ -19287,7 +19522,7 @@ var ProjectTaskObserver = class {
|
|
|
19287
19522
|
}
|
|
19288
19523
|
}
|
|
19289
19524
|
async persistOverflowWarning(event) {
|
|
19290
|
-
const scopeDigest = (0,
|
|
19525
|
+
const scopeDigest = (0, import_node_crypto14.createHash)("sha256").update(JSON.stringify([event.tenantId, event.workspaceId, event.projectId])).digest("hex");
|
|
19291
19526
|
try {
|
|
19292
19527
|
await this.deps.workItems.createIfAbsentByEventKey({
|
|
19293
19528
|
tenantId: event.tenantId,
|
|
@@ -19388,7 +19623,7 @@ function combineSignals(left, right) {
|
|
|
19388
19623
|
}
|
|
19389
19624
|
|
|
19390
19625
|
// src/services/collaboration/RoomProjectionService.ts
|
|
19391
|
-
var
|
|
19626
|
+
var import_node_crypto15 = require("crypto");
|
|
19392
19627
|
var import_core48 = require("@axiom-lattice/core");
|
|
19393
19628
|
var import_protocols18 = require("@axiom-lattice/protocols");
|
|
19394
19629
|
var RoomProjectionService = class {
|
|
@@ -19557,7 +19792,7 @@ function safeRepairIdentity(value, scope) {
|
|
|
19557
19792
|
return taskId && eventKey && tenantId === scope.tenantId && workspaceId === scope.workspaceId && projectId === scope.projectId ? { taskId, eventKey } : void 0;
|
|
19558
19793
|
}
|
|
19559
19794
|
function tupleKey(prefix, values) {
|
|
19560
|
-
const digest = (0,
|
|
19795
|
+
const digest = (0, import_node_crypto15.createHash)("sha256").update(JSON.stringify(values)).digest("hex");
|
|
19561
19796
|
return `${prefix}:${digest}`;
|
|
19562
19797
|
}
|
|
19563
19798
|
function parseProjectionInput(taskValue, itemValue) {
|
|
@@ -19740,7 +19975,7 @@ function isRecord4(value) {
|
|
|
19740
19975
|
var import_core50 = require("@axiom-lattice/core");
|
|
19741
19976
|
|
|
19742
19977
|
// src/services/collaboration/ProjectRoomEventBroker.ts
|
|
19743
|
-
var
|
|
19978
|
+
var import_node_crypto16 = require("crypto");
|
|
19744
19979
|
var import_protocols19 = require("@axiom-lattice/protocols");
|
|
19745
19980
|
var DEFAULT_MAX_EVENTS_PER_ROOM = 1e3;
|
|
19746
19981
|
var DEFAULT_MAX_EVENT_AGE_MS = 10 * 60 * 1e3;
|
|
@@ -19765,7 +20000,7 @@ var ProjectRoomEventBroker = class {
|
|
|
19765
20000
|
this.subscriberCount = 0;
|
|
19766
20001
|
this.usageClock = 0;
|
|
19767
20002
|
this.closed = false;
|
|
19768
|
-
this.epoch = options.epoch ?? (0,
|
|
20003
|
+
this.epoch = options.epoch ?? (0, import_node_crypto16.randomUUID)();
|
|
19769
20004
|
if (!UUID_PATTERN.test(this.epoch)) {
|
|
19770
20005
|
throw new TypeError("Project Room event epoch must be a lowercase canonical UUID");
|
|
19771
20006
|
}
|
|
@@ -20083,7 +20318,7 @@ function snapshotJson(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
|
20083
20318
|
}
|
|
20084
20319
|
|
|
20085
20320
|
// src/services/collaboration/ProjectRoomRealtimePublisher.ts
|
|
20086
|
-
var
|
|
20321
|
+
var import_node_crypto17 = require("crypto");
|
|
20087
20322
|
var import_protocols20 = require("@axiom-lattice/protocols");
|
|
20088
20323
|
var BrokerProjectRoomRealtimePublisher = class {
|
|
20089
20324
|
/** Creates a publisher around a broker and structured warning logger. */
|
|
@@ -20159,7 +20394,7 @@ var BrokerProjectRoomRealtimePublisher = class {
|
|
|
20159
20394
|
try {
|
|
20160
20395
|
event = build();
|
|
20161
20396
|
if (!event) throw new Error("Invalid Project Room realtime projection");
|
|
20162
|
-
const dedupeKey = (0,
|
|
20397
|
+
const dedupeKey = (0, import_node_crypto17.createHash)("sha256").update(JSON.stringify([type, event.scope.tenantId, event.scope.projectId, event.scope.roomId, event.sourceKey])).digest("hex");
|
|
20163
20398
|
if (this.sourceKeys.has(dedupeKey)) return;
|
|
20164
20399
|
this.deps.broker.publish(event.scope, event.draft);
|
|
20165
20400
|
this.sourceKeys.set(dedupeKey, true);
|
|
@@ -21098,12 +21333,24 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21098
21333
|
});
|
|
21099
21334
|
}
|
|
21100
21335
|
if (projectTaskComposition) app2.addHook("onClose", async () => projectTaskComposition.lease.release());
|
|
21101
|
-
const taskThreadService = projectTaskComposition?.lease.runtime.threads ?? new ProjectTaskThreadService({ threads: threadStore, idFactory:
|
|
21336
|
+
const taskThreadService = projectTaskComposition?.lease.runtime.threads ?? new ProjectTaskThreadService({ threads: threadStore, idFactory: import_node_crypto18.randomUUID });
|
|
21102
21337
|
const taskLifecycle = projectTaskComposition?.lease.runtime.lifecycle ?? (0, import_core51.createTaskLifecycleService)({ taskStore, workItemStore: taskWorkItemStore });
|
|
21103
21338
|
const reassignmentAuthorizer = (0, import_core51.createProjectTaskReassignmentAuthorizer)(
|
|
21104
21339
|
new import_core51.ProjectTaskOwnerPolicy(projectBotMembershipStore),
|
|
21105
21340
|
(input) => validateReassignmentThread(threadStore, input)
|
|
21106
21341
|
);
|
|
21342
|
+
const coordinatorProvisioner = new RoomCoordinatorProvisioner({
|
|
21343
|
+
getAssistantById: assistantStore.getAssistantById.bind(assistantStore),
|
|
21344
|
+
createAssistant: assistantStore.createAssistant.bind(assistantStore)
|
|
21345
|
+
});
|
|
21346
|
+
const publicRoomService = new WorkspacePublicRoomService({
|
|
21347
|
+
getProjectById: projectStore.getProjectById.bind(projectStore),
|
|
21348
|
+
createProject: projectStore.createProject.bind(projectStore),
|
|
21349
|
+
ensureMainRoom: projectRoomStore.ensureMainRoom.bind(projectRoomStore),
|
|
21350
|
+
findBotByAssistant: projectBotMembershipStore.findByAssistant.bind(projectBotMembershipStore),
|
|
21351
|
+
saveBot: projectBotMembershipStore.save.bind(projectBotMembershipStore),
|
|
21352
|
+
ensureCoordinator: (tenantId) => coordinatorProvisioner.ensure(tenantId)
|
|
21353
|
+
});
|
|
21107
21354
|
registerProjectRoomRoutes(app2, { roomService, membershipService, messageService });
|
|
21108
21355
|
registerProjectRosterRoutes(app2, { service: rosterService });
|
|
21109
21356
|
registerCoSpaceRoutes(app2, {
|
|
@@ -21142,14 +21389,14 @@ var registerLatticeRoutes = (app2, channelDeps, options = {}) => {
|
|
|
21142
21389
|
findByAssistant: projectBotMembershipStore.findByAssistant.bind(projectBotMembershipStore),
|
|
21143
21390
|
save: projectBotMembershipStore.save.bind(projectBotMembershipStore)
|
|
21144
21391
|
},
|
|
21145
|
-
coordinatorProvisioner
|
|
21146
|
-
getAssistantById: assistantStore.getAssistantById.bind(assistantStore),
|
|
21147
|
-
createAssistant: assistantStore.createAssistant.bind(assistantStore)
|
|
21148
|
-
}),
|
|
21392
|
+
coordinatorProvisioner,
|
|
21149
21393
|
rosterService: {
|
|
21150
21394
|
addBot: async (actor2, input) => {
|
|
21151
21395
|
await rosterService.add(actor2, input);
|
|
21152
21396
|
}
|
|
21397
|
+
},
|
|
21398
|
+
publicRoom: {
|
|
21399
|
+
ensure: (tenantId, workspaceId) => publicRoomService.ensure(tenantId, workspaceId)
|
|
21153
21400
|
}
|
|
21154
21401
|
});
|
|
21155
21402
|
registerCapabilityBundleRoutes(app2, new CapabilityBundleController({
|
|
@@ -21590,7 +21837,7 @@ function tryCreateProjectTaskRuntime(input) {
|
|
|
21590
21837
|
function createRuntime(input, stores, log2) {
|
|
21591
21838
|
const controller = new AbortController();
|
|
21592
21839
|
const mutex = new ProjectTaskExecutionMutex();
|
|
21593
|
-
const threads = new ProjectTaskThreadService({ threads: input.threadStore, idFactory:
|
|
21840
|
+
const threads = new ProjectTaskThreadService({ threads: input.threadStore, idFactory: import_node_crypto18.randomUUID });
|
|
21594
21841
|
const lifecycle = (0, import_core51.createTaskLifecycleService)({ taskStore: input.taskStore, workItemStore: input.taskWorkItemStore });
|
|
21595
21842
|
const projection = new RoomProjectionService({
|
|
21596
21843
|
messages: input.projectRoomMessageStore,
|
|
@@ -21599,7 +21846,7 @@ function createRuntime(input, stores, log2) {
|
|
|
21599
21846
|
warnings: input.taskWorkItemStore,
|
|
21600
21847
|
log: log2,
|
|
21601
21848
|
realtime: input.realtime,
|
|
21602
|
-
idFactory:
|
|
21849
|
+
idFactory: import_node_crypto18.randomUUID
|
|
21603
21850
|
});
|
|
21604
21851
|
const agentFor = (task, thread) => import_core51.agentInstanceManager.getAgent({
|
|
21605
21852
|
tenant_id: task.tenantId,
|