Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default [
'@frontmcp/protocol',
'@frontmcp/testing',
'@frontmcp/observability',
'^#(mcp-.+|crypto-.+|async-.+|event-.+|langchain-.+|sse-.+|express-.+|server-.+|stdio-.+|env|runtime-context|path|client|import-computed)$',
'^#(mcp-.+|crypto-.+|async-.+|event-.+|langchain-.+|sse-.+|express-.+|server-.+|stdio-.+|env|runtime-context|path|client|import-computed|js-yaml|semver|uipack-render)$',
],
depConstraints: [
{
Expand Down
3 changes: 3 additions & 0 deletions jest.imports-mapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ module.exports = {
'^#sse-transport$': path.resolve(root, 'libs/sdk/src/transport/adapters/polyfills/node-sse-transport.ts'),
'^#express-host$': path.resolve(root, 'libs/sdk/src/server/adapters/polyfills/node-express-host.ts'),
'^#import-computed$': path.resolve(root, 'libs/sdk/src/esm-loader/import-computed.ts'),
'^#js-yaml$': path.resolve(root, 'libs/sdk/src/third-party/js-yaml.ts'),
'^#semver$': path.resolve(root, 'libs/sdk/src/third-party/semver.ts'),
'^#uipack-render$': path.resolve(root, 'libs/sdk/src/third-party/uipack-render.ts'),
};
15 changes: 15 additions & 0 deletions libs/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,21 @@
"#import-computed": {
"import": "./src/esm-loader/import-computed.ts",
"default": "./src/esm-loader/import-computed.ts"
},
"#js-yaml": {
"types": "./src/third-party/js-yaml.ts",
"require": "./src/third-party/lazy-js-yaml.ts",
"default": "./src/third-party/js-yaml.ts"
},
"#semver": {
"types": "./src/third-party/semver.ts",
"require": "./src/third-party/lazy-semver.ts",
"default": "./src/third-party/semver.ts"
},
"#uipack-render": {
"types": "./src/third-party/uipack-render.ts",
"require": "./src/third-party/lazy-uipack-render.ts",
"default": "./src/third-party/uipack-render.ts"
}
},
"type": "commonjs",
Expand Down
11 changes: 11 additions & 0 deletions libs/sdk/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,22 @@
"bundle": true,
"thirdParty": false,
"platform": "node",
"additionalEntryPoints": [
"libs/sdk/src/third-party/js-yaml.ts",
"libs/sdk/src/third-party/lazy-js-yaml.ts",
"libs/sdk/src/third-party/semver.ts",
"libs/sdk/src/third-party/lazy-semver.ts",
"libs/sdk/src/third-party/uipack-render.ts",
"libs/sdk/src/third-party/lazy-uipack-render.ts"
],
"assets": ["libs/sdk/README.md", "LICENSE", "libs/sdk/package.json"],
"esbuildOptions": {
"minifyWhitespace": true,
"outExtension": { ".js": ".js" },
"external": [
"#js-yaml",
"#semver",
"#uipack-render",
"@frontmcp/sdk",
"@frontmcp/utils",
"@frontmcp/di",
Expand Down
9 changes: 3 additions & 6 deletions libs/sdk/src/auth/auth-ui/auth-ui.render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,9 @@
*
* @packageDocumentation
*/
import {
createResolverWithOverrides,
renderComponent,
type ShellConfig,
type ShellMountDescriptor,
} from '@frontmcp/uipack';
import type { ShellConfig, ShellMountDescriptor } from '@frontmcp/uipack';

import { createResolverWithOverrides, renderComponent } from '#uipack-render';

import { AUTH_FLOW_GLOBAL_KEY, AUTH_MOUNT_ID, type AuthFlowState, type AuthSlot } from './auth-ui.contract';
import { type AuthUiRegistry } from './auth-ui.registry';
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk/src/builtin/config/providers/config-loader.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as yaml from 'js-yaml';

import { type z } from '@frontmcp/lazy-zod';
import { fileExists, getCwd, pathResolve, readFile } from '@frontmcp/utils';

import * as yaml from '#js-yaml';

import { ConfigValidationError } from './config.service';
import {
canReadConfigFiles,
Expand Down
16 changes: 9 additions & 7 deletions libs/sdk/src/esm-loader/semver.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
* Isolates the semver dependency to a single file for easier maintenance.
*/

import semverCompare from 'semver/functions/compare.js';
import semverGt from 'semver/functions/gt.js';
import semverRcompare from 'semver/functions/rcompare.js';
import semverSatisfies from 'semver/functions/satisfies.js';
import semverValid from 'semver/functions/valid.js';
import semverMaxSatisfying from 'semver/ranges/max-satisfying.js';
import semverValidRange from 'semver/ranges/valid.js';
import {
compare as semverCompare,
gt as semverGt,
maxSatisfying as semverMaxSatisfying,
rcompare as semverRcompare,
satisfies as semverSatisfies,
valid as semverValid,
validRange as semverValidRange,
} from '#semver';

/**
* Check if a range string is a dist-tag (not a semver range).
Expand Down
2 changes: 1 addition & 1 deletion libs/sdk/src/skill/sep-2640/sep-2640.builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* guidance in the SEP.
*/

import * as yaml from 'js-yaml';
import * as yaml from '#js-yaml';

import type { SkillContent } from '../../common/interfaces';
import type { SkillMetadata } from '../../common/metadata';
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk/src/skill/skill-md-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
* @module skill/skill-md-parser
*/

import * as yaml from 'js-yaml';

import { readFile } from '@frontmcp/utils';

import * as yaml from '#js-yaml';

import type {
SkillExample,
SkillMetadata,
Expand Down
30 changes: 30 additions & 0 deletions libs/sdk/src/third-party/__tests__/lazy-js-yaml.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
describe('lazy-js-yaml', () => {
afterEach(() => {
jest.dontMock('js-yaml');
jest.resetModules();
});

it('loads js-yaml the first time one of its functions is read', () => {
const load = jest.fn();
const loadJsYaml = jest.fn(() => ({ load, dump: jest.fn() }));
jest.doMock('js-yaml', loadJsYaml);

jest.isolateModules(() => {
const lazyYaml = require('../lazy-js-yaml');
expect(loadJsYaml).not.toHaveBeenCalled();

expect(lazyYaml.load).toBe(load);
expect(loadJsYaml).toHaveBeenCalledTimes(1);
});
});

it('exports the functions the eager module exports', () => {
const lazyYaml = require('../lazy-js-yaml');
const eagerYaml = require('../js-yaml');

expect(Object.keys(lazyYaml).sort()).toEqual(Object.keys(eagerYaml).sort());
expect(lazyYaml.load).toBe(eagerYaml.load);
expect(lazyYaml.dump).toBe(eagerYaml.dump);
expect(lazyYaml.load('a: 1')).toEqual({ a: 1 });
});
});
33 changes: 33 additions & 0 deletions libs/sdk/src/third-party/__tests__/lazy-semver.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const SEMVER_FUNCTIONS = ['compare', 'gt', 'maxSatisfying', 'rcompare', 'satisfies', 'valid', 'validRange'];

describe('lazy-semver', () => {
afterEach(() => {
jest.dontMock('semver/functions/satisfies.js');
jest.resetModules();
});

it('loads a semver function module the first time the function is read', () => {
const satisfies = jest.fn();
const loadSatisfies = jest.fn(() => satisfies);
jest.doMock('semver/functions/satisfies.js', loadSatisfies);

jest.isolateModules(() => {
const lazySemver = require('../lazy-semver');
expect(loadSatisfies).not.toHaveBeenCalled();

expect(lazySemver.satisfies).toBe(satisfies);
expect(loadSatisfies).toHaveBeenCalledTimes(1);
});
});

it('exports the functions the eager module exports', () => {
const lazySemver = require('../lazy-semver');
const eagerSemver = require('../semver');

expect(Object.keys(lazySemver).sort()).toEqual(SEMVER_FUNCTIONS);
for (const name of SEMVER_FUNCTIONS) {
expect(lazySemver[name]).toBe(eagerSemver[name]);
}
expect(lazySemver.satisfies('1.2.3', '^1.0.0')).toBe(true);
});
});
29 changes: 29 additions & 0 deletions libs/sdk/src/third-party/__tests__/lazy-uipack-render.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
describe('lazy-uipack-render', () => {
afterEach(() => {
jest.dontMock('@frontmcp/uipack');
jest.resetModules();
});

it('loads @frontmcp/uipack the first time one of its functions is read', () => {
const renderComponent = jest.fn();
const loadUipack = jest.fn(() => ({ renderComponent, createResolverWithOverrides: jest.fn() }));
jest.doMock('@frontmcp/uipack', loadUipack);

jest.isolateModules(() => {
const lazyRender = require('../lazy-uipack-render');
expect(loadUipack).not.toHaveBeenCalled();

expect(lazyRender.renderComponent).toBe(renderComponent);
expect(loadUipack).toHaveBeenCalledTimes(1);
});
});

it('exports the functions the eager module exports', () => {
const lazyRender = require('../lazy-uipack-render');
const eagerRender = require('../uipack-render');

expect(Object.keys(lazyRender).sort()).toEqual(Object.keys(eagerRender).sort());
expect(lazyRender.renderComponent).toBe(eagerRender.renderComponent);
expect(lazyRender.createResolverWithOverrides).toBe(eagerRender.createResolverWithOverrides);
});
});
2 changes: 2 additions & 0 deletions libs/sdk/src/third-party/js-yaml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// `#js-yaml` everywhere but a require(): the YAML functions the SDK uses, from js-yaml.
export { dump, load } from 'js-yaml';
5 changes: 5 additions & 0 deletions libs/sdk/src/third-party/lazy-js-yaml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// The `require` variant of `#js-yaml`: js-yaml loads the first time one of its functions is read.
Object.defineProperties(exports, {
dump: { enumerable: true, get: () => require('js-yaml').dump },
load: { enumerable: true, get: () => require('js-yaml').load },
});
10 changes: 10 additions & 0 deletions libs/sdk/src/third-party/lazy-semver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// The `require` variant of `#semver`: each semver function loads its module the first time it is read.
Object.defineProperties(exports, {
compare: { enumerable: true, get: () => require('semver/functions/compare.js') },
gt: { enumerable: true, get: () => require('semver/functions/gt.js') },
rcompare: { enumerable: true, get: () => require('semver/functions/rcompare.js') },
satisfies: { enumerable: true, get: () => require('semver/functions/satisfies.js') },
valid: { enumerable: true, get: () => require('semver/functions/valid.js') },
maxSatisfying: { enumerable: true, get: () => require('semver/ranges/max-satisfying.js') },
validRange: { enumerable: true, get: () => require('semver/ranges/valid.js') },
});
5 changes: 5 additions & 0 deletions libs/sdk/src/third-party/lazy-uipack-render.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// The `require` variant of `#uipack-render`: @frontmcp/uipack loads the first time an auth-UI page is built.
Object.defineProperties(exports, {
createResolverWithOverrides: { enumerable: true, get: () => require('@frontmcp/uipack').createResolverWithOverrides },
renderComponent: { enumerable: true, get: () => require('@frontmcp/uipack').renderComponent },
});
8 changes: 8 additions & 0 deletions libs/sdk/src/third-party/semver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// `#semver` everywhere but a require(): the semver functions the ESM loader uses, each from its own module.
export { default as compare } from 'semver/functions/compare.js';
export { default as gt } from 'semver/functions/gt.js';
export { default as rcompare } from 'semver/functions/rcompare.js';
export { default as satisfies } from 'semver/functions/satisfies.js';
export { default as valid } from 'semver/functions/valid.js';
export { default as maxSatisfying } from 'semver/ranges/max-satisfying.js';
export { default as validRange } from 'semver/ranges/valid.js';
2 changes: 2 additions & 0 deletions libs/sdk/src/third-party/uipack-render.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// `#uipack-render` everywhere but a require(): the uipack functions that build the auth-UI pages.
export { createResolverWithOverrides, renderComponent } from '@frontmcp/uipack';
5 changes: 4 additions & 1 deletion tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,10 @@
"#langchain-anthropic": ["libs/sdk/src/agent/adapters/polyfills/node-langchain-anthropic.ts"],
"#sse-transport": ["libs/sdk/src/transport/adapters/polyfills/node-sse-transport.ts"],
"#express-host": ["libs/sdk/src/server/adapters/polyfills/node-express-host.ts"],
"#import-computed": ["libs/sdk/src/esm-loader/import-computed.ts"]
"#import-computed": ["libs/sdk/src/esm-loader/import-computed.ts"],
"#js-yaml": ["libs/sdk/src/third-party/js-yaml.ts"],
"#semver": ["libs/sdk/src/third-party/semver.ts"],
"#uipack-render": ["libs/sdk/src/third-party/uipack-render.ts"]
}
},
"exclude": ["node_modules", "tmp"]
Expand Down