remove da bad tings
This commit is contained in:
parent
5f87ea58d6
commit
5f6b15bc81
18 changed files with 55 additions and 189 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -6,5 +6,6 @@
|
|||
"eslint.validate": ["typescript"],
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
}
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import { McpbManifestSchema as McpbManifestSchema_v0_1 } from "../dist/schemas/0.1.js";
|
||||
import { McpbManifestSchema as McpbManifestSchema_v0_2 } from "../dist/schemas/0.2.js";
|
||||
import {
|
||||
McpbManifestSchema as McpbManifestSchema_v0_3,
|
||||
McpbSignatureInfoSchema,
|
||||
} from "../dist/schemas/0.3.js";
|
||||
import { McpbManifestSchema as McpbManifestSchema_v0_3 } from "../dist/schemas/0.3.js";
|
||||
import { McpbSignatureInfoSchema } from "../dist/shared/common.js";
|
||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
|
|
|||
|
|
@ -2,4 +2,3 @@
|
|||
export * from "./schemas/index.js";
|
||||
export * from "./shared/config.js";
|
||||
export * from "./shared/constants.js";
|
||||
export * from "./types.js";
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ export * from "./cli/pack.js";
|
|||
export * from "./schemas/index.js";
|
||||
export * from "./shared/config.js";
|
||||
export * from "./shared/constants.js";
|
||||
export * from "./types.js";
|
||||
|
||||
// Include node exports since CLI needs them
|
||||
export * from "./node/files.js";
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import { confirm, input, select } from "@inquirer/prompts";
|
||||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||
import { basename, join, resolve } from "path";
|
||||
import type { z } from "zod";
|
||||
|
||||
// Import the schema for DEFAULT_MANIFEST_VERSION
|
||||
// TODO: Allow dynamic manifest version choice
|
||||
import type { McpbManifestSchema } from "../schemas/0.2.js";
|
||||
import { DEFAULT_MANIFEST_VERSION } from "../shared/constants.js";
|
||||
import type { McpbManifestDefault } from "../types.js";
|
||||
|
||||
interface PackageJson {
|
||||
name?: string;
|
||||
|
|
@ -878,7 +881,7 @@ export function buildManifest(
|
|||
// resources: string;
|
||||
// default_locale: string;
|
||||
// },
|
||||
): McpbManifestDefault {
|
||||
): z.infer<typeof McpbManifestSchema> {
|
||||
const { name, displayName, version, description, authorName } = basicInfo;
|
||||
const { authorEmail, authorUrl } = authorInfo;
|
||||
const { serverType, entryPoint, mcp_config } = serverConfig;
|
||||
|
|
|
|||
|
|
@ -8,4 +8,3 @@ export * from "./node/validate.js";
|
|||
export * from "./schemas/index.js";
|
||||
export * from "./shared/config.js";
|
||||
export * from "./shared/constants.js";
|
||||
export * from "./types.js";
|
||||
|
|
|
|||
|
|
@ -7,4 +7,3 @@ export * from "./node/validate.js";
|
|||
export * from "./schemas/index.js";
|
||||
export * from "./shared/config.js";
|
||||
export * from "./shared/constants.js";
|
||||
export * from "./types.js";
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ import forge from "node-forge";
|
|||
import { tmpdir } from "os";
|
||||
import { join } from "path";
|
||||
import { promisify } from "util";
|
||||
import type { z } from "zod";
|
||||
|
||||
import type { McpbSignatureInfo } from "../types.js";
|
||||
import type { McpbSignatureInfoSchema } from "../shared/common.js";
|
||||
|
||||
// Signature block markers
|
||||
const SIGNATURE_HEADER = "MCPB_SIG_V1";
|
||||
|
|
@ -101,7 +102,7 @@ export function signMcpbFile(
|
|||
*/
|
||||
export async function verifyMcpbFile(
|
||||
mcpbPath: string,
|
||||
): Promise<McpbSignatureInfo> {
|
||||
): Promise<z.infer<typeof McpbSignatureInfoSchema>> {
|
||||
try {
|
||||
const fileContent = readFileSync(mcpbPath);
|
||||
|
||||
|
|
|
|||
|
|
@ -71,11 +71,6 @@ export const McpbUserConfigurationOptionSchema = z.strictObject({
|
|||
max: z.number().optional(),
|
||||
});
|
||||
|
||||
export const McpbUserConfigValuesSchema = z.record(
|
||||
z.string(),
|
||||
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
|
||||
);
|
||||
|
||||
export const McpbManifestSchema = z
|
||||
.strictObject({
|
||||
$schema: z.string().optional(),
|
||||
|
|
@ -113,12 +108,3 @@ export const McpbManifestSchema = z
|
|||
message:
|
||||
"Either 'dxt_version' (deprecated) or 'manifest_version' must be provided",
|
||||
});
|
||||
|
||||
export const McpbSignatureInfoSchema = z.strictObject({
|
||||
status: z.enum(["signed", "unsigned", "self-signed"]),
|
||||
publisher: z.string().optional(),
|
||||
issuer: z.string().optional(),
|
||||
valid_from: z.string().optional(),
|
||||
valid_to: z.string().optional(),
|
||||
fingerprint: z.string().optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -71,11 +71,6 @@ export const McpbUserConfigurationOptionSchema = z.strictObject({
|
|||
max: z.number().optional(),
|
||||
});
|
||||
|
||||
export const McpbUserConfigValuesSchema = z.record(
|
||||
z.string(),
|
||||
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
|
||||
);
|
||||
|
||||
export const McpbManifestSchema = z
|
||||
.strictObject({
|
||||
$schema: z.string().optional(),
|
||||
|
|
@ -113,12 +108,3 @@ export const McpbManifestSchema = z
|
|||
message:
|
||||
"Either 'dxt_version' (deprecated) or 'manifest_version' must be provided",
|
||||
});
|
||||
|
||||
export const McpbSignatureInfoSchema = z.strictObject({
|
||||
status: z.enum(["signed", "unsigned", "self-signed"]),
|
||||
publisher: z.string().optional(),
|
||||
issuer: z.string().optional(),
|
||||
valid_from: z.string().optional(),
|
||||
valid_to: z.string().optional(),
|
||||
fingerprint: z.string().optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -76,11 +76,6 @@ export const McpbUserConfigurationOptionSchema = z.strictObject({
|
|||
max: z.number().optional(),
|
||||
});
|
||||
|
||||
export const McpbUserConfigValuesSchema = z.record(
|
||||
z.string(),
|
||||
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
|
||||
);
|
||||
|
||||
export const McpbManifestLocalizationSchema = z.strictObject({
|
||||
resources: z
|
||||
.string()
|
||||
|
|
@ -147,12 +142,3 @@ export const McpbManifestSchema = z
|
|||
message:
|
||||
"Either 'dxt_version' (deprecated) or 'manifest_version' must be provided",
|
||||
});
|
||||
|
||||
export const McpbSignatureInfoSchema = z.strictObject({
|
||||
status: z.enum(["signed", "unsigned", "self-signed"]),
|
||||
publisher: z.string().optional(),
|
||||
issuer: z.string().optional(),
|
||||
valid_from: z.string().optional(),
|
||||
valid_to: z.string().optional(),
|
||||
fingerprint: z.string().optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -73,11 +73,6 @@ export const McpbUserConfigurationOptionSchema = z.object({
|
|||
max: z.number().optional(),
|
||||
});
|
||||
|
||||
export const McpbUserConfigValuesSchema = z.record(
|
||||
z.string(),
|
||||
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
|
||||
);
|
||||
|
||||
export const McpbManifestSchema = z
|
||||
.object({
|
||||
$schema: z.string().optional(),
|
||||
|
|
@ -115,12 +110,3 @@ export const McpbManifestSchema = z
|
|||
message:
|
||||
"Either 'dxt_version' (deprecated) or 'manifest_version' must be provided",
|
||||
});
|
||||
|
||||
export const McpbSignatureInfoSchema = z.object({
|
||||
status: z.enum(["signed", "unsigned", "self-signed"]),
|
||||
publisher: z.string().optional(),
|
||||
issuer: z.string().optional(),
|
||||
valid_from: z.string().optional(),
|
||||
valid_to: z.string().optional(),
|
||||
fingerprint: z.string().optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -73,11 +73,6 @@ export const McpbUserConfigurationOptionSchema = z.object({
|
|||
max: z.number().optional(),
|
||||
});
|
||||
|
||||
export const McpbUserConfigValuesSchema = z.record(
|
||||
z.string(),
|
||||
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
|
||||
);
|
||||
|
||||
export const McpbManifestSchema = z
|
||||
.object({
|
||||
$schema: z.string().optional(),
|
||||
|
|
@ -116,12 +111,3 @@ export const McpbManifestSchema = z
|
|||
message:
|
||||
"Either 'dxt_version' (deprecated) or 'manifest_version' must be provided",
|
||||
});
|
||||
|
||||
export const McpbSignatureInfoSchema = z.object({
|
||||
status: z.enum(["signed", "unsigned", "self-signed"]),
|
||||
publisher: z.string().optional(),
|
||||
issuer: z.string().optional(),
|
||||
valid_from: z.string().optional(),
|
||||
valid_to: z.string().optional(),
|
||||
fingerprint: z.string().optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -77,11 +77,6 @@ export const McpbUserConfigurationOptionSchema = z.object({
|
|||
max: z.number().optional(),
|
||||
});
|
||||
|
||||
export const McpbUserConfigValuesSchema = z.record(
|
||||
z.string(),
|
||||
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
|
||||
);
|
||||
|
||||
export const McpbManifestLocalizationSchema = z
|
||||
.object({
|
||||
resources: z
|
||||
|
|
@ -153,12 +148,3 @@ export const McpbManifestSchema = z
|
|||
message:
|
||||
"Either 'dxt_version' (deprecated) or 'manifest_version' must be provided",
|
||||
});
|
||||
|
||||
export const McpbSignatureInfoSchema = z.object({
|
||||
status: z.enum(["signed", "unsigned", "self-signed"]),
|
||||
publisher: z.string().optional(),
|
||||
issuer: z.string().optional(),
|
||||
valid_from: z.string().optional(),
|
||||
valid_to: z.string().optional(),
|
||||
fingerprint: z.string().optional(),
|
||||
});
|
||||
|
|
|
|||
15
src/shared/common.ts
Normal file
15
src/shared/common.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { z } from "zod";
|
||||
|
||||
export const McpbUserConfigValuesSchema = z.record(
|
||||
z.string(),
|
||||
z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
|
||||
);
|
||||
|
||||
export const McpbSignatureInfoSchema = z.strictObject({
|
||||
status: z.enum(["signed", "unsigned", "self-signed"]),
|
||||
publisher: z.string().optional(),
|
||||
issuer: z.string().optional(),
|
||||
valid_from: z.string().optional(),
|
||||
valid_to: z.string().optional(),
|
||||
fingerprint: z.string().optional(),
|
||||
});
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
import type {
|
||||
Logger,
|
||||
McpbManifestAny,
|
||||
McpbUserConfigValues,
|
||||
McpServerConfig,
|
||||
} from "../types.js";
|
||||
import type { z } from "zod";
|
||||
|
||||
import type { Logger, McpbManifestAny } from "../types.js";
|
||||
import type { McpbUserConfigValuesSchema } from "./common.js";
|
||||
|
||||
/**
|
||||
* This file contains utility functions for handling MCPB configuration,
|
||||
|
|
@ -88,14 +86,14 @@ interface GetMcpConfigForManifestOptions {
|
|||
manifest: McpbManifestAny;
|
||||
extensionPath: string;
|
||||
systemDirs: Record<string, string>;
|
||||
userConfig: McpbUserConfigValues;
|
||||
userConfig: z.infer<typeof McpbUserConfigValuesSchema>;
|
||||
pathSeparator: string;
|
||||
logger?: Logger;
|
||||
}
|
||||
|
||||
export async function getMcpConfigForManifest(
|
||||
options: GetMcpConfigForManifestOptions,
|
||||
): Promise<McpServerConfig | undefined> {
|
||||
): Promise<McpbManifestAny["server"]["mcp_config"] | undefined> {
|
||||
const {
|
||||
manifest,
|
||||
extensionPath,
|
||||
|
|
@ -109,7 +107,7 @@ export async function getMcpConfigForManifest(
|
|||
return undefined;
|
||||
}
|
||||
|
||||
let result: McpServerConfig = {
|
||||
let result: McpbManifestAny["server"]["mcp_config"] = {
|
||||
...baseConfig,
|
||||
};
|
||||
|
||||
|
|
@ -173,14 +171,17 @@ export async function getMcpConfigForManifest(
|
|||
}
|
||||
|
||||
// Replace all variables in the config
|
||||
result = replaceVariables(result, variables) as McpServerConfig;
|
||||
result = replaceVariables(
|
||||
result,
|
||||
variables,
|
||||
) as McpbManifestAny["server"]["mcp_config"];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
interface HasRequiredConfigMissingOptions {
|
||||
manifest: McpbManifestAny;
|
||||
userConfig?: McpbUserConfigValues;
|
||||
userConfig?: z.infer<typeof McpbUserConfigValuesSchema>;
|
||||
}
|
||||
|
||||
function isInvalidSingleValue(value: unknown): boolean {
|
||||
|
|
|
|||
65
src/types.ts
65
src/types.ts
|
|
@ -1,77 +1,12 @@
|
|||
import type * as z from "zod";
|
||||
|
||||
// Import schema types from the version matching DEFAULT_MANIFEST_VERSION
|
||||
import type {
|
||||
McpbManifestAuthorSchema,
|
||||
McpbManifestCompatibilitySchema,
|
||||
McpbManifestMcpConfigSchema,
|
||||
McpbManifestPlatformOverrideSchema,
|
||||
McpbManifestPromptSchema,
|
||||
McpbManifestRepositorySchema,
|
||||
McpbManifestServerSchema,
|
||||
McpbManifestToolSchema,
|
||||
McpbSignatureInfoSchema,
|
||||
McpbUserConfigurationOptionSchema,
|
||||
McpbUserConfigValuesSchema,
|
||||
McpServerConfigSchema,
|
||||
} from "./schemas/0.2.js";
|
||||
import type { McpbManifestSchema as McpbManifestSchemaAny } from "./schemas/any.js";
|
||||
import type { VERSIONED_MANIFEST_SCHEMAS } from "./schemas/index.js";
|
||||
import type { DEFAULT_MANIFEST_VERSION } from "./shared/constants.js";
|
||||
|
||||
export type McpServerConfig = z.infer<typeof McpServerConfigSchema>;
|
||||
|
||||
export type McpbManifestAuthor = z.infer<typeof McpbManifestAuthorSchema>;
|
||||
|
||||
export type McpbManifestRepository = z.infer<
|
||||
typeof McpbManifestRepositorySchema
|
||||
>;
|
||||
|
||||
export type McpbManifestPlatformOverride = z.infer<
|
||||
typeof McpbManifestPlatformOverrideSchema
|
||||
>;
|
||||
|
||||
export type McpbManifestMcpConfig = z.infer<typeof McpbManifestMcpConfigSchema>;
|
||||
|
||||
export type McpbManifestServer = z.infer<typeof McpbManifestServerSchema>;
|
||||
|
||||
export type McpbManifestCompatibility = z.infer<
|
||||
typeof McpbManifestCompatibilitySchema
|
||||
>;
|
||||
|
||||
export type McpbManifestTool = z.infer<typeof McpbManifestToolSchema>;
|
||||
|
||||
export type McpbManifestPrompt = z.infer<typeof McpbManifestPromptSchema>;
|
||||
|
||||
export type McpbUserConfigurationOption = z.infer<
|
||||
typeof McpbUserConfigurationOptionSchema
|
||||
>;
|
||||
|
||||
export type McpbUserConfigValues = z.infer<typeof McpbUserConfigValuesSchema>;
|
||||
|
||||
/**
|
||||
* McpbManifest type representing the union of all manifest versions
|
||||
*/
|
||||
export type McpbManifestAny = z.infer<typeof McpbManifestSchemaAny>;
|
||||
|
||||
/**
|
||||
* McpbManifest type for the DEFAULT_MANIFEST_VERSION
|
||||
* Use this for creating new manifests with the default version.
|
||||
*/
|
||||
export type McpbManifestDefault = z.infer<
|
||||
(typeof VERSIONED_MANIFEST_SCHEMAS)[typeof DEFAULT_MANIFEST_VERSION]
|
||||
>;
|
||||
|
||||
/**
|
||||
* @deprecated Use McpbManifestAny instead to support all manifest versions, or McpbManifestDefault for the default version.
|
||||
*/
|
||||
export type McpbManifest = McpbManifestDefault;
|
||||
|
||||
/**
|
||||
* Information about a MCPB package signature
|
||||
*/
|
||||
export type McpbSignatureInfo = z.infer<typeof McpbSignatureInfoSchema>;
|
||||
|
||||
export interface Logger {
|
||||
log: (...args: unknown[]) => void;
|
||||
error: (...args: unknown[]) => void;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
hasRequiredConfigMissing,
|
||||
replaceVariables,
|
||||
} from "../src/shared/config";
|
||||
import type { Logger, McpbManifest } from "../src/types";
|
||||
import type { Logger, McpbManifestAny } from "../src/types";
|
||||
|
||||
describe("replaceVariables", () => {
|
||||
it("should replace variables in strings", () => {
|
||||
|
|
@ -89,7 +89,7 @@ describe("getMcpConfigForManifest", () => {
|
|||
data: "/data",
|
||||
};
|
||||
|
||||
const baseManifest: McpbManifest = {
|
||||
const baseManifest: McpbManifestAny = {
|
||||
manifest_version: "0.2",
|
||||
name: "test-extension",
|
||||
version: "1.0.0",
|
||||
|
|
@ -114,7 +114,7 @@ describe("getMcpConfigForManifest", () => {
|
|||
const manifest = {
|
||||
...baseManifest,
|
||||
server: undefined,
|
||||
} as unknown as McpbManifest;
|
||||
} as unknown as McpbManifestAny;
|
||||
|
||||
const result = await getMcpConfigForManifest({
|
||||
manifest,
|
||||
|
|
@ -129,7 +129,7 @@ describe("getMcpConfigForManifest", () => {
|
|||
});
|
||||
|
||||
it("should return undefined when required config is missing", async () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
apiKey: {
|
||||
|
|
@ -171,7 +171,7 @@ describe("getMcpConfigForManifest", () => {
|
|||
});
|
||||
|
||||
it("should apply platform overrides", async () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
server: {
|
||||
type: "node",
|
||||
|
|
@ -203,7 +203,7 @@ describe("getMcpConfigForManifest", () => {
|
|||
});
|
||||
|
||||
it("should handle user config variable replacement with defaults", async () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
port: {
|
||||
|
|
@ -236,7 +236,7 @@ describe("getMcpConfigForManifest", () => {
|
|||
});
|
||||
|
||||
it("should handle user config variable replacement with user values", async () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
paths: {
|
||||
|
|
@ -270,7 +270,7 @@ describe("getMcpConfigForManifest", () => {
|
|||
});
|
||||
|
||||
it("should convert boolean user config values to strings", async () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
verbose: {
|
||||
|
|
@ -304,7 +304,7 @@ describe("getMcpConfigForManifest", () => {
|
|||
});
|
||||
|
||||
describe("hasRequiredConfigMissing", () => {
|
||||
const baseManifest: McpbManifest = {
|
||||
const baseManifest: McpbManifestAny = {
|
||||
manifest_version: "0.2",
|
||||
name: "test-extension",
|
||||
version: "1.0.0",
|
||||
|
|
@ -329,7 +329,7 @@ describe("hasRequiredConfigMissing", () => {
|
|||
});
|
||||
|
||||
it("should return false when no config fields are required", () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
port: {
|
||||
|
|
@ -349,7 +349,7 @@ describe("hasRequiredConfigMissing", () => {
|
|||
});
|
||||
|
||||
it("should return false when required config is provided", () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
apiKey: {
|
||||
|
|
@ -369,7 +369,7 @@ describe("hasRequiredConfigMissing", () => {
|
|||
});
|
||||
|
||||
it("should return true when required config is undefined", () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
apiKey: {
|
||||
|
|
@ -389,7 +389,7 @@ describe("hasRequiredConfigMissing", () => {
|
|||
});
|
||||
|
||||
it("should return true when required config is empty string", () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
apiKey: {
|
||||
|
|
@ -409,7 +409,7 @@ describe("hasRequiredConfigMissing", () => {
|
|||
});
|
||||
|
||||
it("should return true when required config is array with invalid values", () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
paths: {
|
||||
|
|
@ -430,7 +430,7 @@ describe("hasRequiredConfigMissing", () => {
|
|||
});
|
||||
|
||||
it("should return true when required config is empty array", () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
paths: {
|
||||
|
|
@ -459,7 +459,7 @@ describe("hasRequiredConfigMissing", () => {
|
|||
});
|
||||
|
||||
it("should handle multiple required config fields", () => {
|
||||
const manifest: McpbManifest = {
|
||||
const manifest: McpbManifestAny = {
|
||||
...baseManifest,
|
||||
user_config: {
|
||||
apiKey: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue