(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", requestSrLookupPrimaryPillar: "opportunitiesExtension.requestSrLookupPrimaryPillar", requestPostServiceRequest: "opportunitiesExtension.requestPostServiceRequest", requestPostInternalServiceRequest: "opportunitiesExtension.requestPostInternalServiceRequest", prepareSrSession: "opportunitiesExtension.prepareSrSession", requestSrLookupLanguage: "opportunitiesExtension.requestSrLookupLanguage", requestSrLookupTechPlatform: "opportunitiesExtension.requestSrLookupTechPlatform", requestLookupTypePlatform: "opportunitiesExtension.requestLookupTypePlatform", requestInternalSrServices: "opportunitiesExtension.requestInternalSrServices", requestSrLookupOpportunityBusiness: "opportunitiesExtension.requestSrLookupOpportunityBusiness", requestCurrentUser: "opportunitiesExtension.requestCurrentUser", invalidateProductsCache: "opportunitiesExtension.invalidateProductsCache", requestConsumptionTrend: "opportunitiesExtension.requestConsumptionTrend", requestConsumptionPlanDetail: "opportunitiesExtension.requestConsumptionPlanDetail", requestRatecardByPlan: "opportunitiesExtension.requestRatecardByPlan" }); } // Source: src/shared/debug-body.js function createDebugBodyPreview(text) { return { value: text || "(empty response body)", truncated: false }; } // 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/auth/sr-request-headers.js function createSrRequestHeaders({ runtimeApi }) { const origin = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com"; const appPath = "/ic/builder/rt/SeaaS_initiation/"; const internalPath = "/ic/builder/rt/SeaaS_SR_management/live;profile=PROD/services/auth/1.1/proxy/oalsetCRMRestAPICloudAccount/uri/https/eeho.fa.us2.oraclecloud.com/crmRestApi/resources/latest/serviceRequests"; const storageKey = "opportunitiesExtension.srAppBuilderClientId.v1"; const maxAge = 60 * 60 * 1000; let observed = null; let started = false; function valid(record) { return record?.origin === origin && typeof record.value === "string" && /^[\x21-\x7e]{1,2048}$/.test(record.value) && Number.isFinite(record.observedAt) && record.observedAt <= Date.now() && Date.now() - record.observedAt < maxAge; } function observeHeaders(rawUrl, headers) { let url; try { url = new URL(rawUrl); } catch { return; } if (url.origin !== origin || !/^\/ic\/builder\/rt\/(?:SeaaS_initiation|SeaaS_SR_management)\/live(?:\/|;)/.test(url.pathname)) return; // Read only the client ID, not cookies, bodies or authorization. const value = typeof headers?.get === "function" ? headers.get("x-appbuilder-client-id") : headers?.find(item => item.name.toLowerCase() === "x-appbuilder-client-id")?.value; const record = { origin, value: value?.trim(), observedAt: Date.now() }; if (!valid(record)) return; observed = record; // Session storage survives service-worker suspension without persisting across browser sessions. runtimeApi.storage?.session?.set({ [storageKey]: record }).catch(() => {}); } function start() { if (started || !runtimeApi?.webRequest) return; started = true; const filter = { urls: [`${origin}${appPath}*`, `${origin}/ic/builder/rt/SeaaS_SR_management/*`], types: ["xmlhttprequest"] }; runtimeApi.webRequest.onBeforeSendHeaders?.addListener(details => { if (details.tabId >= 0 && !details.incognito) observeHeaders(details.url, details.requestHeaders); }, filter, ["requestHeaders"]); runtimeApi.webRequest.onHeadersReceived?.addListener(details => { if (!details.incognito) observeHeaders(details.url, details.responseHeaders); }, filter, ["responseHeaders"]); } async function previewTokenHeaders(url) { const target = new URL(url); if (target.origin !== origin || !target.pathname.startsWith(appPath) || !/\/Catalogue_c(?:\/\d+)?$/.test(target.pathname)) { throw new Error("Unexpected Service Request token URL."); } return sessionHeaders(target.origin, "application/vnd.oracle.adf.action+json"); } async function sessionHeaders(targetOrigin, contentType) { if (!valid(observed)) { try { const stored = await runtimeApi.storage?.session?.get(storageKey); if (valid(stored?.[storageKey]) && !valid(observed)) observed = stored[storageKey]; } catch { /* A missing capture must not prevent trying the other required headers. */ } } return { Accept: "application/json", "Content-Type": contentType, Authorization: "Session", Origin: targetOrigin, ...(valid(observed) ? { "x-appbuilder-client-id": observed.value } : {}) }; } async function tokenHeaders(url, serviceRequestUrl) { const headers = await previewTokenHeaders(url); if (!/\/Catalogue_c\/\d+$/.test(new URL(url).pathname)) throw new Error("Missing Catalogue Id."); const serviceTarget = new URL(serviceRequestUrl); const isServiceRequest = serviceTarget.pathname.startsWith(appPath) && serviceTarget.pathname.endsWith("/set/seaas/mgmt/serviceRequests"); if (serviceTarget.origin !== headers.Origin || !isServiceRequest || serviceTarget.search || serviceTarget.hash) { throw new Error("Unexpected Service Request URL."); } if (!runtimeApi?.declarativeNetRequest?.updateSessionRules || !runtimeApi.runtime?.getURL) { throw new Error("Reload the extension to enable the Service Request token header permissions."); } const extensionDomain = new URL(runtimeApi.runtime.getURL("/")).hostname; const catalogUrl = url.slice(0, url.lastIndexOf("/") + 1); const escapedCatalogUrl = catalogUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const escapedServiceUrl = serviceTarget.href.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const ruleIds = [7201, 7202]; await runtimeApi.declarativeNetRequest.updateSessionRules({ removeRuleIds: ruleIds, addRules: [`^${escapedCatalogUrl}[0-9]+$`, `^${escapedServiceUrl}$`].map((regexFilter, index) => ({ id: ruleIds[index], priority: 1, action: { type: "modifyHeaders", requestHeaders: [{ header: "Origin", operation: "set", value: headers.Origin }] }, condition: { regexFilter, initiatorDomains: [extensionDomain], requestMethods: ["post"], resourceTypes: ["xmlhttprequest"] } })) }); return headers; } async function internalServiceRequestHeaders(url) { const target = new URL(url); if (target.origin !== origin || target.pathname !== internalPath || target.search || target.hash) { throw new Error("Unexpected Internal Service Request URL."); } if (!runtimeApi?.declarativeNetRequest?.updateSessionRules || !runtimeApi.runtime?.getURL) { throw new Error("Reload the extension to enable the Internal Service Request header permissions."); } const headers = await sessionHeaders(target.origin, "application/json"); const extensionDomain = new URL(runtimeApi.runtime.getURL("/")).hostname; const escapedUrl = target.href.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); await runtimeApi.declarativeNetRequest.updateSessionRules({ removeRuleIds: [7203], addRules: [{ id: 7203, priority: 1, action: { type: "modifyHeaders", requestHeaders: [{ header: "Origin", operation: "set", value: headers.Origin }] }, condition: { regexFilter: `^${escapedUrl}$`, initiatorDomains: [extensionDomain], requestMethods: ["post"], resourceTypes: ["xmlhttprequest"] } }] }); return headers; } return { start, tokenHeaders, previewTokenHeaders, internalServiceRequestHeaders, observeResponseHeaders: observeHeaders }; } // 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, tabsCreate, tabsRemove, supportsFirefoxCookieStoreTabs, cookiesGetAll, cookieChanges, wait }) { const sessions = new Map(); function cookiePart(cookie) { if (!cookie) return null; const match = /^ORA_OCIS_CG_SESSION_idcs-([a-zA-Z0-9-]+)_comcipapic-oalprod\.integration\.ocp\.oraclecloud\.com_([12])$/.exec(cookie.name); const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com"; const cookieDomain = cookie.domain?.replace(/^\./, ""); if (!match || (cookieDomain && cookieDomain !== domain && !domain.endsWith(`.${cookieDomain}`))) return null; return { key: `${match[1]}|${cookie.path || "/"}|${cookie.storeId || ""}`, part: match[2], valid: Boolean(cookie.value) && (cookie.expirationDate == null || cookie.expirationDate > Date.now() / 1000) }; } function watchSession(session, sender) { const pairs = new Map(); let available; session.cookieReady = new Promise(resolve => { available = resolve; }); const listener = change => { const cookie = change.cookie; const part = cookiePart(cookie); if (!part) return; if (sender?.tab?.cookieStoreId && cookie.storeId !== sender.tab.cookieStoreId) return; if (!pairs.has(part.key)) pairs.set(part.key, new Map()); const pair = pairs.get(part.key); if (change.removed || !part.valid) pair.delete(part.part); else pair.set(part.part, cookie); if (pair.size === 2 && [...pair.values()].every(item => cookiePart(item)?.valid)) available(new Set([part.key])); session.wake?.(); }; cookieChanges?.addListener(listener); session.unwatch = () => cookieChanges?.removeListener(listener); } function waitForSessionCookies(session, sender) { if (session.cookieWait) return session.cookieWait; session.cookieWait = (async () => { const deadline = Date.now() + 1000; for (let attempt = 0; attempt < 5; attempt += 1) { // Install the wake-up before reading so a renewal during getAll is not missed. const changed = new Promise(resolve => { session.wake = resolve; }); const current = await sessionCookies(sender); const renewed = [...current].some(pair => !session.baseline.has(pair)); if (renewed || Date.now() >= deadline) { session.baseline = current; return current; } await Promise.race([changed, wait(250)]); } return sessionCookies(sender); })().finally(() => { session.cookieWait = null; session.wake = null; }); return session.cookieWait; } async function sessionCookies(sender) { const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com"; const details = { domain }; if (sender?.tab?.cookieStoreId) details.storeId = sender.tab.cookieStoreId; try { const groups = new Map(); for (const cookie of await cookiesGetAll(details)) { const part = cookiePart(cookie); if (!part?.valid) continue; if (!groups.has(part.key)) groups.set(part.key, {}); groups.get(part.key)[part.part] = [cookie.name, cookie.value, cookie.expirationDate ?? null]; } // Fingerprints remain in memory only; the browser sends the actual Cookie header. return new Set([...groups.values()].filter(pair => pair[1] && pair[2]).map(pair => JSON.stringify([pair[1], pair[2]]))); } catch { return new Set(); } } async function requestLookupWithSession(operation, message, sender, initialize = false) { const existingCookies = initialize ? await sessionCookies(sender) : null; if (existingCookies?.size) return { ok: true, debugRequests: [] }; const logs = []; const query = async () => { try { const result = await operation(message); logs.push(...(result.debugRequests || [])); return { ...result, debugRequests: logs }; } catch (error) { logs.push(...(error.debugRequests || [])); error.debugRequests = logs; throw error; } }; if (!initialize) { try { return await query(); } catch (error) { if (error.httpStatus !== 401) throw error; } } const key = sender?.tab?.cookieStoreId || "default"; let session = sessions.get(key); if (!session) { const details = { url: "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live/webApps/external/", active: false }; if (Number.isInteger(sender?.tab?.windowId)) details.windowId = sender.tab.windowId; if (supportsFirefoxCookieStoreTabs() && sender?.tab?.cookieStoreId) details.cookieStoreId = sender.tab.cookieStoreId; session = { users: 0, closed: null, baseline: null }; watchSession(session, sender); session.tab = (async () => { session.baseline = existingCookies || await sessionCookies(sender); return tabsCreate(details); })(); sessions.set(key, session); } session.users += 1; let tab; try { tab = await session.tab; const deadline = Date.now() + 60000; for (let attempt = 0; attempt < 240 && Date.now() < deadline; attempt += 1) { const pendingCookies = initialize && attempt === 0 ? sessionCookies(sender) : waitForSessionCookies(session, sender); const cookies = await (initialize ? Promise.race([session.cookieReady, pendingCookies]) : pendingCookies); if (initialize) { // Proactive preparation observes cookies only; API requests belong to the form. if (!cookies.size) continue; await closeSessionTab(); return { ok: true, debugRequests: [] }; } try { const result = await query(); // Any successful lookup confirms the shared session; stop the page immediately. await closeSessionTab(); return result; } catch (error) { if (error.httpStatus !== 401) throw error; } } throw new Error("Service Request session could not be established after 60 seconds. Sign in to Oracle and retry."); } catch (error) { error.debugRequests = logs; throw error; } finally { session.users -= 1; if (session.users === 0) { sessions.delete(key); session.unwatch(); await closeSessionTab(); } } function closeSessionTab() { if (!session.closed && Number.isInteger(tab?.id)) { session.closed = tabsRemove(tab.id).catch(() => {}); } return session.closed; } } 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 query = async () => { 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."); return result; }; const result = await query(); 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; } } async function requestLookup(lookupType, requestName) { const debugRequests = []; try { const url = `https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live;profile=PROD/services/auth/1.1/proxy/oke_seaas/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/crm/lookups?lookupType=${lookupType}&type=STANDARD`; const result = await fetchJson(url, { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: "Session" } }, requestName, debugRequests); if (!Array.isArray(result?.items) || result.items.some(item => typeof item?.code !== "string" || typeof item?.name !== "string")) throw new Error(`Invalid ${requestName} response.`); const items = result.items.filter(item => item.enabledFlag !== "N") .sort((a, b) => (Number(a.displaySequence) || 0) - (Number(b.displaySequence) || 0)) .map(({ code, name }) => ({ code, name })); return { ok: true, items, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } async function requestSrLookupOpportunityBusiness(message) { const debugRequests = []; try { if (typeof message.emailAddress !== "string" || !message.emailAddress.trim()) throw new Error("Current user email is unavailable."); const url = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live;profile=PROD/services/auth/1.1/proxy/oke_seaas/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/crm/services" + `?emailAddress=${encodeURIComponent(message.emailAddress.trim())}&salesObject=OPPORTUNITY&serviceType=BUSINESS`; const result = await fetchJson(url, { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: "Session" } }, "requestSrLookupOpportunityBusiness", debugRequests); if (!Array.isArray(result?.items) || result.items.some(item => !/^\d+$/.test(String(item?.Id ?? "")) || typeof item?.RecordName !== "string")) throw new Error("Invalid Services response."); return { ok: true, items: result.items.map(({ Id, RecordName, Abstract_c }) => ({ Id: String(Id), RecordName, Abstract_c: Abstract_c == null ? "" : String(Abstract_c) })), debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } async function requestInternalSrOptions(message, services = false) { const debugRequests = []; const name = services ? "requestInternalSrServices" : "requestLookupTypePlatform"; try { const base = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_SR_management/live;profile=PROD/services/auth/1.1/proxy/oalsetSeaaSOKECustomRestAPI/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/crm/"; let path = "lookups?type=STANDARD&lookupType=SENGG_TECH_PLATFORM"; if (services) { const id = String(message.parentServiceId ?? ""); if (!/^\d+$/.test(id)) throw new Error("A numeric parent SrId is required."); if (typeof message.emailAddress !== "string" || !message.emailAddress.trim()) throw new Error("Current user email is unavailable."); path = `services?emailAddress=${encodeURIComponent(message.emailAddress.trim())}&parentServiceId=${encodeURIComponent(id)}&serviceType=INTERNAL`; } const result = await fetchJson(base + path, { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: "Session" } }, name, debugRequests); if (!Array.isArray(result?.items) || result.items.some(item => services ? !/^\d+$/.test(String(item?.Id ?? "")) || typeof item?.RecordName !== "string" : typeof item?.code !== "string" || typeof item?.name !== "string")) throw new Error(`Invalid ${name} response.`); const items = services ? result.items.map(item => ({ Id: String(item.Id), RecordName: item.RecordName, Description_c: String(item.Description_c ?? "") })) : result.items.filter(item => item.enabledFlag !== "N").map(({ code, name }) => ({ code, name })); return { ok: true, items, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } return { requestLookupWithSession, requestInternalServiceRequest, requestSrLookupOpportunityBusiness, requestLookupTypePlatform: () => requestInternalSrOptions({}), requestInternalSrServices: message => requestInternalSrOptions(message, true), prepareSession: sender => requestLookupWithSession(null, {}, sender, true), requestSrLookupPrimaryPillar: () => requestLookup("SENGG_PRIMARY_PILLAR", "requestSrLookupPrimaryPillar"), requestSrLookupLanguage: () => requestLookup("SENGG_LANGUAGE", "requestSrLookupLanguage"), requestSrLookupTechPlatform: () => requestLookup("SENGG_TECH_PLATFORM", "requestSrLookupTechPlatform") }; } // Source: src/services/fusion/sr-create.js function createFusionSrCreate({ fetchJson, tokenHeaders, previewTokenHeaders, internalServiceRequestHeaders }) { const base = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live;profile=PROD/services/auth/1.1/proxy/"; const catalog = base + "crmRestApiResources/uri/https/eeho.fa.us2.oraclecloud.com/crmRestApi/resources/11.13.18.05/Catalogue_c"; const resourceUsers = base + "oke_seaas/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/crm/resourceUsers"; const endpoint = base + "oke_seaas/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/mgmt/serviceRequests"; function numericId(value, name) { if (!/^\d+$/.test(String(value ?? "")) || !Number.isSafeInteger(Number(value)) || Number(value) <= 0) throw new Error(`Missing or invalid ${name}.`); return Number(value); } function text(value, name) { if (typeof value !== "string" || !value.trim()) throw new Error(`Missing ${name}.`); return value.trim(); } function dateOnly(value, name) { const date = text(value, name); if (!/^\d{4}-\d{2}-\d{2}$/.test(date) || !Number.isFinite(Date.parse(`${date}T00:00:00Z`)) || new Date(`${date}T00:00:00Z`).toISOString().slice(0, 10) !== date) throw new Error(`Invalid ${name}.`); return date; } function payloadFor(input) { const payload = {}; for (const name of ["AccountPartyId", "OpportunityName_Id_c", "ServiceNew_Id_c"]) payload[name] = numericId(input?.[name], name); for (const name of ["Title", "RegionText_c", "ProblemDescription", "Language_c", "CustomerDeadline_c", "TechPlatformLookUp_c", "CountryText_c", "PrimaryPillarNew_c"]) payload[name] = text(input?.[name], name); dateOnly(payload.CustomerDeadline_c, "Customer deadline"); return { ...payload, SvcQuestionsCollection_c: [], SourceCd: "SVC_OPPORTUNITY_SCREEN", SeverityCd: "ORA_SVC_SEV2", ChannelTypeCd: "ORA_SVC_WEB" }; } async function requestResourceUser(email, debugRequests) { const emailAddress = text(email, "current user email"); const resource = await fetchJson(`${resourceUsers}?emailAddress=${encodeURIComponent(emailAddress)}`, { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: "Session" } }, "requestResourceUser", debugRequests); return numericId(resource?.resourcePartyId, "resourcePartyId"); } async function requestPostInternalServiceRequest(message) { const debugRequests = []; try { const source = message.payload; const parentSrId = numericId(source?.ServiceRequest_Id_SRToInternalSR, "parent SrId"); const payload = { Title: text(source?.Title, "Title"), ServiceNew_Id_c: numericId(source?.ServiceNew_Id_c, "ServiceNew_Id_c"), ProblemDescription: text(source?.ProblemDescription, "Description"), CustomerDeadline_c: dateOnly(source?.CustomerDeadline_c, "Customer deadline"), TechPlatformLookUp_c: text(source?.TechPlatformLookUp_c, "Platform"), InternalDeadline_c: `${dateOnly(source?.InternalDeadline_c, "Internal Deadline")}T00:00:00.000Z`, SvcQuestionsCollection_c: [] }; const parent = await requestSRInfo(parentSrId, debugRequests); payload.ServiceRequest_Id_SRToInternalSR = String(parentSrId); for (const name of ["AccountPartyId", "OpportunityName_Id_c"]) payload[name] = numericId(parent[name], name); for (const name of ["OpportunityName_c", "RegionText_c", "SvcHealth_c", "Language_c", "CountryText_c", "PrimaryPillarNew_c"]) payload[name] = text(parent[name], name); payload.SecondaryPillarNew_c = parent.SecondaryPillarNew_c == null ? null : text(parent.SecondaryPillarNew_c, "SecondaryPillarNew_c"); payload.ReportedByPartyId = await requestResourceUser(message.emailAddress, debugRequests); const url = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_SR_management/live;profile=PROD/services/auth/1.1/proxy/oalsetCRMRestAPICloudAccount/uri/https/eeho.fa.us2.oraclecloud.com/crmRestApi/resources/latest/serviceRequests"; const result = await fetchJson(url, { method: "POST", credentials: "include", headers: await internalServiceRequestHeaders(url), body: JSON.stringify(payload) }, "requestPostInternalServiceRequest", debugRequests, { allowEmpty: true }); return { ok: true, result, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } async function requestSRInfo(parentSrId, debugRequests) { const url = new 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"); url.searchParams.set("fields", "PrimaryPillarNew_c,SecondaryPillarNew_c,SvcHealth_c,SrNumber,AccountPartyId,CountryText_c,Language_c,OpportunityName_Id_c,OpportunityName_c,RegionText_c,ServiceNew_Id_c"); url.searchParams.set("onlyData", "true"); url.searchParams.set("orderBy", "LastUpdateDate:desc"); url.searchParams.set("q", `SrId=${parentSrId}`); const result = await fetchJson(url.href, { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: "Session" } }, "requestSRInfo", debugRequests); if (!Array.isArray(result?.items) || result.items.length !== 1 || !result.items[0] || (result.items[0].SrId != null && String(result.items[0].SrId) !== String(parentSrId))) { throw new Error("requestSRInfo did not return the selected parent Service Request."); } return result.items[0]; } async function requestPostServiceRequest(message) { const debugRequests = []; try { if (message.phase !== "prepare" && message.phase !== "confirm") throw new Error("Service Request confirmation is required."); const payload = payloadFor(message.payload); if (message.phase === "prepare") { payload.ReportedByPartyId = await requestResourceUser(message.emailAddress, debugRequests); const sharedHeaders = await previewTokenHeaders(catalog); return { ok: true, payload, debugRequests, headers: { requestSrTokenCatalog: sharedHeaders, requestPostServiceRequest: { ...sharedHeaders, "vb-proxy-header-x-oracle-ectoken": "(generated after confirmation)" } } }; } payload.ReportedByPartyId = numericId(message.payload?.ReportedByPartyId, "ReportedByPartyId"); const headers = await requestCreationHeaders(message.catalogId, endpoint, debugRequests); const result = await fetchJson(endpoint, { method: "POST", credentials: "include", headers, body: JSON.stringify(payload) }, "requestPostServiceRequest", debugRequests, { allowEmpty: true }); return { ok: true, result, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } finally { annotateSigningRequest(debugRequests); } } async function requestCreationHeaders(id, target, debugRequests) { if (id == null) { const result = await fetchJson(`${catalog}?onlyData=true&fields=Id&limit=1`, { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: "Session" } }, "requestSrCatalog", debugRequests); id = result?.items?.[0]?.Id; } id = numericId(id, "Catalogue Id"); const tokenUrl = `${catalog}/${id}`; let catalogHeaders = await tokenHeaders(tokenUrl, target); const requestToken = () => fetchJson(tokenUrl, { method: "POST", credentials: "include", headers: catalogHeaders, body: JSON.stringify({ name: "getJwtToken" }) }, "requestSrTokenCatalog", debugRequests); let token; try { token = await requestToken(); } catch (error) { if (error.httpStatus !== 403) throw error; const refreshed = await previewTokenHeaders(tokenUrl); if (!refreshed["x-appbuilder-client-id"] || refreshed["x-appbuilder-client-id"] === catalogHeaders["x-appbuilder-client-id"]) throw error; catalogHeaders = refreshed; token = await requestToken(); } if (debugRequests.at(-1)?.httpStatus !== 200 || typeof token?.result !== "string" || !token.result.trim()) { throw new Error("requestSrTokenCatalog did not return HTTP 200 with a token."); } return { ...catalogHeaders, "vb-proxy-header-x-oracle-ectoken": token.result.trim() }; } function annotateSigningRequest(debugRequests) { for (const entry of debugRequests) { if (entry.name === "requestSrTokenCatalog") { entry.metadata.appBuilderClientId = entry.requestHeaders?.["x-appbuilder-client-id"] ? "Observed in SeaaS requests" : "Not observed in SeaaS requests"; } } } return { requestPostServiceRequest, requestPostInternalServiceRequest }; } // 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; } } 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, observeResponseHeaders = () => {}, 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; } observeResponseHeaders(response.url || url, response.headers); 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); } 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, requestPostServiceRequest, requestPostInternalServiceRequest, requestInternalServiceRequest, requestSrLookupPrimaryPillar, requestSrLookupWithSession, prepareSrSession, requestSrLookupLanguage, requestSrLookupTechPlatform, requestLookupTypePlatform, requestInternalSrServices, requestSrLookupOpportunityBusiness, requestCurrentUser, requestConsumerTokenService, requestConsumptionTrend, requestConsumptionPlanDetail, requestRatecardByPlan, requestOpptyProducts, runtimeApi }) { runtimeApi.runtime.onMessage.addListener((message, sender, sendResponse) => { if (!message || !message.type) { return false; } if (message.type === messageTypes.requestPostInternalServiceRequest) { requestPostInternalServiceRequest(message).then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message, debugRequests: error.debugRequests || [] })); return true; } if (message.type === messageTypes.requestPostServiceRequest) { requestPostServiceRequest(message).then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message, debugRequests: error.debugRequests || [] })); return true; } if (message.type === messageTypes.prepareSrSession) { prepareSrSession(sender).then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message, debugRequests: error.debugRequests || [] })); return true; } const srLookups = { [messageTypes.requestLookupTypePlatform]: requestLookupTypePlatform, [messageTypes.requestInternalSrServices]: requestInternalSrServices, [messageTypes.requestSrLookupPrimaryPillar]: requestSrLookupPrimaryPillar, [messageTypes.requestSrLookupLanguage]: requestSrLookupLanguage, [messageTypes.requestSrLookupTechPlatform]: requestSrLookupTechPlatform, [messageTypes.requestSrLookupOpportunityBusiness]: requestSrLookupOpportunityBusiness }; if (Object.hasOwn(srLookups, message.type)) { requestSrLookupWithSession(srLookups[message.type], message, sender).then(sendResponse).catch(error => sendResponse({ ok: false, httpStatus: error.httpStatus, error: error.message, debugRequests: error.debugRequests || [] })); return true; } 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, sender).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({ observeResponseHeaders: (...args) => srRequestHeaders.observeResponseHeaders(...args), previewDebugBody: createDebugBodyPreview, 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 srRequestHeaders = createSrRequestHeaders({ runtimeApi }); const fusionSrCreate = createFusionSrCreate({ fetchJson: (...args) => httpBackgroundJson.fetchJson(...args), tokenHeaders: (...args) => srRequestHeaders.tokenHeaders(...args), internalServiceRequestHeaders: url => srRequestHeaders.internalServiceRequestHeaders(url), previewTokenHeaders: url => srRequestHeaders.previewTokenHeaders(url) }); const fusionSrDetails = createFusionSrDetails({ cookieChanges: runtimeApi?.cookies?.onChanged, cookiesGetAll: (...args) => platformBackgroundApi.cookiesGetAll(...args), tabsCreate: (...args) => platformBackgroundApi.tabsCreate(...args), tabsRemove: (...args) => platformBackgroundApi.tabsRemove(...args), supportsFirefoxCookieStoreTabs: () => platformBackgroundApi.supportsFirefoxCookieStoreTabs(), wait: (...args) => platformBackgroundApi.wait(...args), fetchJson: (...args) => httpBackgroundJson.fetchJson(...args) }); function start() { srRequestHeaders.start(); startBackgroundApplication({ requestLookupTypePlatform: () => fusionSrDetails.requestLookupTypePlatform(), requestPostInternalServiceRequest: message => fusionSrCreate.requestPostInternalServiceRequest(message), requestInternalSrServices: message => fusionSrDetails.requestInternalSrServices(message), requestPostServiceRequest: message => fusionSrCreate.requestPostServiceRequest(message), prepareSrSession: sender => fusionSrDetails.prepareSession(sender), requestSrLookupWithSession: (...args) => fusionSrDetails.requestLookupWithSession(...args), messageTypes, requestSrLookupLanguage: () => fusionSrDetails.requestSrLookupLanguage(), requestSrLookupTechPlatform: () => fusionSrDetails.requestSrLookupTechPlatform(), requestSrLookupOpportunityBusiness: message => fusionSrDetails.requestSrLookupOpportunityBusiness(message), requestSrLookupPrimaryPillar: () => fusionSrDetails.requestSrLookupPrimaryPillar(), requestInternalServiceRequest: (message, sender) => fusionSrDetails.requestInternalServiceRequest(message, sender), 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(); })();