@replicated/portal-components 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/metadata/registry.json +2 -2
- package/components/metadata/registry.md +2 -2
- package/dist/actions/change-team.d.mts +10 -0
- package/dist/actions/change-team.d.ts +10 -0
- package/dist/actions/change-team.js +458 -0
- package/dist/actions/change-team.js.map +1 -0
- package/dist/actions/index.d.mts +4 -1
- package/dist/actions/index.d.ts +4 -1
- package/dist/actions/index.js +1232 -430
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/install-actions.d.mts +4 -0
- package/dist/actions/install-actions.d.ts +4 -0
- package/dist/actions/install-actions.js +680 -0
- package/dist/actions/install-actions.js.map +1 -0
- package/dist/actions/service-account.d.mts +4 -0
- package/dist/actions/service-account.d.ts +4 -0
- package/dist/actions/service-account.js +373 -0
- package/dist/actions/service-account.js.map +1 -0
- package/dist/actions/support-bundles.d.mts +4 -0
- package/dist/actions/support-bundles.d.ts +4 -0
- package/dist/actions/support-bundles.js +659 -0
- package/dist/actions/support-bundles.js.map +1 -0
- package/dist/actions/team-settings.d.mts +4 -0
- package/dist/actions/team-settings.d.ts +4 -0
- package/dist/actions/team-settings.js +1040 -0
- package/dist/actions/team-settings.js.map +1 -0
- package/dist/actions/trial-signup.d.mts +24 -0
- package/dist/actions/trial-signup.d.ts +24 -0
- package/dist/actions/trial-signup.js +482 -0
- package/dist/actions/trial-signup.js.map +1 -0
- package/dist/actions/user-settings.d.mts +4 -0
- package/dist/actions/user-settings.d.ts +4 -0
- package/dist/actions/user-settings.js +621 -0
- package/dist/actions/user-settings.js.map +1 -0
- package/dist/airgap-instances.d.mts +4 -1
- package/dist/airgap-instances.d.ts +4 -1
- package/dist/airgap-instances.js +177 -32
- package/dist/airgap-instances.js.map +1 -1
- package/dist/branding-BsMSywts.d.mts +36 -0
- package/dist/branding-BsMSywts.d.ts +36 -0
- package/dist/error-page.js +10 -2
- package/dist/error-page.js.map +1 -1
- package/dist/error.js +10 -2
- package/dist/error.js.map +1 -1
- package/dist/esm/actions/change-team.js +455 -0
- package/dist/esm/actions/change-team.js.map +1 -0
- package/dist/esm/actions/index.js +1200 -428
- package/dist/esm/actions/index.js.map +1 -1
- package/dist/esm/actions/install-actions.js +673 -0
- package/dist/esm/actions/install-actions.js.map +1 -0
- package/dist/esm/actions/service-account.js +371 -0
- package/dist/esm/actions/service-account.js.map +1 -0
- package/dist/esm/actions/support-bundles.js +654 -0
- package/dist/esm/actions/support-bundles.js.map +1 -0
- package/dist/esm/actions/team-settings.js +1026 -0
- package/dist/esm/actions/team-settings.js.map +1 -0
- package/dist/esm/actions/trial-signup.js +478 -0
- package/dist/esm/actions/trial-signup.js.map +1 -0
- package/dist/esm/actions/user-settings.js +615 -0
- package/dist/esm/actions/user-settings.js.map +1 -0
- package/dist/esm/airgap-instances.js +176 -32
- package/dist/esm/airgap-instances.js.map +1 -1
- package/dist/esm/error-page.js +10 -2
- package/dist/esm/error-page.js.map +1 -1
- package/dist/esm/error.js +10 -2
- package/dist/esm/error.js.map +1 -1
- package/dist/esm/helm-install-wizard.js +127 -81
- package/dist/esm/helm-install-wizard.js.map +1 -1
- package/dist/esm/index.js +706 -438
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/install-actions.js +40 -5
- package/dist/esm/install-actions.js.map +1 -1
- package/dist/esm/install-card.js +9 -6
- package/dist/esm/install-card.js.map +1 -1
- package/dist/esm/install-targets.js +9 -2
- package/dist/esm/install-targets.js.map +1 -1
- package/dist/esm/instance-card.js +175 -31
- package/dist/esm/instance-card.js.map +1 -1
- package/dist/esm/join-team.js +9 -3
- package/dist/esm/join-team.js.map +1 -1
- package/dist/esm/license-card.js +24 -22
- package/dist/esm/license-card.js.map +1 -1
- package/dist/esm/license-details.js +128 -334
- package/dist/esm/license-details.js.map +1 -1
- package/dist/esm/linux-install-wizard.js +219 -133
- package/dist/esm/linux-install-wizard.js.map +1 -1
- package/dist/esm/login.js +20 -4
- package/dist/esm/login.js.map +1 -1
- package/dist/esm/middleware.js +33 -0
- package/dist/esm/middleware.js.map +1 -0
- package/dist/esm/online-instance-list.js +176 -32
- package/dist/esm/online-instance-list.js.map +1 -1
- package/dist/esm/pending-installations.js +4 -3
- package/dist/esm/pending-installations.js.map +1 -1
- package/dist/esm/release-history-panel.js +27 -14
- package/dist/esm/release-history-panel.js.map +1 -1
- package/dist/esm/saml-callback-client.js +82 -0
- package/dist/esm/saml-callback-client.js.map +1 -0
- package/dist/esm/saml-handlers.js +138 -0
- package/dist/esm/saml-handlers.js.map +1 -0
- package/dist/esm/security-card.js +53 -38
- package/dist/esm/security-card.js.map +1 -1
- package/dist/esm/service-accounts-tab.js +800 -0
- package/dist/esm/service-accounts-tab.js.map +1 -0
- package/dist/esm/support-bundle-collection-card.js +55 -25
- package/dist/esm/support-bundle-collection-card.js.map +1 -1
- package/dist/esm/support-bundles-card.js +10 -5
- package/dist/esm/support-bundles-card.js.map +1 -1
- package/dist/esm/support-card.js +37 -5
- package/dist/esm/support-card.js.map +1 -1
- package/dist/esm/team-selection.js +5 -1
- package/dist/esm/team-selection.js.map +1 -1
- package/dist/esm/team-settings-card.js +5 -2
- package/dist/esm/team-settings-card.js.map +1 -1
- package/dist/esm/team-settings.js +7 -2
- package/dist/esm/team-settings.js.map +1 -1
- package/dist/esm/top-nav-user-menu.js +5 -1
- package/dist/esm/top-nav-user-menu.js.map +1 -1
- package/dist/esm/top-nav.js +175 -62
- package/dist/esm/top-nav.js.map +1 -1
- package/dist/esm/trial-signup.js +256 -0
- package/dist/esm/trial-signup.js.map +1 -0
- package/dist/esm/update-layout.js +175 -62
- package/dist/esm/update-layout.js.map +1 -1
- package/dist/esm/updates-card.js +15 -4
- package/dist/esm/updates-card.js.map +1 -1
- package/dist/esm/upload-support-bundle-modal.js +9 -4
- package/dist/esm/upload-support-bundle-modal.js.map +1 -1
- package/dist/esm/user-settings-card.js +5 -2
- package/dist/esm/user-settings-card.js.map +1 -1
- package/dist/esm/user-settings.js +12 -6
- package/dist/esm/user-settings.js.map +1 -1
- package/dist/esm/utils/index.js +204 -13
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/fetch-license-iTyF7_GY.d.mts +81 -0
- package/dist/fetch-license-iTyF7_GY.d.ts +81 -0
- package/dist/helm-install-wizard.d.mts +12 -3
- package/dist/helm-install-wizard.d.ts +12 -3
- package/dist/helm-install-wizard.js +127 -81
- package/dist/helm-install-wizard.js.map +1 -1
- package/dist/{index-DkjaogsF.d.ts → index-DyzJ0yKD.d.mts} +194 -49
- package/dist/{index-DkjaogsF.d.mts → index-sMbq94M7.d.ts} +194 -49
- package/dist/index.d.mts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +726 -438
- package/dist/index.js.map +1 -1
- package/dist/install-actions.d.mts +5 -2
- package/dist/install-actions.d.ts +5 -2
- package/dist/install-actions.js +40 -5
- package/dist/install-actions.js.map +1 -1
- package/dist/install-card.d.mts +2 -2
- package/dist/install-card.d.ts +2 -2
- package/dist/install-card.js +9 -6
- package/dist/install-card.js.map +1 -1
- package/dist/install-targets.js +9 -2
- package/dist/install-targets.js.map +1 -1
- package/dist/instance-card.d.mts +4 -1
- package/dist/instance-card.d.ts +4 -1
- package/dist/instance-card.js +176 -31
- package/dist/instance-card.js.map +1 -1
- package/dist/join-team.js +9 -3
- package/dist/join-team.js.map +1 -1
- package/dist/license-card.d.mts +2 -2
- package/dist/license-card.d.ts +2 -2
- package/dist/license-card.js +24 -22
- package/dist/license-card.js.map +1 -1
- package/dist/license-details.js +128 -334
- package/dist/license-details.js.map +1 -1
- package/dist/linux-install-wizard.d.mts +12 -6
- package/dist/linux-install-wizard.d.ts +12 -6
- package/dist/linux-install-wizard.js +219 -133
- package/dist/linux-install-wizard.js.map +1 -1
- package/dist/login.d.mts +4 -0
- package/dist/login.d.ts +4 -0
- package/dist/login.js +20 -4
- package/dist/login.js.map +1 -1
- package/dist/middleware.d.mts +13 -0
- package/dist/middleware.d.ts +13 -0
- package/dist/middleware.js +35 -0
- package/dist/middleware.js.map +1 -0
- package/dist/online-instance-list.d.mts +4 -1
- package/dist/online-instance-list.d.ts +4 -1
- package/dist/online-instance-list.js +177 -32
- package/dist/online-instance-list.js.map +1 -1
- package/dist/pending-installations.d.mts +8 -3
- package/dist/pending-installations.d.ts +8 -3
- package/dist/pending-installations.js +4 -3
- package/dist/pending-installations.js.map +1 -1
- package/dist/release-history-panel.js +27 -14
- package/dist/release-history-panel.js.map +1 -1
- package/dist/saml-callback-client.d.mts +36 -0
- package/dist/saml-callback-client.d.ts +36 -0
- package/dist/saml-callback-client.js +88 -0
- package/dist/saml-callback-client.js.map +1 -0
- package/dist/saml-handlers.d.mts +50 -0
- package/dist/saml-handlers.d.ts +50 -0
- package/dist/saml-handlers.js +141 -0
- package/dist/saml-handlers.js.map +1 -0
- package/dist/security-card.d.mts +4 -1
- package/dist/security-card.d.ts +4 -1
- package/dist/security-card.js +53 -38
- package/dist/security-card.js.map +1 -1
- package/dist/service-accounts-tab.d.mts +51 -0
- package/dist/service-accounts-tab.d.ts +51 -0
- package/dist/service-accounts-tab.js +802 -0
- package/dist/service-accounts-tab.js.map +1 -0
- package/dist/styles.css +380 -143
- package/dist/support-bundle-collection-card.d.mts +1 -1
- package/dist/support-bundle-collection-card.d.ts +1 -1
- package/dist/support-bundle-collection-card.js +54 -24
- package/dist/support-bundle-collection-card.js.map +1 -1
- package/dist/support-bundles-card.d.mts +5 -2
- package/dist/support-bundles-card.d.ts +5 -2
- package/dist/support-bundles-card.js +10 -5
- package/dist/support-bundles-card.js.map +1 -1
- package/dist/support-card.js +37 -5
- package/dist/support-card.js.map +1 -1
- package/dist/team-selection.js +5 -1
- package/dist/team-selection.js.map +1 -1
- package/dist/team-settings-card.js +5 -2
- package/dist/team-settings-card.js.map +1 -1
- package/dist/team-settings.js +7 -2
- package/dist/team-settings.js.map +1 -1
- package/dist/{top-nav-IRIn66wS.d.ts → top-nav-BUQAGoG1.d.mts} +14 -2
- package/dist/{top-nav-IRIn66wS.d.mts → top-nav-CEqw0KpO.d.ts} +14 -2
- package/dist/top-nav-user-menu.js +5 -1
- package/dist/top-nav-user-menu.js.map +1 -1
- package/dist/top-nav.d.mts +2 -1
- package/dist/top-nav.d.ts +2 -1
- package/dist/top-nav.js +175 -62
- package/dist/top-nav.js.map +1 -1
- package/dist/trial-signup.d.mts +31 -0
- package/dist/trial-signup.d.ts +31 -0
- package/dist/trial-signup.js +258 -0
- package/dist/trial-signup.js.map +1 -0
- package/dist/update-layout.js +175 -62
- package/dist/update-layout.js.map +1 -1
- package/dist/updates-card.js +15 -4
- package/dist/updates-card.js.map +1 -1
- package/dist/upload-support-bundle-modal.js +9 -4
- package/dist/upload-support-bundle-modal.js.map +1 -1
- package/dist/user-settings-card.js +5 -2
- package/dist/user-settings-card.js.map +1 -1
- package/dist/user-settings.js +12 -6
- package/dist/user-settings.js.map +1 -1
- package/dist/utils/index.d.mts +74 -16
- package/dist/utils/index.d.ts +74 -16
- package/dist/utils/index.js +215 -12
- package/dist/utils/index.js.map +1 -1
- package/package.json +67 -1
|
@@ -0,0 +1,1040 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var headers = require('next/headers');
|
|
5
|
+
var cache = require('next/cache');
|
|
6
|
+
var buffer = require('buffer');
|
|
7
|
+
var react = require('react');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Enterprise Portal Components
|
|
11
|
+
* This file is generated by tsup. Do not edit manually.
|
|
12
|
+
*/
|
|
13
|
+
var __defProp = Object.defineProperty;
|
|
14
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
15
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
16
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
17
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
18
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
19
|
+
}) : x)(function(x) {
|
|
20
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
21
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
22
|
+
});
|
|
23
|
+
var __esm = (fn, res) => function __init() {
|
|
24
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
25
|
+
};
|
|
26
|
+
var __export = (target, all) => {
|
|
27
|
+
for (var name in all)
|
|
28
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
29
|
+
};
|
|
30
|
+
var __copyProps = (to, from, except, desc) => {
|
|
31
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
32
|
+
for (let key of __getOwnPropNames(from))
|
|
33
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
34
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
35
|
+
}
|
|
36
|
+
return to;
|
|
37
|
+
};
|
|
38
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
39
|
+
|
|
40
|
+
// datadog/tracer.ts
|
|
41
|
+
var tracer_exports = {};
|
|
42
|
+
__export(tracer_exports, {
|
|
43
|
+
default: () => tracer_default
|
|
44
|
+
});
|
|
45
|
+
var rawFlag, isEnabled, tracer, getRoutePattern, tracer_default;
|
|
46
|
+
var init_tracer = __esm({
|
|
47
|
+
"datadog/tracer.ts"() {
|
|
48
|
+
rawFlag = String(process.env.USE_DATADOG_APM || "").toLowerCase();
|
|
49
|
+
isEnabled = rawFlag === "true";
|
|
50
|
+
process.env.DD_TRACE_ENABLED = isEnabled ? "1" : "0";
|
|
51
|
+
tracer = null;
|
|
52
|
+
if (isEnabled) {
|
|
53
|
+
const serviceName = process.env.DD_SERVICE || "enterprise-portal";
|
|
54
|
+
const environment = process.env.DD_ENV || process.env.NODE_ENV || "development";
|
|
55
|
+
const version = process.env.DD_VERSION || process.env.NEXT_PUBLIC_VERSION || "0.0.0-dev";
|
|
56
|
+
const agentHost = process.env.DD_AGENT_HOST || process.env.DATADOG_AGENT_HOST || "127.0.0.1";
|
|
57
|
+
const agentPort = process.env.DD_TRACE_AGENT_PORT || "8126";
|
|
58
|
+
process.env.DD_SERVICE = serviceName;
|
|
59
|
+
process.env.DD_ENV = environment;
|
|
60
|
+
{
|
|
61
|
+
process.env.DD_VERSION = version;
|
|
62
|
+
}
|
|
63
|
+
process.env.DD_AGENT_HOST = agentHost;
|
|
64
|
+
process.env.DD_TRACE_AGENT_PORT = agentPort;
|
|
65
|
+
const dbmPropagationMode = process.env.DD_DBM_PROPAGATION_MODE || "full";
|
|
66
|
+
process.env.DD_DBM_PROPAGATION_MODE = dbmPropagationMode;
|
|
67
|
+
try {
|
|
68
|
+
const ddTrace = __require("dd-trace");
|
|
69
|
+
tracer = ddTrace.init({
|
|
70
|
+
service: serviceName,
|
|
71
|
+
env: environment,
|
|
72
|
+
version,
|
|
73
|
+
logInjection: true,
|
|
74
|
+
runtimeMetrics: true,
|
|
75
|
+
appsec: false,
|
|
76
|
+
profiling: false,
|
|
77
|
+
startupLogs: true
|
|
78
|
+
// Enable for debugging
|
|
79
|
+
});
|
|
80
|
+
console.log(`[datadog] Tracer initialized: service=${serviceName}, env=${environment}, version=${version}, agent=${agentHost}:${agentPort}`);
|
|
81
|
+
tracer.use("dns", false);
|
|
82
|
+
tracer.use("net", false);
|
|
83
|
+
tracer.use("http", {
|
|
84
|
+
server: {
|
|
85
|
+
hooks: {
|
|
86
|
+
request: (span, req) => {
|
|
87
|
+
if (!span) return;
|
|
88
|
+
const url = req?.url || "";
|
|
89
|
+
const method = req?.method || "GET";
|
|
90
|
+
const path = url.split("?")[0];
|
|
91
|
+
if (path.startsWith("/_next/")) {
|
|
92
|
+
span.context()._trace.isRecording = false;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const routePattern = getRoutePattern(path);
|
|
96
|
+
span.setTag("resource.name", `${method} ${routePattern}`);
|
|
97
|
+
span.setTag("http.route", routePattern);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.error("[datadog] failed to initialize tracing", err);
|
|
104
|
+
tracer = null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
getRoutePattern = (path) => {
|
|
108
|
+
const routePatterns = [
|
|
109
|
+
// Update instance routes - normalize dynamic segments (capture suffix to preserve sub-routes)
|
|
110
|
+
{ pattern: /^\/update\/instance\/[^/]+(.*)$/, replacement: "/update/instance/[instanceId]$1" }
|
|
111
|
+
];
|
|
112
|
+
for (const { pattern, replacement } of routePatterns) {
|
|
113
|
+
if (pattern.test(path)) {
|
|
114
|
+
return path.replace(pattern, replacement);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return path;
|
|
118
|
+
};
|
|
119
|
+
tracer_default = tracer;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// src/utils/observability/tracing.ts
|
|
124
|
+
var tracerCache = void 0;
|
|
125
|
+
function getTracer() {
|
|
126
|
+
if (tracerCache !== void 0) {
|
|
127
|
+
return tracerCache;
|
|
128
|
+
}
|
|
129
|
+
const rawFlag2 = String(process.env.USE_DATADOG_APM || "").toLowerCase();
|
|
130
|
+
const isEnabled2 = rawFlag2 === "true";
|
|
131
|
+
if (!isEnabled2) {
|
|
132
|
+
tracerCache = null;
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const tracerModule = (init_tracer(), __toCommonJS(tracer_exports));
|
|
137
|
+
const tracer2 = tracerModule.default || tracerModule;
|
|
138
|
+
if (tracer2 && typeof tracer2.trace === "function") {
|
|
139
|
+
tracerCache = tracer2;
|
|
140
|
+
return tracerCache;
|
|
141
|
+
}
|
|
142
|
+
} catch (err) {
|
|
143
|
+
console.warn("Failed to load tracer:", err);
|
|
144
|
+
}
|
|
145
|
+
tracerCache = null;
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
async function withTrace(name, fn) {
|
|
149
|
+
const activeTracer = getTracer();
|
|
150
|
+
if (!activeTracer) {
|
|
151
|
+
return fn(void 0);
|
|
152
|
+
}
|
|
153
|
+
return activeTracer.trace(name, async (span) => {
|
|
154
|
+
if (span) {
|
|
155
|
+
span.setTag("component", "application");
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const result = await fn(span);
|
|
159
|
+
return result;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (span) {
|
|
162
|
+
span.setTag("error", error);
|
|
163
|
+
}
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
function traceServerAction(name, fn) {
|
|
169
|
+
const spanName = name.startsWith("server.action.") ? name : `server.action.${name}`;
|
|
170
|
+
const traced = async (...args) => {
|
|
171
|
+
return withTrace(spanName, async (span) => {
|
|
172
|
+
if (span) {
|
|
173
|
+
span.setTag("component", "server-action");
|
|
174
|
+
}
|
|
175
|
+
const result = await fn(...args);
|
|
176
|
+
return result;
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
return traced;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/utils/api-client.ts
|
|
183
|
+
async function authenticatedFetch(url, options = {}) {
|
|
184
|
+
const { token, ...fetchOptions } = options;
|
|
185
|
+
const headers = new Headers(fetchOptions.headers);
|
|
186
|
+
if (token) {
|
|
187
|
+
headers.set("authorization", `Bearer ${token}`);
|
|
188
|
+
}
|
|
189
|
+
const response = await fetch(url, {
|
|
190
|
+
...fetchOptions,
|
|
191
|
+
headers
|
|
192
|
+
});
|
|
193
|
+
if (response.status === 401) {
|
|
194
|
+
await handle401();
|
|
195
|
+
}
|
|
196
|
+
if (response.status === 502 || response.status === 503 || response.status === 504) {
|
|
197
|
+
await handleServerError(response.status);
|
|
198
|
+
}
|
|
199
|
+
return response;
|
|
200
|
+
}
|
|
201
|
+
async function handle401() {
|
|
202
|
+
const { redirect } = await import('next/navigation');
|
|
203
|
+
return redirect("/?expired=1");
|
|
204
|
+
}
|
|
205
|
+
function isErrorPage(url) {
|
|
206
|
+
try {
|
|
207
|
+
const urlObj = new URL(url);
|
|
208
|
+
return urlObj.pathname === "/error";
|
|
209
|
+
} catch {
|
|
210
|
+
return url === "/error" || url.startsWith("/error?");
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function handleServerError(statusCode) {
|
|
214
|
+
const { redirect } = await import('next/navigation');
|
|
215
|
+
const { cookies: cookies2 } = await import('next/headers');
|
|
216
|
+
let sourceUrl;
|
|
217
|
+
try {
|
|
218
|
+
const { headers } = await import('next/headers');
|
|
219
|
+
const headersList = await headers();
|
|
220
|
+
const referer = headersList.get("referer");
|
|
221
|
+
const host = headersList.get("host");
|
|
222
|
+
const pathname = headersList.get("x-invoke-path") || headersList.get("x-forwarded-path");
|
|
223
|
+
if (referer && !isErrorPage(referer)) {
|
|
224
|
+
sourceUrl = referer;
|
|
225
|
+
} else if (host && pathname) {
|
|
226
|
+
const protocol = headersList.get("x-forwarded-proto") || "https";
|
|
227
|
+
sourceUrl = `${protocol}://${host}${pathname}`;
|
|
228
|
+
}
|
|
229
|
+
if (!sourceUrl || isErrorPage(sourceUrl)) {
|
|
230
|
+
const cookieStore = await cookies2();
|
|
231
|
+
const preservedSource = cookieStore.get("portal_error_source");
|
|
232
|
+
if (preservedSource?.value) {
|
|
233
|
+
sourceUrl = decodeURIComponent(preservedSource.value);
|
|
234
|
+
cookieStore.delete("portal_error_source");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.debug("[portal-components] Could not determine source URL", error);
|
|
239
|
+
}
|
|
240
|
+
const params = new URLSearchParams({ code: String(statusCode) });
|
|
241
|
+
if (sourceUrl) {
|
|
242
|
+
params.set("source", sourceUrl);
|
|
243
|
+
}
|
|
244
|
+
return redirect(`/error?${params.toString()}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/actions/index.ts
|
|
248
|
+
var getApiOrigin = () => {
|
|
249
|
+
return (process.env.REPLICATED_APP_ORIGIN || "https://replicated.app").replace(/\/+$/, "");
|
|
250
|
+
};
|
|
251
|
+
var defineServerAction = (definition) => definition;
|
|
252
|
+
var createServiceAccount = defineServerAction({
|
|
253
|
+
id: "service-account/create",
|
|
254
|
+
description: "Creates a service account for installing applications",
|
|
255
|
+
visibility: "customer",
|
|
256
|
+
tags: ["service-account", "install"],
|
|
257
|
+
async run({ token, name }) {
|
|
258
|
+
if (!token || typeof token !== "string") {
|
|
259
|
+
throw new Error("Service account creation requires a session token");
|
|
260
|
+
}
|
|
261
|
+
if (!name || typeof name !== "string" || !name.trim()) {
|
|
262
|
+
throw new Error("Service account name is required");
|
|
263
|
+
}
|
|
264
|
+
const endpoint = `${getApiOrigin()}/enterprise-portal/team/service-accounts`;
|
|
265
|
+
if (process.env.NODE_ENV !== "production") {
|
|
266
|
+
console.debug(
|
|
267
|
+
"[portal-components] creating service account via %s (Enterprise Portal API)",
|
|
268
|
+
endpoint
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
const response = await authenticatedFetch(endpoint, {
|
|
272
|
+
method: "POST",
|
|
273
|
+
token,
|
|
274
|
+
headers: {
|
|
275
|
+
"content-type": "application/json"
|
|
276
|
+
},
|
|
277
|
+
body: JSON.stringify({ account_name: name.trim() })
|
|
278
|
+
});
|
|
279
|
+
if (!response.ok) {
|
|
280
|
+
const errorText = await response.text();
|
|
281
|
+
throw new Error(
|
|
282
|
+
`Service account creation failed (${response.status} ${response.statusText}): ${errorText}`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
const data = await response.json();
|
|
286
|
+
return data;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
var fetchCustomBrandingImpl = async () => {
|
|
290
|
+
const appSlug = process.env.PORTAL_APP_SLUG;
|
|
291
|
+
if (!appSlug) {
|
|
292
|
+
throw new Error("PORTAL_APP_SLUG is not configured");
|
|
293
|
+
}
|
|
294
|
+
const url = `${getApiOrigin()}/enterprise-portal/public/branding?app_slug=${encodeURIComponent(
|
|
295
|
+
appSlug
|
|
296
|
+
)}`;
|
|
297
|
+
if (process.env.NODE_ENV !== "production") {
|
|
298
|
+
console.debug(
|
|
299
|
+
"[portal-components] fetching custom branding via %s (Enterprise Portal API)",
|
|
300
|
+
url
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
const response = await fetch(url, {
|
|
304
|
+
headers: {
|
|
305
|
+
accept: "application/json"
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
if (!response.ok) {
|
|
309
|
+
throw new Error(
|
|
310
|
+
`Custom branding request failed (${response.status} ${response.statusText})`
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
const payload = await response.json();
|
|
314
|
+
const brandingObject = {
|
|
315
|
+
logo: payload.logoUrl,
|
|
316
|
+
title: payload.title,
|
|
317
|
+
primaryColor: payload.primaryColor,
|
|
318
|
+
secondaryColor: payload.secondaryColor,
|
|
319
|
+
favicon: payload.faviconUrl,
|
|
320
|
+
supportPortalLink: payload.supportPortalLink || "",
|
|
321
|
+
background: payload.background,
|
|
322
|
+
backgroundImage: payload.backgroundImage,
|
|
323
|
+
customColor1: payload.customColor1,
|
|
324
|
+
customColor2: payload.customColor2
|
|
325
|
+
};
|
|
326
|
+
const brandingData = buffer.Buffer.from(JSON.stringify(brandingObject)).toString("base64");
|
|
327
|
+
return {
|
|
328
|
+
brandingData,
|
|
329
|
+
documentation: null
|
|
330
|
+
// Documentation not included in new API's public endpoint
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
react.cache(fetchCustomBrandingImpl);
|
|
334
|
+
var decodeJwtPayload = (token) => {
|
|
335
|
+
const parts = token.split(".");
|
|
336
|
+
if (parts.length !== 3) {
|
|
337
|
+
throw new Error("Invalid JWT received");
|
|
338
|
+
}
|
|
339
|
+
const payloadSegment = parts[1];
|
|
340
|
+
if (!payloadSegment) {
|
|
341
|
+
throw new Error("JWT payload segment missing");
|
|
342
|
+
}
|
|
343
|
+
const padded = payloadSegment.padEnd(
|
|
344
|
+
payloadSegment.length + (4 - payloadSegment.length % 4) % 4,
|
|
345
|
+
"="
|
|
346
|
+
);
|
|
347
|
+
const decoded = buffer.Buffer.from(padded, "base64").toString("utf-8");
|
|
348
|
+
return JSON.parse(decoded);
|
|
349
|
+
};
|
|
350
|
+
var getCustomerIdFromToken = (token) => {
|
|
351
|
+
const payload = decodeJwtPayload(token);
|
|
352
|
+
const customerId = payload?.customer_id || payload?.customerId;
|
|
353
|
+
if (typeof customerId !== "string" || !customerId.trim()) {
|
|
354
|
+
throw new Error("Unable to determine customer_id from session token");
|
|
355
|
+
}
|
|
356
|
+
return customerId.trim();
|
|
357
|
+
};
|
|
358
|
+
async function listReleasesImpl() {
|
|
359
|
+
const { cookies: cookies2 } = await import('next/headers');
|
|
360
|
+
const sessionStore = await cookies2();
|
|
361
|
+
const session = sessionStore.get("portal_session");
|
|
362
|
+
const token = session?.value;
|
|
363
|
+
if (!token) {
|
|
364
|
+
throw new Error("List releases requires a session token");
|
|
365
|
+
}
|
|
366
|
+
const endpoint = `${getApiOrigin()}/enterprise-portal/releases`;
|
|
367
|
+
if (process.env.NODE_ENV !== "production") {
|
|
368
|
+
console.debug("[portal-components] fetching releases via %s (Enterprise Portal API)", endpoint);
|
|
369
|
+
}
|
|
370
|
+
const response = await authenticatedFetch(endpoint, {
|
|
371
|
+
method: "GET",
|
|
372
|
+
token,
|
|
373
|
+
headers: {
|
|
374
|
+
accept: "application/json"
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
if (!response.ok) {
|
|
378
|
+
throw new Error(
|
|
379
|
+
`List releases request failed (${response.status} ${response.statusText})`
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
const envelope = await response.json();
|
|
383
|
+
const data = envelope.data;
|
|
384
|
+
return {
|
|
385
|
+
releases: Array.isArray(data?.releases) ? data.releases : [],
|
|
386
|
+
totalCount: data?.totalCount || 0
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
traceServerAction("listReleases", listReleasesImpl);
|
|
390
|
+
var fetchTeamUsers = defineServerAction({
|
|
391
|
+
id: "team/fetch-users",
|
|
392
|
+
description: "Fetches paginated list of team users and pending invites",
|
|
393
|
+
visibility: "customer",
|
|
394
|
+
tags: ["team", "users"],
|
|
395
|
+
async run({ token, limit = 25, offset = 0 }, context) {
|
|
396
|
+
if (!token || typeof token !== "string") {
|
|
397
|
+
throw new Error("Fetch team users requires a session token");
|
|
398
|
+
}
|
|
399
|
+
const customerId = getCustomerIdFromToken(token);
|
|
400
|
+
const params = new URLSearchParams({
|
|
401
|
+
customer_id: customerId,
|
|
402
|
+
limit: limit.toString(),
|
|
403
|
+
offset: offset.toString()
|
|
404
|
+
});
|
|
405
|
+
const endpoint = `${getApiOrigin()}/enterprise-portal/team/users?${params.toString()}`;
|
|
406
|
+
if (process.env.NODE_ENV !== "production") {
|
|
407
|
+
console.debug("[portal-components] fetching team users via %s", endpoint);
|
|
408
|
+
}
|
|
409
|
+
const response = await authenticatedFetch(endpoint, {
|
|
410
|
+
method: "GET",
|
|
411
|
+
token,
|
|
412
|
+
headers: { accept: "application/json" },
|
|
413
|
+
signal: context?.signal
|
|
414
|
+
});
|
|
415
|
+
if (!response.ok) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
`Fetch team users request failed (${response.status} ${response.statusText})`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
const data = await response.json();
|
|
421
|
+
return {
|
|
422
|
+
users: data.users || [],
|
|
423
|
+
total: data.total || 0
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
var inviteUser = defineServerAction({
|
|
428
|
+
id: "team/invite-user",
|
|
429
|
+
description: "Sends an invitation email to join the team",
|
|
430
|
+
visibility: "customer",
|
|
431
|
+
tags: ["team", "users", "invite"],
|
|
432
|
+
async run({ token, email }, context) {
|
|
433
|
+
if (!token || typeof token !== "string") {
|
|
434
|
+
throw new Error("Invite user requires a session token");
|
|
435
|
+
}
|
|
436
|
+
if (!email || typeof email !== "string") {
|
|
437
|
+
throw new Error("Invite user requires an email address");
|
|
438
|
+
}
|
|
439
|
+
getCustomerIdFromToken(token);
|
|
440
|
+
const params = new URLSearchParams({
|
|
441
|
+
email_address: email
|
|
442
|
+
});
|
|
443
|
+
const endpoint = `${getApiOrigin()}/enterprise-portal/team/invite?${params.toString()}`;
|
|
444
|
+
if (process.env.NODE_ENV !== "production") {
|
|
445
|
+
console.debug("[portal-components] inviting user via %s", endpoint);
|
|
446
|
+
}
|
|
447
|
+
const response = await authenticatedFetch(endpoint, {
|
|
448
|
+
method: "POST",
|
|
449
|
+
token,
|
|
450
|
+
headers: { accept: "application/json" },
|
|
451
|
+
signal: context?.signal
|
|
452
|
+
});
|
|
453
|
+
if (!response.ok) {
|
|
454
|
+
let errorMessage = "Failed to invite user";
|
|
455
|
+
try {
|
|
456
|
+
const data = await response.json();
|
|
457
|
+
errorMessage = data.message || data.error || errorMessage;
|
|
458
|
+
} catch {
|
|
459
|
+
}
|
|
460
|
+
throw new Error(errorMessage);
|
|
461
|
+
}
|
|
462
|
+
return { success: true };
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
var deleteUser = defineServerAction({
|
|
466
|
+
id: "team/delete-user",
|
|
467
|
+
description: "Removes a user or pending invite from the team by ID",
|
|
468
|
+
visibility: "customer",
|
|
469
|
+
tags: ["team", "users", "delete"],
|
|
470
|
+
async run({ token, id, isPendingInvite }, context) {
|
|
471
|
+
if (!token || typeof token !== "string") {
|
|
472
|
+
throw new Error("Delete user requires a session token");
|
|
473
|
+
}
|
|
474
|
+
if (!id || typeof id !== "string") {
|
|
475
|
+
throw new Error("Delete user requires an ID");
|
|
476
|
+
}
|
|
477
|
+
const resource = isPendingInvite ? "invites" : "users";
|
|
478
|
+
const endpoint = `${getApiOrigin()}/enterprise-portal/team/${resource}/${encodeURIComponent(id)}`;
|
|
479
|
+
if (process.env.NODE_ENV !== "production") {
|
|
480
|
+
console.debug("[portal-components] deleting %s %s via %s", resource, id, endpoint);
|
|
481
|
+
}
|
|
482
|
+
const response = await authenticatedFetch(endpoint, {
|
|
483
|
+
method: "DELETE",
|
|
484
|
+
token,
|
|
485
|
+
headers: { accept: "application/json" },
|
|
486
|
+
signal: context?.signal
|
|
487
|
+
});
|
|
488
|
+
if (!response.ok) {
|
|
489
|
+
let errorMessage = isPendingInvite ? "Failed to delete invite" : "Failed to delete user";
|
|
490
|
+
try {
|
|
491
|
+
const data = await response.json();
|
|
492
|
+
errorMessage = data.message || data.error || errorMessage;
|
|
493
|
+
} catch {
|
|
494
|
+
}
|
|
495
|
+
throw new Error(errorMessage);
|
|
496
|
+
}
|
|
497
|
+
return { success: true };
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
var fetchServiceAccounts = defineServerAction({
|
|
501
|
+
id: "team/fetch-service-accounts",
|
|
502
|
+
description: "Fetches paginated list of service accounts",
|
|
503
|
+
visibility: "customer",
|
|
504
|
+
tags: ["team", "service-accounts"],
|
|
505
|
+
async run({ token, limit = 50, offset = 0, includeRevoked = false }, context) {
|
|
506
|
+
if (!token || typeof token !== "string") {
|
|
507
|
+
throw new Error("Fetch service accounts requires a session token");
|
|
508
|
+
}
|
|
509
|
+
const customerId = getCustomerIdFromToken(token);
|
|
510
|
+
const params = new URLSearchParams({
|
|
511
|
+
customer_id: customerId,
|
|
512
|
+
limit: limit.toString(),
|
|
513
|
+
offset: offset.toString()
|
|
514
|
+
});
|
|
515
|
+
if (!includeRevoked) {
|
|
516
|
+
params.set("filterRevoked", "false");
|
|
517
|
+
}
|
|
518
|
+
const endpoint = `${getApiOrigin()}/enterprise-portal/team/service-accounts?${params.toString()}`;
|
|
519
|
+
if (process.env.NODE_ENV !== "production") {
|
|
520
|
+
console.debug("[portal-components] fetching service accounts via %s", endpoint);
|
|
521
|
+
}
|
|
522
|
+
const response = await authenticatedFetch(endpoint, {
|
|
523
|
+
method: "GET",
|
|
524
|
+
token,
|
|
525
|
+
headers: { accept: "application/json" },
|
|
526
|
+
signal: context?.signal
|
|
527
|
+
});
|
|
528
|
+
if (!response.ok) {
|
|
529
|
+
throw new Error(
|
|
530
|
+
`Fetch service accounts request failed (${response.status} ${response.statusText})`
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
const data = await response.json();
|
|
534
|
+
return {
|
|
535
|
+
serviceAccounts: data.serviceAccounts || [],
|
|
536
|
+
total: data.total || 0
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
var revokeServiceAccount = defineServerAction({
|
|
541
|
+
id: "team/revoke-service-account",
|
|
542
|
+
description: "Revokes a service account (soft delete)",
|
|
543
|
+
visibility: "customer",
|
|
544
|
+
tags: ["team", "service-accounts", "revoke"],
|
|
545
|
+
async run({ token, accountId }, context) {
|
|
546
|
+
if (!token || typeof token !== "string") {
|
|
547
|
+
throw new Error("Revoke service account requires a session token");
|
|
548
|
+
}
|
|
549
|
+
if (!accountId || typeof accountId !== "string") {
|
|
550
|
+
throw new Error("Revoke service account requires an account ID");
|
|
551
|
+
}
|
|
552
|
+
getCustomerIdFromToken(token);
|
|
553
|
+
const endpoint = `${getApiOrigin()}/enterprise-portal/team/service-accounts/${encodeURIComponent(accountId)}`;
|
|
554
|
+
if (process.env.NODE_ENV !== "production") {
|
|
555
|
+
console.debug("[portal-components] revoking service account via %s", endpoint);
|
|
556
|
+
}
|
|
557
|
+
const response = await authenticatedFetch(endpoint, {
|
|
558
|
+
method: "DELETE",
|
|
559
|
+
token,
|
|
560
|
+
headers: { accept: "application/json" },
|
|
561
|
+
signal: context?.signal
|
|
562
|
+
});
|
|
563
|
+
if (!response.ok) {
|
|
564
|
+
let errorMessage = "Failed to revoke service account";
|
|
565
|
+
try {
|
|
566
|
+
const data = await response.json();
|
|
567
|
+
errorMessage = data.message || data.error || errorMessage;
|
|
568
|
+
} catch {
|
|
569
|
+
}
|
|
570
|
+
throw new Error(errorMessage);
|
|
571
|
+
}
|
|
572
|
+
return { success: true };
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
var rotateServiceAccountToken = defineServerAction({
|
|
576
|
+
id: "team/rotate-service-account-token",
|
|
577
|
+
description: "Generates a new token for a service account",
|
|
578
|
+
visibility: "customer",
|
|
579
|
+
tags: ["team", "service-accounts", "rotate"],
|
|
580
|
+
async run({ token, accountId }, context) {
|
|
581
|
+
if (!token || typeof token !== "string") {
|
|
582
|
+
throw new Error("Rotate service account token requires a session token");
|
|
583
|
+
}
|
|
584
|
+
if (!accountId || typeof accountId !== "string") {
|
|
585
|
+
throw new Error("Rotate service account token requires an account ID");
|
|
586
|
+
}
|
|
587
|
+
getCustomerIdFromToken(token);
|
|
588
|
+
const endpoint = `${getApiOrigin()}/enterprise-portal/team/service-accounts/${encodeURIComponent(accountId)}/rotate-token`;
|
|
589
|
+
if (process.env.NODE_ENV !== "production") {
|
|
590
|
+
console.debug("[portal-components] rotating service account token via %s", endpoint);
|
|
591
|
+
}
|
|
592
|
+
const response = await authenticatedFetch(endpoint, {
|
|
593
|
+
method: "POST",
|
|
594
|
+
token,
|
|
595
|
+
headers: { accept: "application/json" },
|
|
596
|
+
signal: context?.signal
|
|
597
|
+
});
|
|
598
|
+
if (!response.ok) {
|
|
599
|
+
let errorMessage = "Failed to rotate service account token";
|
|
600
|
+
try {
|
|
601
|
+
const data2 = await response.json();
|
|
602
|
+
errorMessage = data2.message || data2.error || errorMessage;
|
|
603
|
+
} catch {
|
|
604
|
+
}
|
|
605
|
+
throw new Error(errorMessage);
|
|
606
|
+
}
|
|
607
|
+
const data = await response.json();
|
|
608
|
+
return {
|
|
609
|
+
serviceAccount: data.service_account,
|
|
610
|
+
helmLoginCommand: data.helm_login_cmd || "",
|
|
611
|
+
redeployHelm: data.redeploy_helm || []
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
var fetchInstances = defineServerAction({
|
|
616
|
+
id: "team/fetch-instances",
|
|
617
|
+
description: "Fetches instances to determine service account usage",
|
|
618
|
+
visibility: "customer",
|
|
619
|
+
tags: ["team", "instances"],
|
|
620
|
+
async run({ token }, context) {
|
|
621
|
+
if (!token || typeof token !== "string") {
|
|
622
|
+
throw new Error("Fetch instances requires a session token");
|
|
623
|
+
}
|
|
624
|
+
const customerId = getCustomerIdFromToken(token);
|
|
625
|
+
const endpoint = `${getApiOrigin()}/v3/instances?customer_id=${encodeURIComponent(customerId)}`;
|
|
626
|
+
if (process.env.NODE_ENV !== "production") {
|
|
627
|
+
console.debug("[portal-components] fetching instances via %s", endpoint);
|
|
628
|
+
}
|
|
629
|
+
const response = await authenticatedFetch(endpoint, {
|
|
630
|
+
method: "GET",
|
|
631
|
+
token,
|
|
632
|
+
headers: { accept: "application/json" },
|
|
633
|
+
signal: context?.signal
|
|
634
|
+
});
|
|
635
|
+
if (!response.ok) {
|
|
636
|
+
throw new Error(
|
|
637
|
+
`Fetch instances request failed (${response.status} ${response.statusText})`
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
const data = await response.json();
|
|
641
|
+
return {
|
|
642
|
+
instances: data.instances || []
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
var fetchSamlConfig = defineServerAction({
|
|
647
|
+
id: "team/fetch-saml-config",
|
|
648
|
+
description: "Fetches SAML SSO configuration for the team",
|
|
649
|
+
visibility: "customer",
|
|
650
|
+
tags: ["team", "saml"],
|
|
651
|
+
async run({ token }, context) {
|
|
652
|
+
if (!token || typeof token !== "string") {
|
|
653
|
+
throw new Error("Fetch SAML config requires a session token");
|
|
654
|
+
}
|
|
655
|
+
const customerId = getCustomerIdFromToken(token);
|
|
656
|
+
const endpoint = `${getApiOrigin()}/v3/customer/saml/config?customer_id=${encodeURIComponent(customerId)}`;
|
|
657
|
+
if (process.env.NODE_ENV !== "production") {
|
|
658
|
+
console.debug("[portal-components] fetching SAML config via %s", endpoint);
|
|
659
|
+
}
|
|
660
|
+
const response = await authenticatedFetch(endpoint, {
|
|
661
|
+
method: "GET",
|
|
662
|
+
token,
|
|
663
|
+
headers: { accept: "application/json" },
|
|
664
|
+
signal: context?.signal
|
|
665
|
+
});
|
|
666
|
+
if (!response.ok) {
|
|
667
|
+
throw new Error(
|
|
668
|
+
`Fetch SAML config request failed (${response.status} ${response.statusText})`
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
const data = await response.json();
|
|
672
|
+
return {
|
|
673
|
+
config: {
|
|
674
|
+
samlAllowed: data.samlAllowed || false,
|
|
675
|
+
samlEnabled: data.samlEnabled || false,
|
|
676
|
+
entityId: data.entityId || "",
|
|
677
|
+
acsUrl: data.acsUrl || "",
|
|
678
|
+
hasIdpMetadata: data.hasIdpMetadata || false,
|
|
679
|
+
hasIdpCert: data.hasIdpCert || false
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
var updateSamlConfig = defineServerAction({
|
|
685
|
+
id: "team/update-saml-config",
|
|
686
|
+
description: "Uploads IdP metadata and certificate for SAML SSO",
|
|
687
|
+
visibility: "customer",
|
|
688
|
+
tags: ["team", "saml", "update"],
|
|
689
|
+
async run({ token, idpMetadataXml, idpPublicCert }, context) {
|
|
690
|
+
if (!token || typeof token !== "string") {
|
|
691
|
+
throw new Error("Update SAML config requires a session token");
|
|
692
|
+
}
|
|
693
|
+
if (!idpMetadataXml || !idpPublicCert) {
|
|
694
|
+
throw new Error("Both IdP metadata and certificate are required");
|
|
695
|
+
}
|
|
696
|
+
const customerId = getCustomerIdFromToken(token);
|
|
697
|
+
const endpoint = `${getApiOrigin()}/v3/customer/saml/config?customer_id=${encodeURIComponent(customerId)}`;
|
|
698
|
+
if (process.env.NODE_ENV !== "production") {
|
|
699
|
+
console.debug("[portal-components] updating SAML config via %s", endpoint);
|
|
700
|
+
}
|
|
701
|
+
const response = await authenticatedFetch(endpoint, {
|
|
702
|
+
method: "PUT",
|
|
703
|
+
token,
|
|
704
|
+
headers: {
|
|
705
|
+
"content-type": "application/json",
|
|
706
|
+
accept: "application/json"
|
|
707
|
+
},
|
|
708
|
+
body: JSON.stringify({
|
|
709
|
+
idpMetadataXml,
|
|
710
|
+
idpPublicCert
|
|
711
|
+
}),
|
|
712
|
+
signal: context?.signal
|
|
713
|
+
});
|
|
714
|
+
if (!response.ok) {
|
|
715
|
+
let errorMessage = "Failed to update SAML configuration";
|
|
716
|
+
try {
|
|
717
|
+
const data = await response.json();
|
|
718
|
+
errorMessage = data.message || data.error || errorMessage;
|
|
719
|
+
} catch {
|
|
720
|
+
}
|
|
721
|
+
throw new Error(errorMessage);
|
|
722
|
+
}
|
|
723
|
+
return { success: true };
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
var toggleSamlEnabled = defineServerAction({
|
|
727
|
+
id: "team/toggle-saml-enabled",
|
|
728
|
+
description: "Enables or disables SAML authentication",
|
|
729
|
+
visibility: "customer",
|
|
730
|
+
tags: ["team", "saml", "toggle"],
|
|
731
|
+
async run({ token, enabled }, context) {
|
|
732
|
+
if (!token || typeof token !== "string") {
|
|
733
|
+
throw new Error("Toggle SAML enabled requires a session token");
|
|
734
|
+
}
|
|
735
|
+
const customerId = getCustomerIdFromToken(token);
|
|
736
|
+
const endpoint = `${getApiOrigin()}/v3/customer/saml/enable?customer_id=${encodeURIComponent(customerId)}`;
|
|
737
|
+
if (process.env.NODE_ENV !== "production") {
|
|
738
|
+
console.debug("[portal-components] toggling SAML enabled via %s", endpoint);
|
|
739
|
+
}
|
|
740
|
+
const response = await authenticatedFetch(endpoint, {
|
|
741
|
+
method: "PUT",
|
|
742
|
+
token,
|
|
743
|
+
headers: {
|
|
744
|
+
"content-type": "application/json",
|
|
745
|
+
accept: "application/json"
|
|
746
|
+
},
|
|
747
|
+
body: JSON.stringify({ enabled }),
|
|
748
|
+
signal: context?.signal
|
|
749
|
+
});
|
|
750
|
+
if (!response.ok) {
|
|
751
|
+
let errorMessage = "Failed to toggle SAML";
|
|
752
|
+
try {
|
|
753
|
+
const data2 = await response.json();
|
|
754
|
+
errorMessage = data2.message || data2.error || errorMessage;
|
|
755
|
+
} catch {
|
|
756
|
+
}
|
|
757
|
+
throw new Error(errorMessage);
|
|
758
|
+
}
|
|
759
|
+
const data = await response.json();
|
|
760
|
+
return {
|
|
761
|
+
success: true,
|
|
762
|
+
samlEnabled: data.samlEnabled || enabled
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
var deprovisionSaml = defineServerAction({
|
|
767
|
+
id: "team/deprovision-saml",
|
|
768
|
+
description: "Removes all SAML configuration",
|
|
769
|
+
visibility: "customer",
|
|
770
|
+
tags: ["team", "saml", "delete"],
|
|
771
|
+
async run({ token }, context) {
|
|
772
|
+
if (!token || typeof token !== "string") {
|
|
773
|
+
throw new Error("Deprovision SAML requires a session token");
|
|
774
|
+
}
|
|
775
|
+
const customerId = getCustomerIdFromToken(token);
|
|
776
|
+
const endpoint = `${getApiOrigin()}/v3/customer/saml/config?customer_id=${encodeURIComponent(customerId)}`;
|
|
777
|
+
if (process.env.NODE_ENV !== "production") {
|
|
778
|
+
console.debug("[portal-components] deprovisioning SAML via %s", endpoint);
|
|
779
|
+
}
|
|
780
|
+
const response = await authenticatedFetch(endpoint, {
|
|
781
|
+
method: "DELETE",
|
|
782
|
+
token,
|
|
783
|
+
headers: { accept: "application/json" },
|
|
784
|
+
signal: context?.signal
|
|
785
|
+
});
|
|
786
|
+
if (!response.ok) {
|
|
787
|
+
let errorMessage = "Failed to remove SAML configuration";
|
|
788
|
+
try {
|
|
789
|
+
const data = await response.json();
|
|
790
|
+
errorMessage = data.message || data.error || errorMessage;
|
|
791
|
+
} catch {
|
|
792
|
+
}
|
|
793
|
+
throw new Error(errorMessage);
|
|
794
|
+
}
|
|
795
|
+
return { success: true };
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
// src/actions/team-settings.ts
|
|
800
|
+
async function fetchTeamUsersActionImpl(limit = 25, offset = 0) {
|
|
801
|
+
const sessionStore = await headers.cookies();
|
|
802
|
+
const session = sessionStore.get("portal_session");
|
|
803
|
+
if (!session?.value) {
|
|
804
|
+
throw new Error("No session found");
|
|
805
|
+
}
|
|
806
|
+
const result = await fetchTeamUsers.run({
|
|
807
|
+
token: session.value,
|
|
808
|
+
limit,
|
|
809
|
+
offset
|
|
810
|
+
});
|
|
811
|
+
let currentUserEmail;
|
|
812
|
+
try {
|
|
813
|
+
const payload = decodeJwtPayload(session.value);
|
|
814
|
+
currentUserEmail = payload?.email;
|
|
815
|
+
} catch {
|
|
816
|
+
}
|
|
817
|
+
return {
|
|
818
|
+
users: result.users,
|
|
819
|
+
total: result.total,
|
|
820
|
+
currentUserEmail
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
var fetchTeamUsersAction = traceServerAction("fetchTeamUsersAction", fetchTeamUsersActionImpl);
|
|
824
|
+
async function inviteUserActionImpl(email) {
|
|
825
|
+
const sessionStore = await headers.cookies();
|
|
826
|
+
const session = sessionStore.get("portal_session");
|
|
827
|
+
if (!session?.value) {
|
|
828
|
+
throw new Error("No session found");
|
|
829
|
+
}
|
|
830
|
+
await inviteUser.run({
|
|
831
|
+
token: session.value,
|
|
832
|
+
email
|
|
833
|
+
});
|
|
834
|
+
cache.revalidatePath("/team-settings");
|
|
835
|
+
return { success: true };
|
|
836
|
+
}
|
|
837
|
+
var inviteUserAction = traceServerAction("inviteUserAction", inviteUserActionImpl);
|
|
838
|
+
async function deleteUserActionImpl(id, isPendingInvite) {
|
|
839
|
+
const sessionStore = await headers.cookies();
|
|
840
|
+
const session = sessionStore.get("portal_session");
|
|
841
|
+
if (!session?.value) {
|
|
842
|
+
throw new Error("No session found");
|
|
843
|
+
}
|
|
844
|
+
await deleteUser.run({
|
|
845
|
+
token: session.value,
|
|
846
|
+
id,
|
|
847
|
+
isPendingInvite
|
|
848
|
+
});
|
|
849
|
+
cache.revalidatePath("/team-settings");
|
|
850
|
+
return { success: true };
|
|
851
|
+
}
|
|
852
|
+
var deleteUserAction = traceServerAction("deleteUserAction", deleteUserActionImpl);
|
|
853
|
+
async function fetchServiceAccountsActionImpl(limit = 50, offset = 0, includeRevoked = false) {
|
|
854
|
+
const sessionStore = await headers.cookies();
|
|
855
|
+
const session = sessionStore.get("portal_session");
|
|
856
|
+
if (!session?.value) {
|
|
857
|
+
throw new Error("No session found");
|
|
858
|
+
}
|
|
859
|
+
const result = await fetchServiceAccounts.run({
|
|
860
|
+
token: session.value,
|
|
861
|
+
limit,
|
|
862
|
+
offset,
|
|
863
|
+
includeRevoked
|
|
864
|
+
});
|
|
865
|
+
return {
|
|
866
|
+
serviceAccounts: result.serviceAccounts,
|
|
867
|
+
total: result.total
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
var fetchServiceAccountsAction = traceServerAction("fetchServiceAccountsAction", fetchServiceAccountsActionImpl);
|
|
871
|
+
async function createServiceAccountActionImpl(name) {
|
|
872
|
+
const sessionStore = await headers.cookies();
|
|
873
|
+
const session = sessionStore.get("portal_session");
|
|
874
|
+
if (!session?.value) {
|
|
875
|
+
throw new Error("No session found");
|
|
876
|
+
}
|
|
877
|
+
const result = await createServiceAccount.run({
|
|
878
|
+
token: session.value,
|
|
879
|
+
name
|
|
880
|
+
});
|
|
881
|
+
cache.revalidatePath("/team-settings");
|
|
882
|
+
return {
|
|
883
|
+
serviceAccount: {
|
|
884
|
+
id: result.service_account.id,
|
|
885
|
+
accountName: result.service_account.accountName
|
|
886
|
+
},
|
|
887
|
+
token: result.token
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
var createServiceAccountAction = traceServerAction("createServiceAccountAction", createServiceAccountActionImpl);
|
|
891
|
+
async function revokeServiceAccountActionImpl(accountId) {
|
|
892
|
+
const sessionStore = await headers.cookies();
|
|
893
|
+
const session = sessionStore.get("portal_session");
|
|
894
|
+
if (!session?.value) {
|
|
895
|
+
throw new Error("No session found");
|
|
896
|
+
}
|
|
897
|
+
await revokeServiceAccount.run({
|
|
898
|
+
token: session.value,
|
|
899
|
+
accountId
|
|
900
|
+
});
|
|
901
|
+
cache.revalidatePath("/team-settings");
|
|
902
|
+
return { success: true };
|
|
903
|
+
}
|
|
904
|
+
var revokeServiceAccountAction = traceServerAction("revokeServiceAccountAction", revokeServiceAccountActionImpl);
|
|
905
|
+
async function rotateServiceAccountTokenActionImpl(accountId) {
|
|
906
|
+
const sessionStore = await headers.cookies();
|
|
907
|
+
const session = sessionStore.get("portal_session");
|
|
908
|
+
if (!session?.value) {
|
|
909
|
+
throw new Error("No session found");
|
|
910
|
+
}
|
|
911
|
+
const result = await rotateServiceAccountToken.run({
|
|
912
|
+
token: session.value,
|
|
913
|
+
accountId
|
|
914
|
+
});
|
|
915
|
+
cache.revalidatePath("/team-settings");
|
|
916
|
+
return result;
|
|
917
|
+
}
|
|
918
|
+
var rotateServiceAccountTokenAction = traceServerAction("rotateServiceAccountTokenAction", rotateServiceAccountTokenActionImpl);
|
|
919
|
+
async function fetchInstancesActionImpl() {
|
|
920
|
+
const sessionStore = await headers.cookies();
|
|
921
|
+
const session = sessionStore.get("portal_session");
|
|
922
|
+
if (!session?.value) {
|
|
923
|
+
throw new Error("No session found");
|
|
924
|
+
}
|
|
925
|
+
const result = await fetchInstances.run({
|
|
926
|
+
token: session.value
|
|
927
|
+
});
|
|
928
|
+
return result.instances;
|
|
929
|
+
}
|
|
930
|
+
var fetchInstancesAction = traceServerAction("fetchInstancesAction", fetchInstancesActionImpl);
|
|
931
|
+
async function fetchSamlConfigActionImpl() {
|
|
932
|
+
const sessionStore = await headers.cookies();
|
|
933
|
+
const session = sessionStore.get("portal_session");
|
|
934
|
+
if (!session?.value) {
|
|
935
|
+
throw new Error("No session found");
|
|
936
|
+
}
|
|
937
|
+
const result = await fetchSamlConfig.run({
|
|
938
|
+
token: session.value
|
|
939
|
+
});
|
|
940
|
+
return result.config;
|
|
941
|
+
}
|
|
942
|
+
var fetchSamlConfigAction = traceServerAction("fetchSamlConfigAction", fetchSamlConfigActionImpl);
|
|
943
|
+
async function updateSamlConfigActionImpl(idpMetadataXml, idpPublicCert) {
|
|
944
|
+
const sessionStore = await headers.cookies();
|
|
945
|
+
const session = sessionStore.get("portal_session");
|
|
946
|
+
if (!session?.value) {
|
|
947
|
+
throw new Error("No session found");
|
|
948
|
+
}
|
|
949
|
+
await updateSamlConfig.run({
|
|
950
|
+
token: session.value,
|
|
951
|
+
idpMetadataXml,
|
|
952
|
+
idpPublicCert
|
|
953
|
+
});
|
|
954
|
+
cache.revalidatePath("/team-settings");
|
|
955
|
+
return { success: true };
|
|
956
|
+
}
|
|
957
|
+
var updateSamlConfigAction = traceServerAction("updateSamlConfigAction", updateSamlConfigActionImpl);
|
|
958
|
+
async function toggleSamlEnabledActionImpl(enabled) {
|
|
959
|
+
const sessionStore = await headers.cookies();
|
|
960
|
+
const session = sessionStore.get("portal_session");
|
|
961
|
+
if (!session?.value) {
|
|
962
|
+
throw new Error("No session found");
|
|
963
|
+
}
|
|
964
|
+
const result = await toggleSamlEnabled.run({
|
|
965
|
+
token: session.value,
|
|
966
|
+
enabled
|
|
967
|
+
});
|
|
968
|
+
cache.revalidatePath("/team-settings");
|
|
969
|
+
return result;
|
|
970
|
+
}
|
|
971
|
+
var toggleSamlEnabledAction = traceServerAction("toggleSamlEnabledAction", toggleSamlEnabledActionImpl);
|
|
972
|
+
async function deprovisionSamlActionImpl() {
|
|
973
|
+
const sessionStore = await headers.cookies();
|
|
974
|
+
const session = sessionStore.get("portal_session");
|
|
975
|
+
if (!session?.value) {
|
|
976
|
+
throw new Error("No session found");
|
|
977
|
+
}
|
|
978
|
+
await deprovisionSaml.run({
|
|
979
|
+
token: session.value
|
|
980
|
+
});
|
|
981
|
+
cache.revalidatePath("/team-settings");
|
|
982
|
+
return { success: true };
|
|
983
|
+
}
|
|
984
|
+
var deprovisionSamlAction = traceServerAction("deprovisionSamlAction", deprovisionSamlActionImpl);
|
|
985
|
+
async function fetchAppFeaturesImpl() {
|
|
986
|
+
const sessionStore = await headers.cookies();
|
|
987
|
+
const session = sessionStore.get("portal_session");
|
|
988
|
+
const appSlug = process.env.PORTAL_APP_SLUG;
|
|
989
|
+
if (!appSlug) {
|
|
990
|
+
throw new Error("PORTAL_APP_SLUG is not configured");
|
|
991
|
+
}
|
|
992
|
+
const params = new URLSearchParams({ app_slug: appSlug });
|
|
993
|
+
if (session?.value) {
|
|
994
|
+
try {
|
|
995
|
+
const payload = decodeJwtPayload(session.value);
|
|
996
|
+
const customerId = payload?.customer_id;
|
|
997
|
+
if (customerId) {
|
|
998
|
+
params.set("customer_id", customerId);
|
|
999
|
+
}
|
|
1000
|
+
} catch {
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
const url = `${getApiOrigin()}/enterprise-portal/public/app-features?${params.toString()}`;
|
|
1004
|
+
const response = await fetch(url, {
|
|
1005
|
+
headers: {
|
|
1006
|
+
Accept: "application/json"
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
if (!response.ok) {
|
|
1010
|
+
throw new Error(`Failed to fetch app features: ${response.status} ${response.statusText}`);
|
|
1011
|
+
}
|
|
1012
|
+
const data = await response.json();
|
|
1013
|
+
return {
|
|
1014
|
+
epEnabled: data.ep_enabled ?? false,
|
|
1015
|
+
trialSignupEnabled: data.trial_signup_enabled ?? false,
|
|
1016
|
+
trialExpirationDays: data.trial_expiration_days ?? 30,
|
|
1017
|
+
licenseType: data.license_type ?? "trial",
|
|
1018
|
+
termsAndConditionsUrl: data.terms_and_conditions_url ?? "",
|
|
1019
|
+
epSecurityCenterEnabled: data.ep_security_center_enabled ?? false,
|
|
1020
|
+
epSamlAuthEnabled: data.ep_saml_auth_enabled ?? false,
|
|
1021
|
+
epHideSupportBundleUploadEnabled: data.ep_hide_support_bundle_upload_enabled ?? false
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
var fetchAppFeatures = traceServerAction("fetchAppFeatures", fetchAppFeaturesImpl);
|
|
1025
|
+
|
|
1026
|
+
exports.createServiceAccountAction = createServiceAccountAction;
|
|
1027
|
+
exports.deleteUserAction = deleteUserAction;
|
|
1028
|
+
exports.deprovisionSamlAction = deprovisionSamlAction;
|
|
1029
|
+
exports.fetchAppFeatures = fetchAppFeatures;
|
|
1030
|
+
exports.fetchInstancesAction = fetchInstancesAction;
|
|
1031
|
+
exports.fetchSamlConfigAction = fetchSamlConfigAction;
|
|
1032
|
+
exports.fetchServiceAccountsAction = fetchServiceAccountsAction;
|
|
1033
|
+
exports.fetchTeamUsersAction = fetchTeamUsersAction;
|
|
1034
|
+
exports.inviteUserAction = inviteUserAction;
|
|
1035
|
+
exports.revokeServiceAccountAction = revokeServiceAccountAction;
|
|
1036
|
+
exports.rotateServiceAccountTokenAction = rotateServiceAccountTokenAction;
|
|
1037
|
+
exports.toggleSamlEnabledAction = toggleSamlEnabledAction;
|
|
1038
|
+
exports.updateSamlConfigAction = updateSamlConfigAction;
|
|
1039
|
+
//# sourceMappingURL=team-settings.js.map
|
|
1040
|
+
//# sourceMappingURL=team-settings.js.map
|