(function () { "use strict"; // Source: src/shared/messages.js /** Stable wire names. All payloads remain plain, serializable objects. */ function createMessageTypes() { return Object.freeze({ getXsrfToken: "opportunitiesExtension.getXsrfToken", refreshXsrfCookie: "opportunitiesExtension.refreshXsrfCookie", requestOpptyProducts: "opportunitiesExtension.requestOpptyProducts", opptyProductsProgress: "opportunitiesExtension.opptyProductsProgress", opptyProductsRequestDebug: "opportunitiesExtension.opptyProductsRequestDebug", requestConsumerTokenService: "opportunitiesExtension.requestConsumerTokenService", requestAccountPlans: "opportunitiesExtension.requestAccountPlans", requestInstallBase: "opportunitiesExtension.requestInstallBase", requestCustomerServiceRequest: "opportunitiesExtension.requestCustomerServiceRequest", requestWlActions: "opportunitiesExtension.requestWlActions", requestActionTeamMembers: "opportunitiesExtension.requestActionTeamMembers", requestActionFindLookup: "opportunitiesExtension.requestActionFindLookup", requestMgmtAction: "opportunitiesExtension.requestMgmtAction", requestInternalServiceRequest: "opportunitiesExtension.requestInternalServiceRequest", requestCurrentUser: "opportunitiesExtension.requestCurrentUser", invalidateProductsCache: "opportunitiesExtension.invalidateProductsCache", requestConsumptionTrend: "opportunitiesExtension.requestConsumptionTrend", requestConsumptionPlanDetail: "opportunitiesExtension.requestConsumptionPlanDetail", requestRatecardByPlan: "opportunitiesExtension.requestRatecardByPlan" }); } // Source: src/shared/debug-body.js function createDebugBodyPreview(text, limit) { if (text.length <= limit) return { value: text || "(empty response body)", truncated: false }; try { const normalized = text.replace(/^\uFEFF/, "").trimStart() .replace(/^\)\]\}',?\s*/, "").replace(/^while\s*\(1\);\s*/, ""); let value = JSON.parse(normalized); for (let depth = 0; depth < 2 && typeof value === "string" && /^\s*[\[{]/.test(value); depth += 1) { try { value = JSON.parse(value); } catch { break; } } // Bound retained data without cutting JSON syntax or losing sensitive field names. let remaining = Math.max(0, limit - 256); const visit = (node, depth = 0) => { if (remaining <= 64 || depth >= 30) return "[omitted from debug preview]"; if (node === null || typeof node !== "object") { const serialized = JSON.stringify(node); if (serialized.length > remaining) { remaining = 0; return "[omitted from debug preview]"; } remaining -= serialized.length + 1; return node; } const result = Array.isArray(node) ? [] : Object.create(null); remaining -= 2; for (const key of Object.keys(node)) { const cost = Array.isArray(node) ? 1 : JSON.stringify(key).length + 2; if (remaining < cost + 64) break; remaining -= cost; result[key] = visit(node[key], depth + 1); } return result; }; return { value: JSON.stringify({ debugNotice: "Partial response preview: remaining fields/items omitted due to the debug size limit.", preview: visit(value) }), truncated: true }; } catch { return { value: `${text.slice(0, limit)}\n... truncated ${text.length - limit} characters`, truncated: true }; } } // Source: src/background/contracts.js function createBackgroundContracts() { const ORACLE_DOMAIN = "eeho.fa.us2.oraclecloud.com"; const ORACLE_COOKIE_URLS = [ "https://eeho.fa.us2.oraclecloud.com/", "https://eeho.fa.us2.oraclecloud.com/hcmUI/faces/FuseWelcome", "https://eeho.fa.us2.oraclecloud.com/fscmUI/faces/FuseWelcome", "https://eeho.fa.us2.oraclecloud.com/fscmRestApi/tokenrelay" ]; const XSRF_COOKIE_NAME = "XSRF-TOKEN-US2DZ2V_F"; const XSRF_COOKIE_PREFIX = "XSRF-TOKEN-"; const OPPORTUNITIES_LIST_URL = "https://eeho.fa.us2.oraclecloud.com/fscmUI/redwood/cx-sales/application/container/opportunities/opportunities-list"; const COOKIE_REFRESH_TIMEOUT_MS = 15000; const COOKIE_REFRESH_POLL_MS = 250; const OPPTY_PRODUCTS_CACHE_KEY = "opportunitiesExtension.opptyProductsCache.v1"; const OPPTY_PRODUCTS_PAGE_LIMIT = 15; const OPPTY_PRODUCTS_MAX_PAGES = 250; const OPPTY_PRODUCTS_CONCURRENCY = 4; const CUSTOMER_TOKEN_SERVICE_URL = "https://spa.oracle.com/oalcrm/web/api/g2m-consumer-application/consumerTokenService"; const CUSTOMER_TOKEN_SESSION_URL = "https://spa.oracle.com/oalcrm/web/api/g2m-consumer-application/ui/index.html"; const CUSTOMER_TOKEN_MAX_ATTEMPTS = 5; const CUSTOMER_TOKEN_RETRY_BASE_DELAY_MS = 750; const CUSTOMER_TOKEN_RETRY_MAX_DELAY_MS = 4000; const ACCOUNT_SUMMARY_URL = "https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-account/service/accountsummary"; const ACCOUNT_PLANS_URL = "https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-consumption/service/v1/account/accountPlans"; const CONSUMPTION_TREND_URL = "https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-consumption/service/v1/plan/trend"; const CONSUMPTION_TREND_REQUESTS = { quarterly: "requestConsumptionServiceQuarterly", monthly: "requestConsumptionServiceMonthly", weekly: "requestConsumptionServiceWeekly", daily: "requestConsumptionServiceDaily" }; const ACCOUNT_PLANS_PAYLOAD = { hierarchy: "single", products: "all", language: "english", planStatus: [ "active", "awaiting_provisioning", "awaiting_provisioning_error", "draft", "expired", "final_billing", "onhold", "provisioned", "signed", "superseded", "superseded_pending_final_billing", "suspended", "terminated", "terminated_pending_final_billing" ] }; const DEBUG_BODY_LIMIT = 100000; const OPPTY_PRODUCTS_FIELDS = [ "ProductType", "Description", "InventoryItemId", "ProdGroupName", "ProdGroupId", "OwnerLockAsgnFlag", "Quantity", "RecurTypeCode", "RevnAmountCurcyCode", "UnitPrice", "RevnAmount", "PriceTypeCode", "EffectiveDate", "Name1", "NonRecurringRevenue", "OpportunityOwnerPartyName", "OpportunityOwnerResourcePartyId", "OptyId", "OptyNumber", "PartyName2", "PrTerritoryVersionId", "PrTerritoryVersionIdForManual", "RecurEndDate", "RecurFrequencyCode", "RecurNumberPeriods", "RecurRevenue", "ResourcePartyId", "RevnId", "RevnNumber", "SplitPercent", "SalesCreditTypeCode", "SplitTypeCode", "TerrOwnerPartyName", "UpsideAmount", "UsageRevenue", "StatusCode", "BUOrgId", "TypeCode", "WinProb", "ForecastType_c", "ARRLocalCurrency_c", "CPQLastSyncDate_c", "CPQOperationType_c", "ProdGLID_c", "ProposalNumber_c", "QuoteNumber_c", "ServicesPeriod_c", "CPQIntLastUpdatedBy_c", "CPQUpdatedAmount_c", "CPQUpdatedQuantity_c", "CPQUpdatedRevnType_c", "CPQUpdatedServicePeriod_c", "CPQUpdatedStatus_c", "OrderNumber_c", "PrevAmount_c", "PrevQuantity_c", "PrevRevenueType_c", "PrevServicePeriod_c", "PrevStatus_c", "SubscriptionID_c", "WorkloadName_c", "ConsumptionStartDate_c", "RampMonths_c" ]; return { ORACLE_DOMAIN, ORACLE_COOKIE_URLS, XSRF_COOKIE_NAME, XSRF_COOKIE_PREFIX, OPPORTUNITIES_LIST_URL, COOKIE_REFRESH_TIMEOUT_MS, COOKIE_REFRESH_POLL_MS, OPPTY_PRODUCTS_CACHE_KEY, OPPTY_PRODUCTS_PAGE_LIMIT, OPPTY_PRODUCTS_MAX_PAGES, OPPTY_PRODUCTS_CONCURRENCY, CUSTOMER_TOKEN_SERVICE_URL, CUSTOMER_TOKEN_SESSION_URL, CUSTOMER_TOKEN_MAX_ATTEMPTS, CUSTOMER_TOKEN_RETRY_BASE_DELAY_MS, CUSTOMER_TOKEN_RETRY_MAX_DELAY_MS, ACCOUNT_SUMMARY_URL, ACCOUNT_PLANS_URL, CONSUMPTION_TREND_URL, CONSUMPTION_TREND_REQUESTS, ACCOUNT_PLANS_PAYLOAD, DEBUG_BODY_LIMIT, OPPTY_PRODUCTS_FIELDS }; } // Source: src/features/products/cache-state.js function createProductsCacheState() { return { productsCachePromise: null, productsCacheWritePromise: Promise.resolve(), inFlightProducts: new Map() }; } // Source: src/auth/consumer-session.js function createAuthConsumerSession({ CUSTOMER_TOKEN_MAX_ATTEMPTS, CUSTOMER_TOKEN_RETRY_BASE_DELAY_MS, CUSTOMER_TOKEN_RETRY_MAX_DELAY_MS, CUSTOMER_TOKEN_SERVICE_URL, CUSTOMER_TOKEN_SESSION_URL, extractTokenServiceAuthorization, fetchJson, supportsFirefoxCookieStoreTabs, tabsCreate, tabsRemove, wait }) { async function requestConsumerTokenService(sender) { const debugRequests = []; try { const tokenResponse = await fetchConsumerTokenServiceUntilJson(sender, debugRequests); const accountSummaryAuthorization = extractTokenServiceAuthorization( tokenResponse, "ACCP-TS", "account-ti-authorization" ); const accountPlansAuthorization = extractTokenServiceAuthorization( tokenResponse, "OCICONS-TS", "g2m-authorization" ); const tokenRequestDebugEntry = debugRequests[debugRequests.length - 1]; if (tokenRequestDebugEntry) { tokenRequestDebugEntry.metadata = { ...tokenRequestDebugEntry.metadata, accountSummaryTokenService: "ACCP-TS", accountSummaryAuthorizationHeader: accountSummaryAuthorization.name || "(missing)", accountSummaryAuthorizationValue: accountSummaryAuthorization.value ? `(present, ${accountSummaryAuthorization.value.length} characters)` : "(missing)", accountSummaryAuthorizationExpires: accountSummaryAuthorization.expires || "(not provided)", accountPlansTokenService: "OCICONS-TS", accountPlansAuthorizationHeader: accountPlansAuthorization.name || "(missing)", accountPlansAuthorizationValue: accountPlansAuthorization.value ? `(present, ${accountPlansAuthorization.value.length} characters)` : "(missing)", accountPlansAuthorizationExpires: accountPlansAuthorization.expires || "(not provided)" }; } if (!accountSummaryAuthorization.value) { throw new Error("ACCP-TS uiaasHeader.value was not found in requestConsumerTokenService."); } if (!accountPlansAuthorization.value) { throw new Error("OCICONS-TS uiaasHeader.value was not found in requestConsumerTokenService."); } return { ok: true, authorizations: { accountSummary: accountSummaryAuthorization, accountPlans: accountPlansAuthorization, installBase: extractTokenServiceAuthorization(tokenResponse, "SAIB-TS", ""), customerServiceRequests: extractTokenServiceAuthorization(tokenResponse, "SPA-ORANGE", ""), workloadActions: extractTokenServiceAuthorization(tokenResponse, "WWB-TS", "Wwb-Provider-Authorization") }, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } async function fetchConsumerTokenServiceUntilJson(sender, debugRequests) { let attempt = 0; let sessionTab = null; let receivedValidJson = false; try { while (attempt < CUSTOMER_TOKEN_MAX_ATTEMPTS) { attempt += 1; try { const tokenResponse = await fetchJson(CUSTOMER_TOKEN_SERVICE_URL, { method: "GET", credentials: "include", cache: "no-store", headers: { Accept: "application/json", "Cache-Control": "no-cache, no-store, max-age=0", Pragma: "no-cache" } }, "requestConsumerTokenService", debugRequests); const debugEntry = debugRequests[debugRequests.length - 1]; if (debugEntry) { debugEntry.metadata.attempt = String(attempt); } receivedValidJson = true; return tokenResponse; } catch (error) { const isHtmlFallback = error && error.code === "INVALID_JSON_RESPONSE" && error.httpStatus === 200; const isSessionUnauthorized = error && (error.httpStatus === 401 || error.httpStatus === 403); const needsSessionRecovery = isHtmlFallback || isSessionUnauthorized; const retryReason = isSessionUnauthorized ? `HTTP ${error.httpStatus} response requires SPA session recovery` : "HTTP 200 response did not contain valid JSON"; const debugEntry = debugRequests[debugRequests.length - 1]; if (!needsSessionRecovery || attempt >= CUSTOMER_TOKEN_MAX_ATTEMPTS) { if (debugEntry) { debugEntry.metadata.attempt = String(attempt); if (needsSessionRecovery) { debugEntry.metadata.retryLimitReached = "true"; debugEntry.metadata.retryReason = retryReason; debugEntry.error = isHtmlFallback ? `requestConsumerTokenService returned invalid JSON after ${CUSTOMER_TOKEN_MAX_ATTEMPTS} attempts.` : `requestConsumerTokenService failed with status ${error.httpStatus} after ${CUSTOMER_TOKEN_MAX_ATTEMPTS} attempts.`; error.message = debugEntry.error; } } throw error; } if (!sessionTab) { try { sessionTab = await openConsumerTokenSessionTabWithRetry(sender, debugEntry); if (debugEntry) { debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL; debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab"; } } catch (sessionError) { if (debugEntry) { debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL; debugEntry.metadata.sessionBootstrapState = `tab-open-failed: ${sessionError.message || "unknown error"}`; } } } else if (debugEntry) { debugEntry.metadata.sessionBootstrapState = "waiting-for-valid-session"; } const retryDelayMs = getConsumerTokenRetryDelay(attempt); if (debugEntry) { debugEntry.metadata.attempt = String(attempt); debugEntry.metadata.retryReason = retryReason; debugEntry.metadata.nextRetryDelayMs = String(retryDelayMs); } await wait(retryDelayMs); } } throw new Error("requestConsumerTokenService retry loop ended unexpectedly."); } finally { if (sessionTab && Number.isInteger(sessionTab.id)) { const debugEntry = debugRequests[debugRequests.length - 1]; try { await tabsRemove(sessionTab.id); if (debugEntry) { debugEntry.metadata.sessionBootstrapState = receivedValidJson ? "closed-after-valid-json" : "closed-after-retry-finished"; } } catch (error) { if (debugEntry) { debugEntry.metadata.sessionBootstrapState = `tab-close-failed: ${error.message || "unknown error"}`; } } } } } function getConsumerTokenRetryDelay(attempt) { return Math.min( CUSTOMER_TOKEN_RETRY_BASE_DELAY_MS * (2 ** Math.max(attempt - 1, 0)), CUSTOMER_TOKEN_RETRY_MAX_DELAY_MS ); } async function openConsumerTokenSessionTabWithRetry(sender, debugEntry) { let attempt = 0; // Opening failures must not consume the token service's five attempts. while (true) { attempt += 1; if (debugEntry) { debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL; debugEntry.metadata.sessionTabOpenAttempt = String(attempt); } try { const tab = await openConsumerTokenSessionTab(sender); if (debugEntry) { debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab"; delete debugEntry.metadata.sessionTabNextRetryDelayMs; } return tab; } catch (error) { const retryDelayMs = getConsumerTokenRetryDelay(Math.min(attempt, 5)); if (debugEntry) { debugEntry.metadata.sessionBootstrapState = "retrying-tab-open"; debugEntry.metadata.sessionTabLastOpenError = error.message || "unknown error"; debugEntry.metadata.sessionTabNextRetryDelayMs = String(retryDelayMs); } await wait(retryDelayMs); } } } function openConsumerTokenSessionTab(sender) { const details = { url: CUSTOMER_TOKEN_SESSION_URL, active: false }; if (sender && sender.tab && Number.isInteger(sender.tab.windowId)) { details.windowId = sender.tab.windowId; } if (supportsFirefoxCookieStoreTabs() && sender && sender.tab && sender.tab.cookieStoreId) { details.cookieStoreId = sender.tab.cookieStoreId; } return tabsCreate(details); } return { requestConsumerTokenService, fetchConsumerTokenServiceUntilJson, getConsumerTokenRetryDelay, openConsumerTokenSessionTabWithRetry, openConsumerTokenSessionTab }; } // Source: src/auth/spa-credentials.js function createAuthSpaCredentials({ findNestedObject }) { function normalizeMessageAuthorization(authorization, fallbackHeaderName) { const headerName = authorization && typeof authorization.name === "string" ? authorization.name.trim() : ""; const headerValue = authorization && typeof authorization.value === "string" ? authorization.value.trim() : ""; return { name: headerName || fallbackHeaderName, value: headerValue }; } function extractTokenServiceAuthorization(response, tokenServiceName, fallbackHeaderName) { const tokenService = Array.isArray(response) ? response.find((entry) => entry && entry.tokenService === tokenServiceName) : findNestedObject(response, (entry) => entry.tokenService === tokenServiceName); const authorizationHeader = tokenService && tokenService.uiaasHeader; const headerName = authorizationHeader && typeof authorizationHeader.label === "string" ? authorizationHeader.label.trim() : ""; const headerValue = authorizationHeader && typeof authorizationHeader.value === "string" ? authorizationHeader.value.trim() : ""; return { name: headerName || fallbackHeaderName, value: headerValue, expires: authorizationHeader && authorizationHeader.expires ? String(authorizationHeader.expires) : "" }; } return { normalizeMessageAuthorization, extractTokenServiceAuthorization }; } // Source: src/services/spa/accounts.js function createSpaAccounts({ ACCOUNT_PLANS_PAYLOAD, ACCOUNT_PLANS_URL, ACCOUNT_SUMMARY_URL, extractAccountPlans, fetchJson, findAccountPlanId, normalizeMessageAuthorization }) { async function requestAccountPlans(message) { const partyNumber = typeof message.partyNumber === "string" ? message.partyNumber.trim() : ""; const accountSummaryAuthorization = normalizeMessageAuthorization( message.authorizations && message.authorizations.accountSummary, "account-ti-authorization" ); const accountPlansAuthorization = normalizeMessageAuthorization( message.authorizations && message.authorizations.accountPlans, "g2m-authorization" ); const debugRequests = []; if (!partyNumber) { throw new Error("Customer Party Number is required."); } if (!accountSummaryAuthorization.value) { throw new Error("ACCP-TS authorization is unavailable. requestConsumerTokenService must complete first."); } if (!accountPlansAuthorization.value) { throw new Error("OCICONS-TS authorization is unavailable. requestConsumerTokenService must complete first."); } try { const accountSummary = await fetchJson(ACCOUNT_SUMMARY_URL, { method: "POST", credentials: "include", headers: { Accept: "application/json", [accountSummaryAuthorization.name]: accountSummaryAuthorization.value, "Content-Type": "application/json" }, body: JSON.stringify([{ key: "regId", value: partyNumber }]) }, "requestAccountSummary", debugRequests); const accountPlanId = findAccountPlanId(accountSummary); if (!accountPlanId) { throw new Error("Account plan id was not found in requestAccountSummary."); } const accountPlansResponse = await fetchJson(`${ACCOUNT_PLANS_URL}/${encodeURIComponent(String(accountPlanId))}`, { method: "POST", credentials: "include", headers: { Accept: "application/json", [accountPlansAuthorization.name]: accountPlansAuthorization.value, "Content-Type": "application/json" }, body: JSON.stringify(ACCOUNT_PLANS_PAYLOAD) }, "requestAccountPlans", debugRequests); return { ok: true, accountPlanId: String(accountPlanId), plans: extractAccountPlans(accountPlansResponse), debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } return { requestAccountPlans }; } // Source: src/services/spa/install-base.js function createSpaInstallBase({ ACCOUNT_SUMMARY_URL, fetchJson, findNestedObject, normalizeMessageAuthorization }) { const endpoint = "https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-installbase-provider/service/account/"; async function requestInstallBase(message) { const debugRequests = []; try { const partyNumber = String(message.partyNumber || "").trim(); const summaryAuth = normalizeMessageAuthorization(message.authorizations?.accountSummary, "account-ti-authorization"); const installAuth = normalizeMessageAuthorization(message.authorizations?.installBase, ""); if (!partyNumber) throw new Error("Customer Party Number is required."); if (!summaryAuth.value) throw new Error("ACCP-TS authorization is unavailable."); if (!installAuth.name || !installAuth.value) throw new Error("SAIB-TS uiaasHeader.label/value is unavailable."); const summary = await fetchJson(ACCOUNT_SUMMARY_URL, { method: "POST", credentials: "include", headers: { Accept: "application/json", "Content-Type": "application/json", [summaryAuth.name]: summaryAuth.value }, body: JSON.stringify([{ key: "regId", value: partyNumber }]) }, "requestAccountSummary", debugRequests); const account = findNestedObject(summary, value => (typeof value.registryId === "string" || typeof value.registryId === "number") && String(value.registryId).trim() !== ""); if (!account) throw new Error("registryId was not found in requestAccountSummary."); const payload = { text: "", accountHierarchy: "single", accountScope: "all", productScope: "all", installStatus: ["active", "inactive", "unsupported"], productIds: null, contractEndDate: { to: null, from: null }, contractStartDate: { to: null, from: null }, purchaseStartDate: { to: null, from: null }, registryIds: [], gecPartyNumbers: null }; const items = []; let offset = 0; // Bound malformed pagination without silently returning a partial result. for (let page = 0; page < 1000; page += 1) { const url = `${endpoint}${encodeURIComponent(String(account.registryId).trim())}?orderBy=currentSupport%3Adesc&limit=25&offset=${offset}`; const result = await fetchJson(url, { method: "POST", credentials: "include", headers: { Accept: "application/json", "Content-Type": "application/json", [installAuth.name]: installAuth.value }, body: JSON.stringify(payload) }, "requestInstallBase", debugRequests); if (!result || !Array.isArray(result.items) || typeof result.hasMore !== "boolean" || result.items.some(item => !item || typeof item !== "object" || Array.isArray(item))) { throw new Error("requestInstallBase returned an invalid collection."); } if (result.offset !== undefined && result.offset !== offset) throw new Error("requestInstallBase returned an unexpected offset."); items.push(...result.items); if (!result.hasMore) return { ok: true, items, debugRequests }; if (!result.items.length) throw new Error("requestInstallBase pagination made no progress."); offset += result.items.length; } throw new Error("requestInstallBase pagination limit reached."); } catch (error) { error.debugRequests = debugRequests; throw error; } finally { // The provider chooses the credential header name; never rely on its spelling for redaction. for (const entry of debugRequests) { for (const key of Object.keys(entry.requestHeaders || {})) { if (!/^(accept|content-type)$/i.test(key)) entry.requestHeaders[key] = "(present)"; } } } } return { requestInstallBase }; } // Source: src/services/spa/customer-service-requests.js function createSpaCustomerServiceRequests({ ACCOUNT_SUMMARY_URL, fetchJson, findAccountPlanId, normalizeMessageAuthorization }) { const endpoint = "https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-custsr-provider/service/oscSr/"; const filter = encodeURIComponent(JSON.stringify({ hierarchy: "single", status: "open" })); async function requestCustomerServiceRequest(message) { const debugRequests = []; try { const partyNumber = String(message.partyNumber || "").trim(); const summaryAuth = normalizeMessageAuthorization(message.authorizations?.accountSummary, "account-ti-authorization"); const srAuth = normalizeMessageAuthorization(message.authorizations?.customerServiceRequests, ""); if (!partyNumber) throw new Error("Customer Party Number is required."); if (!summaryAuth.value) throw new Error("ACCP-TS authorization is unavailable."); if (!srAuth.value) throw new Error("SPA-ORANGE uiaasHeader.value is unavailable."); const summary = await fetchJson(ACCOUNT_SUMMARY_URL, { method: "POST", credentials: "include", headers: { Accept: "application/json", "Content-Type": "application/json", [summaryAuth.name]: summaryAuth.value }, body: JSON.stringify([{ key: "regId", value: partyNumber }]) }, "requestAccountSummary", debugRequests); const accountSummaryId = findAccountPlanId(summary); if ((typeof accountSummaryId !== "string" && typeof accountSummaryId !== "number") || !String(accountSummaryId).trim()) { throw new Error("Account id was not found in requestAccountSummary."); } const items = []; let offset = 0; // This endpoint uses totalResults/count rather than hasMore. for (let page = 0; page < 1000; page += 1) { const url = `${endpoint}${encodeURIComponent(String(accountSummaryId))}?customerSRFilter=${filter}&orderBy=creationDate&orderByMode=desc&limit=40&offset=${offset}`; const result = await fetchJson(url, { method: "GET", credentials: "include", // SPA-ORANGE's label may be lead-auth; this provider requires custsr-auth. headers: { Accept: "application/json", "custsr-auth": srAuth.value } }, "requestCustomerServiceRequest", debugRequests); if (!result || !Array.isArray(result.objects) || result.objects.some(item => !item || typeof item !== "object" || Array.isArray(item)) || !Number.isSafeInteger(result.totalResults) || result.totalResults < 0 || !Number.isSafeInteger(result.count) || result.count !== result.objects.length) { throw new Error("requestCustomerServiceRequest returned an invalid collection."); } if (result.offset !== offset) throw new Error("requestCustomerServiceRequest returned an unexpected offset."); items.push(...result.objects); offset += result.count; if (offset >= result.totalResults) return { ok: true, items, debugRequests }; if (!result.count) throw new Error("requestCustomerServiceRequest pagination made no progress."); } throw new Error("requestCustomerServiceRequest pagination limit reached."); } catch (error) { error.debugRequests = debugRequests; throw error; } finally { for (const entry of debugRequests) { for (const key of Object.keys(entry.requestHeaders || {})) { if (!/^(accept|content-type)$/i.test(key)) entry.requestHeaders[key] = "(present)"; } } } } return { requestCustomerServiceRequest }; } // Source: src/services/spa/workload-actions.js function createSpaWorkloadActions({ fetchJson }) { async function requestWlActions(message) { const debugRequests = []; try { const revnId = String(message.revnId ?? "").trim(); const token = message.authorization?.value; if (!/^\d+$/.test(revnId)) throw new Error("A numeric RevnId is required."); if (typeof token !== "string" || !token.trim()) throw new Error("WWB-TS uiaasHeader.value is unavailable."); const url = `https://spa.oracle.com/oalcrm/web/api/provider-proxy/wwb-provider/service/workbench-proxy/wwb/mgmt/actions?parentType=WORKLOAD&parentId=${encodeURIComponent(revnId)}`; const result = await fetchJson(url, { method: "GET", credentials: "include", headers: { Accept: "application/json", "Wwb-Provider-Authorization": token.trim() } }, "requestWlActions", debugRequests); if (!result || !Array.isArray(result.actions) || typeof result.hasNext !== "boolean" || result.actions.some(item => !item || typeof item !== "object" || Array.isArray(item))) { throw new Error("requestWlActions returned an invalid collection."); } return { ok: true, actions: result.actions, hasNext: result.hasNext, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } finally { for (const entry of debugRequests) { if (entry.requestHeaders?.["Wwb-Provider-Authorization"]) entry.requestHeaders["Wwb-Provider-Authorization"] = "(present)"; } } } return { requestWlActions }; } // Source: src/services/spa/action-options.js function createSpaActionOptions({ fetchJson }) { const baseUrl = "https://spa.oracle.com/oalcrm/web/api/provider-proxy/wwb-provider/service/workbench-proxy/wwb/mgmt/workloads"; const lookupKeys = ["WWB_ACTION_ROLE", "WWB_ACTION_NAME", "WWB_ACTION_TEAM", "WWB_ACTION_STATUS", "WWB_ACTION_COMPLEXITY"]; async function request(message, name, path, normalize) { const debugRequests = []; try { const token = message.authorization?.value; if (typeof token !== "string" || !token.trim()) throw new Error("WWB-TS uiaasHeader.value is unavailable."); const result = await fetchJson(`${baseUrl}/${path()}`, { method: "GET", credentials: "include", headers: { Accept: "application/json", "Wwb-Provider-Authorization": token.trim() } }, name, debugRequests); if (debugRequests.at(-1)?.httpStatus !== 200) throw new Error(`${name} requires HTTP 200.`); return { ok: true, ...normalize(result), debugRequests }; } catch (error) { const entry = debugRequests.at(-1); if (entry) { entry.status = "failed"; entry.error = error.message; } error.debugRequests = debugRequests; throw error; } finally { for (const entry of debugRequests) { if (entry.requestHeaders?.["Wwb-Provider-Authorization"]) entry.requestHeaders["Wwb-Provider-Authorization"] = "(present)"; } } } function requestActionTeamMembers(message) { return request(message, "requestActionTeamMembers", () => { const id = String(message.workloadId ?? "").trim(); if (!/^\d+$/.test(id)) throw new Error("A numeric RevnId is required."); return `${encodeURIComponent(id)}/teamMembers?includeLeads=true`; }, result => { if (!Array.isArray(result) || result.some(item => typeof item?.email !== "string" || !item.email.trim())) { throw new Error("requestActionTeamMembers returned an invalid collection."); } return { members: result.map(item => ({ email: item.email })) }; }); } function requestActionFindLookup(message) { return request(message, "requestActionFindLookup", () => "fndLookup", result => { const lookups = {}; for (const key of lookupKeys) { if (!Array.isArray(result?.[key]) || result[key].some(item => typeof item?.code !== "string" || !item.code.trim() || typeof item?.name !== "string" || !item.name.trim())) { throw new Error(`requestActionFindLookup returned an invalid ${key} collection.`); } lookups[key] = result[key].map(({ code, name }) => ({ code, name })); } return { lookups }; }); } async function requestMgmtAction(message) { const debugRequests = []; try { const token = message.authorization?.value; const payload = message.payload; const action = payload?.action; if (!token || typeof token !== "string") throw new Error("WWB-TS uiaasHeader.value is unavailable."); if (payload?.parentType !== "WORKLOAD" || !/^\d+$/.test(String(payload.parentId))) throw new Error("A numeric RevnId is required."); for (const key of ["ownerEmail", "role", "name", "team", "status", "complexity", "createdBy", "updatedBy"]) { if (typeof action?.[key] !== "string" || !action[key].trim()) throw new Error(`Missing ${key}.`); } for (const key of ["startDate", "endDate"]) { if (typeof action[key] !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(action[key]) || !Number.isFinite(Date.parse(action[key]))) throw new Error(`Invalid ${key}.`); } if (action.endDate < action.startDate) throw new Error("End date must not precede start date."); if (!Array.isArray(action.notes) || action.notes.some(note => typeof note !== "string")) throw new Error("Invalid notes."); const result = await fetchJson("https://spa.oracle.com/oalcrm/web/api/provider-proxy/wwb-provider/service/workbench-proxy/wwb/mgmt/actions", { method: "POST", credentials: "include", headers: { Accept: "application/json", "Content-Type": "application/json", "Wwb-Provider-Authorization": token.trim() }, body: JSON.stringify(payload) }, "requestMgmtAction", debugRequests, { allowEmpty: true }); return { ok: true, result, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } finally { for (const entry of debugRequests) { if (entry.requestHeaders?.["Wwb-Provider-Authorization"]) entry.requestHeaders["Wwb-Provider-Authorization"] = "(present)"; } } } return { requestActionTeamMembers, requestActionFindLookup, requestMgmtAction }; } // Source: src/services/fusion/sr-details.js function createFusionSrDetails({ fetchJson }) { async function requestInternalServiceRequest(message) { const debugRequests = []; try { const id = String(message.srId ?? ""); if (!/^\d+$/.test(id)) throw new Error("A numeric SrId is required."); const fields = "Title,SrNumber,SrId,OpportunityName_c,QueueManagers_c,StatusCd,resourceMembers;ServiceRequest_SRToInternalSR_Tgt:ReportedHours_c,Title,OpportunityName_c,StatusCd,SrNumber,ServiceNew_c,AccountPartyName,LastUpdateDate,SvcHealth_c,AssigneePersonName,OpenDate,SrId"; const url = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_SR_management/live;profile=PROD/services/auth/1.1/proxy/oalsetCRMRestAPI/uri/https/eeho.fa.us2.oraclecloud.com/crmRestApi/resources/latest/serviceRequests" + `?fields=${encodeURIComponent(fields)}&onlyData=true&q=${encodeURIComponent(`SrId=${id}`)}`; const result = await fetchJson(url, { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: "Session" } }, "requestInternalServiceRequest", debugRequests); if (!Array.isArray(result?.items)) throw new Error("Invalid SR details response."); const items = result.items.flatMap(item => { const children = item.ServiceRequest_SRToInternalSR_Tgt; if (children == null) return []; if (!Array.isArray(children) || children.some(child => !child || typeof child !== "object")) throw new Error("Invalid linked SR collection."); return children; }); return { ok: true, items, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } return { requestInternalServiceRequest }; } // Source: src/services/spa/current-user.js function createSpaCurrentUser({ fetchJson }) { async function requestCurrentUser() { const debugRequests = []; let user = null; try { const result = await fetchJson("https://spa.oracle.com/oalcrm/web/api/identity-management/users/current", { method: "GET", credentials: "include", cache: "no-store", headers: { Accept: "application/json" } }, "requestCurrentUser", debugRequests); if (!result?.user || !Array.isArray(result.user.roles) || result.user.roles.some(role => typeof role !== "string")) { throw new Error("requestCurrentUser returned invalid user roles."); } user = { id: result.user.id, name: result.user.name, roles: result.user.roles }; return { ok: true, user, debugRequests }; } catch (error) { for (const entry of debugRequests) { entry.status = "failed"; entry.error = error.message; } error.debugRequests = debugRequests; throw error; } finally { // The identity token is not needed by content scripts or debug, including on failures. for (const entry of debugRequests) { entry.responseBody = JSON.stringify(user ? { user, token: "(redacted)" } : { error: "Identity response omitted." }, null, 2); entry.responseBodyTruncated = false; } } } return { requestCurrentUser }; } // Source: src/services/spa/consumption.js function createSpaConsumption({ CONSUMPTION_TREND_REQUESTS, CONSUMPTION_TREND_URL, fetchJson, normalizeMessageAuthorization }) { async function requestConsumptionTrend(message) { const subPlanNum = typeof message.subPlanNum === "string" ? message.subPlanNum.trim() : ""; const period = typeof message.period === "string" ? message.period.toLowerCase() : ""; const requestName = CONSUMPTION_TREND_REQUESTS[period]; const authorization = normalizeMessageAuthorization(message.authorization, "g2m-authorization"); const debugRequests = []; if (!subPlanNum) { throw new Error("Sub plan number is required for the consumption trend."); } if (!requestName) { throw new Error(`Unsupported consumption trend period: ${period || "(missing)"}.`); } if (!authorization.value) { throw new Error("OCICONS-TS authorization is unavailable for the consumption trend."); } const url = `${CONSUMPTION_TREND_URL}/${encodeURIComponent(subPlanNum)}?quarter=All&timePeriod=${period}`; try { const response = await fetchJson(url, { method: "GET", credentials: "include", cache: "no-store", headers: { Accept: "application/json", "G2m-Authorization": authorization.value } }, requestName, debugRequests); const items = Array.isArray(response) ? response : Array.isArray(response && response.items) ? response.items : []; return { ok: true, subPlanNum, period, items, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } async function requestConsumptionPlanDetail(message) { const debugRequests = []; try { const subPlanNum = typeof message.subPlanNum === "string" ? message.subPlanNum.trim() : ""; const authorization = normalizeMessageAuthorization(message.authorization, "g2m-authorization"); if (!subPlanNum) throw new Error("Sub plan number is required for plan details."); if (!authorization.value) throw new Error("OCICONS-TS authorization is unavailable for plan details."); const url = `https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-consumption/service/v1/plan/plandetail/${encodeURIComponent(subPlanNum)}?active=true`; const items = await fetchJson(url, { method: "GET", credentials: "include", cache: "no-store", headers: { Accept: "application/json", "G2m-Authorization": authorization.value } }, "requestConsumptionPlanDetail", debugRequests); const validLines = (lines, depth = 0) => Array.isArray(lines) && depth <= 20 && lines.every(line => line && typeof line === "object" && !Array.isArray(line) && (line.clines === undefined || line.clines === null || validLines(line.clines, depth + 1))); if (!validLines(items)) throw new Error("requestConsumptionPlanDetail returned invalid plan details."); return { ok: true, subPlanNum, items, debugRequests }; } catch (error) { const entry = debugRequests[debugRequests.length - 1]; if (entry && entry.status === "success") { entry.status = "failed"; entry.error = error.message; } error.debugRequests = debugRequests; throw error; } } async function requestRatecardByPlan(message) { const debugRequests = []; try { const planNumber = typeof message.planNumber === "string" ? message.planNumber.trim() : ""; const authorization = normalizeMessageAuthorization(message.authorization, "g2m-authorization"); if (!planNumber) throw new Error("Plan number is required for the rate card."); if (!authorization.value) throw new Error("OCICONS-TS authorization is unavailable for the rate card."); const items = await fetchJson("https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-consumption/service/v1/ratecard/byPlan", { method: "POST", credentials: "include", cache: "no-store", headers: { Accept: "application/json", "Content-Type": "application/json", "G2m-Authorization": authorization.value }, body: JSON.stringify({ planNumber, recordsSize: 10000 }) }, "requestRatecardByPlan", debugRequests); if (!Array.isArray(items) || items.some(item => !item || typeof item !== "object" || Array.isArray(item))) { throw new Error("requestRatecardByPlan returned invalid rate card items."); } return { ok: true, planNumber, items, debugRequests }; } catch (error) { const entry = debugRequests[debugRequests.length - 1]; if (entry && entry.status === "success") { entry.status = "failed"; entry.error = error.message; } error.debugRequests = debugRequests; throw error; } } return { requestConsumptionTrend, requestConsumptionPlanDetail, requestRatecardByPlan }; } // Source: src/services/spa/response-shapes.js function createSpaResponseShapes() { function findNestedObject(value, predicate, visited = new Set()) { if (!value || typeof value !== "object" || visited.has(value)) { return null; } visited.add(value); if (!Array.isArray(value) && predicate(value)) { return value; } for (const child of Object.values(value)) { const match = findNestedObject(child, predicate, visited); if (match) { return match; } } return null; } function findAccountPlanId(response) { const account = findNestedObject(response, (value) => ( Object.prototype.hasOwnProperty.call(value, "id") && value.id !== null && value.id !== undefined && value.id !== "" )); return account ? account.id : ""; } function extractAccountPlans(response) { const plans = []; const visited = new Set(); const visit = (value) => { if (!value || typeof value !== "object" || visited.has(value)) { return; } visited.add(value); if (!Array.isArray(value) && ( Object.prototype.hasOwnProperty.call(value, "planType") || Object.prototype.hasOwnProperty.call(value, "subPlanNum") )) { plans.push(value); return; } Object.values(value).forEach(visit); }; visit(response); return plans; } return { findNestedObject, findAccountPlanId, extractAccountPlans }; } // Source: src/services/http/background-json.js function createHttpBackgroundJson({ previewDebugBody, DEBUG_BODY_LIMIT, environment }) { const { fetch } = environment; async function fetchJson(url, options, requestName, debugRequests = null, { allowEmpty = false } = {}) { const startedAt = new Date(); const debugEntry = createBackgroundDebugEntry(requestName, url, options, startedAt); let response; try { response = await fetch(url, options); } catch (error) { completeBackgroundDebugEntry(debugEntry, null, "", error.message || "Network request failed."); appendBackgroundDebugEntry(debugRequests, debugEntry); throw error; } const responsePayload = await readResponsePayload(response); const responseBody = createDebugBody(responsePayload.text); completeBackgroundDebugEntry(debugEntry, response, responseBody, ""); debugEntry.metadata.responseContentType = response.headers.get("content-type") || "(not provided)"; debugEntry.metadata.responseLength = String(responsePayload.text.length); appendBackgroundDebugEntry(debugRequests, debugEntry); if (!response.ok) { const error = new Error(`${requestName} failed with status ${response.status}.`); error.httpStatus = response.status; debugEntry.error = error.message; throw error; } if (responsePayload.error) { throw new Error(`${requestName} response body could not be read.`); } try { if (allowEmpty && !responsePayload.text.trim()) return null; return parseJsonResponse(responsePayload.text, requestName); } catch (error) { error.httpStatus = response.status; debugEntry.status = "failed"; debugEntry.error = error.message; throw error; } } function createBackgroundDebugEntry(requestName, url, options, startedAt) { return { name: requestName, method: options.method || "GET", url, status: "pending", startedAt: startedAt.toISOString(), completedAt: null, durationMs: null, httpStatus: null, statusText: "", requestHeaders: normalizeDebugHeaders(options.headers), requestBody: formatDebugRequestBody(options.body), metadata: { executionContext: "background" }, responseHeaders: {}, responseBody: "", responseBodyTruncated: false, error: "" }; } function completeBackgroundDebugEntry(entry, response, responseBody, errorMessage) { const completedAt = new Date(); entry.completedAt = completedAt.toISOString(); entry.durationMs = completedAt.getTime() - new Date(entry.startedAt).getTime(); entry.error = errorMessage; if (!response) { entry.status = "failed"; return; } entry.status = response.ok ? "success" : "failed"; entry.httpStatus = response.status; entry.statusText = response.statusText || ""; entry.responseHeaders = headersToObject(response.headers); entry.responseBody = responseBody.value; entry.responseBodyTruncated = responseBody.truncated; } function appendBackgroundDebugEntry(debugRequests, entry) { if (Array.isArray(debugRequests)) { debugRequests.push(entry); } } async function readResponsePayload(response) { try { return { text: await response.text(), error: "" }; } catch (error) { return { text: `Unable to read response body: ${error.message || "unknown error"}`, error: error.message || "unknown error" }; } } function parseJsonResponse(text, requestName) { const normalizedText = String(text) .replace(/^\uFEFF/, "") .trimStart() .replace(/^\)\]\}',?\s*/, "") .replace(/^while\s*\(1\);\s*/, ""); try { return JSON.parse(normalizedText); } catch (error) { const invalidJsonError = new Error(`${requestName} returned an invalid JSON response.`); invalidJsonError.code = "INVALID_JSON_RESPONSE"; throw invalidJsonError; } } function createDebugBody(text) { return previewDebugBody(text, DEBUG_BODY_LIMIT); } function normalizeDebugHeaders(headers) { const normalized = {}; Object.entries(headers || {}).forEach(([key, value]) => { normalized[key] = String(value); }); return normalized; } function headersToObject(headers) { const values = {}; if (headers && typeof headers.forEach === "function") { headers.forEach((value, key) => { values[key] = value; }); } return values; } function formatDebugRequestBody(body) { if (!body) { return ""; } try { return JSON.stringify(JSON.parse(body), null, 2); } catch (error) { return String(body); } } return { fetchJson, createBackgroundDebugEntry, completeBackgroundDebugEntry, appendBackgroundDebugEntry, readResponsePayload, parseJsonResponse, createDebugBody, normalizeDebugHeaders, headersToObject, formatDebugRequestBody }; } // Source: src/features/products/background-jobs.js function createProductsBackgroundJobs({ messageTypes, OPPTY_PRODUCTS_CONCURRENCY, getOpptyProducts, normalizeCacheMaxAge, tabsSendMessage }) { async function requestOpptyProducts(message, sender) { const requestId = typeof message.requestId === "string" ? message.requestId : ""; const accessToken = typeof message.accessToken === "string" ? message.accessToken : ""; const cacheMaxAgeMs = normalizeCacheMaxAge(message.cacheMaxAgeMs); const optyNumbers = Array.from(new Set( (Array.isArray(message.optyNumbers) ? message.optyNumbers : []) .filter(Boolean) .map(String) )); if (!requestId || !accessToken) { throw new Error("A request id and access token are required for requestOpptyProducts."); } let nextIndex = 0; let completed = 0; let failed = 0; let cacheHits = 0; let debugDelivery = Promise.resolve(); const reportRequest = entry => { const message = { type: messageTypes.opptyProductsRequestDebug, requestId, entry: { ...entry, debugKey: JSON.stringify([requestId, entry.metadata.optyNumber, entry.metadata.offset]) } }; debugDelivery = debugDelivery.catch(() => {}).then(() => sendProductsProgress(sender, message)); }; const runWorker = async () => { while (nextIndex < optyNumbers.length) { const index = nextIndex; nextIndex += 1; const optyNumber = optyNumbers[index]; try { const result = await getOpptyProducts(optyNumber, accessToken, cacheMaxAgeMs, reportRequest); completed += 1; if (result.fromCache) { cacheHits += 1; } await sendProductsProgress(sender, { type: messageTypes.opptyProductsProgress, requestId, state: "running", optyNumber, items: result.items, fromCache: result.fromCache, cachedAt: result.cachedAt, completed, total: optyNumbers.length, failed, cacheHits }); } catch (error) { completed += 1; failed += 1; await sendProductsProgress(sender, { type: messageTypes.opptyProductsProgress, requestId, state: "running", optyNumber, items: [], error: error.message || "Unable to load products.", completed, total: optyNumbers.length, failed, cacheHits }); } } }; const workerCount = Math.min(OPPTY_PRODUCTS_CONCURRENCY, Math.max(optyNumbers.length, 1)); await Promise.all(Array.from({ length: workerCount }, runWorker)); await debugDelivery.catch(() => {}); const state = failed > 0 ? "complete-with-errors" : "complete"; await sendProductsProgress(sender, { type: messageTypes.opptyProductsProgress, requestId, state, completed, total: optyNumbers.length, failed, cacheHits }); return { ok: failed === 0, requestId, completed, total: optyNumbers.length, failed, cacheHits }; } function sendProductsProgress(sender, message) { if (!sender || !sender.tab || !Number.isInteger(sender.tab.id)) { return Promise.resolve(); } const options = Number.isInteger(sender.frameId) ? { frameId: sender.frameId } : undefined; return tabsSendMessage(sender.tab.id, message, options).catch(() => {}); } return { requestOpptyProducts, sendProductsProgress }; } // Source: src/features/products/cache.js function createProductsCache({ OPPTY_PRODUCTS_CACHE_KEY, fetchAllOpptyProducts, productsCacheState, storageLocalGet, storageLocalSet }) { let generation = 0; async function invalidate() { generation += 1; productsCacheState.inFlightProducts.clear(); productsCacheState.productsCachePromise = Promise.resolve({}); await saveProductsCache({}); } async function getOpptyProducts(optyNumber, accessToken, cacheMaxAgeMs, onDebug = () => {}) { const currentGeneration = generation; const cache = await getProductsCache(); if (generation !== currentGeneration) return getOpptyProducts(optyNumber, accessToken, cacheMaxAgeMs, onDebug); const cachedEntry = cache[optyNumber]; if (cachedEntry && Array.isArray(cachedEntry.items) && Date.now() - Number(cachedEntry.fetchedAt) < cacheMaxAgeMs) { return { items: cachedEntry.items, fromCache: true, cachedAt: Number(cachedEntry.fetchedAt) }; } if (!productsCacheState.inFlightProducts.has(optyNumber)) { const flight = { listeners: new Set(), entries: new Map(), promise: null }; productsCacheState.inFlightProducts.set(optyNumber, flight); flight.promise = fetchAllOpptyProducts(optyNumber, accessToken, entry => { flight.entries.set(entry.metadata.offset, entry); for (const listener of flight.listeners) { try { listener(entry); } catch (_) {} } }) .then(async (items) => { const fetchedAt = Date.now(); if (generation === currentGeneration) { cache[optyNumber] = { fetchedAt, items }; await saveProductsCache(cache).catch(() => {}); } return { items, fetchedAt }; }) .finally(() => { if (productsCacheState.inFlightProducts.get(optyNumber) === flight) productsCacheState.inFlightProducts.delete(optyNumber); }); } const flight = productsCacheState.inFlightProducts.get(optyNumber); // A second tab/job shares the fetch but still receives its current diagnostics. flight.listeners.add(onDebug); for (const entry of flight.entries.values()) { try { onDebug(entry); } catch (_) {} } try { const fetchedResult = await flight.promise; return { items: fetchedResult.items, cachedAt: fetchedResult.fetchedAt, fromCache: false }; } finally { flight.listeners.delete(onDebug); } } function normalizeCacheMaxAge(value) { const maxAge = Number(value); const defaultMaxAge = 24 * 60 * 60 * 1000; const maximumMaxAge = 30 * 24 * 60 * 60 * 1000; return Number.isFinite(maxAge) && maxAge > 0 ? Math.min(maxAge, maximumMaxAge) : defaultMaxAge; } async function getProductsCache() { if (!productsCacheState.productsCachePromise) { productsCacheState.productsCachePromise = storageLocalGet(OPPTY_PRODUCTS_CACHE_KEY) .then((result) => result && typeof result[OPPTY_PRODUCTS_CACHE_KEY] === "object" ? result[OPPTY_PRODUCTS_CACHE_KEY] : {}) .catch(() => ({})); } return productsCacheState.productsCachePromise; } function saveProductsCache(cache) { productsCacheState.productsCacheWritePromise = productsCacheState.productsCacheWritePromise .catch(() => {}) .then(() => storageLocalSet({ [OPPTY_PRODUCTS_CACHE_KEY]: cache })); return productsCacheState.productsCacheWritePromise; } return { invalidate, getOpptyProducts, normalizeCacheMaxAge, getProductsCache, saveProductsCache }; } // Source: src/services/fusion/products.js function createFusionProducts({ OPPTY_PRODUCTS_FIELDS, OPPTY_PRODUCTS_MAX_PAGES, OPPTY_PRODUCTS_PAGE_LIMIT, ORACLE_DOMAIN, createBackgroundDebugEntry, completeBackgroundDebugEntry, createDebugBody, headersToObject, environment }) { const { fetch } = environment; async function fetchAllOpptyProducts(optyNumber, accessToken, onDebug = () => {}) { let offset = 0; let page = 0; const items = []; while (page < OPPTY_PRODUCTS_MAX_PAGES) { const url = createOpptyProductsUrl(optyNumber, offset); const options = { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: `Bearer ${accessToken}` } }; const entry = createBackgroundDebugEntry("requestOpptyProducts", url, { ...options, headers: { Accept: "application/json", Authorization: "(present)" } }, new Date()); entry.metadata = { executionContext: "background", optyNumber, offset, page: page + 1 }; const report = () => { // Diagnostics must not block requests or transmit the Bearer credential. try { onDebug({ ...entry, metadata: { ...entry.metadata } }); } catch (_) {} }; let response; let responseBody = { value: "", truncated: false }; let responseData; report(); try { response = await fetch(url, options); entry.httpStatus = response.status; entry.statusText = response.statusText || ""; entry.responseHeaders = headersToObject(response.headers); Object.keys(entry.responseHeaders).forEach(key => { if (/authorization|cookie|token/i.test(key)) entry.responseHeaders[key] = "(present)"; }); entry.metadata.phase = "reading-response"; report(); const text = await response.text(); responseBody = createDebugBody(text); if (!response.ok) throw new Error(`requestOpptyProducts failed with status ${response.status}.`); responseData = JSON.parse(text); if (!responseData || typeof responseData !== "object") throw new Error("requestOpptyProducts returned an invalid response."); completeBackgroundDebugEntry(entry, response, responseBody, ""); } catch (error) { completeBackgroundDebugEntry(entry, response, responseBody, error.message || "Unable to load products."); entry.status = "failed"; throw error; } finally { Object.keys(entry.responseHeaders).forEach(key => { if (/authorization|cookie|token/i.test(key)) entry.responseHeaders[key] = "(present)"; }); entry.metadata.phase = "complete"; report(); } const pageItems = Array.isArray(responseData.items) ? responseData.items : []; items.push(...pageItems); page += 1; if (!responseData.hasMore) { return items; } const responseOffset = Number(responseData.offset); const responseCount = Number(responseData.count); const receivedCount = Number.isFinite(responseCount) ? responseCount : pageItems.length; const currentOffset = Number.isFinite(responseOffset) ? responseOffset : offset; if (receivedCount <= 0) { throw new Error("requestOpptyProducts returned hasMore without additional results."); } offset = currentOffset + receivedCount; } throw new Error("requestOpptyProducts exceeded the pagination safety limit."); } function createOpptyProductsUrl(optyNumber, offset) { const url = new URL(`https://${ORACLE_DOMAIN}/crmRestApi/rest/rv:be91c002-2e5d-4ed2-a37e-e0c837bf141f/en/11.13.18.05:9/opportunities/${encodeURIComponent(optyNumber)}/child/ChildRevenue`); url.searchParams.set("onlyData", "true"); url.searchParams.set("q", "(SplitTypeCode!='DETAILCHILDSPLIT') AND (RecurTypeCode!='CHILDRECUR')"); url.searchParams.set("totalResults", "false"); url.searchParams.set("fields", OPPTY_PRODUCTS_FIELDS.join(",")); url.searchParams.set("orderBy", "CreationDate:desc"); url.searchParams.set("limit", String(OPPTY_PRODUCTS_PAGE_LIMIT)); url.searchParams.set("offset", String(offset)); return url.toString(); } return { fetchAllOpptyProducts, createOpptyProductsUrl }; } // Source: src/auth/xsrf-recovery.js function createAuthXsrfRecovery({ COOKIE_REFRESH_POLL_MS, COOKIE_REFRESH_TIMEOUT_MS, OPPORTUNITIES_LIST_URL, getXsrfTokenCookie, supportsFirefoxCookieStoreTabs, tabsCreate, tabsRemove, wait }) { async function refreshXsrfCookie(sender) { const startedAt = Date.now(); const previous = (await getXsrfTokenCookie()).cookie; const createProperties = { url: OPPORTUNITIES_LIST_URL, active: false }; if (sender && sender.tab && Number.isInteger(sender.tab.windowId)) { createProperties.windowId = sender.tab.windowId; } if (supportsFirefoxCookieStoreTabs() && sender && sender.tab && sender.tab.cookieStoreId) { createProperties.cookieStoreId = sender.tab.cookieStoreId; } let refreshTab; try { refreshTab = await tabsCreate(createProperties); const current = await waitForXsrfCookieChange(previous); const refreshed = hasCookieChanged(previous, current); return { ok: Boolean(current), refreshed, cookieName: current ? current.name : "", durationMs: Date.now() - startedAt, error: refreshed ? "" : "XSRF cookie was not created or changed before timeout." }; } finally { if (refreshTab && Number.isInteger(refreshTab.id)) { try { await tabsRemove(refreshTab.id); } catch (error) { // The temporary tab may already have been closed. } } } } async function waitForXsrfCookieChange(previousCookie) { const deadline = Date.now() + COOKIE_REFRESH_TIMEOUT_MS; let currentCookie = null; while (Date.now() < deadline) { currentCookie = (await getXsrfTokenCookie()).cookie; if (hasCookieChanged(previousCookie, currentCookie)) { return currentCookie; } await wait(COOKIE_REFRESH_POLL_MS); } return currentCookie; } function hasCookieChanged(previousCookie, currentCookie) { if (!currentCookie || !currentCookie.value) { return false; } if (!previousCookie) { return true; } return previousCookie.name !== currentCookie.name || previousCookie.value !== currentCookie.value || previousCookie.expirationDate !== currentCookie.expirationDate; } return { refreshXsrfCookie, waitForXsrfCookieChange, hasCookieChanged }; } // Source: src/auth/xsrf-cookies.js function createAuthXsrfCookies({ ORACLE_COOKIE_URLS, ORACLE_DOMAIN, XSRF_COOKIE_NAME, XSRF_COOKIE_PREFIX, cookiesGet, cookiesGetAll, cookiesGetAllCookieStores, removeUndefinedValues }) { async function getXsrfTokenCookie() { const lookupDetails = []; const allCookies = []; const stores = await getCookieStores(lookupDetails); for (const store of stores) { const exactCookie = await getExactCookieFromUrls(store.id, lookupDetails); if (exactCookie) { allCookies.push(exactCookie); } } for (const store of stores) { await collectCookies({ name: XSRF_COOKIE_NAME, storeId: store.id }, allCookies, lookupDetails); } for (const store of stores) { await collectCookies({ domain: ORACLE_DOMAIN, storeId: store.id }, allCookies, lookupDetails); await collectCookies({ domain: `.${ORACLE_DOMAIN}`, storeId: store.id }, allCookies, lookupDetails); } for (const store of stores) { for (const url of ORACLE_COOKIE_URLS) { await collectCookies({ url, storeId: store.id }, allCookies, lookupDetails); } } const uniqueCookies = dedupeCookies(allCookies); const xsrfCookies = uniqueCookies.filter((cookie) => cookie.name.startsWith(XSRF_COOKIE_PREFIX)); const exactCookie = xsrfCookies.find((cookie) => cookie.name === XSRF_COOKIE_NAME); const hostCookie = xsrfCookies.find((cookie) => cookie.domain === ORACLE_DOMAIN || cookie.domain === `.${ORACLE_DOMAIN}`); return { cookie: exactCookie || hostCookie || xsrfCookies[0] || null, matchedCookieNames: xsrfCookies.map((cookie) => `${cookie.name} (${cookie.domain}${cookie.path})`), lookupDetails }; } async function getExactCookieFromUrls(storeId, lookupDetails) { for (const url of ORACLE_COOKIE_URLS) { const cookie = await cookiesGet({ url, name: XSRF_COOKIE_NAME, storeId }); lookupDetails.push(`${JSON.stringify({ url, name: XSRF_COOKIE_NAME, storeId })} => ${cookie ? "found" : "not found"}`); if (cookie) { return cookie; } } return null; } async function getCookieStores(lookupDetails) { try { const stores = await cookiesGetAllCookieStores(); lookupDetails.push(`getAllCookieStores => ${stores.length} store(s)`); return stores.length ? stores : [{ id: undefined }]; } catch (error) { lookupDetails.push(`getAllCookieStores => unavailable (${error.message || "unknown error"})`); return [{ id: undefined }]; } } async function collectCookies(details, target, lookupDetails) { const cleanDetails = removeUndefinedValues(details); const cookies = await cookiesGetAll(cleanDetails); target.push(...cookies); lookupDetails.push(`${JSON.stringify(cleanDetails)} => ${cookies.length} cookie(s)`); } function dedupeCookies(cookies) { const seen = new Set(); return cookies.filter((cookie) => { const key = `${cookie.name}|${cookie.domain}|${cookie.path}|${cookie.storeId || ""}`; if (seen.has(key)) { return false; } seen.add(key); return true; }); } return { getXsrfTokenCookie, getExactCookieFromUrls, getCookieStores, collectCookies, dedupeCookies }; } // Source: src/platform/background-api.js function createPlatformBackgroundApi({ runtimeApi, environment }) { const { browser, setTimeout } = environment; function supportsFirefoxCookieStoreTabs() { return Boolean( runtimeApi.runtime && typeof runtimeApi.runtime.getBrowserInfo === "function" ); } function tabsCreate(details) { if (runtimeApi.tabs.create.length <= 1) { return runtimeApi.tabs.create(details); } return new Promise((resolve, reject) => { runtimeApi.tabs.create(details, (tab) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(tab); }); }); } function tabsRemove(tabId) { if (runtimeApi.tabs.remove.length <= 1) { return runtimeApi.tabs.remove(tabId); } return new Promise((resolve, reject) => { runtimeApi.tabs.remove(tabId, () => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(); }); }); } function tabsSendMessage(tabId, message, options) { if (typeof browser !== "undefined") { return options ? runtimeApi.tabs.sendMessage(tabId, message, options) : runtimeApi.tabs.sendMessage(tabId, message); } return new Promise((resolve, reject) => { const callback = (response) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(response); }; if (options) { runtimeApi.tabs.sendMessage(tabId, message, options, callback); } else { runtimeApi.tabs.sendMessage(tabId, message, callback); } }); } function storageLocalGet(key) { if (typeof browser !== "undefined") { return runtimeApi.storage.local.get(key); } return new Promise((resolve, reject) => { runtimeApi.storage.local.get(key, (result) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(result); }); }); } function storageLocalSet(value) { if (typeof browser !== "undefined") { return runtimeApi.storage.local.set(value); } return new Promise((resolve, reject) => { runtimeApi.storage.local.set(value, () => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(); }); }); } function wait(durationMs) { return new Promise((resolve) => setTimeout(resolve, durationMs)); } function cookiesGetAll(details) { if (runtimeApi.cookies.getAll.length <= 1) { return runtimeApi.cookies.getAll(details); } return new Promise((resolve, reject) => { runtimeApi.cookies.getAll(details, (cookies) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(cookies); }); }); } function cookiesGet(details) { const cleanDetails = removeUndefinedValues(details); if (runtimeApi.cookies.get.length <= 1) { return runtimeApi.cookies.get(cleanDetails); } return new Promise((resolve, reject) => { runtimeApi.cookies.get(cleanDetails, (cookie) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(cookie); }); }); } function cookiesGetAllCookieStores() { if (!runtimeApi.cookies.getAllCookieStores) { return Promise.resolve([{ id: undefined }]); } if (runtimeApi.cookies.getAllCookieStores.length === 0) { return runtimeApi.cookies.getAllCookieStores(); } return new Promise((resolve, reject) => { runtimeApi.cookies.getAllCookieStores((stores) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(stores); }); }); } function removeUndefinedValues(details) { return Object.fromEntries( Object.entries(details).filter((entry) => entry[1] !== undefined) ); } return { supportsFirefoxCookieStoreTabs, tabsCreate, tabsRemove, tabsSendMessage, storageLocalGet, storageLocalSet, wait, cookiesGetAll, cookiesGet, cookiesGetAllCookieStores, removeUndefinedValues }; } // Source: src/background/main.js function startBackgroundApplication(dependencies) { registerBackgroundMessages(dependencies); } // Source: src/background/messages.js /** Register synchronously; replies retain the WebExtension sendResponse contract. */ function registerBackgroundMessages({ messageTypes, invalidateProductsCache, getXsrfTokenCookie, refreshXsrfCookie, requestAccountPlans, requestInstallBase, requestCustomerServiceRequest, requestWlActions, requestActionTeamMembers, requestActionFindLookup, requestMgmtAction, requestInternalServiceRequest, requestCurrentUser, requestConsumerTokenService, requestConsumptionTrend, requestConsumptionPlanDetail, requestRatecardByPlan, requestOpptyProducts, runtimeApi }) { runtimeApi.runtime.onMessage.addListener((message, sender, sendResponse) => { if (!message || !message.type) { return false; } if (message.type === messageTypes.invalidateProductsCache) { invalidateProductsCache().then(() => sendResponse({ ok: true })).catch(error => sendResponse({ ok: false, error: error.message || "Unable to clear products cache." })); return true; } if (message.type === messageTypes.getXsrfToken) { getXsrfTokenCookie() .then((result) => { sendResponse({ ok: true, cookieName: result.cookie ? result.cookie.name : "", token: result.cookie ? result.cookie.value : "", matchedCookieNames: result.matchedCookieNames, lookupDetails: result.lookupDetails }); }) .catch((error) => { sendResponse({ ok: false, cookieName: "", token: "", matchedCookieNames: [], lookupDetails: [], error: error.message || "Unable to read cookies." }); }); return true; } if (message.type === messageTypes.refreshXsrfCookie) { refreshXsrfCookie(sender) .then(sendResponse) .catch((error) => { sendResponse({ ok: false, refreshed: false, cookieName: "", durationMs: 0, error: error.message || "Unable to refresh XSRF cookie." }); }); return true; } if (message.type === messageTypes.requestOpptyProducts) { requestOpptyProducts(message, sender) .then(sendResponse) .catch((error) => { sendResponse({ ok: false, requestId: message.requestId || "", error: error.message || "Unable to load opportunity products." }); }); return true; } if (message.type === messageTypes.requestConsumerTokenService) { requestConsumerTokenService(sender) .then(sendResponse) .catch((error) => { sendResponse({ ok: false, error: error.message || "Unable to load consumer token service.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] }); }); return true; } if (message.type === messageTypes.requestCurrentUser) { requestCurrentUser().then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message || "Unable to load current user.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] })); return true; } if ([messageTypes.requestActionTeamMembers, messageTypes.requestActionFindLookup, messageTypes.requestMgmtAction, messageTypes.requestInternalServiceRequest].includes(message.type)) { const request = message.type === messageTypes.requestInternalServiceRequest ? requestInternalServiceRequest : message.type === messageTypes.requestMgmtAction ? requestMgmtAction : message.type === messageTypes.requestActionTeamMembers ? requestActionTeamMembers : requestActionFindLookup; request(message).then(sendResponse).catch(error => sendResponse({ ok: false, httpStatus: error.httpStatus, error: error.message || "Unable to complete request.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] })); return true; } if (message.type === messageTypes.requestWlActions) { requestWlActions(message).then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message || "Unable to load workload actions.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] })); return true; } if (message.type === messageTypes.requestCustomerServiceRequest) { requestCustomerServiceRequest(message).then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message || "Unable to load service requests.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] })); return true; } if (message.type === messageTypes.requestInstallBase) { requestInstallBase(message).then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message || "Unable to load installed base.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] })); return true; } if (message.type === messageTypes.requestAccountPlans) { requestAccountPlans(message) .then(sendResponse) .catch((error) => { sendResponse({ ok: false, error: error.message || "Unable to load account plans.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] }); }); return true; } if (message.type === messageTypes.requestRatecardByPlan) { requestRatecardByPlan(message).then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message || "Unable to load rate card.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] })); return true; } if (message.type === messageTypes.requestConsumptionPlanDetail) { requestConsumptionPlanDetail(message).then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message || "Unable to load consumption plan details.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] })); return true; } if (message.type === messageTypes.requestConsumptionTrend) { requestConsumptionTrend(message) .then(sendResponse) .catch((error) => { sendResponse({ ok: false, error: error.message || "Unable to load consumption trend.", debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : [] }); }); return true; } return false; }); } // Source: src/background/application.js function createBackgroundApplication(overrides = {}) { const environment = { fetch: globalThis.fetch, browser: globalThis.browser, chrome: globalThis.chrome, setTimeout: globalThis.setTimeout, ...overrides }; const messageTypes = createMessageTypes(); const spaCurrentUser = createSpaCurrentUser({ fetchJson: (...args) => httpBackgroundJson.fetchJson(...args) }); const requestCurrentUser = () => spaCurrentUser.requestCurrentUser(); const contracts = createBackgroundContracts(); const productsCacheState = createProductsCacheState(); const authConsumerSession = createAuthConsumerSession({ CUSTOMER_TOKEN_MAX_ATTEMPTS: contracts.CUSTOMER_TOKEN_MAX_ATTEMPTS, CUSTOMER_TOKEN_RETRY_BASE_DELAY_MS: contracts.CUSTOMER_TOKEN_RETRY_BASE_DELAY_MS, CUSTOMER_TOKEN_RETRY_MAX_DELAY_MS: contracts.CUSTOMER_TOKEN_RETRY_MAX_DELAY_MS, CUSTOMER_TOKEN_SERVICE_URL: contracts.CUSTOMER_TOKEN_SERVICE_URL, CUSTOMER_TOKEN_SESSION_URL: contracts.CUSTOMER_TOKEN_SESSION_URL, extractTokenServiceAuthorization: (...args) => authSpaCredentials.extractTokenServiceAuthorization(...args), fetchJson: (...args) => httpBackgroundJson.fetchJson(...args), supportsFirefoxCookieStoreTabs: (...args) => platformBackgroundApi.supportsFirefoxCookieStoreTabs(...args), tabsCreate: (...args) => platformBackgroundApi.tabsCreate(...args), tabsRemove: (...args) => platformBackgroundApi.tabsRemove(...args), wait: (...args) => platformBackgroundApi.wait(...args) }); const authSpaCredentials = createAuthSpaCredentials({ findNestedObject: (...args) => spaResponseShapes.findNestedObject(...args) }); const spaAccounts = createSpaAccounts({ ACCOUNT_PLANS_PAYLOAD: contracts.ACCOUNT_PLANS_PAYLOAD, ACCOUNT_PLANS_URL: contracts.ACCOUNT_PLANS_URL, ACCOUNT_SUMMARY_URL: contracts.ACCOUNT_SUMMARY_URL, extractAccountPlans: (...args) => spaResponseShapes.extractAccountPlans(...args), fetchJson: (...args) => httpBackgroundJson.fetchJson(...args), findAccountPlanId: (...args) => spaResponseShapes.findAccountPlanId(...args), normalizeMessageAuthorization: (...args) => authSpaCredentials.normalizeMessageAuthorization(...args) }); const spaInstallBase = createSpaInstallBase({ ACCOUNT_SUMMARY_URL: contracts.ACCOUNT_SUMMARY_URL, fetchJson: (...args) => httpBackgroundJson.fetchJson(...args), findNestedObject: (...args) => spaResponseShapes.findNestedObject(...args), normalizeMessageAuthorization: (...args) => authSpaCredentials.normalizeMessageAuthorization(...args) }); const spaCustomerServiceRequests = createSpaCustomerServiceRequests({ ACCOUNT_SUMMARY_URL: contracts.ACCOUNT_SUMMARY_URL, fetchJson: (...args) => httpBackgroundJson.fetchJson(...args), findAccountPlanId: (...args) => spaResponseShapes.findAccountPlanId(...args), normalizeMessageAuthorization: (...args) => authSpaCredentials.normalizeMessageAuthorization(...args) }); const spaConsumption = createSpaConsumption({ CONSUMPTION_TREND_REQUESTS: contracts.CONSUMPTION_TREND_REQUESTS, CONSUMPTION_TREND_URL: contracts.CONSUMPTION_TREND_URL, fetchJson: (...args) => httpBackgroundJson.fetchJson(...args), normalizeMessageAuthorization: (...args) => authSpaCredentials.normalizeMessageAuthorization(...args) }); const spaResponseShapes = createSpaResponseShapes(); const httpBackgroundJson = createHttpBackgroundJson({ previewDebugBody: createDebugBodyPreview, DEBUG_BODY_LIMIT: contracts.DEBUG_BODY_LIMIT, environment }); const productsBackgroundJobs = createProductsBackgroundJobs({ messageTypes, OPPTY_PRODUCTS_CONCURRENCY: contracts.OPPTY_PRODUCTS_CONCURRENCY, getOpptyProducts: (...args) => productsCache.getOpptyProducts(...args), normalizeCacheMaxAge: (...args) => productsCache.normalizeCacheMaxAge(...args), tabsSendMessage: (...args) => platformBackgroundApi.tabsSendMessage(...args) }); const productsCache = createProductsCache({ OPPTY_PRODUCTS_CACHE_KEY: contracts.OPPTY_PRODUCTS_CACHE_KEY, fetchAllOpptyProducts: (...args) => fusionProducts.fetchAllOpptyProducts(...args), productsCacheState, storageLocalGet: (...args) => platformBackgroundApi.storageLocalGet(...args), storageLocalSet: (...args) => platformBackgroundApi.storageLocalSet(...args) }); const fusionProducts = createFusionProducts({ createBackgroundDebugEntry: (...args) => httpBackgroundJson.createBackgroundDebugEntry(...args), completeBackgroundDebugEntry: (...args) => httpBackgroundJson.completeBackgroundDebugEntry(...args), createDebugBody: (...args) => httpBackgroundJson.createDebugBody(...args), headersToObject: (...args) => httpBackgroundJson.headersToObject(...args), OPPTY_PRODUCTS_FIELDS: contracts.OPPTY_PRODUCTS_FIELDS, OPPTY_PRODUCTS_MAX_PAGES: contracts.OPPTY_PRODUCTS_MAX_PAGES, OPPTY_PRODUCTS_PAGE_LIMIT: contracts.OPPTY_PRODUCTS_PAGE_LIMIT, ORACLE_DOMAIN: contracts.ORACLE_DOMAIN, environment }); const authXsrfRecovery = createAuthXsrfRecovery({ COOKIE_REFRESH_POLL_MS: contracts.COOKIE_REFRESH_POLL_MS, COOKIE_REFRESH_TIMEOUT_MS: contracts.COOKIE_REFRESH_TIMEOUT_MS, OPPORTUNITIES_LIST_URL: contracts.OPPORTUNITIES_LIST_URL, getXsrfTokenCookie: (...args) => authXsrfCookies.getXsrfTokenCookie(...args), supportsFirefoxCookieStoreTabs: (...args) => platformBackgroundApi.supportsFirefoxCookieStoreTabs(...args), tabsCreate: (...args) => platformBackgroundApi.tabsCreate(...args), tabsRemove: (...args) => platformBackgroundApi.tabsRemove(...args), wait: (...args) => platformBackgroundApi.wait(...args) }); const authXsrfCookies = createAuthXsrfCookies({ ORACLE_COOKIE_URLS: contracts.ORACLE_COOKIE_URLS, ORACLE_DOMAIN: contracts.ORACLE_DOMAIN, XSRF_COOKIE_NAME: contracts.XSRF_COOKIE_NAME, XSRF_COOKIE_PREFIX: contracts.XSRF_COOKIE_PREFIX, cookiesGet: (...args) => platformBackgroundApi.cookiesGet(...args), cookiesGetAll: (...args) => platformBackgroundApi.cookiesGetAll(...args), cookiesGetAllCookieStores: (...args) => platformBackgroundApi.cookiesGetAllCookieStores(...args), removeUndefinedValues: (...args) => platformBackgroundApi.removeUndefinedValues(...args) }); const platformBackgroundApi = createPlatformBackgroundApi({ runtimeApi: environment.browser || environment.chrome, environment }); const getXsrfTokenCookie = (...args) => authXsrfCookies.getXsrfTokenCookie(...args); const refreshXsrfCookie = (...args) => authXsrfRecovery.refreshXsrfCookie(...args); const requestAccountPlans = (...args) => spaAccounts.requestAccountPlans(...args); const requestInstallBase = (...args) => spaInstallBase.requestInstallBase(...args); const spaWorkloadActions = createSpaWorkloadActions({ fetchJson: (...args) => httpBackgroundJson.fetchJson(...args) }); const requestWlActions = (...args) => spaWorkloadActions.requestWlActions(...args); const spaActionOptions = createSpaActionOptions({ fetchJson: (...args) => httpBackgroundJson.fetchJson(...args) }); const requestActionTeamMembers = (...args) => spaActionOptions.requestActionTeamMembers(...args); const requestActionFindLookup = (...args) => spaActionOptions.requestActionFindLookup(...args); const requestCustomerServiceRequest = (...args) => spaCustomerServiceRequests.requestCustomerServiceRequest(...args); const requestConsumerTokenService = (...args) => authConsumerSession.requestConsumerTokenService(...args); const requestConsumptionTrend = (...args) => spaConsumption.requestConsumptionTrend(...args); const requestConsumptionPlanDetail = (...args) => spaConsumption.requestConsumptionPlanDetail(...args); const requestRatecardByPlan = (...args) => spaConsumption.requestRatecardByPlan(...args); const requestOpptyProducts = (...args) => productsBackgroundJobs.requestOpptyProducts(...args); const runtimeApi = environment.browser || environment.chrome; const fusionSrDetails = createFusionSrDetails({ fetchJson: (...args) => httpBackgroundJson.fetchJson(...args) }); function start() { startBackgroundApplication({ messageTypes, requestInternalServiceRequest: message => fusionSrDetails.requestInternalServiceRequest(message), requestMgmtAction: message => spaActionOptions.requestMgmtAction(message), invalidateProductsCache: () => productsCache.invalidate(), requestCurrentUser, getXsrfTokenCookie, refreshXsrfCookie, requestAccountPlans, requestInstallBase, requestCustomerServiceRequest, requestWlActions, requestActionTeamMembers, requestActionFindLookup, requestConsumerTokenService, requestConsumptionTrend, requestConsumptionPlanDetail, requestRatecardByPlan, requestOpptyProducts, runtimeApi }); } return { start, contracts, productsCacheState, authConsumerSession, authSpaCredentials, spaAccounts, spaInstallBase, spaCustomerServiceRequests, spaConsumption, spaResponseShapes, httpBackgroundJson, productsBackgroundJobs, productsCache, fusionProducts, authXsrfRecovery, authXsrfCookies, platformBackgroundApi }; } createBackgroundApplication().start(); })();