@intlayer/engine 9.5.11 → 9.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/installSkills/skills/bundle-optimization.md +123 -0
- package/dist/assets/installSkills/skills/compat.md +0 -4
- package/dist/assets/installSkills/skills/content.md +8 -2
- package/dist/assets/installSkills/skills/next-js.md +2 -2
- package/dist/assets/installSkills/skills/usage.md +1 -1
- package/dist/cjs/build.cjs +5 -0
- package/dist/cjs/cli.cjs +1 -0
- package/dist/cjs/init/index.cjs +2 -12
- package/dist/cjs/init/index.cjs.map +1 -1
- package/dist/cjs/init/utils/backendPackages.cjs +15 -0
- package/dist/cjs/init/utils/backendPackages.cjs.map +1 -0
- package/dist/cjs/init/utils/index.cjs +2 -3
- package/dist/cjs/installSkills/index.cjs +2 -0
- package/dist/cjs/installSkills/index.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs +9 -8
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs +3 -5
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/remoteDictionaryClient.cjs +18 -0
- package/dist/cjs/loadDictionaries/remoteDictionaryClient.cjs.map +1 -0
- package/dist/cjs/prepareIntlayerServer.cjs +132 -0
- package/dist/cjs/prepareIntlayerServer.cjs.map +1 -0
- package/dist/cjs/utils/getProcessChainCommands.cjs +117 -0
- package/dist/cjs/utils/getProcessChainCommands.cjs.map +1 -0
- package/dist/cjs/utils/index.cjs +2 -0
- package/dist/cjs/utils/startContentWatcher.cjs +99 -0
- package/dist/cjs/utils/startContentWatcher.cjs.map +1 -0
- package/dist/cjs/watcher.cjs +2 -2
- package/dist/cjs/watcher.cjs.map +1 -1
- package/dist/cjs/writeJsonIfChanged.cjs.map +1 -1
- package/dist/esm/build.mjs +2 -1
- package/dist/esm/cli.mjs +2 -2
- package/dist/esm/init/index.mjs +1 -11
- package/dist/esm/init/index.mjs.map +1 -1
- package/dist/esm/init/utils/backendPackages.mjs +14 -0
- package/dist/esm/init/utils/backendPackages.mjs.map +1 -0
- package/dist/esm/init/utils/index.mjs +2 -2
- package/dist/esm/installSkills/index.mjs +2 -0
- package/dist/esm/installSkills/index.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadDictionaries.mjs +9 -8
- package/dist/esm/loadDictionaries/loadDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs +2 -4
- package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/remoteDictionaryClient.mjs +16 -0
- package/dist/esm/loadDictionaries/remoteDictionaryClient.mjs.map +1 -0
- package/dist/esm/prepareIntlayerServer.mjs +128 -0
- package/dist/esm/prepareIntlayerServer.mjs.map +1 -0
- package/dist/esm/utils/getProcessChainCommands.mjs +115 -0
- package/dist/esm/utils/getProcessChainCommands.mjs.map +1 -0
- package/dist/esm/utils/index.mjs +2 -1
- package/dist/esm/utils/startContentWatcher.mjs +98 -0
- package/dist/esm/utils/startContentWatcher.mjs.map +1 -0
- package/dist/esm/watcher.mjs +1 -1
- package/dist/esm/watcher.mjs.map +1 -1
- package/dist/esm/writeJsonIfChanged.mjs +1 -1
- package/dist/esm/writeJsonIfChanged.mjs.map +1 -1
- package/dist/types/build.d.ts +2 -1
- package/dist/types/cli.d.ts +2 -2
- package/dist/types/init/index.d.ts +1 -1
- package/dist/types/init/index.d.ts.map +1 -1
- package/dist/types/init/utils/backendPackages.d.ts +5 -0
- package/dist/types/init/utils/backendPackages.d.ts.map +1 -0
- package/dist/types/init/utils/index.d.ts +2 -2
- package/dist/types/installSkills/index.d.ts +1 -0
- package/dist/types/installSkills/index.d.ts.map +1 -1
- package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts.map +1 -1
- package/dist/types/loadDictionaries/remoteDictionaryClient.d.ts +14 -0
- package/dist/types/loadDictionaries/remoteDictionaryClient.d.ts.map +1 -0
- package/dist/types/prepareIntlayerServer.d.ts +67 -0
- package/dist/types/prepareIntlayerServer.d.ts.map +1 -0
- package/dist/types/utils/getProcessChainCommands.d.ts +35 -0
- package/dist/types/utils/getProcessChainCommands.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +2 -1
- package/dist/types/utils/startContentWatcher.d.ts +40 -0
- package/dist/types/utils/startContentWatcher.d.ts.map +1 -0
- package/dist/types/watcher.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/cjs/init/utils/devScript.cjs +0 -57
- package/dist/cjs/init/utils/devScript.cjs.map +0 -1
- package/dist/esm/init/utils/devScript.mjs +0 -55
- package/dist/esm/init/utils/devScript.mjs.map +0 -1
- package/dist/types/init/utils/devScript.d.ts +0 -48
- package/dist/types/init/utils/devScript.d.ts.map +0 -1
|
@@ -3,7 +3,7 @@ const require_init_utils_astImports = require('./astImports.cjs');
|
|
|
3
3
|
const require_init_utils_configManipulation = require('./configManipulation.cjs');
|
|
4
4
|
const require_init_utils_fileSystem = require('./fileSystem.cjs');
|
|
5
5
|
const require_init_utils_version = require('./version.cjs');
|
|
6
|
-
const
|
|
6
|
+
const require_init_utils_backendPackages = require('./backendPackages.cjs');
|
|
7
7
|
const require_init_utils_packageManager = require('./packageManager.cjs');
|
|
8
8
|
const require_init_utils_githubActions = require('./githubActions.cjs');
|
|
9
9
|
const require_init_utils_intlayerDependencies = require('./intlayerDependencies.cjs');
|
|
@@ -13,7 +13,7 @@ const require_init_utils_nextCompilerBabel = require('./nextCompilerBabel.cjs');
|
|
|
13
13
|
const require_init_utils_tsConfig = require('./tsConfig.cjs');
|
|
14
14
|
const require_init_utils_urlRoutingFramework = require('./urlRoutingFramework.cjs');
|
|
15
15
|
|
|
16
|
-
exports.BACKEND_INTLAYER_PACKAGES =
|
|
16
|
+
exports.BACKEND_INTLAYER_PACKAGES = require_init_utils_backendPackages.BACKEND_INTLAYER_PACKAGES;
|
|
17
17
|
exports.COMPAT_I18N_LIBRARIES = require_init_utils_packageManager.COMPAT_I18N_LIBRARIES;
|
|
18
18
|
exports.COMPAT_PACKAGE_REPLACEMENTS = require_init_utils_packageManager.COMPAT_PACKAGE_REPLACEMENTS;
|
|
19
19
|
exports.GITHUB_FILL_WORKFLOW_PATH = require_init_utils_githubActions.GITHUB_FILL_WORKFLOW_PATH;
|
|
@@ -56,7 +56,6 @@ exports.normalizeVersion = require_init_utils_packageManager.normalizeVersion;
|
|
|
56
56
|
exports.parseJSONWithComments = require_init_utils_jsonParser.parseJSONWithComments;
|
|
57
57
|
exports.readFileFromRoot = require_init_utils_fileSystem.readFileFromRoot;
|
|
58
58
|
exports.replaceViteConfigPluginImportSource = require_init_utils_configManipulation.replaceViteConfigPluginImportSource;
|
|
59
|
-
exports.resolveDevScript = require_init_utils_devScript.resolveDevScript;
|
|
60
59
|
exports.resolveGithubWorkflowsContext = require_init_utils_githubActions.resolveGithubWorkflowsContext;
|
|
61
60
|
exports.runPackageInstall = require_init_utils_packageManager.runPackageInstall;
|
|
62
61
|
exports.setIntlayerConfigCompilerOutput = require_init_utils_configManipulation.setIntlayerConfigCompilerOutput;
|
|
@@ -18,6 +18,7 @@ const SKILLS_METADATA = {
|
|
|
18
18
|
Usage: "How to use Intlayer in your project",
|
|
19
19
|
CLI: "Intlayer CLI commands and usage",
|
|
20
20
|
Compiler: "Intlayer Compiler setup and usage for automatic content extraction without .content files",
|
|
21
|
+
BundleOptimization: "Purge, minify and import modes; writing code the bundle optimizer can follow",
|
|
21
22
|
RemoteContent: "How to use Intlayer with Remote/CMS/Server-side content",
|
|
22
23
|
DevTools: "ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD",
|
|
23
24
|
Compat: "Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API",
|
|
@@ -42,6 +43,7 @@ const BASE_SKILLS = [
|
|
|
42
43
|
"Config",
|
|
43
44
|
"CLI",
|
|
44
45
|
"Compiler",
|
|
46
|
+
"BundleOptimization",
|
|
45
47
|
"DevTools"
|
|
46
48
|
];
|
|
47
49
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["readAsset","path","fs","getMarkdownMetadata","v"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Markdown:\n 'Markdown / rich text content: md(), MDX components, MarkdownProvider, SSR',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n DevTools: 'ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD',\n Compat:\n 'Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid: 'Solid-specific syntax and hooks usage',\n Astro: 'Astro-specific usage, middleware and islands',\n Lit: 'Lit-specific ReactiveController usage (useIntlayer, useLocale)',\n Vanilla: 'Framework-less JavaScript usage (vanilla-intlayer)',\n Remix: 'Remix 3 router middleware and request-scoped hooks',\n Backend:\n 'Server-side usage for Express, Fastify, Hono, NestJS, AdonisJS and Elysia',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\n/** Skills preselected for every project, whatever its stack. */\nconst BASE_SKILLS: Skill[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n 'DevTools',\n];\n\n/**\n * Packages whose presence in `package.json` preselects a framework skill.\n * Both the framework itself and its Intlayer adapter are listed, so a skill is\n * suggested before and after the adapter is installed.\n */\nconst SKILL_TRIGGER_PACKAGES: Partial<Record<Skill, string[]>> = {\n NextJS: ['next', 'next-intlayer'],\n React: [\n 'react',\n 'react-intlayer',\n 'react-native-intlayer',\n 'react-scripts-intlayer',\n 'lynx-intlayer',\n ],\n Preact: ['preact', 'preact-intlayer'],\n Solid: ['solid-js', '@solidjs/start', 'solid-intlayer'],\n Vue: ['vue', 'nuxt', 'vue-intlayer', 'nuxt-intlayer'],\n Svelte: ['svelte', '@sveltejs/kit', 'svelte-intlayer'],\n Angular: ['@angular/core', '@analogjs/platform', 'angular-intlayer'],\n Astro: ['astro', 'astro-intlayer'],\n Lit: ['lit', 'lit-intlayer'],\n Vanilla: ['vanilla-intlayer'],\n Remix: ['remix', 'remix-intlayer'],\n Compat: [\n 'i18next',\n 'react-i18next',\n 'next-i18next',\n 'next-intl',\n 'use-intl',\n 'react-intl',\n 'vue-i18n',\n '@lingui/core',\n '@lingui/react',\n '@nuxtjs/i18n',\n '@ngx-translate/core',\n '@jsverse/transloco',\n 'svelte-i18n',\n 'next-translate',\n 'node-polyglot',\n 'i18n-js',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n '@intlayer/next-i18next',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n '@intlayer/react-intl',\n '@intlayer/vue-i18n',\n '@intlayer/lingui',\n '@intlayer/sync-json-plugin',\n '@intlayer/sync-po-plugin',\n ],\n Backend: [\n 'express',\n 'fastify',\n 'hono',\n 'elysia',\n '@nestjs/core',\n '@adonisjs/core',\n 'express-intlayer',\n 'fastify-intlayer',\n 'hono-intlayer',\n 'elysia-intlayer',\n 'adonis-intlayer',\n ],\n};\n\n/**\n * Resolves the skills to preselect from the project's installed packages.\n *\n * @param dependencies - Merged `dependencies` and `devDependencies` of `package.json`.\n * @returns The base skills plus every framework skill whose packages are installed.\n */\nexport const getInitialSkills = (\n dependencies: Record<string, string>\n): Skill[] => {\n const detectedSkills = SKILLS.filter((skill) =>\n SKILL_TRIGGER_PACKAGES[skill]?.some(\n (packageName) => packageName in dependencies\n )\n );\n\n return [...BASE_SKILLS, ...detectedSkills];\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () => process.env.CLAUDE === 'true',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/** Upper bound on the redirect chain a reference URL may take. */\nconst MAX_FETCH_REDIRECTS = 5;\n\n/**\n * Parses a URL and rejects it unless it is an HTTPS address on an allowed host.\n *\n * @param url - Absolute URL to validate.\n * @returns The parsed URL.\n * @throws When the protocol or host is not allowed.\n */\nconst parseAllowedUrl = (url: string | URL): URL => {\n const parsed = new URL(url);\n\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n\n return parsed;\n};\n\n/**\n * Fetches the content of a URL using native fetch.\n *\n * Redirects are followed manually so every hop is re-checked against the host\n * allowlist — a redirect off `intlayer.org` is refused rather than silently\n * followed. Letting `fetch` refuse them outright (`redirect: 'error'`) instead\n * reported an unhelpful `TypeError: fetch failed` for a documentation URL that\n * merely moved.\n *\n * @param url - Absolute URL to read.\n * @returns The response body as text.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n let target = parseAllowedUrl(url);\n\n for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {\n const response = await fetch(target, { redirect: 'manual' });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n\n if (!location) {\n throw new Error(`Failed to fetch ${url}: redirect without a location`);\n }\n\n target = parseAllowedUrl(new URL(location, target));\n continue;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n\n return response.text();\n }\n\n throw new Error(`Failed to fetch ${url}: too many redirects`);\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform]?.dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs\n .filter((slug) => slug !== 'doc')\n .join('_')\n // Scoped package slugs (`@intlayer/babel`) must not create subfolders\n .replaceAll('/', '_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["readAsset","path","fs","getMarkdownMetadata","v"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Markdown:\n 'Markdown / rich text content: md(), MDX components, MarkdownProvider, SSR',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n BundleOptimization:\n 'Purge, minify and import modes; writing code the bundle optimizer can follow',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n DevTools: 'ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD',\n Compat:\n 'Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid: 'Solid-specific syntax and hooks usage',\n Astro: 'Astro-specific usage, middleware and islands',\n Lit: 'Lit-specific ReactiveController usage (useIntlayer, useLocale)',\n Vanilla: 'Framework-less JavaScript usage (vanilla-intlayer)',\n Remix: 'Remix 3 router middleware and request-scoped hooks',\n Backend:\n 'Server-side usage for Express, Fastify, Hono, NestJS, AdonisJS and Elysia',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\n/** Skills preselected for every project, whatever its stack. */\nconst BASE_SKILLS: Skill[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n 'BundleOptimization',\n 'DevTools',\n];\n\n/**\n * Packages whose presence in `package.json` preselects a framework skill.\n * Both the framework itself and its Intlayer adapter are listed, so a skill is\n * suggested before and after the adapter is installed.\n */\nconst SKILL_TRIGGER_PACKAGES: Partial<Record<Skill, string[]>> = {\n NextJS: ['next', 'next-intlayer'],\n React: [\n 'react',\n 'react-intlayer',\n 'react-native-intlayer',\n 'react-scripts-intlayer',\n 'lynx-intlayer',\n ],\n Preact: ['preact', 'preact-intlayer'],\n Solid: ['solid-js', '@solidjs/start', 'solid-intlayer'],\n Vue: ['vue', 'nuxt', 'vue-intlayer', 'nuxt-intlayer'],\n Svelte: ['svelte', '@sveltejs/kit', 'svelte-intlayer'],\n Angular: ['@angular/core', '@analogjs/platform', 'angular-intlayer'],\n Astro: ['astro', 'astro-intlayer'],\n Lit: ['lit', 'lit-intlayer'],\n Vanilla: ['vanilla-intlayer'],\n Remix: ['remix', 'remix-intlayer'],\n Compat: [\n 'i18next',\n 'react-i18next',\n 'next-i18next',\n 'next-intl',\n 'use-intl',\n 'react-intl',\n 'vue-i18n',\n '@lingui/core',\n '@lingui/react',\n '@nuxtjs/i18n',\n '@ngx-translate/core',\n '@jsverse/transloco',\n 'svelte-i18n',\n 'next-translate',\n 'node-polyglot',\n 'i18n-js',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n '@intlayer/next-i18next',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n '@intlayer/react-intl',\n '@intlayer/vue-i18n',\n '@intlayer/lingui',\n '@intlayer/sync-json-plugin',\n '@intlayer/sync-po-plugin',\n ],\n Backend: [\n 'express',\n 'fastify',\n 'hono',\n 'elysia',\n '@nestjs/core',\n '@adonisjs/core',\n 'express-intlayer',\n 'fastify-intlayer',\n 'hono-intlayer',\n 'elysia-intlayer',\n 'adonis-intlayer',\n ],\n};\n\n/**\n * Resolves the skills to preselect from the project's installed packages.\n *\n * @param dependencies - Merged `dependencies` and `devDependencies` of `package.json`.\n * @returns The base skills plus every framework skill whose packages are installed.\n */\nexport const getInitialSkills = (\n dependencies: Record<string, string>\n): Skill[] => {\n const detectedSkills = SKILLS.filter((skill) =>\n SKILL_TRIGGER_PACKAGES[skill]?.some(\n (packageName) => packageName in dependencies\n )\n );\n\n return [...BASE_SKILLS, ...detectedSkills];\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () => process.env.CLAUDE === 'true',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/** Upper bound on the redirect chain a reference URL may take. */\nconst MAX_FETCH_REDIRECTS = 5;\n\n/**\n * Parses a URL and rejects it unless it is an HTTPS address on an allowed host.\n *\n * @param url - Absolute URL to validate.\n * @returns The parsed URL.\n * @throws When the protocol or host is not allowed.\n */\nconst parseAllowedUrl = (url: string | URL): URL => {\n const parsed = new URL(url);\n\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n\n return parsed;\n};\n\n/**\n * Fetches the content of a URL using native fetch.\n *\n * Redirects are followed manually so every hop is re-checked against the host\n * allowlist — a redirect off `intlayer.org` is refused rather than silently\n * followed. Letting `fetch` refuse them outright (`redirect: 'error'`) instead\n * reported an unhelpful `TypeError: fetch failed` for a documentation URL that\n * merely moved.\n *\n * @param url - Absolute URL to read.\n * @returns The response body as text.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n let target = parseAllowedUrl(url);\n\n for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {\n const response = await fetch(target, { redirect: 'manual' });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n\n if (!location) {\n throw new Error(`Failed to fetch ${url}: redirect without a location`);\n }\n\n target = parseAllowedUrl(new URL(location, target));\n continue;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n\n return response.text();\n }\n\n throw new Error(`Failed to fetch ${url}: too many redirects`);\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform]?.dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs\n .filter((slug) => slug !== 'doc')\n .join('_')\n // Scoped package slugs (`@intlayer/babel`) must not create subfolders\n .replaceAll('/', '_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
|
|
@@ -81,6 +81,14 @@ const loadDictionaries = async (contentDeclarationsPaths, configuration) => {
|
|
|
81
81
|
const { plugins } = configuration;
|
|
82
82
|
const loadDictionariesStartTime = Date.now();
|
|
83
83
|
(0, _intlayer_config_logger.getAppLogger)(configuration)("Dictionaries:", { isVerbose: true });
|
|
84
|
+
const hasRemoteDictionaries = Boolean(configuration.editor.clientId && configuration.editor.clientSecret);
|
|
85
|
+
if (hasRemoteDictionaries) logger.setExpectRemote(true);
|
|
86
|
+
const remoteDictionariesPromise = hasRemoteDictionaries ? require_loadDictionaries_loadRemoteDictionaries.loadRemoteDictionaries(configuration, setLoadDictionariesStatus, {
|
|
87
|
+
onStartRemoteCheck: () => logger.startRemoteCheck(),
|
|
88
|
+
onStopRemoteCheck: () => logger.stopRemoteCheck(),
|
|
89
|
+
onError: (error) => logger.setRemoteError(error)
|
|
90
|
+
}).then((dictionaries) => require_filterInvalidDictionaries.filterInvalidDictionaries(dictionaries, configuration)).then((dictionaries) => require_formatDictionary.formatDictionaries(dictionaries)) : Promise.resolve([]);
|
|
91
|
+
remoteDictionariesPromise.catch(() => void 0);
|
|
84
92
|
const pluginsWithLoadDictionaries = (await Promise.all(plugins ?? [])).filter((plugin) => plugin.loadDictionaries);
|
|
85
93
|
logger.setPluginNames(pluginsWithLoadDictionaries.map(({ name }) => name));
|
|
86
94
|
const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(async (plugin) => {
|
|
@@ -103,14 +111,7 @@ const loadDictionaries = async (contentDeclarationsPaths, configuration) => {
|
|
|
103
111
|
status: "built"
|
|
104
112
|
}));
|
|
105
113
|
setLoadDictionariesStatus(localDictionariesStatus);
|
|
106
|
-
const
|
|
107
|
-
if (hasRemoteDictionaries) logger.setExpectRemote(true);
|
|
108
|
-
let remoteDictionaries = [];
|
|
109
|
-
if (hasRemoteDictionaries) remoteDictionaries = await require_loadDictionaries_loadRemoteDictionaries.loadRemoteDictionaries(configuration, setLoadDictionariesStatus, {
|
|
110
|
-
onStartRemoteCheck: () => logger.startRemoteCheck(),
|
|
111
|
-
onStopRemoteCheck: () => logger.stopRemoteCheck(),
|
|
112
|
-
onError: (e) => logger.setRemoteError(e)
|
|
113
|
-
}).then((dictionaries) => require_filterInvalidDictionaries.filterInvalidDictionaries(dictionaries, configuration)).then((dictionaries) => require_formatDictionary.formatDictionaries(dictionaries));
|
|
114
|
+
const remoteDictionaries = await remoteDictionariesPromise;
|
|
114
115
|
const remoteDictionariesTime = Date.now();
|
|
115
116
|
logger.finish();
|
|
116
117
|
printSummary(configuration);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadDictionaries.cjs","names":["DictionariesLogger","ANSIColors","getAppLogger","colorize","colon","colorizeKey","filterInvalidDictionaries","formatDictionaries","loadContentDeclarations","loadRemoteDictionaries"],"sources":["../../../src/loadDictionaries/loadDictionaries.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeKey,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { formatDictionaries } from '../formatDictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\nimport { loadRemoteDictionaries } from './loadRemoteDictionaries';\nimport { DictionariesLogger } from './log';\n\nexport type DictionariesStatus = {\n dictionaryKey: string;\n type: 'local' | 'remote';\n status:\n | 'pending' // Key found but not fetched yet\n | 'fetching' // If dictionary fetch is in progress\n | 'fetched' // If dictionary fetch succeeded\n | 'error' // If dictionary fetch failed\n | 'imported' // If dictionary already fetched and still up to date\n | 'found' // If dictionary key is found but promise is not resolved yet (ex: fetching distant content)\n | 'building' // If dictionary is being built\n | 'built'; // If dictionary is built;\n error?: string;\n};\n\nlet loadDictionariesStatus: DictionariesStatus[] = [];\nconst logger = new DictionariesLogger();\n\nconst setLoadDictionariesStatus = (statuses: DictionariesStatus[]) => {\n const updated: DictionariesStatus[] = [...loadDictionariesStatus];\n\n for (const incoming of statuses) {\n const index = updated.findIndex(\n (s) =>\n s.dictionaryKey === incoming.dictionaryKey && s.type === incoming.type\n );\n if (index >= 0) {\n updated[index] = incoming;\n } else {\n updated.push(incoming);\n }\n }\n\n loadDictionariesStatus = updated;\n logger.update(statuses);\n\n return updated;\n};\n\ntype StatusRecord = {\n local?: DictionariesStatus['status'];\n remote?: DictionariesStatus['status'];\n};\n\nconst iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n};\n\nconst colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return ANSIColors.GREEN;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n};\n\nconst printSummary = (configuration: IntlayerConfig) => {\n if (configuration.log.mode !== 'verbose') return;\n\n const appLogger = getAppLogger(configuration);\n\n // Aggregate by dictionary key\n const byKey = new Map<string, StatusRecord>();\n for (const status of loadDictionariesStatus) {\n const rec = byKey.get(status.dictionaryKey) ?? {};\n if (status.type === 'local') rec.local = status.status;\n if (status.type === 'remote') rec.remote = status.status;\n byKey.set(status.dictionaryKey, rec);\n }\n\n const keys = Array.from(byKey.keys()).sort((a, b) => a.localeCompare(b));\n\n // Compute the max visible length of the local label to align distant labels\n let maxLocalLabelLen = 0;\n for (const key of keys) {\n const rec = byKey.get(key)!;\n if (rec.local) {\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n if (visibleLocal.length > maxLocalLabelLen) {\n maxLocalLabelLen = visibleLocal.length;\n }\n }\n }\n\n for (const key of keys) {\n const rec = byKey.get(key)!;\n const labels: string[] = [];\n\n if (rec.local) {\n const inner = colorize(\n `${iconFor(rec.local)} ${rec.local}`,\n colorFor(rec.local)\n );\n const coloredLocal =\n `${ANSIColors.GREY}[` +\n colorize('local: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`;\n\n // Pad to align distant label across rows\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n const pad = Math.max(0, maxLocalLabelLen - visibleLocal.length);\n labels.push(coloredLocal + ' '.repeat(pad));\n } else {\n // If no local label, insert spaces to keep distant aligned\n labels.push(' '.repeat(maxLocalLabelLen));\n }\n\n if (rec.remote) {\n const inner = colorize(\n `${iconFor(rec.remote)} ${rec.remote}`,\n colorFor(rec.remote)\n );\n labels.push(\n `${ANSIColors.GREY}[` +\n colorize('distant: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n appLogger(\n ` - ${colon(colorizeKey(key), { colSize: keys })} ${labels.join(' ')}`\n );\n }\n};\n\nexport const loadDictionaries = async (\n contentDeclarationsPaths: string[] | string,\n configuration: IntlayerConfig\n): Promise<{\n localDictionaries: Dictionary[];\n remoteDictionaries: Dictionary[];\n pluginDictionaries: Dictionary[];\n time: {\n localDictionaries: number;\n remoteDictionaries: number;\n pluginDictionaries: number;\n };\n}> => {\n const { plugins } = configuration;\n const loadDictionariesStartTime = Date.now();\n const appLogger = getAppLogger(configuration);\n\n appLogger('Dictionaries:', { isVerbose: true });\n\n // Load additional dictionaries via plugins (e.g., ICU JSON ingestion)\n const resolvedPlugins = await Promise.all(plugins ?? []);\n\n const pluginsWithLoadDictionaries = resolvedPlugins.filter(\n (plugin) => plugin.loadDictionaries\n );\n\n logger.setPluginNames(pluginsWithLoadDictionaries.map(({ name }) => name));\n\n const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(\n async (plugin) => {\n try {\n const res = await plugin.loadDictionaries?.({\n configuration,\n });\n\n return (res as Dictionary[] | undefined) ?? [];\n } catch (error) {\n logger.setPluginError(error as Error, plugin.name);\n\n return [];\n }\n }\n );\n\n const pluginDictionaries: Dictionary[] = await Promise.all(\n loadPluginDictionariesPromise as Promise<Dictionary[]>[]\n )\n .then((dictionaries) => dictionaries.flat())\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n logger.setPluginTotal(pluginDictionaries.length);\n logger.setPluginDone(pluginDictionaries.length);\n\n const pluginDictionariesTime = Date.now();\n\n const files = Array.isArray(contentDeclarationsPaths)\n ? contentDeclarationsPaths\n : [contentDeclarationsPaths];\n\n const localDictionaries: Dictionary[] = await loadContentDeclarations(\n files,\n configuration,\n setLoadDictionariesStatus\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n const localDictionariesTime = Date.now();\n\n const localDictionariesStatus = localDictionaries.map(\n (dictionary) =>\n ({\n dictionaryKey: dictionary.key,\n type: 'local',\n status: 'built',\n }) as const\n );\n\n setLoadDictionariesStatus(localDictionariesStatus);\n\n const hasRemoteDictionaries = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n\n if (hasRemoteDictionaries) {\n // We expect to fetch remote dictionaries soon; suppress a transient local-only render\n logger.setExpectRemote(true);\n }\n\n let remoteDictionaries: Dictionary[] = [];\n\n if (hasRemoteDictionaries) {\n remoteDictionaries = await loadRemoteDictionaries(\n configuration,\n setLoadDictionariesStatus,\n {\n onStartRemoteCheck: () => logger.startRemoteCheck(),\n onStopRemoteCheck: () => logger.stopRemoteCheck(),\n onError: (e) => logger.setRemoteError(e),\n }\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n }\n\n const remoteDictionariesTime = Date.now();\n\n // Stop spinner and show final progress line(s)\n logger.finish();\n\n printSummary(configuration);\n\n return {\n localDictionaries,\n remoteDictionaries,\n pluginDictionaries,\n time: {\n localDictionaries: localDictionariesTime - pluginDictionariesTime,\n remoteDictionaries: remoteDictionariesTime - localDictionariesTime,\n pluginDictionaries: pluginDictionariesTime - loadDictionariesStartTime,\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loadDictionaries.cjs","names":["DictionariesLogger","ANSIColors","getAppLogger","colorize","colon","colorizeKey","loadRemoteDictionaries","filterInvalidDictionaries","formatDictionaries","loadContentDeclarations"],"sources":["../../../src/loadDictionaries/loadDictionaries.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeKey,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { formatDictionaries } from '../formatDictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\nimport { loadRemoteDictionaries } from './loadRemoteDictionaries';\nimport { DictionariesLogger } from './log';\n\nexport type DictionariesStatus = {\n dictionaryKey: string;\n type: 'local' | 'remote';\n status:\n | 'pending' // Key found but not fetched yet\n | 'fetching' // If dictionary fetch is in progress\n | 'fetched' // If dictionary fetch succeeded\n | 'error' // If dictionary fetch failed\n | 'imported' // If dictionary already fetched and still up to date\n | 'found' // If dictionary key is found but promise is not resolved yet (ex: fetching distant content)\n | 'building' // If dictionary is being built\n | 'built'; // If dictionary is built;\n error?: string;\n};\n\nlet loadDictionariesStatus: DictionariesStatus[] = [];\nconst logger = new DictionariesLogger();\n\nconst setLoadDictionariesStatus = (statuses: DictionariesStatus[]) => {\n const updated: DictionariesStatus[] = [...loadDictionariesStatus];\n\n for (const incoming of statuses) {\n const index = updated.findIndex(\n (s) =>\n s.dictionaryKey === incoming.dictionaryKey && s.type === incoming.type\n );\n if (index >= 0) {\n updated[index] = incoming;\n } else {\n updated.push(incoming);\n }\n }\n\n loadDictionariesStatus = updated;\n logger.update(statuses);\n\n return updated;\n};\n\ntype StatusRecord = {\n local?: DictionariesStatus['status'];\n remote?: DictionariesStatus['status'];\n};\n\nconst iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n};\n\nconst colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return ANSIColors.GREEN;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n};\n\nconst printSummary = (configuration: IntlayerConfig) => {\n if (configuration.log.mode !== 'verbose') return;\n\n const appLogger = getAppLogger(configuration);\n\n // Aggregate by dictionary key\n const byKey = new Map<string, StatusRecord>();\n for (const status of loadDictionariesStatus) {\n const rec = byKey.get(status.dictionaryKey) ?? {};\n if (status.type === 'local') rec.local = status.status;\n if (status.type === 'remote') rec.remote = status.status;\n byKey.set(status.dictionaryKey, rec);\n }\n\n const keys = Array.from(byKey.keys()).sort((a, b) => a.localeCompare(b));\n\n // Compute the max visible length of the local label to align distant labels\n let maxLocalLabelLen = 0;\n for (const key of keys) {\n const rec = byKey.get(key)!;\n if (rec.local) {\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n if (visibleLocal.length > maxLocalLabelLen) {\n maxLocalLabelLen = visibleLocal.length;\n }\n }\n }\n\n for (const key of keys) {\n const rec = byKey.get(key)!;\n const labels: string[] = [];\n\n if (rec.local) {\n const inner = colorize(\n `${iconFor(rec.local)} ${rec.local}`,\n colorFor(rec.local)\n );\n const coloredLocal =\n `${ANSIColors.GREY}[` +\n colorize('local: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`;\n\n // Pad to align distant label across rows\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n const pad = Math.max(0, maxLocalLabelLen - visibleLocal.length);\n labels.push(coloredLocal + ' '.repeat(pad));\n } else {\n // If no local label, insert spaces to keep distant aligned\n labels.push(' '.repeat(maxLocalLabelLen));\n }\n\n if (rec.remote) {\n const inner = colorize(\n `${iconFor(rec.remote)} ${rec.remote}`,\n colorFor(rec.remote)\n );\n labels.push(\n `${ANSIColors.GREY}[` +\n colorize('distant: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n appLogger(\n ` - ${colon(colorizeKey(key), { colSize: keys })} ${labels.join(' ')}`\n );\n }\n};\n\nexport const loadDictionaries = async (\n contentDeclarationsPaths: string[] | string,\n configuration: IntlayerConfig\n): Promise<{\n localDictionaries: Dictionary[];\n remoteDictionaries: Dictionary[];\n pluginDictionaries: Dictionary[];\n time: {\n localDictionaries: number;\n remoteDictionaries: number;\n pluginDictionaries: number;\n };\n}> => {\n const { plugins } = configuration;\n const loadDictionariesStartTime = Date.now();\n const appLogger = getAppLogger(configuration);\n\n appLogger('Dictionaries:', { isVerbose: true });\n\n const hasRemoteDictionaries = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n\n if (hasRemoteDictionaries) {\n // We expect to fetch remote dictionaries soon; suppress a transient local-only render\n logger.setExpectRemote(true);\n }\n\n // Started first so the CMS round trips (OAuth2 token, update timestamps)\n // overlap plugin and local loading instead of running after them.\n const remoteDictionariesPromise: Promise<Dictionary[]> = hasRemoteDictionaries\n ? loadRemoteDictionaries(configuration, setLoadDictionariesStatus, {\n onStartRemoteCheck: () => logger.startRemoteCheck(),\n onStopRemoteCheck: () => logger.stopRemoteCheck(),\n onError: (error) => logger.setRemoteError(error),\n })\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries))\n : Promise.resolve([]);\n\n // Awaited later; this keeps an early rejection from being reported as unhandled\n remoteDictionariesPromise.catch(() => undefined);\n\n // Load additional dictionaries via plugins (e.g., ICU JSON ingestion)\n const resolvedPlugins = await Promise.all(plugins ?? []);\n\n const pluginsWithLoadDictionaries = resolvedPlugins.filter(\n (plugin) => plugin.loadDictionaries\n );\n\n logger.setPluginNames(pluginsWithLoadDictionaries.map(({ name }) => name));\n\n const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(\n async (plugin) => {\n try {\n const res = await plugin.loadDictionaries?.({\n configuration,\n });\n\n return (res as Dictionary[] | undefined) ?? [];\n } catch (error) {\n logger.setPluginError(error as Error, plugin.name);\n\n return [];\n }\n }\n );\n\n const pluginDictionaries: Dictionary[] = await Promise.all(\n loadPluginDictionariesPromise as Promise<Dictionary[]>[]\n )\n .then((dictionaries) => dictionaries.flat())\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n logger.setPluginTotal(pluginDictionaries.length);\n logger.setPluginDone(pluginDictionaries.length);\n\n const pluginDictionariesTime = Date.now();\n\n const files = Array.isArray(contentDeclarationsPaths)\n ? contentDeclarationsPaths\n : [contentDeclarationsPaths];\n\n const localDictionaries: Dictionary[] = await loadContentDeclarations(\n files,\n configuration,\n setLoadDictionariesStatus\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n const localDictionariesTime = Date.now();\n\n const localDictionariesStatus = localDictionaries.map(\n (dictionary) =>\n ({\n dictionaryKey: dictionary.key,\n type: 'local',\n status: 'built',\n }) as const\n );\n\n setLoadDictionariesStatus(localDictionariesStatus);\n\n const remoteDictionaries: Dictionary[] = await remoteDictionariesPromise;\n\n const remoteDictionariesTime = Date.now();\n\n // Stop spinner and show final progress line(s)\n logger.finish();\n\n printSummary(configuration);\n\n return {\n localDictionaries,\n remoteDictionaries,\n pluginDictionaries,\n time: {\n localDictionaries: localDictionariesTime - pluginDictionariesTime,\n remoteDictionaries: remoteDictionariesTime - localDictionariesTime,\n pluginDictionaries: pluginDictionariesTime - loadDictionariesStartTime,\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_sortAlphabetically = require('../utils/sortAlphabetically.cjs');
|
|
3
|
-
const require_fetchDistantDictionaries = require('../fetchDistantDictionaries.cjs');
|
|
4
3
|
let _intlayer_config_node = require("@intlayer/config/node");
|
|
5
|
-
let _intlayer_api = require("@intlayer/api");
|
|
6
|
-
let _intlayer_api_dictionary = require("@intlayer/api/dictionary");
|
|
7
4
|
let _intlayer_dictionaries_entry_remote = require("@intlayer/dictionaries-entry/remote");
|
|
8
5
|
|
|
9
6
|
//#region src/loadDictionaries/loadRemoteDictionaries.ts
|
|
@@ -18,7 +15,8 @@ const loadRemoteDictionaries = async (configuration = (0, _intlayer_config_node.
|
|
|
18
15
|
if (!Boolean(editor.clientId && editor.clientSecret)) return [];
|
|
19
16
|
try {
|
|
20
17
|
options?.onStartRemoteCheck?.();
|
|
21
|
-
const
|
|
18
|
+
const { createRemoteDictionaryClient, fetchDistantDictionaries } = await Promise.resolve().then(() => require("./remoteDictionaryClient.cjs"));
|
|
19
|
+
const distantDictionaryUpdateTimeStamp = (await createRemoteDictionaryClient(configuration).getDictionariesUpdateTimestamp()).data;
|
|
22
20
|
if (!distantDictionaryUpdateTimeStamp) throw new Error("No distant dictionaries found");
|
|
23
21
|
const dictionariesIdToFetch = Object.entries(distantDictionaryUpdateTimeStamp).filter(([dictionaryId, data]) => {
|
|
24
22
|
if (!data.updatedAt) return true;
|
|
@@ -46,7 +44,7 @@ const loadRemoteDictionaries = async (configuration = (0, _intlayer_config_node.
|
|
|
46
44
|
type: "remote",
|
|
47
45
|
status: "pending"
|
|
48
46
|
})));
|
|
49
|
-
const distantDictionariesData = await
|
|
47
|
+
const distantDictionariesData = await fetchDistantDictionaries({ dictionaryKeys: orderedDistantDictionaryKeys }, onStatusUpdate);
|
|
50
48
|
const distantDictionaries = formatDistantDictionaries(distantDictionariesData);
|
|
51
49
|
const fetchedDictionaryIds = new Set(distantDictionaries.map((dictionary) => dictionary.id));
|
|
52
50
|
return [...cachedDictionaries.filter((dictionary) => !fetchedDictionaryIds.has(dictionary.id)), ...distantDictionaries];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadRemoteDictionaries.cjs","names":["getConfiguration","getRemoteDictionaries","
|
|
1
|
+
{"version":3,"file":"loadRemoteDictionaries.cjs","names":["getConfiguration","getRemoteDictionaries","sortAlphabetically"],"sources":["../../../src/loadDictionaries/loadRemoteDictionaries.ts"],"sourcesContent":["// @ts-ignore @intlayer/backend is not build yet\nimport type { DictionaryAPI } from '@intlayer/backend';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getRemoteDictionaries } from '@intlayer/dictionaries-entry/remote';\nimport type {\n Dictionary,\n DictionaryId,\n DictionaryKey,\n} from '@intlayer/types/dictionary';\nimport { sortAlphabetically } from '../utils/sortAlphabetically';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport const formatDistantDictionaries = (\n dictionaries: (DictionaryAPI | Dictionary)[]\n): Dictionary[] =>\n dictionaries.map((dict) => ({\n ...dict,\n localId: `${dict.key}::remote::${dict.id}`,\n location: 'remote' as const,\n }));\n\nexport const loadRemoteDictionaries = async (\n configuration = getConfiguration(),\n onStatusUpdate?: (status: DictionariesStatus[]) => void,\n options?: {\n onStartRemoteCheck?: () => void;\n onStopRemoteCheck?: () => void;\n onError?: (error: Error) => void;\n }\n): Promise<Dictionary[]> => {\n const { editor } = configuration;\n const remoteDictionariesRecord = getRemoteDictionaries(configuration);\n\n const hasRemoteDictionaries = Boolean(editor.clientId && editor.clientSecret);\n\n if (!hasRemoteDictionaries) return [];\n\n try {\n options?.onStartRemoteCheck?.();\n\n // Lazy: the CMS client is only needed when remote credentials are set\n const { createRemoteDictionaryClient, fetchDistantDictionaries } =\n await import('./remoteDictionaryClient');\n\n const dictionary = createRemoteDictionaryClient(configuration);\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await dictionary.getDictionariesUpdateTimestamp();\n\n const distantDictionaryUpdateTimeStamp: Record<\n DictionaryId,\n { key: DictionaryKey; updatedAt: number }\n > | null = getDictionariesKeysResult.data;\n\n if (!distantDictionaryUpdateTimeStamp) {\n throw new Error('No distant dictionaries found');\n }\n\n const dictionariesIdToFetch = Object.entries(\n distantDictionaryUpdateTimeStamp\n ).filter(([dictionaryId, data]) => {\n // If remote doesn't provide updatedAt, fetch to be safe\n if (!data.updatedAt) return true;\n\n // If no local cache exists, fetch\n const local: Dictionary | undefined = remoteDictionariesRecord[\n data.key\n ]?.find((dictionary) => dictionary.id === dictionaryId);\n if (!local) return true;\n\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n\n // If local timestamp missing or older than remote, fetch\n if (typeof localUpdatedAt !== 'number') return true;\n\n return data.updatedAt > localUpdatedAt;\n });\n\n const flatRemoteDictionariesRecord: DictionaryAPI[] = Object.values(\n remoteDictionariesRecord\n ).flat();\n\n const cachedDictionaries: Dictionary[] =\n flatRemoteDictionariesRecord.filter((dictionary) => {\n const remoteUpdatedAt = dictionary.id\n ? distantDictionaryUpdateTimeStamp[dictionary.id]?.updatedAt\n : undefined;\n\n const localUpdatedAtRaw = dictionary.updatedAt;\n\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n\n // Consider as cached/imported when local exists and is up-to-date or newer\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n });\n\n // Report cached as already imported\n if (cachedDictionaries.length > 0) {\n onStatusUpdate?.(\n cachedDictionaries.map((dictionary) => ({\n dictionaryKey: dictionary.key,\n type: 'remote',\n status: 'imported',\n }))\n );\n }\n\n // Several qualified dictionaries can share a key, so keys are deduplicated:\n // one request per key already returns all of its siblings.\n const orderedDistantDictionaryKeys = [\n ...new Set(dictionariesIdToFetch.map(([, data]) => data.key)),\n ].sort(sortAlphabetically);\n\n // Report pending for keys to be fetched so totals are visible immediately\n if (orderedDistantDictionaryKeys.length > 0) {\n onStatusUpdate?.(\n orderedDistantDictionaryKeys.map((key) => ({\n dictionaryKey: key,\n type: 'remote',\n status: 'pending',\n }))\n );\n }\n\n const distantDictionariesData = await fetchDistantDictionaries(\n {\n dictionaryKeys: orderedDistantDictionaryKeys,\n },\n onStatusUpdate\n );\n\n const distantDictionaries: Dictionary[] = formatDistantDictionaries(\n distantDictionariesData\n );\n\n // Fetching by key also returns the up-to-date siblings of a stale\n // dictionary, so drop the cached copies the remote just sent back.\n const fetchedDictionaryIds = new Set(\n distantDictionaries.map((dictionary) => dictionary.id)\n );\n\n const notRefetchedCachedDictionaries = cachedDictionaries.filter(\n (dictionary) => !fetchedDictionaryIds.has(dictionary.id)\n );\n\n return [...notRefetchedCachedDictionaries, ...distantDictionaries];\n } catch (error) {\n options?.onError?.(error as Error);\n return [];\n } finally {\n options?.onStopRemoteCheck?.();\n }\n};\n"],"mappings":";;;;;;AAYA,MAAa,6BACX,iBAEA,aAAa,KAAK,UAAU;CAC1B,GAAG;CACH,SAAS,GAAG,KAAK,IAAI,YAAY,KAAK;CACtC,UAAU;AACZ,EAAE;AAEJ,MAAa,yBAAyB,OACpC,oBAAgBA,wCAAiB,GACjC,gBACA,YAK0B;CAC1B,MAAM,EAAE,WAAW;CACnB,MAAM,+BAA2BC,2DAAsB,aAAa;CAIpE,IAAI,CAF0B,QAAQ,OAAO,YAAY,OAAO,YAEvC,GAAG,OAAO,CAAC;CAEpC,IAAI;EACF,SAAS,qBAAqB;EAG9B,MAAM,EAAE,8BAA8B,6BACpC,2CAAM;EAQR,MAAM,oCAGK,MATQ,6BAA6B,aAI/B,CAAC,CAAC,+BAA+B,EAKd,CAAC;EAErC,IAAI,CAAC,kCACH,MAAM,IAAI,MAAM,+BAA+B;EAGjD,MAAM,wBAAwB,OAAO,QACnC,gCACF,CAAC,CAAC,QAAQ,CAAC,cAAc,UAAU;GAEjC,IAAI,CAAC,KAAK,WAAW,OAAO;GAG5B,MAAM,QAAgC,yBACpC,KAAK,IACN,EAAE,MAAM,eAAe,WAAW,OAAO,YAAY;GACtD,IAAI,CAAC,OAAO,OAAO;GAEnB,MAAM,oBAAqB,OAAe;GAK1C,MAAM,iBACJ,OAAO,sBAAsB,WACzB,oBACA,oBACE,IAAI,KAAK,iBAAiB,CAAC,CAAC,QAAQ,IACpC;GAGR,IAAI,OAAO,mBAAmB,UAAU,OAAO;GAE/C,OAAO,KAAK,YAAY;EAC1B,CAAC;EAMD,MAAM,qBAJgD,OAAO,OAC3D,wBACF,CAAC,CAAC,KAG2B,CAAC,CAAC,QAAQ,eAAe;GAClD,MAAM,kBAAkB,WAAW,KAC/B,iCAAiC,WAAW,GAAG,EAAE,YACjD;GAEJ,MAAM,oBAAoB,WAAW;GAErC,MAAM,iBACJ,OAAO,sBAAsB,WACzB,oBACA,oBACE,IAAI,KAAK,iBAAiB,CAAC,CAAC,QAAQ,IACpC;GAGR,OACE,OAAO,mBAAmB,YAC1B,OAAO,oBAAoB,YAC3B,kBAAkB;EAEtB,CAAC;EAGH,IAAI,mBAAmB,SAAS,GAC9B,iBACE,mBAAmB,KAAK,gBAAgB;GACtC,eAAe,WAAW;GAC1B,MAAM;GACN,QAAQ;EACV,EAAE,CACJ;EAKF,MAAM,+BAA+B,CACnC,GAAG,IAAI,IAAI,sBAAsB,KAAK,GAAG,UAAU,KAAK,GAAG,CAAC,CAC9D,CAAC,CAAC,KAAKC,mDAAkB;EAGzB,IAAI,6BAA6B,SAAS,GACxC,iBACE,6BAA6B,KAAK,SAAS;GACzC,eAAe;GACf,MAAM;GACN,QAAQ;EACV,EAAE,CACJ;EAGF,MAAM,0BAA0B,MAAM,yBACpC,EACE,gBAAgB,6BAClB,GACA,cACF;EAEA,MAAM,sBAAoC,0BACxC,uBACF;EAIA,MAAM,uBAAuB,IAAI,IAC/B,oBAAoB,KAAK,eAAe,WAAW,EAAE,CACvD;EAMA,OAAO,CAAC,GAJ+B,mBAAmB,QACvD,eAAe,CAAC,qBAAqB,IAAI,WAAW,EAAE,CAGjB,GAAG,GAAG,mBAAmB;CACnE,SAAS,OAAO;EACd,SAAS,UAAU,KAAc;EACjC,OAAO,CAAC;CACV,UAAU;EACR,SAAS,oBAAoB;CAC/B;AACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_fetchDistantDictionaries = require('../fetchDistantDictionaries.cjs');
|
|
3
|
+
let _intlayer_api = require("@intlayer/api");
|
|
4
|
+
let _intlayer_api_dictionary = require("@intlayer/api/dictionary");
|
|
5
|
+
|
|
6
|
+
//#region src/loadDictionaries/remoteDictionaryClient.ts
|
|
7
|
+
/**
|
|
8
|
+
* Creates the CMS dictionary client.
|
|
9
|
+
*
|
|
10
|
+
* Kept in its own module so `loadRemoteDictionaries` can import it lazily:
|
|
11
|
+
* `@intlayer/api` is only loaded when remote credentials are configured.
|
|
12
|
+
*/
|
|
13
|
+
const createRemoteDictionaryClient = (configuration) => (0, _intlayer_api_dictionary.dictionaryEndpoint)((0, _intlayer_api.createIntlayerCMS)(configuration));
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
exports.createRemoteDictionaryClient = createRemoteDictionaryClient;
|
|
17
|
+
exports.fetchDistantDictionaries = require_fetchDistantDictionaries.fetchDistantDictionaries;
|
|
18
|
+
//# sourceMappingURL=remoteDictionaryClient.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remoteDictionaryClient.cjs","names":["dictionaryEndpoint","createIntlayerCMS"],"sources":["../../../src/loadDictionaries/remoteDictionaryClient.ts"],"sourcesContent":["import { createIntlayerCMS } from '@intlayer/api';\nimport { dictionaryEndpoint } from '@intlayer/api/dictionary';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n\nexport { fetchDistantDictionaries } from '../fetchDistantDictionaries';\n\n/**\n * Creates the CMS dictionary client.\n *\n * Kept in its own module so `loadRemoteDictionaries` can import it lazily:\n * `@intlayer/api` is only loaded when remote credentials are configured.\n */\nexport const createRemoteDictionaryClient = (\n configuration: IntlayerConfig\n): ReturnType<typeof dictionaryEndpoint> =>\n dictionaryEndpoint(createIntlayerCMS(configuration));\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,gCACX,sBAEAA,iDAAmBC,iCAAkB,aAAa,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_utils_startContentWatcher = require('./utils/startContentWatcher.cjs');
|
|
3
|
+
const require_prepareIntlayer = require('./prepareIntlayer.cjs');
|
|
4
|
+
const require_utils_getProcessChainCommands = require('./utils/getProcessChainCommands.cjs');
|
|
5
|
+
let _intlayer_config_logger = require("@intlayer/config/logger");
|
|
6
|
+
|
|
7
|
+
//#region src/prepareIntlayerServer.ts
|
|
8
|
+
/**
|
|
9
|
+
* Explicit override, for any setup the detection below does not recognise:
|
|
10
|
+
* `INTLAYER_WATCH=true` forces the content watcher on, `INTLAYER_WATCH=false`
|
|
11
|
+
* forces it off.
|
|
12
|
+
*/
|
|
13
|
+
const INTLAYER_WATCH_ENV_VAR = "INTLAYER_WATCH";
|
|
14
|
+
/** Runtime flags that restart or reload the process on file changes. */
|
|
15
|
+
const WATCH_MODE_EXEC_ARGUMENTS = [
|
|
16
|
+
"--watch",
|
|
17
|
+
"--watch-path",
|
|
18
|
+
"--hot"
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Environment variables set on the child process by a restarting watcher:
|
|
22
|
+
* `node --watch` and `ts-node-dev`.
|
|
23
|
+
*/
|
|
24
|
+
const WATCH_MODE_ENV_VARS = ["WATCH_REPORT_DEPENDENCIES", "TS_NODE_DEV"];
|
|
25
|
+
/**
|
|
26
|
+
* Package script names that start a dev server (`dev`, `start:dev`,
|
|
27
|
+
* `dev:api`, `watch`…), matched on the `npm_lifecycle_event` that npm, pnpm,
|
|
28
|
+
* yarn and bun set for `<pm> run <script>`.
|
|
29
|
+
*/
|
|
30
|
+
const DEV_SCRIPT_NAME_PATTERN = /\b(dev|develop|development|watch)\b/;
|
|
31
|
+
/**
|
|
32
|
+
* Command lines of the tools that restart a server on file changes, matched on
|
|
33
|
+
* this process and the ones above it. Needed because most of them leave no
|
|
34
|
+
* trace in the child itself.
|
|
35
|
+
*
|
|
36
|
+
* - Dedicated restarters, matched on their executable name (`nodemon`,
|
|
37
|
+
* `watchexec`, `entr`…).
|
|
38
|
+
* - `tsx watch`, whose watch mode is a subcommand.
|
|
39
|
+
* - Any runtime or CLI given `--watch` / `--hot`: `deno run --watch` (which
|
|
40
|
+
* restarts in-process), `nest start --watch`, `tsup --watch --onSuccess`…
|
|
41
|
+
* - The `-w` shorthand of build tools that run the server on each rebuild
|
|
42
|
+
* (`tsdown -w --on-success "node dist/index.mjs"`).
|
|
43
|
+
*/
|
|
44
|
+
const DEV_WATCHER_COMMAND_PATTERNS = [
|
|
45
|
+
/(^|[\s/])(nodemon|ts-node-dev|tsnd|node-dev|tsc-watch|supervisor|watchexec|entr|chokidar|onchange)(\.c?m?js)?(\s|$)/,
|
|
46
|
+
/(^|[\s/])tsx(\/dist\/cli\.m?js)?\s+watch(\s|$)/,
|
|
47
|
+
/\s--(watch|watch-path|hot)(=|\s|$)/,
|
|
48
|
+
/(^|[\s/])(tsdown|tsup|tsc|rollup|rolldown)(\/\S*)?(\s+\S+)*\s+-w(\s|$)/
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Whether a command line is a watcher that restarts its child on changes.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* getIsDevWatcherCommand('node /app/node_modules/.bin/nodemon src/index.ts'); // → true
|
|
56
|
+
* getIsDevWatcherCommand('node dist/index.js'); // → false
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
const getIsDevWatcherCommand = (command) => DEV_WATCHER_COMMAND_PATTERNS.some((pattern) => pattern.test(command));
|
|
60
|
+
/**
|
|
61
|
+
* Whether this process runs under a watcher that restarts or reloads it
|
|
62
|
+
* (`bun --watch`/`--hot`, `node --watch`, `ts-node-dev`).
|
|
63
|
+
*/
|
|
64
|
+
const getIsWatchModeProcess = () => process.execArgv.some((argument) => WATCH_MODE_EXEC_ARGUMENTS.some((flag) => argument === flag || argument.startsWith(`${flag}=`))) || WATCH_MODE_ENV_VARS.some((envVar) => Boolean(process.env[envVar]));
|
|
65
|
+
/**
|
|
66
|
+
* Whether a server process runs in development, and so should watch the
|
|
67
|
+
* content declarations.
|
|
68
|
+
*
|
|
69
|
+
* `INTLAYER_WATCH=true|false` decides first, then `NODE_ENV` when set. An unset
|
|
70
|
+
* `NODE_ENV` is not a sign of development (`bun dist/index.mjs` rarely sets
|
|
71
|
+
* it), so the process must then show a positive signal, cheapest first:
|
|
72
|
+
* 1. a runtime watch flag or marker (`bun --watch`/`--hot`, `node --watch`,
|
|
73
|
+
* `ts-node-dev`);
|
|
74
|
+
* 2. a `dev`-like package script;
|
|
75
|
+
* 3. a restarting watcher in its own command line or its ancestors'
|
|
76
|
+
* (`deno run --watch`, `nodemon`, `tsx watch`…), for those started
|
|
77
|
+
* directly rather than through a script.
|
|
78
|
+
*/
|
|
79
|
+
const getIsServerDevelopment = async () => {
|
|
80
|
+
const watchOverride = process.env[INTLAYER_WATCH_ENV_VAR]?.toLowerCase();
|
|
81
|
+
if (watchOverride === "true" || watchOverride === "1") return true;
|
|
82
|
+
if (watchOverride === "false" || watchOverride === "0") return false;
|
|
83
|
+
const nodeEnv = process.env.NODE_ENV;
|
|
84
|
+
if (nodeEnv) return nodeEnv === "development";
|
|
85
|
+
if (getIsWatchModeProcess()) return true;
|
|
86
|
+
if (DEV_SCRIPT_NAME_PATTERN.test(process.env["npm_lifecycle_event"] ?? "")) return true;
|
|
87
|
+
return (await require_utils_getProcessChainCommands.getProcessChainCommands()).some(getIsDevWatcherCommand);
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* The dev check of this process, computed once: its answer cannot change for
|
|
91
|
+
* the life of the process, and Fastify, Elysia or Remix may register the
|
|
92
|
+
* integration more than once.
|
|
93
|
+
*/
|
|
94
|
+
let serverDevelopmentPromise;
|
|
95
|
+
const getIsServerDevelopmentOnce = () => {
|
|
96
|
+
serverDevelopmentPromise ??= getIsServerDevelopment();
|
|
97
|
+
return serverDevelopmentPromise;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Prepares the dictionaries for a server integration (Express, Fastify, Hono…)
|
|
101
|
+
* and, in development, keeps them in sync with the content declarations.
|
|
102
|
+
*
|
|
103
|
+
* Replaces wrapping the dev server in `intlayer watch --with`: the watcher runs
|
|
104
|
+
* inside the server, deduplicated through the project's watcher lock, so a
|
|
105
|
+
* server restarted by `tsx watch` / `node --watch` hands it over to its
|
|
106
|
+
* successor, and a remaining `intlayer watch` makes it stand down.
|
|
107
|
+
*
|
|
108
|
+
* Fire-and-forget: the server must not wait on the build to start listening.
|
|
109
|
+
*
|
|
110
|
+
* @param configuration - The resolved Intlayer configuration.
|
|
111
|
+
* @param options - How the integration identifies itself, and whether to watch.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* prepareIntlayerServer(getConfiguration(), { label: 'express-intlayer' });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
const prepareIntlayerServer = (configuration, { label, watch }) => {
|
|
119
|
+
require_prepareIntlayer.prepareIntlayer(configuration).then(async () => {
|
|
120
|
+
if (!configuration.content.watch) return;
|
|
121
|
+
if (watch ?? await getIsServerDevelopmentOnce()) require_utils_startContentWatcher.startContentWatcher(configuration, { label });
|
|
122
|
+
}).catch((error) => {
|
|
123
|
+
(0, _intlayer_config_logger.getAppLogger)(configuration)(["Failed to prepare Intlayer dictionaries:", error], { level: "error" });
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
//#endregion
|
|
128
|
+
exports.INTLAYER_WATCH_ENV_VAR = INTLAYER_WATCH_ENV_VAR;
|
|
129
|
+
exports.getIsDevWatcherCommand = getIsDevWatcherCommand;
|
|
130
|
+
exports.getIsServerDevelopment = getIsServerDevelopment;
|
|
131
|
+
exports.prepareIntlayerServer = prepareIntlayerServer;
|
|
132
|
+
//# sourceMappingURL=prepareIntlayerServer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepareIntlayerServer.cjs","names":["getProcessChainCommands"],"sources":["../../src/prepareIntlayerServer.ts"],"sourcesContent":["import { getAppLogger } from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { getProcessChainCommands } from './utils/getProcessChainCommands';\nimport { startContentWatcher } from './utils/startContentWatcher';\n\n/**\n * Explicit override, for any setup the detection below does not recognise:\n * `INTLAYER_WATCH=true` forces the content watcher on, `INTLAYER_WATCH=false`\n * forces it off.\n */\nexport const INTLAYER_WATCH_ENV_VAR = 'INTLAYER_WATCH';\n\n/** Runtime flags that restart or reload the process on file changes. */\nconst WATCH_MODE_EXEC_ARGUMENTS = ['--watch', '--watch-path', '--hot'];\n\n/**\n * Environment variables set on the child process by a restarting watcher:\n * `node --watch` and `ts-node-dev`.\n */\nconst WATCH_MODE_ENV_VARS = ['WATCH_REPORT_DEPENDENCIES', 'TS_NODE_DEV'];\n\n/**\n * Package script names that start a dev server (`dev`, `start:dev`,\n * `dev:api`, `watch`…), matched on the `npm_lifecycle_event` that npm, pnpm,\n * yarn and bun set for `<pm> run <script>`.\n */\nconst DEV_SCRIPT_NAME_PATTERN = /\\b(dev|develop|development|watch)\\b/;\n\n/**\n * Command lines of the tools that restart a server on file changes, matched on\n * this process and the ones above it. Needed because most of them leave no\n * trace in the child itself.\n *\n * - Dedicated restarters, matched on their executable name (`nodemon`,\n * `watchexec`, `entr`…).\n * - `tsx watch`, whose watch mode is a subcommand.\n * - Any runtime or CLI given `--watch` / `--hot`: `deno run --watch` (which\n * restarts in-process), `nest start --watch`, `tsup --watch --onSuccess`…\n * - The `-w` shorthand of build tools that run the server on each rebuild\n * (`tsdown -w --on-success \"node dist/index.mjs\"`).\n */\nconst DEV_WATCHER_COMMAND_PATTERNS = [\n /(^|[\\s/])(nodemon|ts-node-dev|tsnd|node-dev|tsc-watch|supervisor|watchexec|entr|chokidar|onchange)(\\.c?m?js)?(\\s|$)/,\n /(^|[\\s/])tsx(\\/dist\\/cli\\.m?js)?\\s+watch(\\s|$)/,\n /\\s--(watch|watch-path|hot)(=|\\s|$)/,\n // `-w` alone is too common a flag (`grep -w`), so it only counts after a\n // build tool whose `-w` means watch (`tsdown -w --on-success …`, `tsup -w`).\n /(^|[\\s/])(tsdown|tsup|tsc|rollup|rolldown)(\\/\\S*)?(\\s+\\S+)*\\s+-w(\\s|$)/,\n];\n\n/**\n * Whether a command line is a watcher that restarts its child on changes.\n *\n * @example\n * ```ts\n * getIsDevWatcherCommand('node /app/node_modules/.bin/nodemon src/index.ts'); // → true\n * getIsDevWatcherCommand('node dist/index.js'); // → false\n * ```\n */\nexport const getIsDevWatcherCommand = (command: string): boolean =>\n DEV_WATCHER_COMMAND_PATTERNS.some((pattern) => pattern.test(command));\n\n/**\n * Whether this process runs under a watcher that restarts or reloads it\n * (`bun --watch`/`--hot`, `node --watch`, `ts-node-dev`).\n */\nconst getIsWatchModeProcess = (): boolean =>\n process.execArgv.some((argument) =>\n WATCH_MODE_EXEC_ARGUMENTS.some(\n (flag) => argument === flag || argument.startsWith(`${flag}=`)\n )\n ) || WATCH_MODE_ENV_VARS.some((envVar) => Boolean(process.env[envVar]));\n\n/**\n * Whether a server process runs in development, and so should watch the\n * content declarations.\n *\n * `INTLAYER_WATCH=true|false` decides first, then `NODE_ENV` when set. An unset\n * `NODE_ENV` is not a sign of development (`bun dist/index.mjs` rarely sets\n * it), so the process must then show a positive signal, cheapest first:\n * 1. a runtime watch flag or marker (`bun --watch`/`--hot`, `node --watch`,\n * `ts-node-dev`);\n * 2. a `dev`-like package script;\n * 3. a restarting watcher in its own command line or its ancestors'\n * (`deno run --watch`, `nodemon`, `tsx watch`…), for those started\n * directly rather than through a script.\n */\nexport const getIsServerDevelopment = async (): Promise<boolean> => {\n const watchOverride = process.env[INTLAYER_WATCH_ENV_VAR]?.toLowerCase();\n\n if (watchOverride === 'true' || watchOverride === '1') return true;\n if (watchOverride === 'false' || watchOverride === '0') return false;\n\n const nodeEnv = process.env['NODE_ENV'];\n\n if (nodeEnv) return nodeEnv === 'development';\n\n if (getIsWatchModeProcess()) return true;\n\n if (DEV_SCRIPT_NAME_PATTERN.test(process.env['npm_lifecycle_event'] ?? '')) {\n return true;\n }\n\n const processChainCommands = await getProcessChainCommands();\n\n return processChainCommands.some(getIsDevWatcherCommand);\n};\n\n/**\n * The dev check of this process, computed once: its answer cannot change for\n * the life of the process, and Fastify, Elysia or Remix may register the\n * integration more than once.\n */\nlet serverDevelopmentPromise: Promise<boolean> | undefined;\n\nconst getIsServerDevelopmentOnce = (): Promise<boolean> => {\n serverDevelopmentPromise ??= getIsServerDevelopment();\n\n return serverDevelopmentPromise;\n};\n\nexport type PrepareIntlayerServerOptions = {\n /**\n * How the integration names itself in the watcher lock and in messages, e.g.\n * `express-intlayer`.\n */\n label: string;\n /**\n * Whether to watch the content declarations after preparing them.\n * Defaults to {@link getIsServerDevelopment}.\n */\n watch?: boolean;\n};\n\n/**\n * Prepares the dictionaries for a server integration (Express, Fastify, Hono…)\n * and, in development, keeps them in sync with the content declarations.\n *\n * Replaces wrapping the dev server in `intlayer watch --with`: the watcher runs\n * inside the server, deduplicated through the project's watcher lock, so a\n * server restarted by `tsx watch` / `node --watch` hands it over to its\n * successor, and a remaining `intlayer watch` makes it stand down.\n *\n * Fire-and-forget: the server must not wait on the build to start listening.\n *\n * @param configuration - The resolved Intlayer configuration.\n * @param options - How the integration identifies itself, and whether to watch.\n *\n * @example\n * ```ts\n * prepareIntlayerServer(getConfiguration(), { label: 'express-intlayer' });\n * ```\n */\nexport const prepareIntlayerServer = (\n configuration: IntlayerConfig,\n { label, watch }: PrepareIntlayerServerOptions\n): void => {\n prepareIntlayer(configuration)\n .then(async () => {\n if (!configuration.content.watch) return;\n\n const shouldWatch = watch ?? (await getIsServerDevelopmentOnce());\n\n if (shouldWatch) startContentWatcher(configuration, { label });\n })\n .catch((error: unknown) => {\n getAppLogger(configuration)(\n ['Failed to prepare Intlayer dictionaries:', error],\n { level: 'error' }\n );\n });\n};\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,yBAAyB;;AAGtC,MAAM,4BAA4B;CAAC;CAAW;CAAgB;AAAO;;;;;AAMrE,MAAM,sBAAsB,CAAC,6BAA6B,aAAa;;;;;;AAOvE,MAAM,0BAA0B;;;;;;;;;;;;;;AAehC,MAAM,+BAA+B;CACnC;CACA;CACA;CAGA;AACF;;;;;;;;;;AAWA,MAAa,0BAA0B,YACrC,6BAA6B,MAAM,YAAY,QAAQ,KAAK,OAAO,CAAC;;;;;AAMtE,MAAM,8BACJ,QAAQ,SAAS,MAAM,aACrB,0BAA0B,MACvB,SAAS,aAAa,QAAQ,SAAS,WAAW,GAAG,KAAK,EAAE,CAC/D,CACF,KAAK,oBAAoB,MAAM,WAAW,QAAQ,QAAQ,IAAI,OAAO,CAAC;;;;;;;;;;;;;;;AAgBxE,MAAa,yBAAyB,YAA8B;CAClE,MAAM,gBAAgB,QAAQ,IAAI,uBAAuB,EAAE,YAAY;CAEvE,IAAI,kBAAkB,UAAU,kBAAkB,KAAK,OAAO;CAC9D,IAAI,kBAAkB,WAAW,kBAAkB,KAAK,OAAO;CAE/D,MAAM;CAEN,IAAI,SAAS,OAAO,YAAY;CAEhC,IAAI,sBAAsB,GAAG,OAAO;CAEpC,IAAI,wBAAwB,KAAK,QAAQ,IAAI,0BAA0B,EAAE,GACvE,OAAO;CAKT,QAAO,MAF4BA,8DAAwB,EAEhC,CAAC,KAAK,sBAAsB;AACzD;;;;;;AAOA,IAAI;AAEJ,MAAM,mCAAqD;CACzD,6BAA6B,uBAAuB;CAEpD,OAAO;AACT;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,yBACX,eACA,EAAE,OAAO,YACA;CACT,wCAAgB,aAAa,CAAC,CAC3B,KAAK,YAAY;EAChB,IAAI,CAAC,cAAc,QAAQ,OAAO;EAIlC,IAFoB,SAAU,MAAM,2BAA2B,GAE9C,sDAAoB,eAAe,EAAE,MAAM,CAAC;CAC/D,CAAC,CAAC,CACD,OAAO,UAAmB;EACzB,0CAAa,aAAa,CAAC,CACzB,CAAC,4CAA4C,KAAK,GAClD,EAAE,OAAO,QAAQ,CACnB;CACF,CAAC;AACL"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let node_fs_promises = require("node:fs/promises");
|
|
3
|
+
let node_child_process = require("node:child_process");
|
|
4
|
+
let node_util = require("node:util");
|
|
5
|
+
|
|
6
|
+
//#region src/utils/getProcessChainCommands.ts
|
|
7
|
+
/** How long listing the processes may take before giving up. */
|
|
8
|
+
const PROCESS_LIST_TIMEOUT_MS = 2e3;
|
|
9
|
+
/**
|
|
10
|
+
* Parses the output of `ps -A -o pid=,ppid=,command=`.
|
|
11
|
+
*
|
|
12
|
+
* @param output - One `<pid> <ppid> <command>` row per line.
|
|
13
|
+
* @returns The processes, keyed by PID.
|
|
14
|
+
*/
|
|
15
|
+
const parseProcessTable = (output) => {
|
|
16
|
+
const processes = /* @__PURE__ */ new Map();
|
|
17
|
+
for (const line of output.split("\n")) {
|
|
18
|
+
const match = /^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(line);
|
|
19
|
+
if (!match) continue;
|
|
20
|
+
processes.set(Number(match[1]), {
|
|
21
|
+
parentPid: Number(match[2]),
|
|
22
|
+
command: match[3].trim()
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return processes;
|
|
26
|
+
};
|
|
27
|
+
/** Reads one process from `/proc` (Linux): no subprocess needed. */
|
|
28
|
+
const readLinuxProcess = async (pid) => {
|
|
29
|
+
try {
|
|
30
|
+
const stat = await (0, node_fs_promises.readFile)(`/proc/${pid}/stat`, "utf8");
|
|
31
|
+
const [, parentPidField] = stat.slice(stat.lastIndexOf(")") + 2).split(" ");
|
|
32
|
+
const commandLine = await (0, node_fs_promises.readFile)(`/proc/${pid}/cmdline`, "utf8");
|
|
33
|
+
return {
|
|
34
|
+
parentPid: Number(parentPidField),
|
|
35
|
+
command: commandLine.split("\0").join(" ").trim()
|
|
36
|
+
};
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/** Lists every process through one `ps` call (macOS, BSD). */
|
|
42
|
+
const readProcessTable = async () => {
|
|
43
|
+
try {
|
|
44
|
+
const { stdout } = await (0, node_util.promisify)(node_child_process.execFile)("ps", [
|
|
45
|
+
"-A",
|
|
46
|
+
"-o",
|
|
47
|
+
"pid=,ppid=,command="
|
|
48
|
+
], {
|
|
49
|
+
timeout: PROCESS_LIST_TIMEOUT_MS,
|
|
50
|
+
maxBuffer: 16777216
|
|
51
|
+
});
|
|
52
|
+
return parseProcessTable(stdout);
|
|
53
|
+
} catch {
|
|
54
|
+
return /* @__PURE__ */ new Map();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Whether reading the process list is allowed without side effects.
|
|
59
|
+
*
|
|
60
|
+
* Under Deno, a missing permission makes an interactive process stop and
|
|
61
|
+
* prompt the user, so the list is only read when access is already granted.
|
|
62
|
+
* Node and Bun have no permission model on these calls.
|
|
63
|
+
*/
|
|
64
|
+
const getCanReadProcessList = () => {
|
|
65
|
+
const permissions = globalThis.Deno?.permissions;
|
|
66
|
+
if (!permissions) return true;
|
|
67
|
+
try {
|
|
68
|
+
const descriptor = process.platform === "linux" ? {
|
|
69
|
+
name: "read",
|
|
70
|
+
path: "/proc"
|
|
71
|
+
} : {
|
|
72
|
+
name: "run",
|
|
73
|
+
command: "ps"
|
|
74
|
+
};
|
|
75
|
+
return permissions.querySync?.(descriptor).state === "granted";
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Command lines of this process and of the processes above it, closest first.
|
|
82
|
+
*
|
|
83
|
+
* This process is included because some runtimes restart the script inside
|
|
84
|
+
* the same process, leaving their watch flag only on their own command line
|
|
85
|
+
* (`deno run --watch`).
|
|
86
|
+
*
|
|
87
|
+
* Best effort: resolves to an empty list on Windows, or when the process list
|
|
88
|
+
* cannot be read (sandbox, missing `ps`, Deno without the permission), and
|
|
89
|
+
* never throws.
|
|
90
|
+
*
|
|
91
|
+
* @param maxDepth - How many processes to read at most, this one included.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* await getProcessChainCommands();
|
|
96
|
+
* // → ['node src/index.js', 'node …/nodemon src/index.js', 'npm run dev']
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
const getProcessChainCommands = async (maxDepth = 6) => {
|
|
100
|
+
if (process.platform === "win32") return [];
|
|
101
|
+
if (!getCanReadProcessList()) return [];
|
|
102
|
+
const getProcess = process.platform === "linux" ? readLinuxProcess : await readProcessTable().then((processes) => async (pid) => processes.get(pid));
|
|
103
|
+
const commands = [];
|
|
104
|
+
let pid = process.pid;
|
|
105
|
+
while (pid > 1 && commands.length < maxDepth) {
|
|
106
|
+
const entry = await getProcess(pid);
|
|
107
|
+
if (!entry) break;
|
|
108
|
+
commands.push(entry.command);
|
|
109
|
+
pid = entry.parentPid;
|
|
110
|
+
}
|
|
111
|
+
return commands;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
exports.getProcessChainCommands = getProcessChainCommands;
|
|
116
|
+
exports.parseProcessTable = parseProcessTable;
|
|
117
|
+
//# sourceMappingURL=getProcessChainCommands.cjs.map
|