@nuvlore/extension-access-okta-slack 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +52 -0
  3. package/package.json +64 -0
  4. package/src/slackApi.mjs +68 -0
  5. package/src/slackBotChat.mjs +129 -0
  6. package/src/slackBotRead.mjs +106 -0
  7. package/src/slackCanvasCreate.mjs +165 -0
  8. package/src/slackConfig.mjs +18 -0
  9. package/src/slackMessageSend.mjs +71 -0
  10. package/src/slackSearch.mjs +103 -0
  11. package/src/slackSessionRead.mjs +200 -0
  12. package/src/slackSyncExport.mjs +346 -0
  13. package/src/slackSyncPaths.mjs +47 -0
  14. package/src/slackSyncState.mjs +35 -0
  15. package/tools/okta_slack_okta_read.mjs +41 -0
  16. package/tools/okta_slack_okta_verify.mjs +26 -0
  17. package/tools/slack_okta_ai_capabilities.mjs +26 -0
  18. package/tools/slack_okta_bot_ask.mjs +42 -0
  19. package/tools/slack_okta_bot_history.mjs +32 -0
  20. package/tools/slack_okta_create_canvas.mjs +38 -0
  21. package/tools/slack_okta_search_all.mjs +33 -0
  22. package/tools/slack_okta_search_messages.mjs +34 -0
  23. package/tools/slack_okta_send_message.mjs +42 -0
  24. package/tools/slack_okta_sync_all.mjs +35 -0
  25. package/tools/slack_okta_sync_status.mjs +26 -0
  26. package/vendor/extension-sso/LICENSE +202 -0
  27. package/vendor/extension-sso/README.md +35 -0
  28. package/vendor/extension-sso/commands/okta-login.md +10 -0
  29. package/vendor/extension-sso/package.json +53 -0
  30. package/vendor/extension-sso/skills/workday-okta-auth/SKILL.md +20 -0
  31. package/vendor/extension-sso/src/autoAuth.mjs +25 -0
  32. package/vendor/extension-sso/src/browserLogin.mjs +1 -0
  33. package/vendor/extension-sso/src/chromeCookies.mjs +1 -0
  34. package/vendor/extension-sso/src/cookieJar.mjs +1 -0
  35. package/vendor/extension-sso/src/extensionAccess.mjs +173 -0
  36. package/vendor/extension-sso/src/htmlSessionExtract.mjs +1 -0
  37. package/vendor/extension-sso/src/oktaAppAccess.mjs +133 -0
  38. package/vendor/extension-sso/src/oktaAppCatalog.mjs +118 -0
  39. package/vendor/extension-sso/src/oktaAppRead.mjs +119 -0
  40. package/vendor/extension-sso/src/oktaConfig.mjs +12 -0
  41. package/vendor/extension-sso/src/oktaSession.mjs +32 -0
  42. package/vendor/extension-sso/src/serviceOperations.mjs +407 -0
  43. package/vendor/extension-sso/src/serviceReadSearch.mjs +395 -0
  44. package/vendor/extension-sso/src/serviceReads.mjs +109 -0
  45. package/vendor/extension-sso/src/serviceRegistry.mjs +497 -0
  46. package/vendor/extension-sso/src/sessionAuth.mjs +339 -0
  47. package/vendor/extension-sso/src/sessionManager.mjs +212 -0
  48. package/vendor/extension-sso/src/sessionValidate.mjs +74 -0
  49. package/vendor/extension-sso/src/ssoConfig.mjs +31 -0
  50. package/vendor/extension-sso/src/ssoHttpRead.mjs +292 -0
  51. package/vendor/extension-sso/tools/extension-access-tools.shared.mjs +16 -0
  52. package/vendor/extension-sso/tools/okta-app-tools.shared.mjs +5 -0
  53. package/vendor/extension-sso/tools/okta-tools.shared.mjs +18 -0
  54. package/vendor/extension-sso/tools/workday_extension_read.mjs +51 -0
  55. package/vendor/extension-sso/tools/workday_extension_read_access.mjs +65 -0
  56. package/vendor/extension-sso/tools/workday_list_extension_access.mjs +39 -0
  57. package/vendor/extension-sso/tools/workday_list_okta_apps.mjs +18 -0
  58. package/vendor/extension-sso/tools/workday_list_service_operations.mjs +41 -0
  59. package/vendor/extension-sso/tools/workday_list_service_read_search_capabilities.mjs +34 -0
  60. package/vendor/extension-sso/tools/workday_list_services.mjs +31 -0
  61. package/vendor/extension-sso/tools/workday_okta_app_probe_all.mjs +24 -0
  62. package/vendor/extension-sso/tools/workday_okta_app_read.mjs +30 -0
  63. package/vendor/extension-sso/tools/workday_okta_app_read_access.mjs +25 -0
  64. package/vendor/extension-sso/tools/workday_okta_auth_header.mjs +58 -0
  65. package/vendor/extension-sso/tools/workday_okta_login.mjs +65 -0
  66. package/vendor/extension-sso/tools/workday_okta_open_app.mjs +63 -0
  67. package/vendor/extension-sso/tools/workday_okta_open_service.mjs +63 -0
  68. package/vendor/extension-sso/tools/workday_okta_status.mjs +35 -0
  69. package/vendor/extension-sso/tools/workday_service_auth.mjs +65 -0
  70. package/vendor/extension-sso/tools/workday_service_operation_read.mjs +51 -0
  71. package/vendor/extension-sso/tools/workday_service_read.mjs +56 -0
  72. package/vendor/extension-sso/tools/workday_service_search.mjs +62 -0
  73. package/vendor/extension-sso/tools/workday_sso_cookie_header.mjs +59 -0
  74. package/vendor/extension-sso/vendor/extension-browser-sso/LICENSE +202 -0
  75. package/vendor/extension-sso/vendor/extension-browser-sso/README.md +16 -0
  76. package/vendor/extension-sso/vendor/extension-browser-sso/package.json +47 -0
  77. package/vendor/extension-sso/vendor/extension-browser-sso/src/autoAuth.mjs +47 -0
  78. package/vendor/extension-sso/vendor/extension-browser-sso/src/browserHttpRead.mjs +76 -0
  79. package/vendor/extension-sso/vendor/extension-browser-sso/src/browserLogin.mjs +24 -0
  80. package/vendor/extension-sso/vendor/extension-browser-sso/src/chromeCookies.mjs +192 -0
  81. package/vendor/extension-sso/vendor/extension-browser-sso/src/cookieJar.mjs +132 -0
  82. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/devops-data-paths.mjs +222 -0
  83. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/devops-diagnostics.mjs +440 -0
  84. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/enterprise-api-read.mjs +180 -0
  85. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-command-pack.mjs +1 -0
  86. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-plan.mjs +45 -0
  87. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-shell-policy.d.mts +26 -0
  88. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-shell-policy.mjs +170 -0
  89. package/vendor/extension-sso/vendor/extension-browser-sso/src/htmlSessionExtract.mjs +64 -0
  90. package/vendor/extension-sso/vendor/extension-read-only-toolkit/LICENSE +202 -0
  91. package/vendor/extension-sso/vendor/extension-read-only-toolkit/README.md +29 -0
  92. package/vendor/extension-sso/vendor/extension-read-only-toolkit/package.json +43 -0
  93. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/devops-data-paths.mjs +222 -0
  94. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/devops-diagnostics.mjs +440 -0
  95. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/enterprise-api-read.mjs +180 -0
  96. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-command-pack.mjs +1 -0
  97. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-plan.mjs +45 -0
  98. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.d.mts +26 -0
  99. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.mjs +170 -0
