@cmmd-center/forge 0.13.125 → 0.13.126
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/bin.cjs +138 -41
- package/dist/bin.mjs +138 -41
- package/dist/client/assets/{CanvasPanel-BOh2xUZv.js → CanvasPanel-Db1Iz4JN.js} +2 -2
- package/dist/client/assets/CompositeItem-BxPZ_9BJ.js +2 -0
- package/dist/client/assets/DiffPanel-CNil6OV-.js +64 -0
- package/dist/client/assets/{DiffPanel.logic-DS1mmUZB.js → DiffPanel.logic-yEOXCs0u.js} +2 -2
- package/dist/client/assets/{DiffWorkerPoolProvider-C2tnM5gq.js → DiffWorkerPoolProvider-BF-pZpUl.js} +11 -11
- package/dist/client/assets/PullRequestCodePanel-eldrSbZ3.js +5 -0
- package/dist/client/assets/{ThemeEditorPanel-v2mnY18G.js → ThemeEditorPanel-DTfrlPBc.js} +2 -2
- package/dist/client/assets/{Virtualizer-Ds5-GzY3.js → Virtualizer-BvsCWf4E.js} +2 -2
- package/dist/client/assets/WorkerPoolContext-CaivT_VA.js +1533 -0
- package/dist/client/assets/{canvasStateStore-xaZAenqH.js → canvasStateStore-DKtQcBVc.js} +2 -2
- package/dist/client/assets/cmmdForgeRuntimeListResource-CRVF6pin.js +1008 -0
- package/dist/client/assets/currentForgeWorkspaceStore-DH-DGTJm.js +2 -0
- package/dist/client/assets/{index-Rx6Z6FPS.js → index-CIM7fDFV.js} +68 -68
- package/dist/client/assets/popover-Cvb1Axgx.js +2 -0
- package/dist/client/assets/scroll-area-DzReJmNn.js +2 -0
- package/dist/client/assets/switch-RuRK1onH.js +2 -0
- package/dist/client/assets/{themePalette-eOA8OvYM.js → themePalette-gr6ZYaOx.js} +2 -2
- package/dist/client/assets/toggle-D8xaJAgP.js +2 -0
- package/dist/client/assets/toggle-group-CwSbXP07.js +2 -0
- package/dist/client/assets/useOpenInteractionType-B983ff5H.js +2 -0
- package/dist/client/assets/utils-B4G-Q0s7.js +2 -0
- package/dist/client/index.html +16 -13
- package/dist/forge-build.json +1 -1
- package/package.json +1 -1
- package/dist/client/assets/CompositeItem-DNVaubQt.js +0 -2
- package/dist/client/assets/DiffPanel-BM-qanPT.js +0 -64
- package/dist/client/assets/PullRequestCodePanel-zxkVGUeq.js +0 -5
- package/dist/client/assets/WorkerPoolContext-BWuPUnhX.js +0 -2538
- package/dist/client/assets/popover-Cxnw5kve.js +0 -2
- package/dist/client/assets/scroll-area-DDcW71H4.js +0 -2
- package/dist/client/assets/switch-Wi-2Dkh9.js +0 -2
- package/dist/client/assets/toggle-group-Cqh7gA8I.js +0 -2
- package/dist/client/assets/toggle-m8ncTpRB.js +0 -2
- package/dist/client/assets/useOpenInteractionType-CN3hnnfp.js +0 -2
package/dist/bin.cjs
CHANGED
|
@@ -66337,7 +66337,7 @@ function normalizeNumberish(value) {
|
|
|
66337
66337
|
}
|
|
66338
66338
|
//#endregion
|
|
66339
66339
|
//#region package.json
|
|
66340
|
-
var version$1 = "0.13.
|
|
66340
|
+
var version$1 = "0.13.126";
|
|
66341
66341
|
//#endregion
|
|
66342
66342
|
//#region src/sentry.ts
|
|
66343
66343
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -72634,20 +72634,25 @@ const legacyCmmdToolBridge = {
|
|
|
72634
72634
|
};
|
|
72635
72635
|
//#endregion
|
|
72636
72636
|
//#region src/command/workIntakeCache.ts
|
|
72637
|
-
const
|
|
72637
|
+
const cacheByKey = /* @__PURE__ */ new Map();
|
|
72638
|
+
function cacheKeyFor(sessionId, orgId) {
|
|
72639
|
+
return `${sessionId}\u0000${orgId ?? ""}`;
|
|
72640
|
+
}
|
|
72638
72641
|
function resolveCmmdWorkIntakeCacheIdentity(subject, cmmdUserId) {
|
|
72639
72642
|
return cmmdUserId ? `cmmd-user:${cmmdUserId}` : `forge-subject:${subject}`;
|
|
72640
72643
|
}
|
|
72641
72644
|
function fingerprintToken(token) {
|
|
72642
72645
|
return (0, node_crypto.createHash)("sha256").update(token).digest("hex");
|
|
72643
72646
|
}
|
|
72644
|
-
async function fetchBlockingSnapshot(input, identityKey, tokenFingerprint, existing) {
|
|
72647
|
+
async function fetchBlockingSnapshot(input, cacheKey, identityKey, tokenFingerprint, existing) {
|
|
72645
72648
|
if (existing?.inFlight) return existing.inFlight;
|
|
72646
72649
|
const nowMs = input.nowMs ?? Date.now;
|
|
72647
72650
|
let promise;
|
|
72648
72651
|
promise = input.fetchFresh().then((snapshot) => {
|
|
72649
|
-
const current =
|
|
72650
|
-
if (current?.tokenFingerprint === tokenFingerprint && current.inFlight === promise)
|
|
72652
|
+
const current = cacheByKey.get(cacheKey);
|
|
72653
|
+
if (current?.tokenFingerprint === tokenFingerprint && current.inFlight === promise) cacheByKey.set(cacheKey, {
|
|
72654
|
+
sessionId: input.sessionId,
|
|
72655
|
+
orgId: input.orgId,
|
|
72651
72656
|
identityKey,
|
|
72652
72657
|
tokenFingerprint,
|
|
72653
72658
|
snapshot,
|
|
@@ -72656,12 +72661,14 @@ async function fetchBlockingSnapshot(input, identityKey, tokenFingerprint, exist
|
|
|
72656
72661
|
});
|
|
72657
72662
|
return snapshot;
|
|
72658
72663
|
}).catch((error) => {
|
|
72659
|
-
const current =
|
|
72660
|
-
if (current?.tokenFingerprint === tokenFingerprint && current.inFlight === promise) if (legacyCmmdToolBridge.isAuthError(error))
|
|
72664
|
+
const current = cacheByKey.get(cacheKey);
|
|
72665
|
+
if (current?.tokenFingerprint === tokenFingerprint && current.inFlight === promise) if (legacyCmmdToolBridge.isAuthError(error)) cacheByKey.delete(cacheKey);
|
|
72661
72666
|
else current.inFlight = null;
|
|
72662
72667
|
throw error;
|
|
72663
72668
|
});
|
|
72664
|
-
|
|
72669
|
+
cacheByKey.set(cacheKey, {
|
|
72670
|
+
sessionId: input.sessionId,
|
|
72671
|
+
orgId: input.orgId,
|
|
72665
72672
|
identityKey,
|
|
72666
72673
|
tokenFingerprint,
|
|
72667
72674
|
snapshot: existing?.snapshot ?? null,
|
|
@@ -72677,9 +72684,9 @@ async function fetchBlockingSnapshot(input, identityKey, tokenFingerprint, exist
|
|
|
72677
72684
|
* opportunistically on every read.
|
|
72678
72685
|
*/
|
|
72679
72686
|
function sweepExpiredWorkIntakeEntries(nowMs) {
|
|
72680
|
-
for (const [
|
|
72687
|
+
for (const [key, entry] of cacheByKey) {
|
|
72681
72688
|
if (entry.inFlight) continue;
|
|
72682
|
-
if (nowMs - entry.cachedAtMs > 3e5)
|
|
72689
|
+
if (nowMs - entry.cachedAtMs > 3e5) cacheByKey.delete(key);
|
|
72683
72690
|
}
|
|
72684
72691
|
}
|
|
72685
72692
|
async function readCachedCmmdWorkIntakeForSession(input) {
|
|
@@ -72688,17 +72695,18 @@ async function readCachedCmmdWorkIntakeForSession(input) {
|
|
|
72688
72695
|
const identityKey = input.identityKey ?? input.sessionId;
|
|
72689
72696
|
if (input.forceFresh) invalidateCachedCmmdWorkIntakeForIdentity(identityKey);
|
|
72690
72697
|
const tokenFingerprint = fingerprintToken(input.token);
|
|
72691
|
-
const
|
|
72692
|
-
|
|
72693
|
-
|
|
72694
|
-
|
|
72698
|
+
const cacheKey = cacheKeyFor(input.sessionId, input.orgId);
|
|
72699
|
+
const existing = cacheByKey.get(cacheKey);
|
|
72700
|
+
if (existing && (existing.identityKey !== identityKey || existing.tokenFingerprint !== tokenFingerprint)) cacheByKey.delete(cacheKey);
|
|
72701
|
+
const current = cacheByKey.get(cacheKey);
|
|
72702
|
+
if (!current?.snapshot) return fetchBlockingSnapshot(input, cacheKey, identityKey, tokenFingerprint, current);
|
|
72695
72703
|
const ageMs = Math.max(0, nowMs() - current.cachedAtMs);
|
|
72696
72704
|
if (ageMs <= 12e4) return current.snapshot;
|
|
72697
72705
|
if (ageMs <= 3e5) {
|
|
72698
72706
|
if (!current.inFlight) {
|
|
72699
72707
|
let refreshPromise;
|
|
72700
72708
|
refreshPromise = input.fetchFresh().then((snapshot) => {
|
|
72701
|
-
const latest =
|
|
72709
|
+
const latest = cacheByKey.get(cacheKey);
|
|
72702
72710
|
if (latest?.tokenFingerprint === tokenFingerprint && latest.inFlight === refreshPromise) {
|
|
72703
72711
|
latest.snapshot = snapshot;
|
|
72704
72712
|
latest.cachedAtMs = nowMs();
|
|
@@ -72706,25 +72714,25 @@ async function readCachedCmmdWorkIntakeForSession(input) {
|
|
|
72706
72714
|
return snapshot;
|
|
72707
72715
|
}).catch((error) => {
|
|
72708
72716
|
if (legacyCmmdToolBridge.isAuthError(error)) {
|
|
72709
|
-
const latest =
|
|
72710
|
-
if (latest?.tokenFingerprint === tokenFingerprint && latest.inFlight === refreshPromise)
|
|
72717
|
+
const latest = cacheByKey.get(cacheKey);
|
|
72718
|
+
if (latest?.tokenFingerprint === tokenFingerprint && latest.inFlight === refreshPromise) cacheByKey.delete(cacheKey);
|
|
72711
72719
|
}
|
|
72712
72720
|
return current.snapshot;
|
|
72713
72721
|
}).finally(() => {
|
|
72714
|
-
const latest =
|
|
72722
|
+
const latest = cacheByKey.get(cacheKey);
|
|
72715
72723
|
if (latest?.tokenFingerprint === tokenFingerprint && latest.inFlight === refreshPromise) latest.inFlight = null;
|
|
72716
72724
|
});
|
|
72717
72725
|
current.inFlight = refreshPromise;
|
|
72718
72726
|
}
|
|
72719
72727
|
return current.snapshot;
|
|
72720
72728
|
}
|
|
72721
|
-
return fetchBlockingSnapshot(input, identityKey, tokenFingerprint, current);
|
|
72729
|
+
return fetchBlockingSnapshot(input, cacheKey, identityKey, tokenFingerprint, current);
|
|
72722
72730
|
}
|
|
72723
72731
|
function invalidateCachedCmmdWorkIntakeForSession(sessionId) {
|
|
72724
|
-
|
|
72732
|
+
for (const [key, entry] of cacheByKey) if (entry.sessionId === sessionId) cacheByKey.delete(key);
|
|
72725
72733
|
}
|
|
72726
72734
|
function invalidateCachedCmmdWorkIntakeForIdentity(identityKey) {
|
|
72727
|
-
for (const [
|
|
72735
|
+
for (const [key, entry] of cacheByKey) if (entry.identityKey === identityKey) cacheByKey.delete(key);
|
|
72728
72736
|
}
|
|
72729
72737
|
//#endregion
|
|
72730
72738
|
//#region src/cmmdData/proxyRouteRegistry.ts
|
|
@@ -105231,6 +105239,29 @@ function warn$1(label, cause) {
|
|
|
105231
105239
|
return `${label} fetch failed: ${cause instanceof Error ? cause.message : String(cause)}`;
|
|
105232
105240
|
}
|
|
105233
105241
|
/**
|
|
105242
|
+
* Reads the workspace catalog off a settled bootstrap call. No explicit org
|
|
105243
|
+
* means CMMD answered `activeWorkspace` with its own default-organization
|
|
105244
|
+
* guess, not a confirmed fact -- leave it null rather than publish it
|
|
105245
|
+
* (forge#3636).
|
|
105246
|
+
*/
|
|
105247
|
+
function resolveWorkspacesFromBootstrap(bootstrapResult, orgId, warnings) {
|
|
105248
|
+
if (bootstrapResult.status !== "fulfilled") {
|
|
105249
|
+
warnings.push(warn$1("Workspaces (bootstrap)", bootstrapResult.reason));
|
|
105250
|
+
return {
|
|
105251
|
+
workspaces: [],
|
|
105252
|
+
activeWorkspace: null
|
|
105253
|
+
};
|
|
105254
|
+
}
|
|
105255
|
+
const bootstrap = unwrapRestObject(bootstrapResult.value);
|
|
105256
|
+
const rawWorkspaces = bootstrap?.["workspaces"];
|
|
105257
|
+
const workspaces = Array.isArray(rawWorkspaces) ? rawWorkspaces.map(adaptBootstrapWorkspace) : [];
|
|
105258
|
+
const rawActive = orgId !== void 0 ? bootstrap?.["activeWorkspace"] : void 0;
|
|
105259
|
+
return {
|
|
105260
|
+
workspaces,
|
|
105261
|
+
activeWorkspace: rawActive && typeof rawActive === "object" ? adaptBootstrapWorkspace(rawActive) : null
|
|
105262
|
+
};
|
|
105263
|
+
}
|
|
105264
|
+
/**
|
|
105234
105265
|
* Build the CMMD work-intake snapshot via the JWT REST API:
|
|
105235
105266
|
* bootstrap (workspaces) + campaigns + projects + center-board (tasks WITH deps).
|
|
105236
105267
|
* `identity` is supplied by the session (resolved at login), matching the MCP builder.
|
|
@@ -105238,21 +105269,13 @@ function warn$1(label, cause) {
|
|
|
105238
105269
|
async function fetchCmmdWorkIntakeViaRest(jwt, identity, deps = {}) {
|
|
105239
105270
|
const get = deps.proxyGet ?? proxyGet;
|
|
105240
105271
|
const [bootstrapResult, campaignsResult, projectsResult, boardResult] = await Promise.allSettled([
|
|
105241
|
-
get(jwt, "/api/forge/context/bootstrap"),
|
|
105272
|
+
get(jwt, "/api/forge/context/bootstrap", void 0, deps.orgId),
|
|
105242
105273
|
get(jwt, "/api/forge/context/campaigns"),
|
|
105243
105274
|
fetchAllProjects(get, jwt),
|
|
105244
105275
|
get(jwt, "/api/forge/context/work-items/board")
|
|
105245
105276
|
]);
|
|
105246
105277
|
const warnings = [];
|
|
105247
|
-
|
|
105248
|
-
let activeWorkspace = null;
|
|
105249
|
-
if (bootstrapResult.status === "fulfilled") {
|
|
105250
|
-
const bootstrap = unwrapRestObject(bootstrapResult.value);
|
|
105251
|
-
const rawWorkspaces = bootstrap?.["workspaces"];
|
|
105252
|
-
if (Array.isArray(rawWorkspaces)) workspaces = rawWorkspaces.map(adaptBootstrapWorkspace);
|
|
105253
|
-
const rawActive = bootstrap?.["activeWorkspace"];
|
|
105254
|
-
if (rawActive && typeof rawActive === "object") activeWorkspace = adaptBootstrapWorkspace(rawActive);
|
|
105255
|
-
} else warnings.push(warn$1("Workspaces (bootstrap)", bootstrapResult.reason));
|
|
105278
|
+
const { workspaces, activeWorkspace } = resolveWorkspacesFromBootstrap(bootstrapResult, deps.orgId, warnings);
|
|
105256
105279
|
if (projectsResult.status === "rejected") throw projectsResult.reason;
|
|
105257
105280
|
if (campaignsResult.status === "rejected") warnings.push(warn$1("Campaigns", campaignsResult.reason));
|
|
105258
105281
|
if (boardResult.status === "rejected") warnings.push(warn$1("Tasks (board)", boardResult.reason));
|
|
@@ -300572,7 +300595,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
300572
300595
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
300573
300596
|
*/
|
|
300574
300597
|
function readBakedBuildCommit() {
|
|
300575
|
-
return "
|
|
300598
|
+
return "8a4057a4a58eeb014b73143ffbb1bb091089d750";
|
|
300576
300599
|
}
|
|
300577
300600
|
async function resolveServerBuildCommit(input) {
|
|
300578
300601
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -310992,6 +311015,24 @@ function logWorkIntakeFailure(cause) {
|
|
|
310992
311015
|
}
|
|
310993
311016
|
console.error("[work-intake] fetch failed:", cause);
|
|
310994
311017
|
}
|
|
311018
|
+
/**
|
|
311019
|
+
* `?orgId=` present but empty (a stripped or malformed query string) is not
|
|
311020
|
+
* an explicit org. Treat it the same as an absent param rather than sending
|
|
311021
|
+
* CMMD an empty `X-Organization-ID` header (forge#3636).
|
|
311022
|
+
*/
|
|
311023
|
+
function normalizeOrgIdQueryParam(raw) {
|
|
311024
|
+
const trimmed = raw?.trim();
|
|
311025
|
+
return trimmed ? trimmed : void 0;
|
|
311026
|
+
}
|
|
311027
|
+
/**
|
|
311028
|
+
* `{ orgId }` when present, `{}` when not -- the `exactOptionalPropertyTypes`
|
|
311029
|
+
* shape every `orgId?: string` deps object here needs, since spreading
|
|
311030
|
+
* `{ orgId: possiblyUndefined }` inline assigns `undefined` to a property
|
|
311031
|
+
* the type says is only ever absent or a string.
|
|
311032
|
+
*/
|
|
311033
|
+
function orgIdDeps(orgId) {
|
|
311034
|
+
return orgId !== void 0 ? { orgId } : {};
|
|
311035
|
+
}
|
|
310995
311036
|
function fetchRestFallbackWorkIntakeForSession(session, dependencies = {}) {
|
|
310996
311037
|
return require_Schema$1.gen(function* () {
|
|
310997
311038
|
const jwt = yield* (dependencies.resolveJwt ?? resolveCmmdJwtForSession)({
|
|
@@ -311003,7 +311044,7 @@ function fetchRestFallbackWorkIntakeForSession(session, dependencies = {}) {
|
|
|
311003
311044
|
const identity = (dependencies.readIdentity ?? readCmmdUserIdentityForSession)(session.sessionId);
|
|
311004
311045
|
const fetchFallback = dependencies.fetchFallback ?? fetchCmmdWorkIntakeViaRest;
|
|
311005
311046
|
return yield* require_Schema$1.tryPromise({
|
|
311006
|
-
try: () => fetchFallback(jwt, identity),
|
|
311047
|
+
try: () => fetchFallback(jwt, identity, orgIdDeps(dependencies.orgId)),
|
|
311007
311048
|
catch: (cause) => new WorkIntakeSnapshotReadError({
|
|
311008
311049
|
detail: "Failed to build CMMD REST work-intake fallback.",
|
|
311009
311050
|
cause
|
|
@@ -311115,7 +311156,9 @@ function unwrapForgeEnvelopeJsonText(text) {
|
|
|
311115
311156
|
const cmmdWorkIntakeRouteLayer = add$1("GET", "/api/cmmd/work-intake", require_Schema$1.gen(function* () {
|
|
311116
311157
|
const request = yield* require_HttpServer.HttpServerRequest;
|
|
311117
311158
|
const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
|
|
311118
|
-
const
|
|
311159
|
+
const requestUrl = new URL(request.url, "http://localhost");
|
|
311160
|
+
const forceFresh = requestUrl.searchParams.get("fresh") === "1";
|
|
311161
|
+
const orgId = normalizeOrgIdQueryParam(requestUrl.searchParams.get("orgId"));
|
|
311119
311162
|
let accessToken = readCommandAccessTokenForSession(session.sessionId);
|
|
311120
311163
|
if (!accessToken && session.role === "owner" && (session.subject === "owner-bootstrap" || session.subject === "desktop-bootstrap")) accessToken = (yield* promoteMostRecentOwnerCommandAuthToSession(session.sessionId).pipe(require_Schema$1.catch_((error) => require_Schema$1.logWarning("Failed to promote owner CMMD auth for work intake.", {
|
|
311121
311164
|
cause: error,
|
|
@@ -311160,8 +311203,9 @@ const cmmdWorkIntakeRouteLayer = add$1("GET", "/api/cmmd/work-intake", require_S
|
|
|
311160
311203
|
sessionId: session.sessionId,
|
|
311161
311204
|
identityKey: workIntakeCacheIdentity,
|
|
311162
311205
|
token: accessToken,
|
|
311206
|
+
...orgIdDeps(orgId),
|
|
311163
311207
|
forceFresh,
|
|
311164
|
-
fetchFresh: () => cmmdJwt ? fetchCmmdWorkIntakeViaRest(cmmdJwt, sessionIdentity) : Promise.reject(/* @__PURE__ */ new Error("CMMD JWT unavailable for work-intake fetch."))
|
|
311208
|
+
fetchFresh: () => cmmdJwt ? fetchCmmdWorkIntakeViaRest(cmmdJwt, sessionIdentity, orgIdDeps(orgId)) : Promise.reject(/* @__PURE__ */ new Error("CMMD JWT unavailable for work-intake fetch."))
|
|
311165
311209
|
}),
|
|
311166
311210
|
catch: (cause) => new WorkIntakeSnapshotReadError({
|
|
311167
311211
|
detail: "Failed to read CMMD work intake snapshot.",
|
|
@@ -311179,7 +311223,7 @@ const cmmdWorkIntakeRouteLayer = add$1("GET", "/api/cmmd/work-intake", require_S
|
|
|
311179
311223
|
if (isCmmdMcpAuthError(cause)) {
|
|
311180
311224
|
console.error("[WORK_INTAKE] CMMD_AUTH_EXPIRED mcp_error:", cause instanceof Error ? cause.message : String(cause));
|
|
311181
311225
|
invalidateCachedCmmdWorkIntakeForSession(session.sessionId);
|
|
311182
|
-
const fallback = yield* fetchRestFallbackWorkIntakeForSession(session);
|
|
311226
|
+
const fallback = yield* fetchRestFallbackWorkIntakeForSession(session, orgIdDeps(orgId));
|
|
311183
311227
|
yield* clearCommandAccessTokenForSession(session.sessionId).pipe(require_Schema$1.catch_((error) => require_Schema$1.logWarning("Failed to clear expired CMMD token after MCP auth failure.", {
|
|
311184
311228
|
cause: error,
|
|
311185
311229
|
sessionId: session.sessionId
|
|
@@ -311204,7 +311248,7 @@ const cmmdWorkIntakeRouteLayer = add$1("GET", "/api/cmmd/work-intake", require_S
|
|
|
311204
311248
|
connected: snapshot.connected
|
|
311205
311249
|
});
|
|
311206
311250
|
invalidateCachedCmmdWorkIntakeForSession(session.sessionId);
|
|
311207
|
-
const fallback = yield* fetchRestFallbackWorkIntakeForSession(session);
|
|
311251
|
+
const fallback = yield* fetchRestFallbackWorkIntakeForSession(session, orgIdDeps(orgId));
|
|
311208
311252
|
yield* clearCommandAccessTokenForSession(session.sessionId).pipe(require_Schema$1.catch_((error) => require_Schema$1.logWarning("Failed to clear expired CMMD token after auth warning.", {
|
|
311209
311253
|
cause: error,
|
|
311210
311254
|
sessionId: session.sessionId
|
|
@@ -312560,12 +312604,65 @@ registerProxyRoute({
|
|
|
312560
312604
|
responseShape: "unwrapData",
|
|
312561
312605
|
requestBody: "none"
|
|
312562
312606
|
});
|
|
312563
|
-
|
|
312607
|
+
function parseCmmdBootstrapRequest(request) {
|
|
312608
|
+
return require_Schema$1.sync(() => {
|
|
312609
|
+
return {
|
|
312610
|
+
ok: true,
|
|
312611
|
+
value: normalizeOrgIdQueryParam(new URL(request.url, "http://localhost").searchParams.get("orgId"))
|
|
312612
|
+
};
|
|
312613
|
+
});
|
|
312614
|
+
}
|
|
312615
|
+
/**
|
|
312616
|
+
* Nulls `activeWorkspace` on a bootstrap body, wherever it sits. CMMD answers
|
|
312617
|
+
* `GET /api/forge/context/bootstrap` either flat (`{ activeWorkspace, ... }`)
|
|
312618
|
+
* or enveloped (`{ data: { activeWorkspace, ... } }`) -- `workIntakeRest.ts`'s
|
|
312619
|
+
* `unwrapRestObject` already treats both as live shapes for this exact
|
|
312620
|
+
* endpoint. Nulling only the top level left `data.activeWorkspace` (CMMD's
|
|
312621
|
+
* guess) untouched on the enveloped shape.
|
|
312622
|
+
*/
|
|
312623
|
+
function nullActiveWorkspace(body) {
|
|
312624
|
+
const data = body["data"];
|
|
312625
|
+
const nulledData = typeof data === "object" && data !== null && !Array.isArray(data) ? {
|
|
312626
|
+
...data,
|
|
312627
|
+
activeWorkspace: null
|
|
312628
|
+
} : data;
|
|
312629
|
+
return {
|
|
312630
|
+
...body,
|
|
312631
|
+
activeWorkspace: null,
|
|
312632
|
+
...data !== void 0 ? { data: nulledData } : {}
|
|
312633
|
+
};
|
|
312634
|
+
}
|
|
312635
|
+
/**
|
|
312636
|
+
* CMMD resolves `activeWorkspace` to the caller's own default organization
|
|
312637
|
+
* whenever the request carries no `X-Organization-ID` header (forge#3636:
|
|
312638
|
+
* the owner working in org 2119 kept getting org 2142, CMMD's default, back).
|
|
312639
|
+
* Passing the client's explicit `?orgId=` scopes CMMD's answer to that
|
|
312640
|
+
* workspace; without one, CMMD still guesses, so `activeWorkspace` is nulled
|
|
312641
|
+
* here rather than forwarded as fact. Everything else in the bootstrap
|
|
312642
|
+
* response passes through untouched.
|
|
312643
|
+
*/
|
|
312644
|
+
function runCmmdBootstrap(orgId, { session }) {
|
|
312645
|
+
return runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.request({
|
|
312646
|
+
method: "GET",
|
|
312647
|
+
jwt,
|
|
312648
|
+
path: "/api/forge/context/bootstrap",
|
|
312649
|
+
...orgId !== void 0 ? { orgId } : {}
|
|
312650
|
+
}), (value) => {
|
|
312651
|
+
if (orgId !== void 0 || value === null || typeof value !== "object") return {
|
|
312652
|
+
status: 200,
|
|
312653
|
+
body: value
|
|
312654
|
+
};
|
|
312655
|
+
return {
|
|
312656
|
+
status: 200,
|
|
312657
|
+
body: nullActiveWorkspace(value)
|
|
312658
|
+
};
|
|
312659
|
+
});
|
|
312660
|
+
}
|
|
312661
|
+
registerProxyHandler({
|
|
312564
312662
|
forgePath: "/api/cmmd/bootstrap",
|
|
312565
312663
|
method: "GET",
|
|
312566
|
-
|
|
312567
|
-
|
|
312568
|
-
responseShape: "passthrough"
|
|
312664
|
+
parse: parseCmmdBootstrapRequest,
|
|
312665
|
+
run: runCmmdBootstrap
|
|
312569
312666
|
});
|
|
312570
312667
|
registerProxyRoute({
|
|
312571
312668
|
forgePath: "/api/cmmd/account/preferences",
|
package/dist/bin.mjs
CHANGED
|
@@ -66046,7 +66046,7 @@ function normalizeNumberish(value) {
|
|
|
66046
66046
|
}
|
|
66047
66047
|
//#endregion
|
|
66048
66048
|
//#region package.json
|
|
66049
|
-
var version$1 = "0.13.
|
|
66049
|
+
var version$1 = "0.13.126";
|
|
66050
66050
|
//#endregion
|
|
66051
66051
|
//#region src/sentry.ts
|
|
66052
66052
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -72318,20 +72318,25 @@ const legacyCmmdToolBridge = {
|
|
|
72318
72318
|
};
|
|
72319
72319
|
//#endregion
|
|
72320
72320
|
//#region src/command/workIntakeCache.ts
|
|
72321
|
-
const
|
|
72321
|
+
const cacheByKey = /* @__PURE__ */ new Map();
|
|
72322
|
+
function cacheKeyFor(sessionId, orgId) {
|
|
72323
|
+
return `${sessionId}\u0000${orgId ?? ""}`;
|
|
72324
|
+
}
|
|
72322
72325
|
function resolveCmmdWorkIntakeCacheIdentity(subject, cmmdUserId) {
|
|
72323
72326
|
return cmmdUserId ? `cmmd-user:${cmmdUserId}` : `forge-subject:${subject}`;
|
|
72324
72327
|
}
|
|
72325
72328
|
function fingerprintToken(token) {
|
|
72326
72329
|
return createHash("sha256").update(token).digest("hex");
|
|
72327
72330
|
}
|
|
72328
|
-
async function fetchBlockingSnapshot(input, identityKey, tokenFingerprint, existing) {
|
|
72331
|
+
async function fetchBlockingSnapshot(input, cacheKey, identityKey, tokenFingerprint, existing) {
|
|
72329
72332
|
if (existing?.inFlight) return existing.inFlight;
|
|
72330
72333
|
const nowMs = input.nowMs ?? Date.now;
|
|
72331
72334
|
let promise;
|
|
72332
72335
|
promise = input.fetchFresh().then((snapshot) => {
|
|
72333
|
-
const current =
|
|
72334
|
-
if (current?.tokenFingerprint === tokenFingerprint && current.inFlight === promise)
|
|
72336
|
+
const current = cacheByKey.get(cacheKey);
|
|
72337
|
+
if (current?.tokenFingerprint === tokenFingerprint && current.inFlight === promise) cacheByKey.set(cacheKey, {
|
|
72338
|
+
sessionId: input.sessionId,
|
|
72339
|
+
orgId: input.orgId,
|
|
72335
72340
|
identityKey,
|
|
72336
72341
|
tokenFingerprint,
|
|
72337
72342
|
snapshot,
|
|
@@ -72340,12 +72345,14 @@ async function fetchBlockingSnapshot(input, identityKey, tokenFingerprint, exist
|
|
|
72340
72345
|
});
|
|
72341
72346
|
return snapshot;
|
|
72342
72347
|
}).catch((error) => {
|
|
72343
|
-
const current =
|
|
72344
|
-
if (current?.tokenFingerprint === tokenFingerprint && current.inFlight === promise) if (legacyCmmdToolBridge.isAuthError(error))
|
|
72348
|
+
const current = cacheByKey.get(cacheKey);
|
|
72349
|
+
if (current?.tokenFingerprint === tokenFingerprint && current.inFlight === promise) if (legacyCmmdToolBridge.isAuthError(error)) cacheByKey.delete(cacheKey);
|
|
72345
72350
|
else current.inFlight = null;
|
|
72346
72351
|
throw error;
|
|
72347
72352
|
});
|
|
72348
|
-
|
|
72353
|
+
cacheByKey.set(cacheKey, {
|
|
72354
|
+
sessionId: input.sessionId,
|
|
72355
|
+
orgId: input.orgId,
|
|
72349
72356
|
identityKey,
|
|
72350
72357
|
tokenFingerprint,
|
|
72351
72358
|
snapshot: existing?.snapshot ?? null,
|
|
@@ -72361,9 +72368,9 @@ async function fetchBlockingSnapshot(input, identityKey, tokenFingerprint, exist
|
|
|
72361
72368
|
* opportunistically on every read.
|
|
72362
72369
|
*/
|
|
72363
72370
|
function sweepExpiredWorkIntakeEntries(nowMs) {
|
|
72364
|
-
for (const [
|
|
72371
|
+
for (const [key, entry] of cacheByKey) {
|
|
72365
72372
|
if (entry.inFlight) continue;
|
|
72366
|
-
if (nowMs - entry.cachedAtMs > 3e5)
|
|
72373
|
+
if (nowMs - entry.cachedAtMs > 3e5) cacheByKey.delete(key);
|
|
72367
72374
|
}
|
|
72368
72375
|
}
|
|
72369
72376
|
async function readCachedCmmdWorkIntakeForSession(input) {
|
|
@@ -72372,17 +72379,18 @@ async function readCachedCmmdWorkIntakeForSession(input) {
|
|
|
72372
72379
|
const identityKey = input.identityKey ?? input.sessionId;
|
|
72373
72380
|
if (input.forceFresh) invalidateCachedCmmdWorkIntakeForIdentity(identityKey);
|
|
72374
72381
|
const tokenFingerprint = fingerprintToken(input.token);
|
|
72375
|
-
const
|
|
72376
|
-
|
|
72377
|
-
|
|
72378
|
-
|
|
72382
|
+
const cacheKey = cacheKeyFor(input.sessionId, input.orgId);
|
|
72383
|
+
const existing = cacheByKey.get(cacheKey);
|
|
72384
|
+
if (existing && (existing.identityKey !== identityKey || existing.tokenFingerprint !== tokenFingerprint)) cacheByKey.delete(cacheKey);
|
|
72385
|
+
const current = cacheByKey.get(cacheKey);
|
|
72386
|
+
if (!current?.snapshot) return fetchBlockingSnapshot(input, cacheKey, identityKey, tokenFingerprint, current);
|
|
72379
72387
|
const ageMs = Math.max(0, nowMs() - current.cachedAtMs);
|
|
72380
72388
|
if (ageMs <= 12e4) return current.snapshot;
|
|
72381
72389
|
if (ageMs <= 3e5) {
|
|
72382
72390
|
if (!current.inFlight) {
|
|
72383
72391
|
let refreshPromise;
|
|
72384
72392
|
refreshPromise = input.fetchFresh().then((snapshot) => {
|
|
72385
|
-
const latest =
|
|
72393
|
+
const latest = cacheByKey.get(cacheKey);
|
|
72386
72394
|
if (latest?.tokenFingerprint === tokenFingerprint && latest.inFlight === refreshPromise) {
|
|
72387
72395
|
latest.snapshot = snapshot;
|
|
72388
72396
|
latest.cachedAtMs = nowMs();
|
|
@@ -72390,25 +72398,25 @@ async function readCachedCmmdWorkIntakeForSession(input) {
|
|
|
72390
72398
|
return snapshot;
|
|
72391
72399
|
}).catch((error) => {
|
|
72392
72400
|
if (legacyCmmdToolBridge.isAuthError(error)) {
|
|
72393
|
-
const latest =
|
|
72394
|
-
if (latest?.tokenFingerprint === tokenFingerprint && latest.inFlight === refreshPromise)
|
|
72401
|
+
const latest = cacheByKey.get(cacheKey);
|
|
72402
|
+
if (latest?.tokenFingerprint === tokenFingerprint && latest.inFlight === refreshPromise) cacheByKey.delete(cacheKey);
|
|
72395
72403
|
}
|
|
72396
72404
|
return current.snapshot;
|
|
72397
72405
|
}).finally(() => {
|
|
72398
|
-
const latest =
|
|
72406
|
+
const latest = cacheByKey.get(cacheKey);
|
|
72399
72407
|
if (latest?.tokenFingerprint === tokenFingerprint && latest.inFlight === refreshPromise) latest.inFlight = null;
|
|
72400
72408
|
});
|
|
72401
72409
|
current.inFlight = refreshPromise;
|
|
72402
72410
|
}
|
|
72403
72411
|
return current.snapshot;
|
|
72404
72412
|
}
|
|
72405
|
-
return fetchBlockingSnapshot(input, identityKey, tokenFingerprint, current);
|
|
72413
|
+
return fetchBlockingSnapshot(input, cacheKey, identityKey, tokenFingerprint, current);
|
|
72406
72414
|
}
|
|
72407
72415
|
function invalidateCachedCmmdWorkIntakeForSession(sessionId) {
|
|
72408
|
-
|
|
72416
|
+
for (const [key, entry] of cacheByKey) if (entry.sessionId === sessionId) cacheByKey.delete(key);
|
|
72409
72417
|
}
|
|
72410
72418
|
function invalidateCachedCmmdWorkIntakeForIdentity(identityKey) {
|
|
72411
|
-
for (const [
|
|
72419
|
+
for (const [key, entry] of cacheByKey) if (entry.identityKey === identityKey) cacheByKey.delete(key);
|
|
72412
72420
|
}
|
|
72413
72421
|
//#endregion
|
|
72414
72422
|
//#region src/cmmdData/proxyRouteRegistry.ts
|
|
@@ -104835,6 +104843,29 @@ function warn$1(label, cause) {
|
|
|
104835
104843
|
return `${label} fetch failed: ${cause instanceof Error ? cause.message : String(cause)}`;
|
|
104836
104844
|
}
|
|
104837
104845
|
/**
|
|
104846
|
+
* Reads the workspace catalog off a settled bootstrap call. No explicit org
|
|
104847
|
+
* means CMMD answered `activeWorkspace` with its own default-organization
|
|
104848
|
+
* guess, not a confirmed fact -- leave it null rather than publish it
|
|
104849
|
+
* (forge#3636).
|
|
104850
|
+
*/
|
|
104851
|
+
function resolveWorkspacesFromBootstrap(bootstrapResult, orgId, warnings) {
|
|
104852
|
+
if (bootstrapResult.status !== "fulfilled") {
|
|
104853
|
+
warnings.push(warn$1("Workspaces (bootstrap)", bootstrapResult.reason));
|
|
104854
|
+
return {
|
|
104855
|
+
workspaces: [],
|
|
104856
|
+
activeWorkspace: null
|
|
104857
|
+
};
|
|
104858
|
+
}
|
|
104859
|
+
const bootstrap = unwrapRestObject(bootstrapResult.value);
|
|
104860
|
+
const rawWorkspaces = bootstrap?.["workspaces"];
|
|
104861
|
+
const workspaces = Array.isArray(rawWorkspaces) ? rawWorkspaces.map(adaptBootstrapWorkspace) : [];
|
|
104862
|
+
const rawActive = orgId !== void 0 ? bootstrap?.["activeWorkspace"] : void 0;
|
|
104863
|
+
return {
|
|
104864
|
+
workspaces,
|
|
104865
|
+
activeWorkspace: rawActive && typeof rawActive === "object" ? adaptBootstrapWorkspace(rawActive) : null
|
|
104866
|
+
};
|
|
104867
|
+
}
|
|
104868
|
+
/**
|
|
104838
104869
|
* Build the CMMD work-intake snapshot via the JWT REST API:
|
|
104839
104870
|
* bootstrap (workspaces) + campaigns + projects + center-board (tasks WITH deps).
|
|
104840
104871
|
* `identity` is supplied by the session (resolved at login), matching the MCP builder.
|
|
@@ -104842,21 +104873,13 @@ function warn$1(label, cause) {
|
|
|
104842
104873
|
async function fetchCmmdWorkIntakeViaRest(jwt, identity, deps = {}) {
|
|
104843
104874
|
const get = deps.proxyGet ?? proxyGet;
|
|
104844
104875
|
const [bootstrapResult, campaignsResult, projectsResult, boardResult] = await Promise.allSettled([
|
|
104845
|
-
get(jwt, "/api/forge/context/bootstrap"),
|
|
104876
|
+
get(jwt, "/api/forge/context/bootstrap", void 0, deps.orgId),
|
|
104846
104877
|
get(jwt, "/api/forge/context/campaigns"),
|
|
104847
104878
|
fetchAllProjects(get, jwt),
|
|
104848
104879
|
get(jwt, "/api/forge/context/work-items/board")
|
|
104849
104880
|
]);
|
|
104850
104881
|
const warnings = [];
|
|
104851
|
-
|
|
104852
|
-
let activeWorkspace = null;
|
|
104853
|
-
if (bootstrapResult.status === "fulfilled") {
|
|
104854
|
-
const bootstrap = unwrapRestObject(bootstrapResult.value);
|
|
104855
|
-
const rawWorkspaces = bootstrap?.["workspaces"];
|
|
104856
|
-
if (Array.isArray(rawWorkspaces)) workspaces = rawWorkspaces.map(adaptBootstrapWorkspace);
|
|
104857
|
-
const rawActive = bootstrap?.["activeWorkspace"];
|
|
104858
|
-
if (rawActive && typeof rawActive === "object") activeWorkspace = adaptBootstrapWorkspace(rawActive);
|
|
104859
|
-
} else warnings.push(warn$1("Workspaces (bootstrap)", bootstrapResult.reason));
|
|
104882
|
+
const { workspaces, activeWorkspace } = resolveWorkspacesFromBootstrap(bootstrapResult, deps.orgId, warnings);
|
|
104860
104883
|
if (projectsResult.status === "rejected") throw projectsResult.reason;
|
|
104861
104884
|
if (campaignsResult.status === "rejected") warnings.push(warn$1("Campaigns", campaignsResult.reason));
|
|
104862
104885
|
if (boardResult.status === "rejected") warnings.push(warn$1("Tasks (board)", boardResult.reason));
|
|
@@ -300019,7 +300042,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
300019
300042
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
300020
300043
|
*/
|
|
300021
300044
|
function readBakedBuildCommit() {
|
|
300022
|
-
return "
|
|
300045
|
+
return "8a4057a4a58eeb014b73143ffbb1bb091089d750";
|
|
300023
300046
|
}
|
|
300024
300047
|
async function resolveServerBuildCommit(input) {
|
|
300025
300048
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -310369,6 +310392,24 @@ function logWorkIntakeFailure(cause) {
|
|
|
310369
310392
|
}
|
|
310370
310393
|
console.error("[work-intake] fetch failed:", cause);
|
|
310371
310394
|
}
|
|
310395
|
+
/**
|
|
310396
|
+
* `?orgId=` present but empty (a stripped or malformed query string) is not
|
|
310397
|
+
* an explicit org. Treat it the same as an absent param rather than sending
|
|
310398
|
+
* CMMD an empty `X-Organization-ID` header (forge#3636).
|
|
310399
|
+
*/
|
|
310400
|
+
function normalizeOrgIdQueryParam(raw) {
|
|
310401
|
+
const trimmed = raw?.trim();
|
|
310402
|
+
return trimmed ? trimmed : void 0;
|
|
310403
|
+
}
|
|
310404
|
+
/**
|
|
310405
|
+
* `{ orgId }` when present, `{}` when not -- the `exactOptionalPropertyTypes`
|
|
310406
|
+
* shape every `orgId?: string` deps object here needs, since spreading
|
|
310407
|
+
* `{ orgId: possiblyUndefined }` inline assigns `undefined` to a property
|
|
310408
|
+
* the type says is only ever absent or a string.
|
|
310409
|
+
*/
|
|
310410
|
+
function orgIdDeps(orgId) {
|
|
310411
|
+
return orgId !== void 0 ? { orgId } : {};
|
|
310412
|
+
}
|
|
310372
310413
|
function fetchRestFallbackWorkIntakeForSession(session, dependencies = {}) {
|
|
310373
310414
|
return gen(function* () {
|
|
310374
310415
|
const jwt = yield* (dependencies.resolveJwt ?? resolveCmmdJwtForSession)({
|
|
@@ -310380,7 +310421,7 @@ function fetchRestFallbackWorkIntakeForSession(session, dependencies = {}) {
|
|
|
310380
310421
|
const identity = (dependencies.readIdentity ?? readCmmdUserIdentityForSession)(session.sessionId);
|
|
310381
310422
|
const fetchFallback = dependencies.fetchFallback ?? fetchCmmdWorkIntakeViaRest;
|
|
310382
310423
|
return yield* tryPromise({
|
|
310383
|
-
try: () => fetchFallback(jwt, identity),
|
|
310424
|
+
try: () => fetchFallback(jwt, identity, orgIdDeps(dependencies.orgId)),
|
|
310384
310425
|
catch: (cause) => new WorkIntakeSnapshotReadError({
|
|
310385
310426
|
detail: "Failed to build CMMD REST work-intake fallback.",
|
|
310386
310427
|
cause
|
|
@@ -310492,7 +310533,9 @@ function unwrapForgeEnvelopeJsonText(text) {
|
|
|
310492
310533
|
const cmmdWorkIntakeRouteLayer = add$1("GET", "/api/cmmd/work-intake", gen(function* () {
|
|
310493
310534
|
const request = yield* HttpServerRequest;
|
|
310494
310535
|
const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
|
|
310495
|
-
const
|
|
310536
|
+
const requestUrl = new URL(request.url, "http://localhost");
|
|
310537
|
+
const forceFresh = requestUrl.searchParams.get("fresh") === "1";
|
|
310538
|
+
const orgId = normalizeOrgIdQueryParam(requestUrl.searchParams.get("orgId"));
|
|
310496
310539
|
let accessToken = readCommandAccessTokenForSession(session.sessionId);
|
|
310497
310540
|
if (!accessToken && session.role === "owner" && (session.subject === "owner-bootstrap" || session.subject === "desktop-bootstrap")) accessToken = (yield* promoteMostRecentOwnerCommandAuthToSession(session.sessionId).pipe(catch_((error) => logWarning$1("Failed to promote owner CMMD auth for work intake.", {
|
|
310498
310541
|
cause: error,
|
|
@@ -310537,8 +310580,9 @@ const cmmdWorkIntakeRouteLayer = add$1("GET", "/api/cmmd/work-intake", gen(funct
|
|
|
310537
310580
|
sessionId: session.sessionId,
|
|
310538
310581
|
identityKey: workIntakeCacheIdentity,
|
|
310539
310582
|
token: accessToken,
|
|
310583
|
+
...orgIdDeps(orgId),
|
|
310540
310584
|
forceFresh,
|
|
310541
|
-
fetchFresh: () => cmmdJwt ? fetchCmmdWorkIntakeViaRest(cmmdJwt, sessionIdentity) : Promise.reject(/* @__PURE__ */ new Error("CMMD JWT unavailable for work-intake fetch."))
|
|
310585
|
+
fetchFresh: () => cmmdJwt ? fetchCmmdWorkIntakeViaRest(cmmdJwt, sessionIdentity, orgIdDeps(orgId)) : Promise.reject(/* @__PURE__ */ new Error("CMMD JWT unavailable for work-intake fetch."))
|
|
310542
310586
|
}),
|
|
310543
310587
|
catch: (cause) => new WorkIntakeSnapshotReadError({
|
|
310544
310588
|
detail: "Failed to read CMMD work intake snapshot.",
|
|
@@ -310556,7 +310600,7 @@ const cmmdWorkIntakeRouteLayer = add$1("GET", "/api/cmmd/work-intake", gen(funct
|
|
|
310556
310600
|
if (isCmmdMcpAuthError(cause)) {
|
|
310557
310601
|
console.error("[WORK_INTAKE] CMMD_AUTH_EXPIRED mcp_error:", cause instanceof Error ? cause.message : String(cause));
|
|
310558
310602
|
invalidateCachedCmmdWorkIntakeForSession(session.sessionId);
|
|
310559
|
-
const fallback = yield* fetchRestFallbackWorkIntakeForSession(session);
|
|
310603
|
+
const fallback = yield* fetchRestFallbackWorkIntakeForSession(session, orgIdDeps(orgId));
|
|
310560
310604
|
yield* clearCommandAccessTokenForSession(session.sessionId).pipe(catch_((error) => logWarning$1("Failed to clear expired CMMD token after MCP auth failure.", {
|
|
310561
310605
|
cause: error,
|
|
310562
310606
|
sessionId: session.sessionId
|
|
@@ -310581,7 +310625,7 @@ const cmmdWorkIntakeRouteLayer = add$1("GET", "/api/cmmd/work-intake", gen(funct
|
|
|
310581
310625
|
connected: snapshot.connected
|
|
310582
310626
|
});
|
|
310583
310627
|
invalidateCachedCmmdWorkIntakeForSession(session.sessionId);
|
|
310584
|
-
const fallback = yield* fetchRestFallbackWorkIntakeForSession(session);
|
|
310628
|
+
const fallback = yield* fetchRestFallbackWorkIntakeForSession(session, orgIdDeps(orgId));
|
|
310585
310629
|
yield* clearCommandAccessTokenForSession(session.sessionId).pipe(catch_((error) => logWarning$1("Failed to clear expired CMMD token after auth warning.", {
|
|
310586
310630
|
cause: error,
|
|
310587
310631
|
sessionId: session.sessionId
|
|
@@ -311936,12 +311980,65 @@ registerProxyRoute({
|
|
|
311936
311980
|
responseShape: "unwrapData",
|
|
311937
311981
|
requestBody: "none"
|
|
311938
311982
|
});
|
|
311939
|
-
|
|
311983
|
+
function parseCmmdBootstrapRequest(request) {
|
|
311984
|
+
return sync$1(() => {
|
|
311985
|
+
return {
|
|
311986
|
+
ok: true,
|
|
311987
|
+
value: normalizeOrgIdQueryParam(new URL(request.url, "http://localhost").searchParams.get("orgId"))
|
|
311988
|
+
};
|
|
311989
|
+
});
|
|
311990
|
+
}
|
|
311991
|
+
/**
|
|
311992
|
+
* Nulls `activeWorkspace` on a bootstrap body, wherever it sits. CMMD answers
|
|
311993
|
+
* `GET /api/forge/context/bootstrap` either flat (`{ activeWorkspace, ... }`)
|
|
311994
|
+
* or enveloped (`{ data: { activeWorkspace, ... } }`) -- `workIntakeRest.ts`'s
|
|
311995
|
+
* `unwrapRestObject` already treats both as live shapes for this exact
|
|
311996
|
+
* endpoint. Nulling only the top level left `data.activeWorkspace` (CMMD's
|
|
311997
|
+
* guess) untouched on the enveloped shape.
|
|
311998
|
+
*/
|
|
311999
|
+
function nullActiveWorkspace(body) {
|
|
312000
|
+
const data = body["data"];
|
|
312001
|
+
const nulledData = typeof data === "object" && data !== null && !Array.isArray(data) ? {
|
|
312002
|
+
...data,
|
|
312003
|
+
activeWorkspace: null
|
|
312004
|
+
} : data;
|
|
312005
|
+
return {
|
|
312006
|
+
...body,
|
|
312007
|
+
activeWorkspace: null,
|
|
312008
|
+
...data !== void 0 ? { data: nulledData } : {}
|
|
312009
|
+
};
|
|
312010
|
+
}
|
|
312011
|
+
/**
|
|
312012
|
+
* CMMD resolves `activeWorkspace` to the caller's own default organization
|
|
312013
|
+
* whenever the request carries no `X-Organization-ID` header (forge#3636:
|
|
312014
|
+
* the owner working in org 2119 kept getting org 2142, CMMD's default, back).
|
|
312015
|
+
* Passing the client's explicit `?orgId=` scopes CMMD's answer to that
|
|
312016
|
+
* workspace; without one, CMMD still guesses, so `activeWorkspace` is nulled
|
|
312017
|
+
* here rather than forwarded as fact. Everything else in the bootstrap
|
|
312018
|
+
* response passes through untouched.
|
|
312019
|
+
*/
|
|
312020
|
+
function runCmmdBootstrap(orgId, { session }) {
|
|
312021
|
+
return runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.request({
|
|
312022
|
+
method: "GET",
|
|
312023
|
+
jwt,
|
|
312024
|
+
path: "/api/forge/context/bootstrap",
|
|
312025
|
+
...orgId !== void 0 ? { orgId } : {}
|
|
312026
|
+
}), (value) => {
|
|
312027
|
+
if (orgId !== void 0 || value === null || typeof value !== "object") return {
|
|
312028
|
+
status: 200,
|
|
312029
|
+
body: value
|
|
312030
|
+
};
|
|
312031
|
+
return {
|
|
312032
|
+
status: 200,
|
|
312033
|
+
body: nullActiveWorkspace(value)
|
|
312034
|
+
};
|
|
312035
|
+
});
|
|
312036
|
+
}
|
|
312037
|
+
registerProxyHandler({
|
|
311940
312038
|
forgePath: "/api/cmmd/bootstrap",
|
|
311941
312039
|
method: "GET",
|
|
311942
|
-
|
|
311943
|
-
|
|
311944
|
-
responseShape: "passthrough"
|
|
312040
|
+
parse: parseCmmdBootstrapRequest,
|
|
312041
|
+
run: runCmmdBootstrap
|
|
311945
312042
|
});
|
|
311946
312043
|
registerProxyRoute({
|
|
311947
312044
|
forgePath: "/api/cmmd/account/preferences",
|