Compare commits

..

3 Commits

Author SHA1 Message Date
nishthaAhujaa
811a6dd363 cloudshell screenshot fix 2025-08-18 18:44:24 +05:30
BChoudhury-ms
012d043c78 Fix CloudShell terminal hanging for Mongo and Cassandra shells due to missing updateTerminalData method (#2199) 2025-08-13 13:02:27 -07:00
Mike Krüger
3afd74a957 Fix faifax default cloud shell region. (#2201) 2025-08-13 11:25:18 -07:00
43 changed files with 36386 additions and 2571 deletions

View File

@@ -144,5 +144,3 @@ __mocks__/monaco-editor.ts
src/Explorer/Tree/ResourceTree.tsx src/Explorer/Tree/ResourceTree.tsx
src/Utils/EndpointUtils.ts src/Utils/EndpointUtils.ts
src/Utils/PriorityBasedExecutionUtils.ts src/Utils/PriorityBasedExecutionUtils.ts
utils/local-proxy/**

View File

@@ -1,3 +0,0 @@
{
"EMULATOR_ENDPOINT": "http://localhost:8081"
}

80
package-lock.json generated
View File

@@ -205,58 +205,6 @@
"webpack-dev-server": "4.15.2" "webpack-dev-server": "4.15.2"
} }
}, },
"canvas": {
"version": "1.0.0",
"extraneous": true,
"license": "ISC"
},
"local_dependencies/@azure/cosmos": {
"version": "4.0.1-beta.3",
"extraneous": true,
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0",
"@azure/core-rest-pipeline": "^1.2.0",
"@azure/core-tracing": "^1.0.0",
"debug": "^4.1.1",
"fast-json-stable-stringify": "^2.1.0",
"jsbi": "^3.1.3",
"node-abort-controller": "^3.0.0",
"priorityqueuejs": "^2.0.0",
"semaphore": "^1.0.5",
"tslib": "^2.2.0",
"universal-user-agent": "^6.0.0",
"uuid": "^8.3.0"
},
"engines": {
"node": ">=18.0.0"
}
},
"local_dependencies/cosmos": {
"name": "@azure/cosmos",
"version": "4.0.1-beta.3",
"extraneous": true,
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0",
"@azure/core-rest-pipeline": "^1.2.0",
"@azure/core-tracing": "^1.0.0",
"debug": "^4.1.1",
"fast-json-stable-stringify": "^2.1.0",
"jsbi": "^3.1.3",
"node-abort-controller": "^3.0.0",
"priorityqueuejs": "^2.0.0",
"semaphore": "^1.0.5",
"tslib": "^2.2.0",
"universal-user-agent": "^6.0.0",
"uuid": "^8.3.0"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6", "version": "1.2.6",
"license": "MIT", "license": "MIT",
@@ -7945,7 +7893,7 @@
} }
}, },
"node_modules/@nteract/data-explorer/node_modules/cross-spawn": { "node_modules/@nteract/data-explorer/node_modules/cross-spawn": {
"version": "7.0.5", "version": "6.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nice-try": "^1.0.4", "nice-try": "^1.0.4",
@@ -8069,7 +8017,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cross-spawn": "^7.0.5", "cross-spawn": "^6.0.0",
"get-stream": "^4.0.0", "get-stream": "^4.0.0",
"is-stream": "^1.1.0", "is-stream": "^1.1.0",
"npm-run-path": "^2.0.0", "npm-run-path": "^2.0.0",
@@ -16497,7 +16445,7 @@
} }
}, },
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.5", "version": "7.0.3",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"path-key": "^3.1.0", "path-key": "^3.1.0",
@@ -18411,7 +18359,7 @@
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.12.4", "ajv": "^6.12.4",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"cross-spawn": "^7.0.5", "cross-spawn": "^7.0.2",
"debug": "^4.3.2", "debug": "^4.3.2",
"doctrine": "^3.0.0", "doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
@@ -18998,7 +18946,7 @@
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
"devOptional": true, "devOptional": true,
"dependencies": { "dependencies": {
"cross-spawn": "^7.0.5", "cross-spawn": "^7.0.3",
"get-stream": "^6.0.0", "get-stream": "^6.0.0",
"human-signals": "^2.1.0", "human-signals": "^2.1.0",
"is-stream": "^2.0.0", "is-stream": "^2.0.0",
@@ -19263,7 +19211,7 @@
"methods": "~1.1.2", "methods": "~1.1.2",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"path-to-regexp": "0.1.12", "path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.7", "proxy-addr": "~2.0.7",
"qs": "6.11.0", "qs": "6.11.0",
"range-parser": "~1.2.1", "range-parser": "~1.2.1",
@@ -19299,7 +19247,7 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/express/node_modules/path-to-regexp": { "node_modules/express/node_modules/path-to-regexp": {
"version": "0.1.12", "version": "0.1.7",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -30587,7 +30535,7 @@
"@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/lockfile": "^1.1.0",
"chalk": "^4.1.2", "chalk": "^4.1.2",
"ci-info": "^3.7.0", "ci-info": "^3.7.0",
"cross-spawn": "^7.0.5", "cross-spawn": "^7.0.3",
"find-yarn-workspace-root": "^2.0.0", "find-yarn-workspace-root": "^2.0.0",
"fs-extra": "^9.0.0", "fs-extra": "^9.0.0",
"json-stable-stringify": "^1.0.2", "json-stable-stringify": "^1.0.2",
@@ -31565,7 +31513,7 @@
"address": "^1.1.2", "address": "^1.1.2",
"browserslist": "^4.18.1", "browserslist": "^4.18.1",
"chalk": "^4.1.2", "chalk": "^4.1.2",
"cross-spawn": "^7.0.5", "cross-spawn": "^7.0.3",
"detect-port-alt": "^1.1.6", "detect-port-alt": "^1.1.6",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"filesize": "^8.0.6", "filesize": "^8.0.6",
@@ -33021,7 +32969,7 @@
} }
}, },
"node_modules/sane/node_modules/cross-spawn": { "node_modules/sane/node_modules/cross-spawn": {
"version": "7.0.5", "version": "6.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nice-try": "^1.0.4", "nice-try": "^1.0.4",
@@ -33038,7 +32986,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cross-spawn": "^7.0.5", "cross-spawn": "^6.0.0",
"get-stream": "^4.0.0", "get-stream": "^4.0.0",
"is-stream": "^1.1.0", "is-stream": "^1.1.0",
"npm-run-path": "^2.0.0", "npm-run-path": "^2.0.0",
@@ -36007,7 +35955,7 @@
"@webpack-cli/serve": "^2.0.5", "@webpack-cli/serve": "^2.0.5",
"colorette": "^2.0.14", "colorette": "^2.0.14",
"commander": "^10.0.1", "commander": "^10.0.1",
"cross-spawn": "^7.0.5", "cross-spawn": "^7.0.3",
"envinfo": "^7.7.3", "envinfo": "^7.7.3",
"fastest-levenshtein": "^1.0.12", "fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2", "import-local": "^3.0.2",
@@ -36532,7 +36480,7 @@
} }
}, },
"node_modules/windows-release/node_modules/cross-spawn": { "node_modules/windows-release/node_modules/cross-spawn": {
"version": "7.0.5", "version": "6.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nice-try": "^1.0.4", "nice-try": "^1.0.4",
@@ -36549,7 +36497,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cross-spawn": "^7.0.5", "cross-spawn": "^6.0.0",
"get-stream": "^4.0.0", "get-stream": "^4.0.0",
"is-stream": "^1.1.0", "is-stream": "^1.1.0",
"npm-run-path": "^2.0.0", "npm-run-path": "^2.0.0",

View File

@@ -206,11 +206,9 @@
"build:dataExplorer:ci": "npm run build:ci", "build:dataExplorer:ci": "npm run build:ci",
"build": "npm run format:check && npm run lint && npm run compile && npm run compile:strict && npm run pack:prod && npm run copyToConsumers", "build": "npm run format:check && npm run lint && npm run compile && npm run compile:strict && npm run pack:prod && npm run copyToConsumers",
"build:ci": "npm run format:check && npm run lint && npm run compile && npm run compile:strict && npm run pack:fast", "build:ci": "npm run format:check && npm run lint && npm run compile && npm run compile:strict && npm run pack:fast",
"build:proxy": "npm run compile && npm run compile:strict && npm run pack:prod && npm run copyToProxy",
"pack:prod": "webpack --mode production", "pack:prod": "webpack --mode production",
"pack:fast": "webpack --mode development --progress", "pack:fast": "webpack --mode development --progress",
"copyToConsumers": "node copyToConsumers", "copyToConsumers": "node copyToConsumers",
"copyToProxy": "rm -rf ./utils/local-proxy/dist && cp -r ./dist ./utils/local-proxy",
"test": "rimraf coverage && jest", "test": "rimraf coverage && jest",
"test:debug": "jest --runInBand", "test:debug": "jest --runInBand",
"test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles", "test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles",

36267
preview/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,7 @@ export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => {
return authorizationToken; return authorizationToken;
} }
if (configContext.platform === Platform.Emulator || configContext.platform === Platform.VNextEmulator) { if (configContext.platform === Platform.Emulator) {
// TODO This SDK method mutates the headers object. Find a better one or fix the SDK. // TODO This SDK method mutates the headers object. Find a better one or fix the SDK.
await Cosmos.setAuthorizationTokenHeaderUsingMasterKey(verb, resourceId, resourceType, headers, EmulatorMasterKey); await Cosmos.setAuthorizationTokenHeaderUsingMasterKey(verb, resourceId, resourceType, headers, EmulatorMasterKey);
return decodeURIComponent(headers.authorization); return decodeURIComponent(headers.authorization);
@@ -119,7 +119,7 @@ export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, diagnost
}; };
export const endpoint = () => { export const endpoint = () => {
if (configContext.platform === Platform.Emulator || configContext.platform === Platform.VNextEmulator) { if (configContext.platform === Platform.Emulator) {
// In worker scope, _global(self).parent does not exist // In worker scope, _global(self).parent does not exist
const location = _global.parent ? _global.parent.location : _global.location; const location = _global.parent ? _global.parent.location : _global.location;
return configContext.EMULATOR_ENDPOINT || location.origin; return configContext.EMULATOR_ENDPOINT || location.origin;

View File

@@ -19,7 +19,6 @@ export enum Platform {
Hosted = "Hosted", Hosted = "Hosted",
Emulator = "Emulator", Emulator = "Emulator",
Fabric = "Fabric", Fabric = "Fabric",
VNextEmulator = "VNextEmulator",
} }
export interface ConfigContext { export interface ConfigContext {
@@ -216,7 +215,7 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
const AAD_ENDPOINT = params.get("aadEndpoint") || ""; const AAD_ENDPOINT = params.get("aadEndpoint") || "";
updateConfigContext({ AAD_ENDPOINT }); updateConfigContext({ AAD_ENDPOINT });
} }
if (params.has("platform") && configContext.platform !== Platform.VNextEmulator) { if (params.has("platform")) {
const platform = params.get("platform"); const platform = params.get("platform");
switch (platform) { switch (platform) {
default: default:

View File

@@ -10,7 +10,6 @@ import { useDatabases } from "Explorer/useDatabases";
import { isFabric, isFabricNative } from "Platform/Fabric/FabricUtil"; import { isFabric, isFabricNative } from "Platform/Fabric/FabricUtil";
import { Action } from "Shared/Telemetry/TelemetryConstants"; import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor"; import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import { areAdvancedScriptsSupported } from "Utils/PlatformFeatureUtils";
import { ReactTabKind, useTabs } from "hooks/useTabs"; import { ReactTabKind, useTabs } from "hooks/useTabs";
import React from "react"; import React from "react";
import AddCollectionIcon from "../../images/AddCollection.svg"; import AddCollectionIcon from "../../images/AddCollection.svg";
@@ -131,7 +130,6 @@ export const createCollectionContextMenuButton = (
} }
if ( if (
areAdvancedScriptsSupported(configContext.platform) &&
configContext.platform !== Platform.Fabric && configContext.platform !== Platform.Fabric &&
(userContext.apiType === "SQL" || userContext.apiType === "Gremlin") (userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
) { ) {

View File

@@ -15,7 +15,6 @@ import { useDatabases } from "Explorer/useDatabases";
import { isFabricNative } from "Platform/Fabric/FabricUtil"; import { isFabricNative } from "Platform/Fabric/FabricUtil";
import { isVectorSearchEnabled } from "Utils/CapabilityUtils"; import { isVectorSearchEnabled } from "Utils/CapabilityUtils";
import { isRunningOnPublicCloud } from "Utils/CloudUtils"; import { isRunningOnPublicCloud } from "Utils/CloudUtils";
import { isFeatureSupported, PlatformFeature } from "Utils/PlatformFeatureUtils";
import * as React from "react"; import * as React from "react";
import DiscardIcon from "../../../../images/discard.svg"; import DiscardIcon from "../../../../images/discard.svg";
import SaveIcon from "../../../../images/save-cosmos.svg"; import SaveIcon from "../../../../images/save-cosmos.svg";
@@ -61,15 +60,15 @@ import {
AddMongoIndexProps, AddMongoIndexProps,
ChangeFeedPolicyState, ChangeFeedPolicyState,
GeospatialConfigType, GeospatialConfigType,
MongoIndexTypes,
SettingsV2TabTypes,
TtlType,
getMongoNotification, getMongoNotification,
getTabTitle, getTabTitle,
hasDatabaseSharedThroughput, hasDatabaseSharedThroughput,
isDirty, isDirty,
MongoIndexTypes,
parseConflictResolutionMode, parseConflictResolutionMode,
parseConflictResolutionProcedure, parseConflictResolutionProcedure,
SettingsV2TabTypes,
TtlType,
} from "./SettingsUtils"; } from "./SettingsUtils";
interface SettingsV2TabInfo { interface SettingsV2TabInfo {
@@ -277,14 +276,14 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
this.saveSettingsButton = { this.saveSettingsButton = {
isEnabled: this.isSaveSettingsButtonEnabled, isEnabled: this.isSaveSettingsButtonEnabled,
isVisible: () => { isVisible: () => {
return isFeatureSupported(PlatformFeature.UpdateCollection); return true;
}, },
}; };
this.discardSettingsChangesButton = { this.discardSettingsChangesButton = {
isEnabled: this.isDiscardSettingsButtonEnabled, isEnabled: this.isDiscardSettingsButtonEnabled,
isVisible: () => { isVisible: () => {
return isFeatureSupported(PlatformFeature.UpdateCollection); return true;
}, },
}; };
@@ -1336,7 +1335,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
}); });
} }
if (isFeatureSupported(PlatformFeature.ComputedProperties) && this.shouldShowComputedPropertiesEditor) { if (this.shouldShowComputedPropertiesEditor) {
tabs.push({ tabs.push({
tab: SettingsV2TabTypes.ComputedPropertiesTab, tab: SettingsV2TabTypes.ComputedPropertiesTab,
content: <ComputedPropertiesComponent {...computedPropertiesComponentProps} />, content: <ComputedPropertiesComponent {...computedPropertiesComponentProps} />,

View File

@@ -45,7 +45,7 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
constructor(props: ScaleComponentProps) { constructor(props: ScaleComponentProps) {
super(props); super(props);
this.isEmulator = configContext.platform === Platform.Emulator || configContext.platform === Platform.VNextEmulator; this.isEmulator = configContext.platform === Platform.Emulator;
this.offer = this.props.database?.offer() || this.props.collection?.offer(); this.offer = this.props.database?.offer() || this.props.collection?.offer();
this.databaseId = this.props.database?.id() || this.props.collection.databaseId; this.databaseId = this.props.database?.id() || this.props.collection.databaseId;
this.collectionId = this.props.collection?.id(); this.collectionId = this.props.collection?.id();

View File

@@ -3,7 +3,7 @@ import { Link } from "@fluentui/react/lib/Link";
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility"; import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
import { Environment, getEnvironment } from "Common/EnvironmentUtility"; import { Environment, getEnvironment } from "Common/EnvironmentUtility";
import { sendMessage } from "Common/MessageHandler"; import { sendMessage } from "Common/MessageHandler";
import { configContext, Platform } from "ConfigContext"; import { Platform, configContext } from "ConfigContext";
import { MessageTypes } from "Contracts/ExplorerContracts"; import { MessageTypes } from "Contracts/ExplorerContracts";
import { useDataPlaneRbac } from "Explorer/Panes/SettingsPane/SettingsPane"; import { useDataPlaneRbac } from "Explorer/Panes/SettingsPane/SettingsPane";
import { getCopilotEnabled, isCopilotFeatureRegistered } from "Explorer/QueryCopilot/Shared/QueryCopilotClient"; import { getCopilotEnabled, isCopilotFeatureRegistered } from "Explorer/QueryCopilot/Shared/QueryCopilotClient";
@@ -18,7 +18,6 @@ import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
import { acquireMsalTokenForAccount } from "Utils/AuthorizationUtils"; import { acquireMsalTokenForAccount } from "Utils/AuthorizationUtils";
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointUtils"; import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointUtils";
import { featureRegistered } from "Utils/FeatureRegistrationUtils"; import { featureRegistered } from "Utils/FeatureRegistrationUtils";
import { isFeatureSupported, PlatformFeature } from "Utils/PlatformFeatureUtils";
import { update } from "Utils/arm/generatedClients/cosmos/databaseAccounts"; import { update } from "Utils/arm/generatedClients/cosmos/databaseAccounts";
import { useQueryCopilot } from "hooks/useQueryCopilot"; import { useQueryCopilot } from "hooks/useQueryCopilot";
import * as ko from "knockout"; import * as ko from "knockout";
@@ -1188,7 +1187,6 @@ export default class Explorer {
// TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount // TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount
const isNotebookEnabled = const isNotebookEnabled =
isFeatureSupported(PlatformFeature.Notebooks) &&
configContext.platform !== Platform.Fabric && configContext.platform !== Platform.Fabric &&
(userContext.features.notebooksDownBanner || (userContext.features.notebooksDownBanner ||
useNotebook.getState().isPhoenixNotebooks || useNotebook.getState().isPhoenixNotebooks ||
@@ -1196,11 +1194,7 @@ export default class Explorer {
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled); useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
useNotebook useNotebook
.getState() .getState()
.setIsShellEnabled( .setIsShellEnabled(useNotebook.getState().isPhoenixFeatures && isPublicInternetAccessAllowed());
isFeatureSupported(PlatformFeature.CloudShell) &&
useNotebook.getState().isPhoenixFeatures &&
isPublicInternetAccessAllowed(),
);
TelemetryProcessor.trace(Action.NotebookEnabled, ActionModifiers.Mark, { TelemetryProcessor.trace(Action.NotebookEnabled, ActionModifiers.Mark, {
isNotebookEnabled, isNotebookEnabled,
@@ -1221,7 +1215,6 @@ export default class Explorer {
public async configureCopilot(): Promise<void> { public async configureCopilot(): Promise<void> {
if ( if (
!isFeatureSupported(PlatformFeature.Copilot) ||
userContext.apiType !== "SQL" || userContext.apiType !== "SQL" ||
!userContext.subscriptionId || !userContext.subscriptionId ||
![Environment.Development, Environment.Mpac, Environment.Prod].includes(getEnvironment()) ![Environment.Development, Environment.Mpac, Environment.Prod].includes(getEnvironment())

View File

@@ -1,6 +1,5 @@
import { KeyboardAction } from "KeyboardShortcuts"; import { KeyboardAction } from "KeyboardShortcuts";
import { isDataplaneRbacSupported } from "Utils/APITypeUtils"; import { isDataplaneRbacSupported } from "Utils/APITypeUtils";
import { areAdvancedScriptsSupported, isFeatureSupported, PlatformFeature } from "Utils/PlatformFeatureUtils";
import * as React from "react"; import * as React from "react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import AddSqlQueryIcon from "../../../../images/AddSqlQuery_16x16.svg"; import AddSqlQueryIcon from "../../../../images/AddSqlQuery_16x16.svg";
@@ -18,7 +17,7 @@ import SynapseIcon from "../../../../images/synapse-link.svg";
import VSCodeIcon from "../../../../images/vscode.svg"; import VSCodeIcon from "../../../../images/vscode.svg";
import { AuthType } from "../../../AuthType"; import { AuthType } from "../../../AuthType";
import * as Constants from "../../../Common/Constants"; import * as Constants from "../../../Common/Constants";
import { configContext, Platform } from "../../../ConfigContext"; import { Platform, configContext } from "../../../ConfigContext";
import * as ViewModels from "../../../Contracts/ViewModels"; import * as ViewModels from "../../../Contracts/ViewModels";
import { userContext } from "../../../UserContext"; import { userContext } from "../../../UserContext";
import { isRunningOnNationalCloud } from "../../../Utils/CloudUtils"; import { isRunningOnNationalCloud } from "../../../Utils/CloudUtils";
@@ -53,7 +52,6 @@ export function createStaticCommandBarButtons(
}; };
if ( if (
isFeatureSupported(PlatformFeature.SynapseLink) &&
configContext.platform !== Platform.Fabric && configContext.platform !== Platform.Fabric &&
userContext.apiType !== "Tables" && userContext.apiType !== "Tables" &&
userContext.apiType !== "Cassandra" userContext.apiType !== "Cassandra"
@@ -65,11 +63,9 @@ export function createStaticCommandBarButtons(
} }
if (userContext.apiType !== "Gremlin") { if (userContext.apiType !== "Gremlin") {
const addVsCode = createOpenVsCodeDialogButton(container); const addVsCode = createOpenVsCodeDialogButton(container);
if (addVsCode) {
buttons.push(addVsCode); buttons.push(addVsCode);
} }
} }
}
if (isDataplaneRbacSupported(userContext.apiType)) { if (isDataplaneRbacSupported(userContext.apiType)) {
const [loginButtonProps, setLoginButtonProps] = useState<CommandButtonComponentProps | undefined>(undefined); const [loginButtonProps, setLoginButtonProps] = useState<CommandButtonComponentProps | undefined>(undefined);
@@ -246,17 +242,11 @@ export function createDivider(): CommandButtonComponentProps {
function areScriptsSupported(): boolean { function areScriptsSupported(): boolean {
return ( return (
areAdvancedScriptsSupported() && configContext.platform !== Platform.Fabric && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
configContext.platform !== Platform.Fabric &&
(userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
); );
} }
function createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonComponentProps { function createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonComponentProps {
if (!isFeatureSupported(PlatformFeature.SynapseLink)) {
return undefined;
}
if (configContext.platform === Platform.Emulator) { if (configContext.platform === Platform.Emulator) {
return undefined; return undefined;
} }
@@ -284,10 +274,6 @@ function createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonCo
} }
function createOpenVsCodeDialogButton(container: Explorer): CommandButtonComponentProps { function createOpenVsCodeDialogButton(container: Explorer): CommandButtonComponentProps {
if (!isFeatureSupported(PlatformFeature.VSCodeIntegration)) {
return undefined;
}
const label = "Visual Studio Code"; const label = "Visual Studio Code";
return { return {
iconSrc: VSCodeIcon, iconSrc: VSCodeIcon,

View File

@@ -50,7 +50,6 @@ import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext"; import { userContext } from "UserContext";
import { getCollectionName } from "Utils/APITypeUtils"; import { getCollectionName } from "Utils/APITypeUtils";
import { isCapabilityEnabled, isServerlessAccount, isVectorSearchEnabled } from "Utils/CapabilityUtils"; import { isCapabilityEnabled, isServerlessAccount, isVectorSearchEnabled } from "Utils/CapabilityUtils";
import { isFeatureSupported, PlatformFeature } from "Utils/PlatformFeatureUtils";
import { getUpsellMessage } from "Utils/PricingUtils"; import { getUpsellMessage } from "Utils/PricingUtils";
import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils"; import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils";
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils"; import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
@@ -728,7 +727,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
/> />
)} )}
{isFeatureSupported(PlatformFeature.UniqueKeys) && !isFabricNative() && userContext.apiType === "SQL" && ( {!isFabricNative() && userContext.apiType === "SQL" && (
<Stack style={{ marginTop: -2, marginBottom: -4 }}> <Stack style={{ marginTop: -2, marginBottom: -4 }}>
{UniqueKeysHeader()} {UniqueKeysHeader()}
{this.state.uniqueKeys.map((uniqueKey: string, i: number): JSX.Element => { {this.state.uniqueKeys.map((uniqueKey: string, i: number): JSX.Element => {
@@ -901,9 +900,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
</CollapsibleSectionComponent> </CollapsibleSectionComponent>
</Stack> </Stack>
)} )}
{isFeatureSupported(PlatformFeature.AdvancedContainerSettings) && {!isFabricNative() && userContext.apiType !== "Tables" && (
!isFabricNative() &&
userContext.apiType !== "Tables" && (
<CollapsibleSectionComponent <CollapsibleSectionComponent
title="Advanced" title="Advanced"
isExpandedByDefault={false} isExpandedByDefault={false}
@@ -956,22 +953,16 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
styles={{ styles={{
text: { fontSize: 12 }, text: { fontSize: 12 },
checkbox: { width: 12, height: 12 }, checkbox: { width: 12, height: 12 },
label: { label: { padding: 0, alignItems: "center", wordWrap: "break-word", whiteSpace: "break-spaces" },
padding: 0,
alignItems: "center",
wordWrap: "break-word",
whiteSpace: "break-spaces",
},
}} }}
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) => onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
this.setState({ useHashV1: isChecked, subPartitionKeys: [] }) this.setState({ useHashV1: isChecked, subPartitionKeys: [] })
} }
/> />
<Text variant="small"> <Text variant="small">
<Icon iconName="InfoSolid" className="removeIcon" /> To ensure compatibility with older SDKs, <Icon iconName="InfoSolid" className="removeIcon" /> To ensure compatibility with older SDKs, the
the created container will use a legacy partitioning scheme that supports partition key values created container will use a legacy partitioning scheme that supports partition key values of size
of size only up to 101 bytes. If this is enabled, you will not be able to use hierarchical only up to 101 bytes. If this is enabled, you will not be able to use hierarchical partition keys.{" "}
partition keys.{" "}
<Link href="https://aka.ms/cosmos-large-pk" target="_blank"> <Link href="https://aka.ms/cosmos-large-pk" target="_blank">
Learn more Learn more
</Link> </Link>
@@ -1143,10 +1134,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
// } // }
private shouldShowCollectionThroughputInput(): boolean { private shouldShowCollectionThroughputInput(): boolean {
if (!isFeatureSupported(PlatformFeature.ContainerThroughput)) {
return false;
}
if (isServerlessAccount()) { if (isServerlessAccount()) {
return false; return false;
} }
@@ -1173,15 +1160,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
} }
private shouldShowVectorSearchParameters() { private shouldShowVectorSearchParameters() {
return ( return isVectorSearchEnabled() && (isServerlessAccount() || this.shouldShowCollectionThroughputInput());
isFeatureSupported(PlatformFeature.VectorSearch) &&
isVectorSearchEnabled() &&
(isServerlessAccount() || this.shouldShowCollectionThroughputInput())
);
} }
private shouldShowFullTextSearchParameters() { private shouldShowFullTextSearchParameters() {
return isFeatureSupported(PlatformFeature.FullTextSearch) && !isFabricNative() && this.showFullTextSearch; return !isFabricNative() && this.showFullTextSearch;
} }
private parseUniqueKeys(): DataModels.UniqueKeyPolicy { private parseUniqueKeys(): DataModels.UniqueKeyPolicy {

View File

@@ -6,7 +6,6 @@ import { getFullTextLanguageOptions } from "Explorer/Controls/FullTextSeach/Full
import { isFabricNative } from "Platform/Fabric/FabricUtil"; import { isFabricNative } from "Platform/Fabric/FabricUtil";
import React from "react"; import React from "react";
import { userContext } from "UserContext"; import { userContext } from "UserContext";
import { isFeatureSupported, PlatformFeature } from "Utils/PlatformFeatureUtils";
export function getPartitionKeyTooltipText(): string { export function getPartitionKeyTooltipText(): string {
if (userContext.apiType === "Mongo") { if (userContext.apiType === "Mongo") {
@@ -86,11 +85,7 @@ export function UniqueKeysHeader(): JSX.Element {
} }
export function shouldShowAnalyticalStoreOptions(): boolean { export function shouldShowAnalyticalStoreOptions(): boolean {
if ( if (isFabricNative() || configContext.platform === Platform.Emulator) {
!isFeatureSupported(PlatformFeature.AnalyticalStore) ||
isFabricNative() ||
configContext.platform === Platform.Emulator
) {
return false; return false;
} }

View File

@@ -202,7 +202,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
const styles = useStyles(); const styles = useStyles();
const explorerVersion = configContext.gitSha; const explorerVersion = configContext.gitSha;
const isEmulator = configContext.platform === Platform.Emulator || configContext.platform === Platform.VNextEmulator; const isEmulator = configContext.platform === Platform.Emulator;
const shouldShowQueryPageOptions = userContext.apiType === "SQL"; const shouldShowQueryPageOptions = userContext.apiType === "SQL";
const showRetrySettings = const showRetrySettings =
(userContext.apiType === "SQL" || userContext.apiType === "Tables" || userContext.apiType === "Gremlin") && (userContext.apiType === "SQL" || userContext.apiType === "Tables" || userContext.apiType === "Gremlin") &&

View File

@@ -22,6 +22,7 @@ import { formatErrorMessage, formatInfoMessage, formatWarningMessage } from "./U
// Constants // Constants
const DEFAULT_CLOUDSHELL_REGION = "westus"; const DEFAULT_CLOUDSHELL_REGION = "westus";
const DEFAULT_FAIRFAX_CLOUDSHELL_REGION = "usgovvirginia";
const POLLING_INTERVAL_MS = 2000; const POLLING_INTERVAL_MS = 2000;
const MAX_RETRY_COUNT = 10; const MAX_RETRY_COUNT = 10;
const MAX_PING_COUNT = 120 * 60; // 120 minutes (60 seconds/minute) const MAX_PING_COUNT = 120 * 60; // 120 minutes (60 seconds/minute)
@@ -153,7 +154,9 @@ export const ensureCloudShellProviderRegistered = async (): Promise<void> => {
* Determines the appropriate CloudShell region * Determines the appropriate CloudShell region
*/ */
export const determineCloudShellRegion = (): string => { export const determineCloudShellRegion = (): string => {
return getNormalizedRegion(userContext.databaseAccount?.location, DEFAULT_CLOUDSHELL_REGION); const defaultRegion =
userContext.portalEnv === "fairfax" ? DEFAULT_FAIRFAX_CLOUDSHELL_REGION : DEFAULT_CLOUDSHELL_REGION;
return getNormalizedRegion(userContext.databaseAccount?.location, defaultRegion);
}; };
/** /**

View File

@@ -33,6 +33,7 @@ jest.mock("../../../../UserContext", () => ({
})); }));
jest.mock("../Utils/CommonUtils", () => ({ jest.mock("../Utils/CommonUtils", () => ({
...jest.requireActual("../Utils/CommonUtils"),
getHostFromUrl: jest.fn().mockReturnValue("test-mongo.documents.azure.com"), getHostFromUrl: jest.fn().mockReturnValue("test-mongo.documents.azure.com"),
})); }));
@@ -124,7 +125,10 @@ describe("MongoShellHandler", () => {
describe("getTerminalSuppressedData", () => { describe("getTerminalSuppressedData", () => {
it("should return the correct warning message", () => { it("should return the correct warning message", () => {
expect(mongoShellHandler.getTerminalSuppressedData()).toEqual(["Warning: Non-Genuine MongoDB Detected"]); expect(mongoShellHandler.getTerminalSuppressedData()).toEqual([
"Warning: Non-Genuine MongoDB Detected",
"Telemetry is now disabled.",
]);
}); });
}); });
}); });

View File

@@ -1,10 +1,11 @@
import { userContext } from "../../../../UserContext"; import { userContext } from "../../../../UserContext";
import { getHostFromUrl } from "../Utils/CommonUtils"; import { filterAndCleanTerminalOutput, getHostFromUrl, getMongoShellRemoveInfoText } from "../Utils/CommonUtils";
import { AbstractShellHandler, DISABLE_TELEMETRY_COMMAND } from "./AbstractShellHandler"; import { AbstractShellHandler, DISABLE_TELEMETRY_COMMAND } from "./AbstractShellHandler";
export class MongoShellHandler extends AbstractShellHandler { export class MongoShellHandler extends AbstractShellHandler {
private _key: string; private _key: string;
private _endpoint: string | undefined; private _endpoint: string | undefined;
private _removeInfoText: string[] = getMongoShellRemoveInfoText();
constructor(private key: string) { constructor(private key: string) {
super(); super();
this._key = key; this._key = key;
@@ -44,6 +45,10 @@ export class MongoShellHandler extends AbstractShellHandler {
} }
public getTerminalSuppressedData(): string[] { public getTerminalSuppressedData(): string[] {
return ["Warning: Non-Genuine MongoDB Detected"]; return ["Warning: Non-Genuine MongoDB Detected", "Telemetry is now disabled."];
}
updateTerminalData(data: string): string {
return filterAndCleanTerminalOutput(data, this._removeInfoText);
} }
} }

View File

@@ -1,13 +1,10 @@
import { userContext } from "../../../../UserContext"; import { userContext } from "../../../../UserContext";
import { filterAndCleanTerminalOutput, getMongoShellRemoveInfoText } from "../Utils/CommonUtils";
import { AbstractShellHandler, DISABLE_TELEMETRY_COMMAND } from "./AbstractShellHandler"; import { AbstractShellHandler, DISABLE_TELEMETRY_COMMAND } from "./AbstractShellHandler";
export class VCoreMongoShellHandler extends AbstractShellHandler { export class VCoreMongoShellHandler extends AbstractShellHandler {
private _endpoint: string | undefined; private _endpoint: string | undefined;
private _textFilterRules: string[] = [ private _removeInfoText: string[] = getMongoShellRemoveInfoText();
"For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/",
"disableTelemetry() command",
"https://www.mongodb.com/legal/privacy-policy",
];
constructor() { constructor() {
super(); super();
@@ -38,12 +35,7 @@ export class VCoreMongoShellHandler extends AbstractShellHandler {
return ["Warning: Non-Genuine MongoDB Detected", "Telemetry is now disabled."]; return ["Warning: Non-Genuine MongoDB Detected", "Telemetry is now disabled."];
} }
updateTerminalData(content: string): string { updateTerminalData(data: string): string {
const updatedContent = content return filterAndCleanTerminalOutput(data, this._removeInfoText);
.split("\n")
.filter((line) => !this._textFilterRules.some((part) => line.includes(part)))
.filter((line, idx, arr) => (arr.length > 3 && idx <= arr.length - 3 ? !["", "\r"].includes(line) : true)) // Filter out empty lines and carriage returns, but keep the last 3 lines if they exist
.join("\n");
return updatedContent;
} }
} }

View File

@@ -135,7 +135,11 @@ export class AttachAddon implements ITerminalAddon {
} }
if (this._allowTerminalWrite) { if (this._allowTerminalWrite) {
const updatedData = this._shellHandler?.updateTerminalData(data) ?? data; const updatedData =
typeof this._shellHandler?.updateTerminalData === "function"
? this._shellHandler.updateTerminalData(data)
: data;
const suppressedData = this._shellHandler?.getTerminalSuppressedData(); const suppressedData = this._shellHandler?.getTerminalSuppressedData();
const shouldNotWrite = suppressedData.filter(Boolean).some((item) => updatedData.includes(item)); const shouldNotWrite = suppressedData.filter(Boolean).some((item) => updatedData.includes(item));

View File

@@ -0,0 +1,71 @@
import { userContext } from "../../../../UserContext";
export const CLOUDSHELL_IP_RECOMMENDATIONS = {
centralindia: [
{ startIP: "4.247.135.109", endIP: "4.247.135.109" },
{ startIP: "74.225.207.63", endIP: "74.225.207.63" },
],
southeastasia: [{ startIP: "4.194.5.74", endIP: "4.194.213.10" }],
centraluseuap: [
{ startIP: "52.158.186.182", endIP: "52.158.186.182" },
{ startIP: "172.215.26.246", endIP: "172.215.26.246" },
{ startIP: "134.138.154.177", endIP: "134.138.154.177" },
{ startIP: "134.138.129.52", endIP: "134.138.129.52" },
{ startIP: "172.215.31.177", endIP: "172.215.31.177" },
],
eastus2euap: [
{ startIP: "135.18.43.51", endIP: "135.18.43.51" },
{ startIP: "20.252.175.33", endIP: "20.252.175.33" },
{ startIP: "40.89.88.111", endIP: "40.89.88.111" },
{ startIP: "135.18.17.187", endIP: "135.18.17.187" },
{ startIP: "135.18.67.251", endIP: "135.18.67.251" },
],
eastus: [
{ startIP: "40.71.199.151", endIP: "40.71.199.151" },
{ startIP: "20.42.18.188", endIP: "20.42.18.188" },
{ startIP: "52.190.17.9", endIP: "52.190.17.9" },
{ startIP: "20.120.96.152", endIP: "20.120.96.152" },
],
northeurope: [
{ startIP: "74.234.65.146", endIP: "74.234.65.146" },
{ startIP: "52.169.70.113", endIP: "52.169.70.113" },
],
southcentralus: [
{ startIP: "4.151.247.81", endIP: "4.151.247.81" },
{ startIP: "20.225.211.35", endIP: "20.225.211.35" },
{ startIP: "4.151.48.133", endIP: "4.151.48.133" },
{ startIP: "4.151.247.225", endIP: "4.151.247.225" },
],
westeurope: [
{ startIP: "52.166.126.216", endIP: "52.166.126.216" },
{ startIP: "108.142.162.20", endIP: "108.142.162.20" },
{ startIP: "52.178.13.125", endIP: "52.178.13.125" },
{ startIP: "172.201.33.160", endIP: "172.201.33.160" },
],
westus: [
{ startIP: "20.245.161.131", endIP: "20.245.161.131" },
{ startIP: "57.154.182.51", endIP: "57.154.182.51" },
{ startIP: "40.118.133.244", endIP: "40.118.133.244" },
{ startIP: "20.253.192.12", endIP: "20.253.192.12" },
{ startIP: "20.43.245.209", endIP: "20.43.245.209" },
{ startIP: "20.66.22.66", endIP: "20.66.22.66" },
],
} as const;
export interface CloudShellIPRange {
startIP: string;
endIP: string;
}
export function getCloudShellIPsForRegion(region: string): readonly CloudShellIPRange[] {
const normalizedRegion = region.toLowerCase();
return CLOUDSHELL_IP_RECOMMENDATIONS[normalizedRegion as keyof typeof CLOUDSHELL_IP_RECOMMENDATIONS] || [];
}
export function getClusterRegion(): string {
const location = userContext?.databaseAccount?.location;
if (location) {
return location.toLowerCase();
}
return "";
}

View File

@@ -50,3 +50,34 @@ export const getShellNameForDisplay = (terminalKind: TerminalKind): string => {
return ""; return "";
} }
}; };
/**
* Get MongoDB shell information text that should be removed from terminal output
*/
export const getMongoShellRemoveInfoText = (): string[] => {
return [
"For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/",
"disableTelemetry() command",
"https://www.mongodb.com/legal/privacy-policy",
];
};
export const filterAndCleanTerminalOutput = (data: string, removeInfoText: string[]): string => {
if (!data || removeInfoText.length === 0) {
return data;
}
const lines = data.split("\n");
const filteredLines: string[] = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const shouldRemove = removeInfoText.some((text) => line.includes(text));
if (!shouldRemove) {
filteredLines.push(line);
}
}
return filteredLines.join("\n").replace(/((\r\n)|\n|\r){2,}/g, "\r\n");
};

View File

@@ -8,6 +8,8 @@ const validCloudShellRegions = new Set([
"centralindia", "centralindia",
"southeastasia", "southeastasia",
"westcentralus", "westcentralus",
"usgovvirginia",
"usgovarizona",
]); ]);
/** /**

View File

@@ -0,0 +1,78 @@
import { configContext } from "ConfigContext";
import * as DataModels from "Contracts/DataModels";
import { userContext } from "UserContext";
import { armRequest } from "Utils/arm/request";
import {
CloudShellIPRange,
getCloudShellIPsForRegion,
getClusterRegion,
} from "../CloudShellTab/Utils/CloudShellIPUtils";
import { getNormalizedRegion } from "../CloudShellTab/Utils/RegionUtils";
// Constants
const DEFAULT_CLOUDSHELL_REGION = "westus";
/**
* Check if user has added all CloudShell IPs for their normalized region
* @param apiVersion - The API version to use for the ARM request
* @returns Promise<boolean> - true if all CloudShell IPs are configured (don't show screenshot), false if missing (show screenshot)
*/
export async function checkCloudShellIPsConfigured(apiVersion: string): Promise<boolean> {
const clusterRegion = getClusterRegion();
if (!clusterRegion) {
return false;
}
const normalizedRegion = getNormalizedRegion(clusterRegion, DEFAULT_CLOUDSHELL_REGION);
const cloudShellIPs = getCloudShellIPsForRegion(normalizedRegion);
if (cloudShellIPs.length === 0) {
return false;
}
const firewallRulesUri = `${userContext.databaseAccount.id}/firewallRules`;
const response: any = await armRequest({
host: configContext.ARM_ENDPOINT,
path: firewallRulesUri,
method: "GET",
apiVersion: apiVersion,
});
const firewallRules: DataModels.FirewallRule[] = response?.data?.value || response?.value || [];
const missingIPs: Array<{ startIP: string; endIP: string; reason?: string }> = [];
const foundIPs: Array<{ startIP: string; endIP: string; ruleName?: string }> = [];
for (const cloudShellIP of cloudShellIPs) {
const matchingRule = firewallRules.find((rule) => {
const startMatch = rule.properties.startIpAddress === cloudShellIP.startIP;
const endMatch = rule.properties.endIpAddress === cloudShellIP.endIP;
return startMatch && endMatch;
});
if (matchingRule) {
foundIPs.push({ ...cloudShellIP, ruleName: matchingRule.name });
} else {
missingIPs.push({ ...cloudShellIP, reason: "No exact IP match in firewall rules" });
}
}
const allConfigured = missingIPs.length === 0;
return allConfigured;
}
/**
* Get the normalized region and its CloudShell IPs for display in the guide
* @returns Object with region and IPs for the guide
*/
export function getCloudShellGuideInfo(): { region: string; cloudShellIPs: readonly CloudShellIPRange[] } {
const clusterRegion = getClusterRegion();
const normalizedRegion = getNormalizedRegion(clusterRegion || "", DEFAULT_CLOUDSHELL_REGION);
const cloudShellIPs = getCloudShellIPsForRegion(normalizedRegion);
return {
region: normalizedRegion,
cloudShellIPs: cloudShellIPs,
};
}