@@ -0,0 +1,173 @@
1
+ import { buildRequestUrl, normalizeBaseUrl, parseResponseBody } from "@nuvlore/extension-read-only-toolkit/enterprise-api-read";
2
+ import { assertNonHtmlApiResponse } from "@nuvlore/extension-read-only-toolkit/devops-diagnostics";
3
+ import { resolveAutoAuthOptions } from "./autoAuth.mjs";
4
+ import { getServiceCookieHeader } from "./sessionAuth.mjs";
5
+ import { getSsoConfig } from "./ssoConfig.mjs";
6
+ import { getRequiredServices, getWorkdayService, listWorkdayServices } from "./serviceRegistry.mjs";
7
+ import { ssoReadGet } from "./ssoHttpRead.mjs";
8
+ import { oktaAppReadGet } from "./oktaAppAccess.mjs";
9
+
10
+ export function assertReadOnlyHttpRequest({ method = "GET", path = "" } = {}) {
11
+ const normalizedMethod = String(method).toUpperCase();
12
+ if (normalizedMethod !== "GET") {
13
+ throw new Error(`Read-only product: HTTP method ${normalizedMethod} is not allowed. Use GET only.`);
14
+ }
15
+ const rawPath = String(path || "");
16
+ if (/^https?:\/\//i.test(rawPath)) {
17
+ throw new Error("Read-only extension access: use restPath relative to defaultBaseUrl, not an absolute URL.");
18
+ }
19
+ if (rawPath.includes("..")) {
20
+ throw new Error("Read-only extension access: path cannot contain parent directory traversal.");
21
+ }
22
+ if (/\/(delete|edit|transition|merge|deploy|apply|update|create)(\/|$)/i.test(rawPath)) {
23
+ throw new Error(`Read-only product: path appears mutating and is blocked: ${rawPath}`);
24
+ }
25
+ }
26
+
27
+ function accessMode(service) {
28
+ return service.readAccess?.mode ?? "unsupported";
29
+ }
30
+
31
+ export async function getExtensionReadAccess(serviceId, options = {}) {
32
+ const service = getWorkdayService(serviceId);
33
+ const readAccess = service.readAccess ?? { readOnly: true, mode: "unsupported" };
34
+ const mode = accessMode(service);
35
+
36
+ if (mode === "workflow") {
37
+ return {
38
+ readOnly: true,
39
+ methods: readAccess.methods ?? ["GET"],
40
+ mode,
41
+ service: serviceId,
42
+ extension: service.extension,
43
+ label: service.label,
44
+ requires: getRequiredServices(serviceId).map((dep) => ({
45
+ service: dep.id,
46
+ extension: dep.extension,
47
+ label: dep.label,
48
+ readOnly: true,
49
+ mode: dep.readAccess?.mode ?? "unsupported"
50
+ })),
51
+ recommendation: "Workflow extension — call workday_extension_read_access on each required extension service directly."
52
+ };
53
+ }
54
+
55
+ if (mode === "cli-readonly" || mode === "ssh-readonly" || mode === "local" || mode === "library" || mode === "mcp" || mode === "unsupported") {
56
+ return {
57
+ readOnly: true,
58
+ methods: readAccess.methods ?? [],
59
+ mode,
60
+ service: serviceId,
61
+ extension: service.extension,
62
+ label: service.label,
63
+ ready: mode !== "unsupported",
64
+ platforms: readAccess.platforms,
65
+ note: readAccess.note ?? `${service.label} uses read-only tools, not browser cookie HTTP.`,
66
+ recommendation:
67
+ mode === "local" || mode === "library"
68
+ ? "No remote SSO needed."
69
+ : "Use the extension's read-only command-pack tool."
70
+ };
71
+ }
72
+
73
+ const authOptions = resolveAutoAuthOptions(options);
74
+ const config = authOptions.config ?? getSsoConfig();
75
+ const baseUrl = normalizeBaseUrl(
76
+ authOptions.baseUrl || readAccess.defaultBaseUrl || `https://${service.domains?.[0] || ""}`
77
+ );
78
+ const cookieResult =
79
+ mode === "public-http"
80
+ ? { ok: true, cookie: "", host: new URL(baseUrl).host, summary: { authenticated: true } }
81
+ : await getServiceCookieHeader(serviceId, { ...authOptions, config });
82
+
83
+ return {
84
+ readOnly: true,
85
+ methods: readAccess.methods ?? ["GET"],
86
+ mode,
87
+ service: serviceId,
88
+ extension: service.extension,
89
+ label: service.label,
90
+ baseUrl,
91
+ host: cookieResult.host,
92
+ restPathPrefix: readAccess.restPathPrefix ?? "",
93
+ ready: cookieResult.ok || mode === "public-http",
94
+ headers: {
95
+ accept: "application/json",
96
+ ...(cookieResult.cookie ? { cookie: cookieResult.cookie } : {})
97
+ },
98
+ userAgent: `Mozilla/5.0 nuvlore/0.1 ${serviceId}-read`,
99
+ summary: cookieResult.summary,
100
+ recommendation: cookieResult.ok
101
+ ? `Read-only GET ${baseUrl}<restPath> via workday_extension_read (service=${serviceId}).`
102
+ : cookieResult.authUrl
103
+ ? `Open ${cookieResult.authUrl} in Chrome via Okta to refresh session, then retry.`
104
+ : "Run workday_okta_login, then retry."
105
+ };
106
+ }
107
+
108
+ export async function extensionReadGet(serviceId, input = {}, options = {}) {
109
+ assertReadOnlyHttpRequest({ method: "GET", path: input.restPath || input.path });
110
+ const authOptions = resolveAutoAuthOptions(options);
111
+ const service = getWorkdayService(serviceId);
112
+ if (service.readAccess?.oktaAppName) {
113
+ return oktaAppReadGet(service.readAccess.oktaAppName, input, authOptions);
114
+ }
115
+ const access = await getExtensionReadAccess(serviceId, authOptions);
116
+ if (access.mode === "workflow") {
117
+ throw new Error(
118
+ `Extension ${access.extension} is a workflow bundle. Use workday_extension_read_access and call a required extension service directly.`
119
+ );
120
+ }
121
+ if (access.mode === "cookie-http") {
122
+ return ssoReadGet(serviceId, input, authOptions);
123
+ }
124
+ if (access.mode !== "public-http") {
125
+ throw new Error(`Extension ${access.extension} does not support read-only HTTP GET (${access.mode}).`);
126
+ }
127
+ if (!access.ready) {
128
+ throw new Error(access.recommendation || `Read access not ready for ${serviceId}.`);
129
+ }
130
+
131
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
132
+ const restPath = String(input.restPath || input.path || "").trim();
133
+ if (!restPath) throw new Error("restPath is required for read-only extension GET.");
134
+ const baseUrl = normalizeBaseUrl(input.baseUrl || access.baseUrl);
135
+ const url = buildRequestUrl(baseUrl, restPath, input.query);
136
+ const response = await fetchImpl(url, {
137
+ method: "GET",
138
+ headers: {
139
+ accept: access.headers.accept,
140
+ "user-agent": access.userAgent,
141
+ ...(access.headers.cookie ? { cookie: access.headers.cookie } : {})
142
+ }
143
+ });
144
+ const text = await response.text();
145
+ assertNonHtmlApiResponse(access.label, text);
146
+ const data = parseResponseBody(text);
147
+ if (!response.ok) {
148
+ throw new Error(`${access.label} read failed with status ${response.status}.`);
149
+ }
150
+ return {
151
+ readOnly: true,
152
+ method: "GET",
153
+ service: serviceId,
154
+ extension: access.extension,
155
+ baseUrl,
156
+ restPath,
157
+ url: url.toString(),
158
+ status: response.status,
159
+ data
160
+ };
161
+ }
162
+
163
+ export function listExtensionReadAccess() {
164
+ return listWorkdayServices().map((service) => ({
165
+ service: service.id,
166
+ extension: service.extension,
167
+ label: service.label,
168
+ auth: service.auth,
169
+ readOnly: service.readAccess?.readOnly !== false,
170
+ mode: accessMode(service),
171
+ requires: service.requires ?? []
172
+ }));
173
+ }
@@ -0,0 +1 @@
1
+ export * from "@nuvlore/extension-browser-sso/html-session-extract";
@@ -0,0 +1,133 @@
1
+ import { resolveBestCookieHost } from "./cookieJar.mjs";
2
+ import { getExtensionReadAccess, extensionReadGet } from "./extensionAccess.mjs";
3
+ import { ensureSsoSession, syncAllOktaCatalogCookies } from "./sessionManager.mjs";
4
+ import { resolveAutoAuthOptions } from "./autoAuth.mjs";
5
+ import { ensureOktaAppSession } from "./sessionAuth.mjs";
6
+ import { getSsoConfig } from "./ssoConfig.mjs";
7
+ import { getOktaApp, listOktaApps } from "./oktaAppCatalog.mjs";
8
+ import { oktaAppHttpRead } from "./oktaAppRead.mjs";
9
+ import { readServiceDefault } from "./serviceReads.mjs";
10
+ import { probeReadOnlyUrl } from "./sessionValidate.mjs";
11
+
12
+ export { probeReadOnlyUrl };
13
+
14
+ export async function getOktaAppReadAccess(appName, options = {}) {
15
+ const app = getOktaApp(appName);
16
+ const readOnly = true;
17
+
18
+ if (app.serviceId && app.mode !== "cli-readonly") {
19
+ try {
20
+ const extensionAccess = await getExtensionReadAccess(app.serviceId, options);
21
+ return {
22
+ readOnly,
23
+ oktaApp: appName,
24
+ ...extensionAccess,
25
+ probePath: app.probePath,
26
+ defaultBaseUrl: app.defaultBaseUrl ?? extensionAccess.baseUrl
27
+ };
28
+ } catch {
29
+ // fall through to cookie probe
30
+ }
31
+ }
32
+
33
+ if (app.mode === "cli-readonly") {
34
+ return {
35
+ readOnly,
36
+ oktaApp: appName,
37
+ service: app.serviceId,
38
+ mode: "cli-readonly",
39
+ platform: app.platform,
40
+ ready: true,
41
+ recommendation: "Read-only CLI tools only — describe/list/get/logs."
42
+ };
43
+ }
44
+
45
+ const authOptions = resolveAutoAuthOptions(options);
46
+ const config = authOptions.config ?? getSsoConfig();
47
+ const { jar } = await ensureOktaAppSession(appName, { ...authOptions, config });
48
+ const { host, cookie, hasCookies } = resolveBestCookieHost(jar, app.domains ?? []);
49
+ const probe = hasCookies
50
+ ? await probeReadOnlyUrl(jar, { host, path: app.probePath ?? "/", cookie, fetchImpl: options.fetchImpl })
51
+ : { ready: false, reason: "no_cookies" };
52
+
53
+ return {
54
+ readOnly,
55
+ methods: ["GET"],
56
+ oktaApp: appName,
57
+ service: app.serviceId,
58
+ mode: app.mode ?? "cookie-http",
59
+ baseUrl: app.defaultBaseUrl,
60
+ host,
61
+ hasCookies,
62
+ ready: Boolean(hasCookies && probe.ready),
63
+ probe,
64
+ cookiePresent: Boolean(cookie),
65
+ recommendation: probe.ready
66
+ ? `Read-only GET ${app.defaultBaseUrl}${app.probePath ?? "/"}`
67
+ : hasCookies
68
+ ? "Cookies present but session probe failed — open app in Chrome once."
69
+ : "Open app in Chrome via Okta, then retry."
70
+ };
71
+ }
72
+
73
+ export async function oktaAppReadGet(appName, input = {}, options = {}) {
74
+ const app = getOktaApp(appName);
75
+
76
+ if (app.serviceId && !input.forceCookie) {
77
+ try {
78
+ if (input.useDefault) {
79
+ return readServiceDefault(app.serviceId, options);
80
+ }
81
+ return await extensionReadGet(
82
+ app.serviceId,
83
+ {
84
+ restPath: input.restPath || app.probePath,
85
+ baseUrl: input.baseUrl || app.defaultBaseUrl,
86
+ query: input.query,
87
+ followRedirects: input.followRedirects
88
+ },
89
+ options
90
+ );
91
+ } catch (error) {
92
+ if (!input.allowCookieFallback) throw error;
93
+ }
94
+ }
95
+
96
+ return oktaAppHttpRead(appName, input, options);
97
+ }
98
+
99
+ export async function probeAllOktaApps(options = {}) {
100
+ const authOptions = resolveAutoAuthOptions(options);
101
+ if (!authOptions.probeOnly) {
102
+ await ensureSsoSession({
103
+ config: authOptions.config ?? getSsoConfig(),
104
+ openBrowserOnMissing: authOptions.openBrowserOnMissing,
105
+ forceBrowser: authOptions.forceBrowser === true,
106
+ onStatus: authOptions.onStatus
107
+ }).catch(() => {});
108
+ }
109
+ await syncAllOktaCatalogCookies(options);
110
+ const results = [];
111
+ for (const app of listOktaApps()) {
112
+ try {
113
+ const access = await getOktaAppReadAccess(app.name, { ...options, probeOnly: true });
114
+ results.push({
115
+ app: app.name,
116
+ service: app.serviceId,
117
+ mode: access.mode,
118
+ ready: access.ready === true,
119
+ host: access.host,
120
+ status: access.probe?.status
121
+ });
122
+ } catch (error) {
123
+ results.push({
124
+ app: app.name,
125
+ ready: false,
126
+ error: error instanceof Error ? error.message : String(error)
127
+ });
128
+ }
129
+ }
130
+ return results;
131
+ }
132
+
133
+ export { listOktaApps };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * All apps visible on https://workday.okta.com/app/UserHome
3
+ * Read-only access only — probe paths are GET.
4
+ */
5
+ export const OKTA_USER_HOME_APPS = {
6
+ Workday: {
7
+ serviceId: "sso",
8
+ domains: ["workday.okta.com"],
9
+ defaultBaseUrl: "https://workday.okta.com",
10
+ probePath: "/app/UserHome"
11
+ },
12
+ JIRA2: { serviceId: "jira", domains: ["jira2.workday.com"], defaultBaseUrl: "https://jira2.workday.com", probePath: "/rest/api/latest/myself" },
13
+ Bitbucket: { serviceId: "bitbucket", domains: ["bitbucket.workday.com"], defaultBaseUrl: "https://bitbucket.workday.com", probePath: "/" },
14
+ Confluence: { serviceId: "confluence", domains: ["confluence.workday.com"], defaultBaseUrl: "https://confluence.workday.com", probePath: "/rest/api/user/current" },
15
+ Pharos: { serviceId: "pharos", domains: ["grafana.produs.us.wdpharos.io"], defaultBaseUrl: "https://grafana.produs.us.wdpharos.io", probePath: "/login" },
16
+ "GitHub EMU Cloud": { serviceId: "github", domains: ["ghe.megaleo.com"], defaultBaseUrl: "https://ghe.megaleo.com", probePath: "/" },
17
+ PagerDuty: { serviceId: "pagerduty", domains: ["workday.pagerduty.com"], defaultBaseUrl: "https://workday.pagerduty.com", probePath: "/" },
18
+ "Amazon Web Services - AWS": { serviceId: "workday-infra-access", platform: "aws", domains: ["signin.aws.amazon.com"], defaultBaseUrl: "https://signin.aws.amazon.com", probePath: "/", mode: "cli-readonly" },
19
+ Slack: {
20
+ domains: ["workday.enterprise.slack.com", "workday.slack.com", "workday-dev.slack.com", "slack.com", "app.slack.com"],
21
+ defaultBaseUrl: "https://workday.enterprise.slack.com",
22
+ probePath: "/"
23
+ },
24
+ Zoom: { domains: ["workday.zoom.us", "zoom.us", "us.telemetry.zoom.us"], defaultBaseUrl: "https://workday.zoom.us", probePath: "/" },
25
+ Horizon: { domains: ["horizon.workdayinternal.com"], defaultBaseUrl: "https://horizon.workdayinternal.com", probePath: "/" },
26
+ "On Horizon": { domains: ["horizon.workdayinternal.com"], defaultBaseUrl: "https://horizon.workdayinternal.com", probePath: "/" },
27
+ "People & Purpose on Horizon": { domains: ["horizon.workdayinternal.com"], defaultBaseUrl: "https://horizon.workdayinternal.com", probePath: "/" },
28
+ "Workday Service Hub": { domains: ["workday.service-now.com"], defaultBaseUrl: "https://workday.service-now.com", probePath: "/" },
29
+ "Analytics Hub": { domains: ["console.cloud.google.com"], defaultBaseUrl: "https://console.cloud.google.com", probePath: "/", mode: "cli-readonly" },
30
+ "Internal Analytics": { domains: ["console.cloud.google.com"], defaultBaseUrl: "https://console.cloud.google.com", probePath: "/", mode: "cli-readonly" },
31
+ "Workday - Google Apps Drive": {
32
+ domains: ["drive.google.com", "accounts.google.com", "google.com"],
33
+ defaultBaseUrl: "https://drive.google.com",
34
+ probePath: "/drive/"
35
+ },
36
+ Sana: {
37
+ domains: ["workday.sana.ai", "sana.ai", "sanalabs.com"],
38
+ defaultBaseUrl: "https://workday.sana.ai",
39
+ agentsUrl: "https://sana.ai/tPNxyS5GyK1r",
40
+ agentsWorkspaceId: "tPNxyS5GyK1r",
41
+ probePath: "/",
42
+ launchViaUserHome: true
43
+ },
44
+ Peakon: { domains: ["workday.peakon.com", "peakon.com"], defaultBaseUrl: "https://workday.peakon.com", probePath: "/" },
45
+ "Workday Community": { domains: ["community.workday.com"], defaultBaseUrl: "https://community.workday.com", probePath: "/" },
46
+ Achievers: { domains: ["workday.achievers.com"], defaultBaseUrl: "https://workday.achievers.com", probePath: "/" },
47
+ Workboard: { domains: ["workboard.com"], defaultBaseUrl: "https://www.workboard.com", probePath: "/" },
48
+ "Eptura Office Space Tool & Desk Reservations": { domains: ["workday.iofficeconnect.com"], defaultBaseUrl: "https://workday.iofficeconnect.com", probePath: "/" },
49
+ Miro: { domains: ["miro.com", "www.miro.com"], defaultBaseUrl: "https://miro.com", probePath: "/app/dashboard/" },
50
+ OneTrust: { domains: ["app.onetrust.com"], defaultBaseUrl: "https://app.onetrust.com", probePath: "/" },
51
+ "Collibra Data Intelligence Platform": { domains: ["workday.collibra.com"], defaultBaseUrl: "https://workday.collibra.com", probePath: "/" },
52
+ Snyk: { domains: ["app.snyk.io"], defaultBaseUrl: "https://app.snyk.io", probePath: "/" },
53
+ Seismic: { domains: ["workday.seismic.com"], defaultBaseUrl: "https://workday.seismic.com", probePath: "/" },
54
+ Togglr: { domains: ["togglr.io"], defaultBaseUrl: "https://togglr.io", probePath: "/" },
55
+ "Togglr - Internal": { domains: ["togglr.io"], defaultBaseUrl: "https://togglr.io", probePath: "/" },
56
+ "Metrics Portal": { domains: ["metrics.workday.com"], defaultBaseUrl: "https://metrics.workday.com", probePath: "/" },
57
+ "Security Portal": { domains: ["security.workday.com"], defaultBaseUrl: "https://security.workday.com", probePath: "/" },
58
+ "Microsoft Office 365 Office Portal": { domains: ["office.com"], defaultBaseUrl: "https://www.office.com", probePath: "/" },
59
+ "Microsoft Outlook": { domains: ["outlook.office.com"], defaultBaseUrl: "https://outlook.office.com", probePath: "/" },
60
+ Mixpanel: { domains: ["mixpanel.com"], defaultBaseUrl: "https://mixpanel.com", probePath: "/" },
61
+ "Secure Code Warrior": { domains: ["securecodewarrior.com"], defaultBaseUrl: "https://portal.securecodewarrior.com", probePath: "/" },
62
+ "Proofpoint Security Education Platform": { domains: ["proofpoint.com"], defaultBaseUrl: "https://www.proofpoint.com", probePath: "/" },
63
+ "HackerRank For Work": { domains: ["hackerrank.com"], defaultBaseUrl: "https://www.hackerrank.com", probePath: "/" },
64
+ "Visitor Registration": { domains: ["envoy.com"], defaultBaseUrl: "https://envoy.com", probePath: "/" },
65
+ "Healthy Working": { domains: ["cardinus.com"], defaultBaseUrl: "https://www.cardinus.com", probePath: "/" },
66
+ Meetingselect: { domains: ["meetingselect.com"], defaultBaseUrl: "https://www.meetingselect.com", probePath: "/" },
67
+ EveryoneSocial: { domains: ["everyonesocial.com"], defaultBaseUrl: "https://everyonesocial.com", probePath: "/" },
68
+ Aperian: { domains: ["aperianglobal.com"], defaultBaseUrl: "https://www.aperianglobal.com", probePath: "/" },
69
+ "BT diagramming": { domains: ["lucid.co"], defaultBaseUrl: "https://lucid.co", probePath: "/" },
70
+ "Fragomen Nomadic": { domains: ["fragomen.com"], defaultBaseUrl: "https://www.fragomen.com", probePath: "/" },
71
+ "6120 Meeting Center Booking": { domains: ["briefingsource.com"], defaultBaseUrl: "https://www.briefingsource.com", probePath: "/" },
72
+ "WCP Dev Site": { domains: ["workday.com"], defaultBaseUrl: "https://developer.workday.com", probePath: "/" },
73
+ "Workday Procurement": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
74
+ "Workday Travel Tool - US": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
75
+ "Workday Policies": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
76
+ "Workday Pattern Library": { domains: ["workday.com"], defaultBaseUrl: "https://canvas.workday.com", probePath: "/" },
77
+ "Canvas Design System": { domains: ["workday.com"], defaultBaseUrl: "https://canvas.workday.com", probePath: "/" },
78
+ "Global Records Retention Schedule": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
79
+ "Digital Event Library": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
80
+ "Employee Event Registration": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
81
+ DevCon: { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
82
+ WOAH: { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
83
+ "VitalSource eBooks": { domains: ["vitalsource.com"], defaultBaseUrl: "https://www.vitalsource.com", probePath: "/" },
84
+ "P&T Planner": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
85
+ "P&T Okta Password Check": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/" },
86
+ "INF-IDM": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/" },
87
+ ISD: { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
88
+ "SkyLab Portal": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
89
+ "Prod LDAP Password Tool": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
90
+ "PRM-Wallboard": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
91
+ Osprey: { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
92
+ ArcPrime: { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
93
+ "Google Gemini": { domains: ["gemini.google.com"], defaultBaseUrl: "https://gemini.google.com", probePath: "/", mode: "bookmark" },
94
+ NotebookLM: { domains: ["notebooklm.google.com"], defaultBaseUrl: "https://notebooklm.google.com", probePath: "/", mode: "bookmark" },
95
+ Lovable: { domains: ["lovable.dev"], defaultBaseUrl: "https://lovable.dev", probePath: "/", mode: "bookmark" }
96
+ };
97
+
98
+ export function listOktaApps() {
99
+ return Object.entries(OKTA_USER_HOME_APPS).map(([name, app]) => ({
100
+ name,
101
+ readOnly: true,
102
+ ...app,
103
+ mode: app.mode ?? (app.serviceId ? "extension" : "cookie-http")
104
+ }));
105
+ }
106
+
107
+ export function getOktaApp(name) {
108
+ const app = OKTA_USER_HOME_APPS[name];
109
+ if (!app) {
110
+ throw new Error(`Unknown Okta app: ${name}`);
111
+ }
112
+ return { name, readOnly: true, ...app, mode: app.mode ?? (app.serviceId ? "extension" : "cookie-http") };
113
+ }
114
+
115
+ export function getOktaAppByServiceId(serviceId) {
116
+ const match = listOktaApps().find((app) => app.serviceId === serviceId);
117
+ return match ?? null;
118
+ }
@@ -0,0 +1,119 @@
1
+ import { buildRequestUrl, normalizeBaseUrl, parseResponseBody } from "@nuvlore/extension-read-only-toolkit/enterprise-api-read";
2
+ import { assertReadOnlyHttpRequest } from "./extensionAccess.mjs";
3
+ import { resolveBestCookieHost } from "./cookieJar.mjs";
4
+ import { isAuthStatusResponse, resolveAutoAuthOptions, shouldRetryAuthAfterFailure } from "./autoAuth.mjs";
5
+ import { ensureOktaAppSession } from "./sessionAuth.mjs";
6
+ import { getSsoConfig } from "./ssoConfig.mjs";
7
+ import { getOktaApp } from "./oktaAppCatalog.mjs";
8
+ import { extractHtmlSession, extractEmbeddedJson } from "./htmlSessionExtract.mjs";
9
+
10
+ /** Default read targets for Okta-only apps (GET, read-only). */
11
+ export const OKTA_APP_READ_TARGETS = {
12
+ Slack: {
13
+ defaultPath: "/messages",
14
+ extract: "generic",
15
+ extraHeaders: { accept: "text/html,application/json" }
16
+ },
17
+ Zoom: { defaultPath: "/", extract: "generic" },
18
+ Horizon: { defaultPath: "/", extract: "generic" },
19
+ "Workday Service Hub": {
20
+ defaultPath: "/api/now/table/sys_user?sysparm_limit=1&sysparm_fields=user_name,name",
21
+ accept: "application/json"
22
+ },
23
+ "Workday - Google Apps Drive": { defaultPath: "/drive/home", extract: "generic" },
24
+ Sana: { defaultPath: "/", extract: "generic" },
25
+ Peakon: { defaultPath: "/", extract: "generic" },
26
+ Miro: { defaultPath: "/app/dashboard/", extract: "generic" },
27
+ "Microsoft Outlook": { defaultPath: "/mail/", extract: "generic" }
28
+ };
29
+
30
+ export async function oktaAppHttpRead(appName, input = {}, options = {}) {
31
+ assertReadOnlyHttpRequest({ method: "GET", path: input.restPath || "/" });
32
+ const app = getOktaApp(appName);
33
+ const target = OKTA_APP_READ_TARGETS[appName] ?? {};
34
+ const authOptions = resolveAutoAuthOptions(options);
35
+ const config = authOptions.config ?? getSsoConfig();
36
+ const session = await ensureOktaAppSession(appName, { ...authOptions, config });
37
+ const { jar } = session;
38
+ const { host, cookie, hasCookies } = resolveBestCookieHost(jar, app.domains ?? []);
39
+ if (!hasCookies || !cookie) {
40
+ if (session.openedBrowser) {
41
+ throw new Error(
42
+ `Okta app "${appName}" auth incomplete. Finish login in Chrome (${session.authUrl}), then retry.`
43
+ );
44
+ }
45
+ throw new Error(
46
+ `No SSO cookies for Okta app "${appName}". Set WORKDAY_SSO_AUTO_AUTH=true or run workday_okta_login.`
47
+ );
48
+ }
49
+
50
+ const baseUrl = normalizeBaseUrl(input.baseUrl || app.defaultBaseUrl || `https://${host}`);
51
+ const restPath = String(input.restPath || target.defaultPath || app.probePath || "/").trim();
52
+ const url = buildRequestUrl(baseUrl, restPath, input.query);
53
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
54
+ const follow = input.followRedirects ?? target.followRedirects ?? true;
55
+
56
+ const response = await fetchImpl(url.toString(), {
57
+ method: "GET",
58
+ redirect: follow ? "follow" : "manual",
59
+ headers: {
60
+ accept: target.accept ?? input.accept ?? "application/json,text/html",
61
+ cookie,
62
+ "user-agent": `Mozilla/5.0 nuvlore/0.1 okta-${appName.replace(/\s+/g, "-").toLowerCase()}-read`,
63
+ ...(target.extraHeaders ?? {}),
64
+ ...(input.headers ?? {})
65
+ }
66
+ });
67
+
68
+ const text = await response.text();
69
+ const contentType = response.headers.get("content-type") || "";
70
+ const isJson = contentType.includes("json") || (text.trim().startsWith("{") || text.trim().startsWith("["));
71
+
72
+ let data = isJson ? parseResponseBody(text) : null;
73
+ let extracted = null;
74
+ if (!isJson || input.extractHtml) {
75
+ const extractKind = input.extract || target.extract || "generic";
76
+ extracted = extractHtmlSession(extractKind, text, { url: response.url || url.toString() });
77
+ if (target.embeddedJsonMarker) {
78
+ const embedded = extractEmbeddedJson(text, target.embeddedJsonMarker);
79
+ if (embedded) extracted = { ...extracted, embedded };
80
+ }
81
+ }
82
+
83
+ if (
84
+ !response.ok &&
85
+ !extracted?.authenticated &&
86
+ isAuthStatusResponse(response.status) &&
87
+ shouldRetryAuthAfterFailure({ status: response.status }, authOptions)
88
+ ) {
89
+ await ensureOktaAppSession(appName, {
90
+ ...authOptions,
91
+ config,
92
+ forceBrowser: true,
93
+ openBrowserOnMissing: true
94
+ });
95
+ return oktaAppHttpRead(appName, input, { ...authOptions, _retriedAuth: true });
96
+ }
97
+
98
+ if (!response.ok && !extracted?.authenticated) {
99
+ throw new Error(
100
+ `Okta app "${appName}" read failed (${response.status}) at ${restPath}. Open ${session.authUrl} in Chrome to refresh login.`
101
+ );
102
+ }
103
+
104
+ return {
105
+ readOnly: true,
106
+ method: "GET",
107
+ oktaApp: appName,
108
+ service: app.serviceId,
109
+ baseUrl,
110
+ host,
111
+ restPath,
112
+ url: (response.url || url).toString(),
113
+ status: response.status,
114
+ contentType,
115
+ data: data ?? (extracted ? undefined : text.slice(0, 4000)),
116
+ extracted,
117
+ bodyLength: text.length
118
+ };
119
+ }
@@ -0,0 +1,12 @@
1
+ import { getSsoConfig } from "./ssoConfig.mjs";
2
+
3
+ /** @deprecated Use getSsoConfig — kept for backward compatibility. */
4
+ export function getOktaConfig(env = process.env) {
5
+ return getSsoConfig(env);
6
+ }
7
+
8
+ export function assertOktaConfig(config = getSsoConfig()) {
9
+ if (!config.domain) {
10
+ throw new Error("Missing WORKDAY_OKTA_DOMAIN. Copy .env.example to .env and set your Okta org domain.");
11
+ }
12
+ }
@@ -0,0 +1,32 @@
1
+ import {
2
+ buildCookieHeader,
3
+ isValidationFresh,
4
+ jarSummary,
5
+ loadCookieJar,
6
+ saveCookieJar
7
+ } from "./cookieJar.mjs";
8
+ import { getSsoConfig } from "./ssoConfig.mjs";
9
+
10
+ /** @deprecated Use loadCookieJar — session is now a browser cookie jar. */
11
+ export async function loadSession(sessionPath) {
12
+ const config = getSsoConfig();
13
+ return loadCookieJar(sessionPath ?? config.cookieJarPath);
14
+ }
15
+
16
+ /** @deprecated Use saveCookieJar */
17
+ export async function saveSession(sessionPath, session) {
18
+ return saveCookieJar(sessionPath, session);
19
+ }
20
+
21
+ /** @deprecated Use jar validation via sessionManager */
22
+ export function isSessionValid(jar, now = Date.now()) {
23
+ if (!jar?.cookies?.length) return false;
24
+ const config = getSsoConfig();
25
+ if (jar.authenticated && isValidationFresh(jar, config.validateTtlMs, now)) return true;
26
+ return Boolean(buildCookieHeader(jar.cookies, config.domain));
27
+ }
28
+
29
+ /** @deprecated Use jarSummary */
30
+ export function sessionSummary(jar, config) {
31
+ return jarSummary(jar, config ?? getSsoConfig());
32
+ }