View File

@@ -22,10 +22,22 @@ export abstract class BaseTerminalComponentAdapter implements ReactAdapter {
protected getUsername: () => string, protected getUsername: () => string,
protected isAllPublicIPAddressesEnabled: ko.Observable<boolean>, protected isAllPublicIPAddressesEnabled: ko.Observable<boolean>,
protected kind: ViewModels.TerminalKind, protected kind: ViewModels.TerminalKind,
protected isCloudShellIPsConfigured?: ko.Observable<boolean>,
) { } ) { }
public renderComponent(): JSX.Element { public renderComponent(): JSX.Element {
if (!this.isAllPublicIPAddressesEnabled()) { const publicIPEnabled = this.isAllPublicIPAddressesEnabled();
const cloudShellConfigured = this.isCloudShellIPsConfigured ? this.isCloudShellIPsConfigured() : true;
let shouldShowScreenshot: boolean;
if (this.isCloudShellIPsConfigured) {
shouldShowScreenshot = !cloudShellConfigured;
} else {
shouldShowScreenshot = !publicIPEnabled;
}
if (shouldShowScreenshot) {
return ( return (
<QuickstartFirewallNotification <QuickstartFirewallNotification
messageType={this.getMessageType()} messageType={this.getMessageType()}

View File

@@ -1,4 +1,5 @@
import { checkFirewallRules } from "Explorer/Tabs/Shared/CheckFirewallRules"; import { checkFirewallRules } from "Explorer/Tabs/Shared/CheckFirewallRules";
import { checkCloudShellIPsConfigured } from "Explorer/Tabs/Shared/CloudShellIPChecker";
import { CloudShellTerminalComponentAdapter } from "Explorer/Tabs/ShellAdapters/CloudShellTerminalComponentAdapter"; import { CloudShellTerminalComponentAdapter } from "Explorer/Tabs/ShellAdapters/CloudShellTerminalComponentAdapter";
import * as ko from "knockout"; import * as ko from "knockout";
import { ReactAdapter } from "../../Bindings/ReactBindingHandler"; import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
@@ -23,11 +24,13 @@ export default class TerminalTab extends TabsBase {
private container: Explorer; private container: Explorer;
private notebookTerminalComponentAdapter: ReactAdapter; private notebookTerminalComponentAdapter: ReactAdapter;
private isAllPublicIPAddressesEnabled: ko.Observable<boolean>; private isAllPublicIPAddressesEnabled: ko.Observable<boolean>;
private isCloudShellIPsConfigured: ko.Observable<boolean>;
constructor(options: TerminalTabOptions) { constructor(options: TerminalTabOptions) {
super(options); super(options);
this.container = options.container; this.container = options.container;
this.isAllPublicIPAddressesEnabled = ko.observable(true); this.isAllPublicIPAddressesEnabled = ko.observable(true);
this.isCloudShellIPsConfigured = ko.observable(true); // Start optimistic, will be updated
const commonArgs: [ const commonArgs: [
() => DataModels.DatabaseAccount, () => DataModels.DatabaseAccount,
@@ -44,10 +47,25 @@ export default class TerminalTab extends TabsBase {
]; ];
if (userContext.features.enableCloudShell) { if (userContext.features.enableCloudShell) {
this.notebookTerminalComponentAdapter = new CloudShellTerminalComponentAdapter(...commonArgs); this.notebookTerminalComponentAdapter = new CloudShellTerminalComponentAdapter(
() => userContext?.databaseAccount,
() => this.tabId,
() => this.getUsername(),
this.isAllPublicIPAddressesEnabled,
options.kind,
this.isCloudShellIPsConfigured,
);
this.notebookTerminalComponentAdapter.parameters = ko.computed<boolean>(() => { this.notebookTerminalComponentAdapter.parameters = ko.computed<boolean>(() => {
return this.isTemplateReady() && this.isAllPublicIPAddressesEnabled(); const cloudShellConfigured = this.isCloudShellIPsConfigured();
return this.isTemplateReady() && cloudShellConfigured;
});
checkCloudShellIPsConfigured("2023-03-01-preview").then(result => {
this.isCloudShellIPsConfigured(result);
}).catch(error => {
console.error(`CloudShell IP Check failed for ${ViewModels.TerminalKind[options.kind]} terminal:`, error);
this.isCloudShellIPsConfigured(false);
}); });
} else { } else {
this.notebookTerminalComponentAdapter = new NotebookTerminalComponentAdapter( this.notebookTerminalComponentAdapter = new NotebookTerminalComponentAdapter(
@@ -65,6 +83,8 @@ export default class TerminalTab extends TabsBase {
}); });
} }
// Only run legacy firewall checks for NON-CloudShell terminals cloudShell terminals use the CloudShell IP checker instead
if (!userContext.features.enableCloudShell) {
if (options.kind === ViewModels.TerminalKind.Postgres) { if (options.kind === ViewModels.TerminalKind.Postgres) {
checkFirewallRules( checkFirewallRules(
"2022-11-08", "2022-11-08",
@@ -83,6 +103,7 @@ export default class TerminalTab extends TabsBase {
); );
} }
} }
}
public getContainer(): Explorer { public getContainer(): Explorer {
return this.container; return this.container;

View File

@@ -21,12 +21,7 @@ import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
import { useSelectedNode } from "../useSelectedNode"; import { useSelectedNode } from "../useSelectedNode";
export const shouldShowScriptNodes = (): boolean => { export const shouldShowScriptNodes = (): boolean => {
return ( return !isFabric() && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin");
!isFabric() &&
configContext.platform !== Platform.Emulator &&
configContext.platform !== Platform.VNextEmulator &&
(userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
);
}; };
const TreeDatabaseIcon = <DatabaseRegular fontSize={16} />; const TreeDatabaseIcon = <DatabaseRegular fontSize={16} />;

View File

@@ -79,22 +79,7 @@ export const defaultAllowedCassandraProxyEndpoints: ReadonlyArray<string> = [
CassandraProxyEndpoints.Mooncake, CassandraProxyEndpoints.Mooncake,
]; ];
export const allowedCassandraProxyEndpoints_ToBeDeprecated: ReadonlyArray<string> = [ export const allowedEmulatorEndpoints: ReadonlyArray<string> = ["https://localhost:8081"];
"https://main.documentdb.ext.azure.com",
"https://main.documentdb.ext.azure.cn",
"https://main.documentdb.ext.azure.us",
"https://main.cosmos.ext.azure",
"https://localhost:12901",
];
export const CassandraProxyOutboundIPs: { [key: string]: string[] } = {
[CassandraProxyEndpoints.Mpac]: ["40.113.96.14", "104.42.11.145"],
[CassandraProxyEndpoints.Prod]: ["137.117.230.240", "168.61.72.237"],
[CassandraProxyEndpoints.Fairfax]: ["52.244.50.101", "52.227.165.24"],
[CassandraProxyEndpoints.Mooncake]: ["40.73.99.146", "143.64.62.47"],
};
export const allowedEmulatorEndpoints: ReadonlyArray<string> = ["https://localhost:8081", "http://localhost:8081"];
export const allowedArcadiaEndpoints: ReadonlyArray<string> = ["https://workspaceartifacts.projectarcadia.net"]; export const allowedArcadiaEndpoints: ReadonlyArray<string> = ["https://workspaceartifacts.projectarcadia.net"];

View File

@@ -1,116 +0,0 @@
import { Platform, configContext } from "../ConfigContext";
/**
* Feature flags enumeration - centralized feature definitions
*/
export enum PlatformFeature {
// UI/Core Features
Queries = "Queries",
Notebooks = "Notebooks",
SynapseLink = "SynapseLink",
VSCodeIntegration = "VSCodeIntegration",
GlobalSecondaryIndex = "GlobalSecondaryIndex",
DataPlaneRbac = "DataPlaneRbac",
EntraIDLogin = "EntraIDLogin",
EntreIDRbac = "EntreIDRbac",
RetrySettings = "RetrySettings",
GraphAutoVizOption = "GraphAutoVizOption",
CrossPartitionOption = "CrossPartitionOption",
EnhancedQueryControl = "EnhancedQueryControl",
ParallelismOption = "ParallelismOption",
EnableEntraIdRbac = "EnableEntraIdRbac",
PriorityBasedExecution = "PriorityBasedExecution",
RegionSelection = "RegionSelection",
Copilot = "Copilot",
CloudShell = "CloudShell",
ContainerPagination = "ContainerPagination",
FullTextSearch = "FullTextSearch",
VectorSearch = "VectorSearch",
ThroughputBucketing = "ThroughputBucketing",
ComputedProperties = "ComputedProperties",
AnalyticalStore = "AnalyticalStore",
UniqueKeys = "UniqueKeys",
ContainerThroughput = "ContainerThroughput",
AdvancedContainerSettings = "AdvancedContainerSettings",
// CRUD Operations - Database
CreateDatabase = "CreateDatabase",
ReadDatabase = "ReadDatabase",
DeleteDatabase = "DeleteDatabase",
// CRUD Operations - Collection
CreateCollection = "CreateCollection",
ReadCollection = "ReadCollection",
UpdateCollection = "UpdateCollection",
DeleteCollection = "DeleteCollection",
// CRUD Operations - Document
CreateDocument = "CreateDocument",
ReadDocument = "ReadDocument",
UpdateDocument = "UpdateDocument",
DeleteDocument = "DeleteDocument",
// Advanced Database Features
StoredProcedures = "StoredProcedures",
UDF = "UDF",
Trigger = "Trigger",
}
/**
* Feature matrix per platform.
* - Only list platforms that have restrictions. If a platform is not present, all features are considered supported.
* - Start with VNextEmulator today; add more platforms/flags here later without touching calling code.
*/
const FEATURE_MATRIX: ReadonlyMap<Platform, ReadonlySet<PlatformFeature>> = new Map([
[
Platform.VNextEmulator,
new Set<PlatformFeature>([
PlatformFeature.Queries,
PlatformFeature.UniqueKeys,
PlatformFeature.CreateDatabase,
PlatformFeature.ReadDatabase,
PlatformFeature.DeleteDatabase,
PlatformFeature.CreateCollection,
PlatformFeature.ReadCollection,
PlatformFeature.UpdateCollection,
PlatformFeature.DeleteCollection,
PlatformFeature.CreateDocument,
PlatformFeature.ReadDocument,
PlatformFeature.UpdateDocument,
PlatformFeature.DeleteDocument,
]),
],
]);
/**
* Central feature flag function - checks if a feature is enabled for current platform
* @param feature The feature to check
* @param platform Optional platform override, defaults to current platform
* @returns True if the feature is enabled for the platform, false otherwise
*/
export const isFeatureSupported = (feature: PlatformFeature, platform?: Platform): boolean => {
const currentPlatform = platform ?? configContext.platform;
if (currentPlatform !== Platform.VNextEmulator) {
return true;
}
// VNextEmulator: check from the feature matrix
const vnextFeatures = FEATURE_MATRIX.get(Platform.VNextEmulator);
return vnextFeatures?.has(feature) ?? false;
};
export const areAdvancedScriptsSupported = (platform?: Platform): boolean => {
const currentPlatform = platform ?? configContext.platform;
if (currentPlatform !== Platform.VNextEmulator) {
return true;
}
// Otherwise, require all script features to be enabled
return (
isFeatureSupported(PlatformFeature.StoredProcedures, currentPlatform) &&
isFeatureSupported(PlatformFeature.UDF, currentPlatform) &&
isFeatureSupported(PlatformFeature.Trigger, currentPlatform)
);
};

View File

@@ -1,5 +1,4 @@
import { PartitionKey, PartitionKeyDefinition } from "@azure/cosmos"; import { PartitionKey, PartitionKeyDefinition } from "@azure/cosmos";
import { configContext, Platform } from "ConfigContext";
import { getRUThreshold, ruThresholdEnabled } from "Shared/StorageUtility"; import { getRUThreshold, ruThresholdEnabled } from "Shared/StorageUtility";
import { userContext } from "UserContext"; import { userContext } from "UserContext";
import { logConsoleWarning } from "Utils/NotificationConsoleUtils"; import { logConsoleWarning } from "Utils/NotificationConsoleUtils";
@@ -67,11 +66,7 @@ export function buildDocumentsQueryPartitionProjections(
} }
}); });
const fullAccess = `${collectionAlias}${projectedProperty}`; const fullAccess = `${collectionAlias}${projectedProperty}`;
if ( if (!isSystemPartitionKey) {
!isSystemPartitionKey &&
configContext.platform !== Platform.Emulator &&
configContext.platform !== Platform.VNextEmulator
) {
const wrappedProjection = `IIF(IS_DEFINED(${fullAccess}), ${fullAccess}, {})`; const wrappedProjection = `IIF(IS_DEFINED(${fullAccess}), ${fullAccess}, {})`;
projections.push(wrappedProjection); projections.push(wrappedProjection);
} else { } else {

View File

@@ -86,7 +86,7 @@ export function useKnockoutExplorer(platform: Platform): Explorer {
let explorer: Explorer; let explorer: Explorer;
if (platform === Platform.Hosted) { if (platform === Platform.Hosted) {
explorer = await configureHosted(); explorer = await configureHosted();
} else if (platform === Platform.Emulator || platform === Platform.VNextEmulator) { } else if (platform === Platform.Emulator) {
explorer = configureEmulator(); explorer = configureEmulator();
} else if (platform === Platform.Portal) { } else if (platform === Platform.Portal) {
explorer = await configurePortal(); explorer = await configurePortal();

View File

@@ -1,200 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0" />
<title>Azure Cosmos DB Emulator</title>
</head>
<body>
<div id="divQuickStart">
<div class="Introlines">
<p class="Introline1">Congratulations! Your Azure Cosmos DB emulator is running.</p>
<p class="Introline2">Now, let's connect a sample app to it.</p>
<div id="divQuickStartConnections">
<p class="Introline2">URI</p>
<input type="text" class="codeblock" readonly="readonly" value="http://localhost:8081" />
<p class="Introline2">Primary Key</p>
<input
type="text"
class="codeblock"
readonly="readonly"
value="C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
/>
<p class="Introline2">Primary Connection String</p>
<input
type="text"
class="codeblock"
readonly="readonly"
value="AccountEndpoint=http://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
/>
</div>
<p class="Introline3"><b>Choose a platform</b></p>
</div>
<div class="container-fluid">
<ul class="nav nav-tabs qslevel">
<li class="active">
<a data-toggle="tab" href="#net">
<img class="qsmenuicons" src="../images/dotnet.png" alt=".NET" /> .NET
</a>
</li>
<li>
<a data-toggle="tab" href="#java"> <img class="qsmenuicons" src="../images/java.png" alt="Java" /> Java </a>
</li>
<li>
<a data-toggle="tab" href="#nodejs">
<img class="qsmenuicons" src="../images/nodejs.png" alt="Node.js" /> Node.js
</a>
</li>
<li>
<a data-toggle="tab" href="#python">
<img class="qsmenuicons" src="../images/python.png" alt="Python" /> Python
</a>
</li>
<li>
<a data-toggle="tab" href="#go"> <img class="qsmenuicons" src="../images/golang.svg" alt="Go" /> Go </a>
</li>
<li>
<a data-toggle="tab" href="#springboot">
<img class="qsmenuicons" src="../images/springboot.svg" alt="Spring Boot" /> Spring Boot
</a>
</li>
</ul>
<div class="tab-content">
<div id="net" class="tab-pane fade in active">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new .NET app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-dotnet" target="_blank"
>tutorial
</a>
to create a new .NET app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="java" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Java app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-java" target="_blank"
>tutorial
</a>
to create a new Java app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="nodejs" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Node.js app
<p>
Follow this
<a
href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-nodejs?pivots=programming-language-ts"
target="_blank"
>tutorial
</a>
to create a new Node.js app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="python" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Python app
<p>
Follow this
<a href="https://aka.ms/cosmos-db-emulator/tutorial/python" target="_blank">tutorial</a>
to create a new Python app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="go" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Go app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-go" target="_blank">tutorial</a>
to create a new Go app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="springboot" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Spring Boot app
<p>
Follow this
<a
href="https://learn.microsoft.com/azure/cosmos-db/nosql/tutorial-springboot-azure-kubernetes-service"
target="_blank"
>tutorial</a
>
to create a new Spring Boot app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
</div>
</div>
</div>
<template id="learnMoreTpl">
<div class="app-block">
<div class="numbersize">2</div>
<div class="numberheading">
Learn more about Azure Cosmos DB
<ul>
<li>
<a href="https://azurecosmosdb.github.io/gallery/?tags=example" target="_blank" class="atags"
>Code Samples</a
>
</li>
<li><a href="https://aka.ms/cosmos-db-emulator/docs" target="_blank" class="atags">Documentation</a></li>
<li><a href="https://aka.ms/cosmos-db-emulator/pricing" target="_blank" class="atags">Pricing</a></li>
<li>
<a href="https://cosmos.azure.com/capacitycalculator/" target="_blank" class="atags">Capacity planner</a>
</li>
<li><a href="https://aka.ms/cosmos-db-emulator/stackoverflow" target="_blank" class="atags">Forum</a></li>
</ul>
</div>
</div>
</template>
<script>
document.querySelectorAll(".learn-more").forEach((slot) => {
const node = document.getElementById("learnMoreTpl").content.cloneNode(true);
slot.appendChild(node);
});
</script>
</body>
</html>

View File

@@ -1,200 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0" />
<title>Azure Cosmos DB Emulator</title>
</head>
<body>
<div id="divQuickStart">
<div class="Introlines">
<p class="Introline1">Congratulations! Your Azure Cosmos DB emulator is running.</p>
<p class="Introline2">Now, let's connect a sample app to it.</p>
<div id="divQuickStartConnections">
<p class="Introline2">URI</p>
<input type="text" class="codeblock" readonly="readonly" value="https://localhost:8081" />
<p class="Introline2">Primary Key</p>
<input
type="text"
class="codeblock"
readonly="readonly"
value="C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
/>
<p class="Introline2">Primary Connection String</p>
<input
type="text"
class="codeblock"
readonly="readonly"
value="AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
/>
</div>
<p class="Introline3"><b>Choose a platform</b></p>
</div>
<div class="container-fluid">
<ul class="nav nav-tabs qslevel">
<li class="active">
<a data-toggle="tab" href="#net">
<img class="qsmenuicons" src="../images/dotnet.png" alt=".NET" /> .NET
</a>
</li>
<li>
<a data-toggle="tab" href="#java"> <img class="qsmenuicons" src="../images/java.png" alt="Java" /> Java </a>
</li>
<li>
<a data-toggle="tab" href="#nodejs">
<img class="qsmenuicons" src="../images/nodejs.png" alt="Node.js" /> Node.js
</a>
</li>
<li>
<a data-toggle="tab" href="#python">
<img class="qsmenuicons" src="../images/python.png" alt="Python" /> Python
</a>
</li>
<li>
<a data-toggle="tab" href="#go"> <img class="qsmenuicons" src="../images/golang.svg" alt="Go" /> Go </a>
</li>
<li>
<a data-toggle="tab" href="#springboot">
<img class="qsmenuicons" src="../images/springboot.svg" alt="Spring Boot" /> Spring Boot
</a>
</li>
</ul>
<div class="tab-content">
<div id="net" class="tab-pane fade in active">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new .NET app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-dotnet" target="_blank"
>tutorial
</a>
to create a new .NET app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="java" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Java app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-java" target="_blank"
>tutorial
</a>
to create a new Java app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="nodejs" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Node.js app
<p>
Follow this
<a
href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-nodejs?pivots=programming-language-ts"
target="_blank"
>tutorial
</a>
to create a new Node.js app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="python" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Python app
<p>
Follow this
<a href="https://aka.ms/cosmos-db-emulator/tutorial/python" target="_blank">tutorial</a>
to create a new Python app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="go" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Go app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-go" target="_blank">tutorial</a>
to create a new Go app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="springboot" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Spring Boot app
<p>
Follow this
<a
href="https://learn.microsoft.com/azure/cosmos-db/nosql/tutorial-springboot-azure-kubernetes-service"
target="_blank"
>tutorial</a
>
to create a new Spring Boot app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
</div>
</div>
</div>
<template id="learnMoreTpl">
<div class="app-block">
<div class="numbersize">2</div>
<div class="numberheading">
Learn more about Azure Cosmos DB
<ul>
<li>
<a href="https://azurecosmosdb.github.io/gallery/?tags=example" target="_blank" class="atags"
>Code Samples</a
>
</li>
<li><a href="https://aka.ms/cosmos-db-emulator/docs" target="_blank" class="atags">Documentation</a></li>
<li><a href="https://aka.ms/cosmos-db-emulator/pricing" target="_blank" class="atags">Pricing</a></li>
<li>
<a href="https://cosmos.azure.com/capacitycalculator/" target="_blank" class="atags">Capacity planner</a>
</li>
<li><a href="https://aka.ms/cosmos-db-emulator/stackoverflow" target="_blank" class="atags">Forum</a></li>
</ul>
</div>
</div>
</template>
<script>
document.querySelectorAll(".learn-more").forEach((slot) => {
const node = document.getElementById("learnMoreTpl").content.cloneNode(true);
slot.appendChild(node);
});
</script>
</body>
</html>

View File

@@ -1,179 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0" />
<title>Azure Cosmos DB Emulator (SQL)</title>
</head>
<body>
<div id="divQuickStart">
<div class="Introlines">
<p class="Introline1">Congratulations! Your Azure Cosmos DB emulator is running.</p>
<p class="Introline2">Now, let's connect a sample app to it.</p>
<div id="divQuickStartConnections">
<p class="Introline2">URI</p>
<input type="text" class="codeblock" readonly value="<%= endpointUri %>" />
<p class="Introline2">Primary Key</p>
<input type="text" class="codeblock" readonly value="<%= primaryKey %>" />
<p class="Introline2">Primary Connection String</p>
<input type="text" class="codeblock" readonly value="<%= primaryConnString %>" />
</div>
<p class="Introline3"><b>Choose a platform</b></p>
</div>
<div class="container-fluid">
<ul class="nav nav-tabs qslevel">
<li class="active">
<a data-toggle="tab" href="#net"> <img class="qsmenuicons" src="images/dotnet.png" alt=".NET" /> .NET </a>
</li>
<li>
<a data-toggle="tab" href="#java"><img class="qsmenuicons" src="images/java.png" alt="Java" /> Java</a>
</li>
<li>
<a data-toggle="tab" href="#nodejs"
><img class="qsmenuicons" src="images/nodejs.png" alt="Node.js" /> Node.js</a
>
</li>
<li>
<a data-toggle="tab" href="#python"
><img class="qsmenuicons" src="images/python.png" alt="Python" /> Python</a
>
</li>
<li>
<a data-toggle="tab" href="#go"><img class="qsmenuicons" src="images/golang.svg" alt="Go" /> Go</a>
</li>
<li>
<a data-toggle="tab" href="#springboot"
><img class="qsmenuicons" src="images/springboot.svg" alt="Spring Boot" /> Spring Boot</a
>
</li>
</ul>
<div class="tab-content">
<div id="net" class="tab-pane fade in active">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new .NET app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-dotnet" target="_blank"
>tutorial</a
>
to create a new .NET app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="java" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Java app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-java" target="_blank"
>tutorial</a
>
to create a new Java app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="nodejs" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Node.js app
<p>
Follow this
<a
href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-nodejs?pivots=programming-language-ts"
target="_blank"
>tutorial</a
>
to create a new Node.js app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="python" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Python app
<p>
Follow this <a href="https://aka.ms/cosmos-db-emulator/tutorial/python" target="_blank">tutorial</a>
to create a new Python app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="go" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Go app
<p>
Follow this
<a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-go" target="_blank">tutorial</a>
to create a new Go app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
<div id="springboot" class="tab-pane fade">
<div class="sampleApp">
<div class="numbersize numbersizePadding">1</div>
<div class="numberheading">
Create a new Spring Boot app
<p>
Follow this
<a
href="https://learn.microsoft.com/azure/cosmos-db/nosql/tutorial-springboot-azure-kubernetes-service"
target="_blank"
>tutorial</a
>
to create a new Spring Boot app connected to Azure Cosmos DB.
</p>
</div>
</div>
<div class="learn-more"></div>
</div>
</div>
</div>
</div>
<template id="learnMoreTpl">
<div class="app-block">
<div class="numbersize">2</div>
<div class="numberheading">
Learn more about Azure Cosmos DB
<ul>
<li>
<a href="https://azurecosmosdb.github.io/gallery/?tags=example" target="_blank" class="atags"
>Code Samples</a
>
</li>
<li><a href="https://aka.ms/cosmos-db-emulator/docs" target="_blank" class="atags">Documentation</a></li>
<li><a href="https://aka.ms/cosmos-db-emulator/pricing" target="_blank" class="atags">Pricing</a></li>
<li>
<a href="https://cosmos.azure.com/capacitycalculator/" target="_blank" class="atags">Capacity planner</a>
</li>
<li><a href="https://aka.ms/cosmos-db-emulator/stackoverflow" target="_blank" class="atags">Forum</a></li>
</ul>
</div>
</div>
</template>
<script>
document.querySelectorAll(".learn-more").forEach((slot) => {
const node = document.getElementById("learnMoreTpl").content.cloneNode(true);
slot.appendChild(node);
});
</script>
</body>
</html>

View File

@@ -15,12 +15,18 @@
"target": "es2017", "target": "es2017",
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"lib": ["es5", "es6", "dom"], "lib": [
"es5",
"es6",
"dom"
],
"jsx": "react", "jsx": "react",
"moduleResolution": "node", "moduleResolution": "node",
"resolveJsonModule": true, "resolveJsonModule": true,
"noEmit": true, "noEmit": true,
"types": ["jest"], "types": [
"jest"
],
"baseUrl": "src" "baseUrl": "src"
}, },
"typedocOptions": { "typedocOptions": {
@@ -37,8 +43,14 @@
"includes": "./src/SelfServe/Documentation", "includes": "./src/SelfServe/Documentation",
"disableSources": true "disableSources": true
}, },
"include": ["src", "./src/**/*", "./utils/**/*"], "include": [
"exclude": ["./src/**/__mocks__/**/*", "./utils/local-proxy/**/*"], "src",
"./src/**/*",
"./utils/**/*"
],
"exclude": [
"./src/**/__mocks__/**/*"
],
"ts-node": { "ts-node": {
"compilerOptions": { "compilerOptions": {
"module": "CommonJS" "module": "CommonJS"

View File

@@ -1,6 +0,0 @@
dist*
node_modules
*.cert
*.key
*.pfx
*.log

View File

@@ -1,177 +0,0 @@
const express = require("express");
const { createProxyMiddleware } = require("http-proxy-middleware");
const { inspect } = require("util");
const fs = require("fs");
const https = require("https");
const conf = {};
conf.PORT = process.env.EXPLORER_PORT || 1234;
conf.LOG_LEVEL = process.env.LOG_LEVEL || "info";
conf.EMULATOR_ENDPOINT = process.env.EMULATOR_ENDPOINT || "http://localhost:8081";
conf.ENDPOINT_DISCOVERY_ENABLED = (process.env.ENDPOINT_DISCOVERY_ENABLED || "false").toLowerCase() === "true";
conf.GATEWAY_TLS_ENABLED = (process.env.GATEWAY_TLS_ENABLED || "false").toLowerCase() === "true";
conf.CERT_PATH = process.env.CERT_PATH;
conf.CERT_SECRET = process.env.CERT_SECRET;
const LOG_NUM = levelToNumber(conf.LOG_LEVEL);
function _log(level, msg, color) {
if (levelToNumber(level) >= LOG_NUM) {
console.log(`${colorToCode(color)}[${level || "debug"}]${msg}\x1b[0m`);
}
}
function _debug(msg, color) {
_log("debug", msg, color);
}
function _info(msg, color) {
_log("info", msg, color);
}
function _warn(msg, color) {
_log("warn", msg, color || "yellow");
}
function _err(msg, color) {
_log("error", msg, color || "red");
}
function levelToNumber(level) {
switch (level) {
case "debug":
return 0;
case "info":
return 1;
case "warn":
return 2;
case "error":
return 3;
default:
return 0;
}
}
function colorToCode(color) {
switch (color) {
case "red":
return "\x1b[31m";
case "green":
return "\x1b[32m";
case "blue":
return "\x1b[34m";
case "yellow":
return "\x1b[33m";
default:
return "\x1b[0m";
}
}
function statusToColor(status) {
if (status < 300) {
return "green";
} else if (status < 400) {
return "blue";
} else {
return "red";
}
}
const testEndpoint = () => {
fetch(conf.EMULATOR_ENDPOINT)
.then(async (res) => {
const body = await res.json();
_info("[EMU] Emulator is accessible");
})
.catch((e) => {
_warn("[EMU] Emulator is not accessible");
_warn(`[EMU] ${inspect(e)}`);
});
};
testEndpoint();
const app = express();
app.use((e, req, res, next) => {
_err(`[APP] ${inspect(e)}`);
res.status(500).json({ error: _err.message });
});
app.use((req, res, next) => {
req.startTime = new Date();
res.append("Access-Control-Allow-Origin", "*");
res.append("Access-Control-Allow-Credentials", "true");
res.append("Access-Control-Max-Age", "3600");
res.append("Access-Control-Allow-Headers", "*");
res.append("Access-Control-Allow-Methods", "*");
res.once("finish", () => {
const ms = new Date() - req.startTime;
(res.statusCode < 400 ? _debug : _err)(
`[APP] ${req.method} ${req.url} ${res.statusCode} - ${ms}ms`,
statusToColor(res.statusCode),
);
});
next();
});
app.get("/_ready", (_, res) => {
res.status(200).send("Compilation complete.");
});
const appConf = {
PROXY_PATH: "/proxy",
EMULATOR_ENDPOINT: conf.EMULATOR_ENDPOINT,
platform: "VNextEmulator",
};
app.get("/config.json", (_, res) => {
res.status(200).json(appConf).end();
});
const proxyProxy = createProxyMiddleware({
target: "https://cdb-ms-mpac-pbe.cosmos.azure.com",
changeOrigin: true,
secure: false,
logLevel: conf.LOG_LEVEL,
pathRewrite: { "^/proxy": "" },
router: (req) => {
if (conf.ENDPOINT_DISCOVERY_ENABLED) {
let newTarget = req.headers["x-ms-proxy-target"];
return newTarget;
} else {
return conf.EMULATOR_ENDPOINT;
}
},
});
app.use("/proxy", proxyProxy);
const unsupported = (req, res) => {
res.status(404).send("Unexpected operation. Please create issue.");
};
// TODO: andersonc - I don't believe these are needed for emulator, should confirm and remove.
app.use("/api", unsupported);
app.use("/_explorer", unsupported);
app.use("/explorerProxy", unsupported);
app.use(`/${conf.AZURE_TENANT_ID}`, unsupported);
app.use(express.static("dist"));
_info(`[EMU] Expecting emulator on [${conf.EMULATOR_ENDPOINT}]`);
_info(`[APP] Listening on [${conf.PORT}]`);
if (conf.GATEWAY_TLS_ENABLED) {
if (!conf.CERT_PATH || !conf.CERT_SECRET) {
_err("[APP] Certificate path or secret not provided");
process.exit(1);
}
const options = {
pfx: fs.readFileSync(conf.CERT_PATH),
passphrase: conf.CERT_SECRET,
};
const server = https.createServer(options, app);
server.listen(conf.PORT);
} else {
app.listen(conf.PORT);
}

View File

@@ -1 +0,0 @@
require('./index.js');

View File

@@ -1,984 +0,0 @@
{
"name": "local-proxy",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "local-proxy",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"express": "^4.21.1",
"http-proxy-middleware": "^3.0.3"
}
},
"node_modules/@types/http-proxy": {
"version": "1.17.15",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz",
"integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "22.10.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
"integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"license": "MIT",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/body-parser": {
"version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"license": "MIT",
"dependencies": {
"safe-buffer": "5.2.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
"node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"license": "MIT",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"license": "MIT"
},
"node_modules/express": {
"version": "4.21.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.7.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.19.0",
"serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/finalhandler": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"statuses": "2.0.1",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"hasown": "^2.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.1.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-proto": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"license": "MIT",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/http-proxy": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
"license": "MIT",
"dependencies": {
"eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/http-proxy-middleware": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz",
"integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==",
"license": "MIT",
"dependencies": {
"@types/http-proxy": "^1.17.15",
"debug": "^4.3.6",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.3",
"is-plain-object": "^5.0.0",
"micromatch": "^4.0.8"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/http-proxy-middleware/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/http-proxy-middleware/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/merge-descriptors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=8.6"
}
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"license": "MIT",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/object-inspect": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/path-to-regexp": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"license": "MIT",
"dependencies": {
"forwarded": "0.2.0",
"ipaddr.js": "1.9.1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/qs": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/raw-body": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"license": "MIT"
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/send": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/send/node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/send/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/serve-static": {
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"license": "MIT",
"dependencies": {
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.19.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
"node_modules/side-channel": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.4",
"object-inspect": "^1.13.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"license": "MIT",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"license": "MIT"
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
"license": "MIT",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
}
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "local-proxy",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node main.js",
"pack": "cd ../.. && npm run build:proxy && cd utils/local-proxy"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"express": "^4.21.1",
"http-proxy-middleware": "^3.0.3"
}
}

View File

@@ -1,39 +0,0 @@
# local-proxy
Lightweight host for Cosmos Explorer
## Quickstart
1. Pre-req - install packages for root project (`cd ../.. && npm ci && cd utils/local-proxy`)
2. Install - install packages for local-proxy (`npm ci`)
3. Pack - `npm run pack` - builds and packs Cosmos Explorer and copies files into project
4. Start - `npm start` - starts the proxy
```bash
cd ../..
npm ci
cd utils/local-proxy
npm ci
npm run pack
npm start
```
## Config
All config is current set via environment variables
| Name | Options (Default) | Description |
| ---------------------------- | ----------------------------------------- | ------------------------------------------------------------ |
| `PORT` | number (`1234`) | The port on which the proxy runs. |
| `LOG_LEVEL` | `debug`, `info`, `warn`, `error` (`info`) | The logging level for the proxy. |
| `EMULATOR_ENDPOINT` | string (`http://localhost:8081`) | The endpoint for the emulator which will be proxied. |
| `ENDPOINT_DISCOVERY_ENABLED` | boolean (`false`) | Determine whether the proxy will rewrite the endpoint or not |
## Dependenies
Node.js v20+
npm (optional)
## Deployment
Copy the entire local-proxy directory to wherever you'd like. If you have npm, you can use `npm start`, else `node main.js`

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env bash
pushd $(dirname $0) > /dev/null
echo Creating self-signed certificate
# Create a self-signed certificate
export CERT_SECRET=$(openssl rand -base64 20)
openssl genrsa 2048 > host.key
chmod 400 host.key
#openssl req -new -x509 -nodes -sha256 -days 365 -key host.key -out host.cert --passin env:CERT_SECRET -subj "/C=US/ST=WA/L=BELLEVUE/O=Microsoft/OU=Azure Cosmos DB/CN=CHRIS ANDERSON/emailAddress=andersonc@microsoft.com"
openssl pkcs12 -export -out host.pfx -inkey host.key -in host.cert --passout env:CERT_SECRET --name "CHRIS ANDERSON"
export CERT_PATH=$(realpath host.pfx)
echo CERT_PATH=$CERT_PATH
popd > /dev/null
export GATEWAY_TLS_ENABLED=true
export EXPLORER_PORT=12345
# Use node to start so we can kill it later
node main.js > ./https-test.log &
node_pid=$!
echo node pid=$node_pid
sleep .5
output=$(curl --insecure -s "https://localhost:12345/_ready")
kill -KILL $node_pid
if [ "$output" != "Compilation complete." ]; then
echo "Failed to start HTTPS server"
cat ./https-test.log
exit 1
fi
echo https test completed

View File

@@ -24,8 +24,6 @@ const AZURE_TENANT_ID = "72f988bf-86f1-41af-91ab-2d7cd011db47";
const RESOURCE_GROUP = "de-e2e-tests"; const RESOURCE_GROUP = "de-e2e-tests";
const AZURE_CLIENT_SECRET = process.env.AZURE_CLIENT_SECRET || process.env.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET; // TODO Remove. Exists for backwards compat with old .env files. Prefer AZURE_CLIENT_SECRET const AZURE_CLIENT_SECRET = process.env.AZURE_CLIENT_SECRET || process.env.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET; // TODO Remove. Exists for backwards compat with old .env files. Prefer AZURE_CLIENT_SECRET
const ishttps = process.env.GATEWAY_TLS_ENABLED !== "false"; // false -> false, true -> true, default -> true
if (!AZURE_CLIENT_SECRET) { if (!AZURE_CLIENT_SECRET) {
console.warn("AZURE_CLIENT_SECRET is not set. testExplorer.html will not work."); console.warn("AZURE_CLIENT_SECRET is not set. testExplorer.html will not work.");
} }
@@ -122,23 +120,6 @@ module.exports = function (_env = {}, argv = {}) {
...(mode !== "production" && { testExplorer: "./test/testExplorer/TestExplorer.ts" }), ...(mode !== "production" && { testExplorer: "./test/testExplorer/TestExplorer.ts" }),
}; };
// Derive emulator endpoint components from EMULATOR_ENDPOINT (fallback to localhost defaults)
const rawEndpoint = process.env.EMULATOR_ENDPOINT || (ishttps ? "https://localhost:8081/" : "http://localhost:8081/");
let endpointProtocol = ishttps ? "https" : "http";
let endpointHost = "localhost";
let endpointPort = "8081";
try {
const u = new URL(rawEndpoint);
endpointProtocol = u.protocol.replace(":", "");
endpointHost = u.hostname;
endpointPort = u.port || (endpointProtocol === "https" ? "443" : "80");
} catch (e) {
// Ignore parse errors and keep defaults
}
const endpointUri = `${endpointProtocol}://${endpointHost}:${endpointPort}`;
const primaryKeyConst = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
const primaryConnString = `AccountEndpoint=${endpointUri}/;AccountKey=${primaryKeyConst}`;
const htmlWebpackPlugins = [ const htmlWebpackPlugins = [
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: "explorer.html", filename: "explorer.html",
@@ -150,16 +131,10 @@ module.exports = function (_env = {}, argv = {}) {
template: "src/Terminal/index.html", template: "src/Terminal/index.html",
chunks: ["terminal"], chunks: ["terminal"],
}), }),
//todo - dynamically include apis
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: "quickstart.html", filename: "quickstart.html",
template: "src/quickstart-sql.template.ejs", template: "src/quickstart.html",
chunks: ["quickstart"], chunks: ["quickstart"],
templateParameters: {
endpointUri,
primaryKey: primaryKeyConst,
primaryConnString,
},
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: "index.html", filename: "index.html",
@@ -236,20 +211,11 @@ module.exports = function (_env = {}, argv = {}) {
{ from: "DataExplorer.proj" }, { from: "DataExplorer.proj" },
{ from: "web.config" }, { from: "web.config" },
{ from: "quickstart/*.zip" }, { from: "quickstart/*.zip" },
{ from: "images", to: "images" },
], ],
}), }),
new EnvironmentPlugin(envVars), new EnvironmentPlugin(envVars),
]; ];
if (process.env.EXPLORER_CONFIG_PATH) {
plugins.push(
new CopyWebpackPlugin({
patterns: [{ from: process.env.EXPLORER_CONFIG_PATH, to: "config.json" }],
}),
);
}
if (argv.analyze) { if (argv.analyze) {
plugins.push(new BundleAnalyzerPlugin()); plugins.push(new BundleAnalyzerPlugin());
} }
@@ -314,7 +280,7 @@ module.exports = function (_env = {}, argv = {}) {
// disableHostCheck: true, // disableHostCheck: true,
liveReload: !isCI, liveReload: !isCI,
server: { server: {
type: ishttps ? "https" : "http", type: "https",
}, },
host: "0.0.0.0", host: "0.0.0.0",
port: envVars.PORT, port: envVars.PORT,