@open-mercato/cli 0.10.1-develop.7990.1.82d0a183c5 → 0.10.1-develop.8004.1.a8a79ee43f
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/.turbo/turbo-build.log +1 -1
- package/build.mjs +1 -0
- package/dist/agentic/guides/module-facts.json +162 -162
- package/dist/agentic/guides/module-facts.v2.json +162 -162
- package/dist/agentic/guides/module-tool.md +21 -0
- package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
- package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
- package/dist/agentic/guides/modules/api_docs/index.md +1 -1
- package/dist/agentic/guides/modules/api_keys/index.md +1 -1
- package/dist/agentic/guides/modules/attachments/index.md +1 -1
- package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
- package/dist/agentic/guides/modules/auth/index.md +1 -1
- package/dist/agentic/guides/modules/availability/index.md +1 -1
- package/dist/agentic/guides/modules/business_rules/index.md +1 -1
- package/dist/agentic/guides/modules/carrier_inpost/index.md +1 -1
- package/dist/agentic/guides/modules/cart/index.md +1 -1
- package/dist/agentic/guides/modules/catalog/index.md +1 -1
- package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
- package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
- package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
- package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
- package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
- package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
- package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
- package/dist/agentic/guides/modules/channel_smtp/index.md +1 -1
- package/dist/agentic/guides/modules/checkout/index.md +1 -1
- package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
- package/dist/agentic/guides/modules/configs/index.md +1 -1
- package/dist/agentic/guides/modules/content/index.md +1 -1
- package/dist/agentic/guides/modules/currencies/index.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
- package/dist/agentic/guides/modules/customer_groups/index.md +1 -1
- package/dist/agentic/guides/modules/customers/index.md +1 -1
- package/dist/agentic/guides/modules/dashboards/index.md +1 -1
- package/dist/agentic/guides/modules/data_sync/index.md +1 -1
- package/dist/agentic/guides/modules/design_system/index.md +1 -1
- package/dist/agentic/guides/modules/devices/index.md +1 -1
- package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
- package/dist/agentic/guides/modules/directory/index.md +1 -1
- package/dist/agentic/guides/modules/documents/index.md +1 -1
- package/dist/agentic/guides/modules/ecommerce/index.md +1 -1
- package/dist/agentic/guides/modules/entities/index.md +1 -1
- package/dist/agentic/guides/modules/eudr/index.md +1 -1
- package/dist/agentic/guides/modules/events/index.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
- package/dist/agentic/guides/modules/forms/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_autopay/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_tpay/index.md +1 -1
- package/dist/agentic/guides/modules/generators/index.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
- package/dist/agentic/guides/modules/integrations/index.md +1 -1
- package/dist/agentic/guides/modules/messages/index.md +1 -1
- package/dist/agentic/guides/modules/notifications/index.md +1 -1
- package/dist/agentic/guides/modules/onboarding/index.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
- package/dist/agentic/guides/modules/perspectives/index.md +1 -1
- package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
- package/dist/agentic/guides/modules/planner/index.md +1 -1
- package/dist/agentic/guides/modules/portal/index.md +1 -1
- package/dist/agentic/guides/modules/progress/index.md +1 -1
- package/dist/agentic/guides/modules/promotions/index.md +1 -1
- package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
- package/dist/agentic/guides/modules/query_index/index.md +1 -1
- package/dist/agentic/guides/modules/record_locks/index.md +1 -1
- package/dist/agentic/guides/modules/resources/index.md +1 -1
- package/dist/agentic/guides/modules/sales/index.md +1 -1
- package/dist/agentic/guides/modules/scheduler/index.md +1 -1
- package/dist/agentic/guides/modules/search/index.md +1 -1
- package/dist/agentic/guides/modules/security/index.md +1 -1
- package/dist/agentic/guides/modules/seeds/index.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
- package/dist/agentic/guides/modules/sso/index.md +1 -1
- package/dist/agentic/guides/modules/staff/index.md +1 -1
- package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
- package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
- package/dist/agentic/guides/modules/telemetry/index.md +1 -1
- package/dist/agentic/guides/modules/tillio/index.md +1 -1
- package/dist/agentic/guides/modules/translations/index.md +1 -1
- package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
- package/dist/agentic/guides/modules/webhooks/index.md +1 -1
- package/dist/agentic/guides/modules/wms/index.md +1 -1
- package/dist/agentic/guides/modules/workflows/index.md +1 -1
- package/dist/agentic/guides/reference-module-facts.json +1 -1
- package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +4 -0
- package/dist/agentic/guides/upstream/manifest.json +2 -2
- package/dist/agentic/shared/ai/harness/cases.json +23 -9
- package/dist/agentic/shared/ai/harness/source-link-inventory.json +90 -4
- package/dist/i18n/de.json +4 -0
- package/dist/i18n/en.json +4 -0
- package/dist/i18n/es.json +4 -0
- package/dist/i18n/ko.json +4 -0
- package/dist/i18n/pl.json +4 -0
- package/dist/lib/__fixtures__/module-search/built-in.json +235 -0
- package/dist/lib/__fixtures__/module-search/catalog-parity.json +4076 -0
- package/dist/lib/__fixtures__/module-search/modules-index.json +1980 -0
- package/dist/lib/__fixtures__/official-module-package/package.json +33 -0
- package/dist/lib/__integration__/TC-INT-007.spec.js +207 -19
- package/dist/lib/__integration__/TC-INT-007.spec.js.map +2 -2
- package/dist/lib/__integration__/TC-INT-009.spec.js +267 -0
- package/dist/lib/__integration__/TC-INT-009.spec.js.map +7 -0
- package/dist/lib/eject.js +25 -9
- package/dist/lib/eject.js.map +2 -2
- package/dist/lib/generators/entity-ids.js +2 -0
- package/dist/lib/generators/entity-ids.js.map +2 -2
- package/dist/lib/generators/module-di.js +2 -0
- package/dist/lib/generators/module-di.js.map +2 -2
- package/dist/lib/generators/module-entities.js +2 -0
- package/dist/lib/generators/module-entities.js.map +2 -2
- package/dist/lib/generators/module-package-sources.js +6 -4
- package/dist/lib/generators/module-package-sources.js.map +2 -2
- package/dist/lib/generators/module-registry.js +32 -86
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/generators/openapi.js +2 -0
- package/dist/lib/generators/openapi.js.map +2 -2
- package/dist/lib/generators/source-exports.js +73 -0
- package/dist/lib/generators/source-exports.js.map +7 -0
- package/dist/lib/init-secrets.js +33 -1
- package/dist/lib/init-secrets.js.map +2 -2
- package/dist/lib/init-summary.js +44 -0
- package/dist/lib/init-summary.js.map +7 -0
- package/dist/lib/module-github.js +98 -0
- package/dist/lib/module-github.js.map +7 -0
- package/dist/lib/module-identity.js +131 -0
- package/dist/lib/module-identity.js.map +7 -0
- package/dist/lib/module-inspection.js +124 -0
- package/dist/lib/module-inspection.js.map +7 -0
- package/dist/lib/module-install.js +150 -21
- package/dist/lib/module-install.js.map +3 -3
- package/dist/lib/module-package.js +205 -15
- package/dist/lib/module-package.js.map +2 -2
- package/dist/lib/modules-config.js +69 -30
- package/dist/lib/modules-config.js.map +2 -2
- package/dist/lib/resolver.js +33 -34
- package/dist/lib/resolver.js.map +2 -2
- package/dist/mercato.js +17 -37
- package/dist/mercato.js.map +2 -2
- package/package.json +7 -7
- package/src/__tests__/mercato.test.ts +71 -4
- package/src/i18n/de.json +4 -0
- package/src/i18n/en.json +4 -0
- package/src/i18n/es.json +4 -0
- package/src/i18n/ko.json +4 -0
- package/src/i18n/pl.json +4 -0
- package/src/lib/__fixtures__/official-module-package/dist/modules/test_package/widgets/injection/test/widget.js +1 -0
- package/src/lib/__integration__/TC-INT-007.spec.ts +219 -19
- package/src/lib/__integration__/TC-INT-009.spec.ts +279 -0
- package/src/lib/__tests__/eject.test.ts +98 -4
- package/src/lib/__tests__/init-secrets.test.ts +85 -1
- package/src/lib/__tests__/init-summary.test.ts +50 -0
- package/src/lib/__tests__/module-github.test.ts +108 -0
- package/src/lib/__tests__/module-identity.test.ts +144 -0
- package/src/lib/__tests__/module-inspection.test.ts +195 -0
- package/src/lib/__tests__/module-install.test.ts +399 -10
- package/src/lib/__tests__/module-package.test.ts +154 -0
- package/src/lib/__tests__/modules-config.test.ts +55 -0
- package/src/lib/__tests__/resolver.packages.test.ts +29 -0
- package/src/lib/eject.ts +28 -10
- package/src/lib/generators/__tests__/module-id-collisions.test.ts +146 -0
- package/src/lib/generators/__tests__/module-package-sources.test.ts +19 -2
- package/src/lib/generators/__tests__/module-requirements.test.ts +56 -0
- package/src/lib/generators/entity-ids.ts +2 -0
- package/src/lib/generators/module-di.ts +2 -0
- package/src/lib/generators/module-entities.ts +2 -0
- package/src/lib/generators/module-package-sources.ts +7 -5
- package/src/lib/generators/module-registry.ts +33 -115
- package/src/lib/generators/openapi.ts +3 -0
- package/src/lib/generators/source-exports.ts +93 -0
- package/src/lib/init-secrets.ts +37 -0
- package/src/lib/init-summary.ts +54 -0
- package/src/lib/module-github.ts +109 -0
- package/src/lib/module-identity.ts +145 -0
- package/src/lib/module-inspection.ts +133 -0
- package/src/lib/module-install.ts +170 -22
- package/src/lib/module-package.ts +243 -16
- package/src/lib/modules-config.ts +80 -32
- package/src/lib/resolver.ts +35 -39
- package/src/mercato.ts +18 -44
- package/src/types/cross-spawn.d.ts +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { getEnabledModuleIdentities } from "../module-identity.js";
|
|
3
4
|
import { isModuleRouteFile } from "./scanner.js";
|
|
4
5
|
import {
|
|
5
6
|
calculateChecksum,
|
|
@@ -513,6 +514,7 @@ async function generateOpenApi(options) {
|
|
|
513
514
|
const outFile = path.join(outputDir, "openapi.generated.json");
|
|
514
515
|
const checksumFile = path.join(outputDir, "openapi.generated.checksum");
|
|
515
516
|
const inputManifestFile = path.join(outputDir, "openapi.generated.inputs.json");
|
|
517
|
+
getEnabledModuleIdentities(resolver, resolver.loadEnabledModules());
|
|
516
518
|
if (!fs.existsSync(outputDir)) {
|
|
517
519
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
518
520
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/generators/openapi.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * OpenAPI JSON Generator\n *\n * Generates a static openapi.generated.json file at build time.\n * This allows CLI tools (like MCP dev server) to access API endpoint\n * information without requiring a running Next.js app.\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { ModuleEntry, PackageResolver } from '../resolver'\nimport { isModuleRouteFile } from './scanner'\nimport {\n calculateChecksum,\n calculateStructureChecksum,\n readChecksumRecord,\n writeChecksumRecord,\n logGenerationResult,\n type GeneratorResult,\n createGeneratorResult,\n} from '../utils'\n\nexport interface GenerateOpenApiOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\ninterface ApiRouteInfo {\n path: string\n methods: HttpMethod[]\n openApiPath: string\n}\n\ninterface OpenApiInputManifest {\n version: 1\n inputPaths: string[]\n}\n\ninterface OpenApiInputContext {\n enabled: ModuleEntry[]\n apiRoots: string[]\n moduleIdentity: Array<{\n id: string\n from: string\n appBase: string\n pkgBase: string\n }>\n}\n\ninterface OpenApiBundleResult {\n doc: Record<string, any> | null\n inputPaths: string[]\n}\n\nconst OPENAPI_INPUT_MANIFEST_VERSION = 1\n\nfunction createOpenApiInputContext(resolver: PackageResolver): OpenApiInputContext {\n const enabled = resolver.loadEnabledModules()\n const apiRoots: string[] = []\n const moduleIdentity = enabled.map((entry) => {\n const roots = resolver.getModulePaths(entry)\n apiRoots.push(path.join(roots.appBase, 'api'), path.join(roots.pkgBase, 'api'))\n return {\n id: entry.id,\n from: entry.from ?? '@open-mercato/core',\n appBase: path.resolve(roots.appBase),\n pkgBase: path.resolve(roots.pkgBase),\n }\n })\n return { enabled, apiRoots, moduleIdentity }\n}\n\nfunction readOpenApiInputManifest(filePath: string): OpenApiInputManifest | null {\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as Partial<OpenApiInputManifest>\n if (\n parsed.version !== OPENAPI_INPUT_MANIFEST_VERSION\n || !Array.isArray(parsed.inputPaths)\n || parsed.inputPaths.some((entry) => typeof entry !== 'string')\n ) {\n return null\n }\n return {\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n inputPaths: Array.from(new Set(parsed.inputPaths.map((entry) => path.resolve(entry))))\n .sort((a, b) => a.localeCompare(b)),\n }\n } catch {\n return null\n }\n}\n\nfunction trackedPathRecord(filePath: string): string {\n try {\n const stat = fs.statSync(filePath)\n if (stat.isFile()) {\n return `${path.resolve(filePath)}:${calculateChecksum(fs.readFileSync(filePath, 'utf8'))}`\n }\n return `${path.resolve(filePath)}:${stat.size}:${stat.mtimeMs}`\n } catch {\n return `missing:${path.resolve(filePath)}`\n }\n}\n\nfunction calculateOpenApiInputFingerprint(\n resolver: PackageResolver,\n context: OpenApiInputContext,\n manifest: OpenApiInputManifest,\n): string {\n const rootDir = resolver.getRootDir()\n const appDir = resolver.getAppDir()\n const configPaths = [\n resolver.getModulesConfigPath(),\n path.join(rootDir, 'package.json'),\n path.join(rootDir, 'yarn.lock'),\n path.join(rootDir, 'package-lock.json'),\n path.join(rootDir, 'pnpm-lock.yaml'),\n path.join(rootDir, 'tsconfig.json'),\n path.join(rootDir, 'tsconfig.base.json'),\n path.join(appDir, 'package.json'),\n path.join(appDir, 'tsconfig.json'),\n ]\n const trackedRecords = [...manifest.inputPaths, ...configPaths]\n .map(trackedPathRecord)\n .sort((a, b) => a.localeCompare(b))\n return calculateChecksum(JSON.stringify({\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n modules: context.moduleIdentity,\n routeStructure: calculateStructureChecksum(context.apiRoots),\n trackedRecords,\n environment: {\n node: process.version,\n nodeEnv: process.env.NODE_ENV ?? '',\n publicAppUrl: process.env.NEXT_PUBLIC_APP_URL ?? '',\n },\n }))\n}\n\nfunction resolveExistingPath(paths: string[]): string | null {\n for (const candidate of paths) {\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n\n/**\n * Find all API route files and extract their OpenAPI specs.\n */\nasync function findApiRoutes(\n resolver: PackageResolver,\n enabled: ModuleEntry[],\n): Promise<ApiRouteInfo[]> {\n const routes: ApiRouteInfo[] = []\n\n for (const entry of enabled) {\n const modId = entry.id\n const roots = resolver.getModulePaths(entry)\n\n const apiApp = path.join(roots.appBase, 'api')\n const apiPkg = path.join(roots.pkgBase, 'api')\n\n // Scan route files\n const routeFiles: Array<{ relativePath: string; fullPath: string }> = []\n\n const walkDir = (dir: string, rel: string[] = []) => {\n if (!fs.existsSync(dir)) return\n for (const e of fs.readdirSync(dir, { withFileTypes: true })) {\n if (e.isDirectory()) {\n if (e.name === '__tests__' || e.name === '__mocks__') continue\n walkDir(path.join(dir, e.name), [...rel, e.name])\n } else if (e.isFile() && isModuleRouteFile(e.name)) {\n routeFiles.push({\n relativePath: [...rel].join('/'),\n fullPath: path.join(dir, e.name),\n })\n }\n }\n }\n\n // Scan package first, then app (app overrides)\n if (fs.existsSync(apiPkg)) walkDir(apiPkg)\n if (fs.existsSync(apiApp)) walkDir(apiApp)\n\n // Process unique routes (later app files overwrite earlier package files)\n const filesByRelativePath = new Map<string, string>()\n for (const { relativePath, fullPath } of routeFiles) {\n filesByRelativePath.set(relativePath, fullPath)\n }\n\n for (const [relativePath, fullPath] of filesByRelativePath) {\n\n // Build API path\n const routeSegs = relativePath ? relativePath.split('/') : []\n const apiPath = `/api/${modId}${routeSegs.length ? '/' + routeSegs.join('/') : ''}`\n // Convert [param] to {param} for OpenAPI format\n .replace(/\\[([^\\]]+)\\]/g, '{$1}')\n\n routes.push({\n path: fullPath,\n methods: await detectMethods(fullPath),\n openApiPath: apiPath,\n })\n }\n }\n\n return routes\n}\n\n/**\n * Detect which HTTP methods are exported from a route file.\n */\nasync function detectMethods(filePath: string): Promise<HttpMethod[]> {\n const methods: HttpMethod[] = []\n const content = fs.readFileSync(filePath, 'utf-8')\n\n const methodPatterns: HttpMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n for (const method of methodPatterns) {\n // Check for export { GET }, export const GET, export async function GET\n const patterns = [\n new RegExp(`export\\\\s+(const|async\\\\s+function|function)\\\\s+${method}\\\\b`),\n new RegExp(`export\\\\s*\\\\{[^}]*\\\\b${method}\\\\b[^}]*\\\\}`),\n ]\n if (patterns.some((p) => p.test(content))) {\n methods.push(method)\n }\n }\n\n return methods\n}\n\n/**\n * Parse openApi export from route file source code statically.\n * This extracts basic operation info without needing to compile the file.\n */\nfunction parseOpenApiFromSource(filePath: string): Record<string, any> | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8')\n\n // Check if file exports openApi\n if (!content.includes('export const openApi') && !content.includes('export { openApi')) {\n return null\n }\n\n // Extract operationId, summary, description from the source\n const result: Record<string, any> = {}\n const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n\n for (const method of methods) {\n // Look for method specs in the openApi object\n // Pattern: GET: { operationId: '...', summary: '...', ... }\n const methodPattern = new RegExp(\n `${method}\\\\s*:\\\\s*\\\\{([^}]+(?:\\\\{[^}]*\\\\}[^}]*)*)\\\\}`,\n 's'\n )\n const methodMatch = content.match(methodPattern)\n\n if (methodMatch) {\n const methodContent = methodMatch[1]\n const spec: Record<string, any> = {}\n\n // Extract operationId\n const opIdMatch = methodContent.match(/operationId\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (opIdMatch) spec.operationId = opIdMatch[1]\n\n // Extract summary\n const summaryMatch = methodContent.match(/summary\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (summaryMatch) spec.summary = summaryMatch[1]\n\n // Extract description\n const descMatch = methodContent.match(/description\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descMatch) spec.description = descMatch[1]\n\n // Extract tags\n const tagsMatch = methodContent.match(/tags\\s*:\\s*\\[([^\\]]*)\\]/)\n if (tagsMatch) {\n const tagsContent = tagsMatch[1]\n const tags = tagsContent.match(/['\"]([^'\"]+)['\"]/g)\n if (tags) {\n spec.tags = tags.map(t => t.replace(/['\"]/g, ''))\n }\n }\n\n if (Object.keys(spec).length > 0) {\n result[method] = spec\n }\n }\n }\n\n return Object.keys(result).length > 0 ? result : null\n } catch {\n return null\n }\n}\n\n/**\n * Generate a complete OpenAPI document by bundling route files with esbuild\n * and executing the bundle to call buildOpenApiDocument from @open-mercato/shared.\n *\n * esbuild compiles TypeScript with legacy decorator support (reads experimentalDecorators\n * from tsconfig.json), avoiding the TC39 decorator mismatch that breaks tsx-based imports.\n * External packages (zod, mikro-orm, etc.) are resolved from node_modules at runtime.\n */\nasync function generateOpenApiViaBundle(\n routes: ApiRouteInfo[],\n resolver: PackageResolver,\n quiet: boolean\n): Promise<OpenApiBundleResult> {\n let esbuild: typeof import('esbuild')\n try {\n esbuild = await import('esbuild')\n } catch {\n if (!quiet) console.log('[OpenAPI] esbuild not available, skipping bundle approach')\n return { doc: null, inputPaths: [] }\n }\n\n const { execFileSync } = await import('node:child_process')\n\n const rootDir = resolver.getRootDir()\n const appDir = resolver.getAppDir()\n const sharedPackageRoot = resolver.getPackageRoot('@open-mercato/shared')\n const corePackageRoot = resolver.getPackageRoot('@open-mercato/core')\n const tsconfigPath = resolveExistingPath([\n path.join(appDir, 'tsconfig.json'),\n path.join(rootDir, 'tsconfig.base.json'),\n path.join(rootDir, 'tsconfig.json'),\n ])\n const generatorPath = path.join(sharedPackageRoot, 'src', 'lib', 'openapi', 'generator.ts')\n const coreGeneratedRoot = path.join(corePackageRoot, 'generated')\n\n if (!fs.existsSync(generatorPath)) {\n if (!quiet) {\n console.log(`[OpenAPI] Generator source not found at ${generatorPath}, skipping bundle approach`)\n }\n return { doc: null, inputPaths: [] }\n }\n\n const cacheDir = path.join(rootDir, 'node_modules', '.cache')\n if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true })\n\n const bundlePath = path.join(cacheDir, '_openapi-bundle.mjs')\n let inputPaths: string[] = []\n\n // Build the entry script that imports all routes and calls buildOpenApiDocument\n const importLines: string[] = [\n `import { buildOpenApiDocument } from ${JSON.stringify(generatorPath)};`,\n ]\n const routeMapLines: string[] = []\n\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i]\n importLines.push(`import * as R${i} from ${JSON.stringify(route.path)};`)\n // Use [param] format so normalizePath in buildOpenApiDocument extracts path params\n const bracketPath = route.openApiPath.replace(/\\{([^}]+)\\}/g, '[$1]')\n routeMapLines.push(` [${JSON.stringify(bracketPath)}, R${i}],`)\n }\n\n const entryScript = `${importLines.join('\\n')}\n\nconst routeEntries = [\n${routeMapLines.join('\\n')}\n];\n\nconst modules = new Map();\nfor (const [apiPath, mod] of routeEntries) {\n const moduleId = apiPath.replace(/^\\\\/api\\\\//, '').split('/')[0];\n if (!modules.has(moduleId)) modules.set(moduleId, { id: moduleId, apis: [] });\n modules.get(moduleId).apis.push({\n path: apiPath,\n handlers: mod,\n metadata: mod.metadata,\n });\n}\n\nconst doc = buildOpenApiDocument([...modules.values()], {\n title: 'Open Mercato API',\n version: '1.0.0',\n description: 'Auto-generated OpenAPI specification',\n servers: [{ url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' }],\n});\n\n// Deep-clone to break shared object references before serializing.\n// The zodToJsonSchema memo cache returns the same object instance for\n// fields like currencyCode that appear on both parent and child schemas.\n// A naive WeakSet-based circular-ref guard would drop the second occurrence,\n// causing properties to vanish from the generated spec (while the field\n// still appears in the 'required' array, since those are plain strings).\nconst deepClone = (v, ancestors = []) => {\n if (v === null || typeof v !== 'object') return v;\n if (typeof v === 'bigint') return Number(v);\n if (typeof v === 'function') return undefined;\n if (ancestors.includes(v)) return undefined; // true circular ref\n const next = [...ancestors, v];\n if (Array.isArray(v)) return v.map((item) => deepClone(item, next));\n const out = {};\n for (const [k, val] of Object.entries(v)) {\n const cloned = deepClone(val, next);\n if (cloned !== undefined) out[k] = cloned;\n }\n return out;\n};\nprocess.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>\n typeof v === 'bigint' ? Number(v) : v\n));\n`\n\n // Plugin: stub next/* imports (not available outside Next.js app context)\n const stubNextPlugin = {\n name: 'stub-next',\n setup(build: any) {\n build.onResolve({ filter: /^next($|\\/)/ }, () => ({\n path: 'next-stub',\n namespace: 'next-stub',\n }))\n build.onLoad({ filter: /.*/, namespace: 'next-stub' }, () => ({\n contents: [\n 'const p = new Proxy(function(){}, {',\n ' get(_, k) { return k === \"__esModule\" ? true : k === \"default\" ? p : p; },',\n ' apply() { return p; },',\n ' construct() { return p; },',\n '});',\n 'export default p;',\n 'export const NextRequest = p, NextResponse = p, headers = p, cookies = p;',\n 'export const redirect = p, notFound = p, useRouter = p, usePathname = p;',\n 'export const useSearchParams = p, permanentRedirect = p, revalidatePath = p;',\n ].join('\\n'),\n loader: 'js' as const,\n }))\n },\n }\n\n // Plugin: resolve workspace imports, aliases, and subpath imports\n const resolveProjectImportsPlugin = {\n name: 'resolve-project-imports',\n setup(build: any) {\n // @open-mercato/<pkg>/<path> \u2192 packageRoot/src/<path>.ts\n build.onResolve({ filter: /^@open-mercato\\// }, (args: any) => {\n const withoutScope = args.path.slice('@open-mercato/'.length)\n const slashIdx = withoutScope.indexOf('/')\n const pkg = slashIdx === -1 ? withoutScope : withoutScope.slice(0, slashIdx)\n const rest = slashIdx === -1 ? '' : withoutScope.slice(slashIdx + 1)\n const packageName = `@open-mercato/${pkg}`\n const packageRoot = resolver.getPackageRoot(packageName)\n\n const base = rest\n ? path.join(packageRoot, 'src', rest)\n : path.join(packageRoot, 'src', 'index')\n\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // @/.mercato/* \u2192 app/.mercato/* (tsconfig paths)\n build.onResolve({ filter: /^@\\/\\.mercato\\// }, (args: any) => {\n const rest = args.path.slice('@/'.length) // '.mercato/generated/...'\n const base = path.join(appDir, rest)\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx', '']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // @/* \u2192 app/src/* (tsconfig paths)\n build.onResolve({ filter: /^@\\// }, (args: any) => {\n const rest = args.path.slice('@/'.length)\n const base = path.join(appDir, 'src', rest)\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // #generated/* \u2192 core package generated/* (Node subpath imports)\n build.onResolve({ filter: /^#generated\\// }, (args: any) => {\n const rest = args.path.slice('#generated/'.length)\n const base = path.join(coreGeneratedRoot, rest)\n for (const ext of ['.ts', '/index.ts']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n },\n }\n\n // Plugin: externalize installed packages, stub missing ones\n const nodeBuiltins = new Set([\n 'assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',\n 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2',\n 'https', 'module', 'net', 'os', 'path', 'perf_hooks', 'process',\n 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder',\n 'sys', 'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'wasi',\n 'worker_threads', 'zlib', 'async_hooks', 'diagnostics_channel', 'inspector',\n 'trace_events',\n ])\n const externalNonWorkspacePlugin = {\n name: 'external-non-workspace',\n setup(build: any) {\n build.onResolve({ filter: /^[^./]/ }, (args: any) => {\n if (path.isAbsolute(args.path)) return undefined\n if (args.path.startsWith('@open-mercato/')) return undefined\n if (args.path.startsWith('@/')) return undefined\n if (args.path.startsWith('#generated/')) return undefined\n if (args.path.startsWith('next')) return undefined\n // Let esbuild handle Node builtins (with or without node: prefix)\n if (args.path.startsWith('node:')) return undefined\n const topLevel = args.path.split('/')[0]\n if (nodeBuiltins.has(topLevel)) return undefined\n\n // Extract package name (handle scoped packages like @mikro-orm/core)\n const pkgName = args.path.startsWith('@')\n ? args.path.split('/').slice(0, 2).join('/')\n : topLevel\n const pkgDir = path.join(rootDir, 'node_modules', pkgName)\n if (fs.existsSync(pkgDir)) return { external: true }\n\n // Package not installed \u2014 provide CJS stub (allows any named import)\n return { path: args.path, namespace: 'missing-pkg' }\n })\n build.onLoad({ filter: /.*/, namespace: 'missing-pkg' }, () => ({\n contents: 'var h={get:(_,k)=>k===\"__esModule\"?true:p};var p=new Proxy(function(){return p},{get:h.get,apply:()=>p,construct:()=>p});module.exports=p;',\n loader: 'js' as const,\n }))\n },\n }\n\n try {\n const buildResult = await esbuild.build({\n stdin: {\n contents: entryScript,\n resolveDir: appDir,\n sourcefile: 'openapi-entry.ts',\n loader: 'ts',\n },\n bundle: true,\n metafile: true,\n absWorkingDir: rootDir,\n format: 'esm',\n platform: 'node',\n target: 'node18',\n outfile: bundlePath,\n write: true,\n ...(tsconfigPath ? { tsconfig: tsconfigPath } : {}),\n logLevel: 'silent',\n jsx: 'automatic',\n plugins: [stubNextPlugin, resolveProjectImportsPlugin, externalNonWorkspacePlugin],\n })\n\n inputPaths = Object.keys(buildResult.metafile?.inputs ?? {})\n .filter((inputPath) => !inputPath.startsWith('<'))\n .map((inputPath) => path.resolve(rootDir, inputPath))\n .filter((inputPath) => fs.existsSync(inputPath))\n .sort((a, b) => a.localeCompare(b))\n\n const stdout = execFileSync(process.execPath, [bundlePath], {\n timeout: 60_000,\n maxBuffer: 20 * 1024 * 1024,\n encoding: 'utf-8',\n env: { ...process.env, NODE_NO_WARNINGS: '1' },\n cwd: rootDir,\n })\n\n const lastLine = stdout.trim().split('\\n').pop()!\n const doc = JSON.parse(lastLine) as Record<string, any>\n\n if (!quiet) {\n const pathCount = Object.keys(doc.paths || {}).length\n const withBody = Object.values(doc.paths || {}).reduce((n: number, methods: any) => {\n for (const m of Object.values(methods)) {\n if ((m as any)?.requestBody) n++\n }\n return n\n }, 0)\n console.log(`[OpenAPI] Bundle approach: ${pathCount} paths, ${withBody} with requestBody schemas`)\n }\n\n return { doc, inputPaths }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err)\n const stderr = (err as any)?.stderr\n const esbuildErrors = (err as any)?.errors as Array<{ text: string; location?: { file: string } }> | undefined\n if (!quiet) {\n console.log(`[OpenAPI] Bundle approach failed, will use static fallback: ${errMsg.split('\\n')[0]}`)\n if (esbuildErrors?.length) {\n const unique = new Map<string, string>()\n for (const e of esbuildErrors) {\n const key = e.text\n if (!unique.has(key)) unique.set(key, e.location?.file ?? '')\n }\n for (const [text, file] of [...unique.entries()].slice(0, 10)) {\n console.log(`[OpenAPI] ${text}${file ? ` (${path.basename(file)})` : ''}`)\n }\n if (unique.size > 10) console.log(`[OpenAPI] ... and ${unique.size - 10} more`)\n }\n if (stderr) {\n for (const line of String(stderr).trim().split('\\n').slice(0, 3)) {\n console.log(`[OpenAPI] ${line}`)\n }\n }\n }\n return { doc: null, inputPaths }\n } finally {\n // Shut down esbuild's persistent Go service so it does not deadlock at\n // process exit when a plugin request is still in flight.\n try { await esbuild.stop() } catch {}\n // Clean up old files from previous tsx-based approach\n for (const file of ['_openapi-register.mjs', '_openapi-loader.mjs', '_next-stub.cjs']) {\n try { fs.unlinkSync(path.join(cacheDir, file)) } catch {}\n }\n }\n}\n\n/**\n * Build OpenAPI paths from discovered routes.\n * Extracts basic operation info from route files statically.\n */\nfunction buildOpenApiPaths(routes: ApiRouteInfo[]): Record<string, any> {\n const paths: Record<string, any> = {}\n\n for (const route of routes) {\n const pathEntry: Record<string, any> = {}\n\n // Try to extract OpenAPI specs from source\n const openApiSpec = parseOpenApiFromSource(route.path)\n\n for (const method of route.methods) {\n const methodLower = method.toLowerCase()\n const spec = openApiSpec?.[method]\n\n // Generate a default operationId if not found\n const pathSegments = route.openApiPath\n .replace(/^\\/api\\//, '')\n .replace(/\\{[^}]+\\}/g, 'by_id')\n .split('/')\n .filter(Boolean)\n .join('_')\n const defaultOperationId = `${methodLower}_${pathSegments}`\n\n pathEntry[methodLower] = {\n operationId: spec?.operationId || defaultOperationId,\n summary: spec?.summary || `${method} ${route.openApiPath}`,\n description: spec?.description || `${method} operation for ${route.openApiPath}`,\n tags: spec?.tags || [route.openApiPath.split('/')[2] || 'api'],\n responses: {\n '200': {\n description: 'Successful response',\n },\n },\n }\n }\n\n if (Object.keys(pathEntry).length > 0) {\n paths[route.openApiPath] = pathEntry\n }\n }\n\n return paths\n}\n\n/**\n * Generate the OpenAPI JSON file.\n */\nexport async function generateOpenApi(options: GenerateOpenApiOptions): Promise<GeneratorResult> {\n const { resolver, quiet = false } = options\n const result = createGeneratorResult()\n\n const outputDir = resolver.getOutputDir()\n const outFile = path.join(outputDir, 'openapi.generated.json')\n const checksumFile = path.join(outputDir, 'openapi.generated.checksum')\n const inputManifestFile = path.join(outputDir, 'openapi.generated.inputs.json')\n\n // Ensure output directory exists\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n const inputContext = createOpenApiInputContext(resolver)\n const existingChecksums = readChecksumRecord(checksumFile)\n const existingManifest = readOpenApiInputManifest(inputManifestFile)\n\n if (\n existingChecksums?.structure\n && existingManifest\n && fs.existsSync(outFile)\n && calculateChecksum(fs.readFileSync(outFile, 'utf8')) === existingChecksums.content\n && calculateOpenApiInputFingerprint(resolver, inputContext, existingManifest) === existingChecksums.structure\n ) {\n result.filesUnchanged.push(outFile)\n if (!quiet) {\n console.log(`[OpenAPI] Skipped (inputs unchanged): ${outFile}`)\n }\n return result\n }\n\n // Find all API routes\n const routes = await findApiRoutes(resolver, inputContext.enabled)\n\n if (!quiet) {\n console.log(`[OpenAPI] Found ${routes.length} API route files`)\n }\n\n // Determine project root (cli package is at packages/cli/src/lib/generators/)\n // Try esbuild bundle approach first \u2014 produces full requestBody/response schemas\n const bundleResult = await generateOpenApiViaBundle(routes, resolver, quiet)\n let doc: Record<string, any> | null = bundleResult.doc\n\n // Fallback to static regex approach (extracts operationId/summary/tags but no schemas)\n if (!doc) {\n if (!quiet) {\n console.warn(\n '[OpenAPI] \u26A0 Bundling failed; falling back to static regex extraction \u2014 '\n + 'request/response schemas are OMITTED from the generated document. '\n + 'The usual cause is a route file importing a module specifier that does not resolve.',\n )\n }\n const paths = buildOpenApiPaths(routes)\n doc = {\n openapi: '3.1.0',\n info: {\n title: 'Open Mercato API',\n version: '1.0.0',\n description: 'Auto-generated OpenAPI specification',\n },\n servers: [\n { url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' },\n ],\n paths,\n components: {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: 'Send an `Authorization: Bearer <token>` header with a valid API token.',\n },\n },\n },\n }\n }\n\n const output = JSON.stringify(doc, null, 2)\n const checksum = calculateChecksum(output)\n let structureChecksum = ''\n\n if (bundleResult.doc && bundleResult.inputPaths.length > 0) {\n const manifest: OpenApiInputManifest = {\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n inputPaths: Array.from(new Set(bundleResult.inputPaths)).sort((a, b) => a.localeCompare(b)),\n }\n fs.writeFileSync(inputManifestFile, `${JSON.stringify(manifest, null, 2)}\\n`)\n structureChecksum = calculateOpenApiInputFingerprint(resolver, inputContext, manifest)\n } else {\n try { fs.unlinkSync(inputManifestFile) } catch {}\n }\n\n // Check if unchanged\n const existingOutputMatches = fs.existsSync(outFile)\n && calculateChecksum(fs.readFileSync(outFile, 'utf8')) === checksum\n if (existingChecksums && existingChecksums.content === checksum && existingOutputMatches) {\n if (existingChecksums.structure !== structureChecksum) {\n writeChecksumRecord(checksumFile, { content: checksum, structure: structureChecksum })\n }\n result.filesUnchanged.push(outFile)\n if (!quiet) {\n console.log(`[OpenAPI] Skipped (unchanged): ${outFile}`)\n }\n return result\n }\n\n // Write the file\n fs.writeFileSync(outFile, output)\n writeChecksumRecord(checksumFile, { content: checksum, structure: structureChecksum })\n\n result.filesWritten.push(outFile)\n\n if (!quiet) {\n logGenerationResult(outFile, true)\n const pathCount = Object.keys(doc.paths || {}).length\n console.log(`[OpenAPI] Generated ${pathCount} API paths`)\n }\n\n return result\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * OpenAPI JSON Generator\n *\n * Generates a static openapi.generated.json file at build time.\n * This allows CLI tools (like MCP dev server) to access API endpoint\n * information without requiring a running Next.js app.\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { ModuleEntry, PackageResolver } from '../resolver'\nimport { getEnabledModuleIdentities } from '../module-identity'\nimport { isModuleRouteFile } from './scanner'\nimport {\n calculateChecksum,\n calculateStructureChecksum,\n readChecksumRecord,\n writeChecksumRecord,\n logGenerationResult,\n type GeneratorResult,\n createGeneratorResult,\n} from '../utils'\n\nexport interface GenerateOpenApiOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\ninterface ApiRouteInfo {\n path: string\n methods: HttpMethod[]\n openApiPath: string\n}\n\ninterface OpenApiInputManifest {\n version: 1\n inputPaths: string[]\n}\n\ninterface OpenApiInputContext {\n enabled: ModuleEntry[]\n apiRoots: string[]\n moduleIdentity: Array<{\n id: string\n from: string\n appBase: string\n pkgBase: string\n }>\n}\n\ninterface OpenApiBundleResult {\n doc: Record<string, any> | null\n inputPaths: string[]\n}\n\nconst OPENAPI_INPUT_MANIFEST_VERSION = 1\n\nfunction createOpenApiInputContext(resolver: PackageResolver): OpenApiInputContext {\n const enabled = resolver.loadEnabledModules()\n const apiRoots: string[] = []\n const moduleIdentity = enabled.map((entry) => {\n const roots = resolver.getModulePaths(entry)\n apiRoots.push(path.join(roots.appBase, 'api'), path.join(roots.pkgBase, 'api'))\n return {\n id: entry.id,\n from: entry.from ?? '@open-mercato/core',\n appBase: path.resolve(roots.appBase),\n pkgBase: path.resolve(roots.pkgBase),\n }\n })\n return { enabled, apiRoots, moduleIdentity }\n}\n\nfunction readOpenApiInputManifest(filePath: string): OpenApiInputManifest | null {\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as Partial<OpenApiInputManifest>\n if (\n parsed.version !== OPENAPI_INPUT_MANIFEST_VERSION\n || !Array.isArray(parsed.inputPaths)\n || parsed.inputPaths.some((entry) => typeof entry !== 'string')\n ) {\n return null\n }\n return {\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n inputPaths: Array.from(new Set(parsed.inputPaths.map((entry) => path.resolve(entry))))\n .sort((a, b) => a.localeCompare(b)),\n }\n } catch {\n return null\n }\n}\n\nfunction trackedPathRecord(filePath: string): string {\n try {\n const stat = fs.statSync(filePath)\n if (stat.isFile()) {\n return `${path.resolve(filePath)}:${calculateChecksum(fs.readFileSync(filePath, 'utf8'))}`\n }\n return `${path.resolve(filePath)}:${stat.size}:${stat.mtimeMs}`\n } catch {\n return `missing:${path.resolve(filePath)}`\n }\n}\n\nfunction calculateOpenApiInputFingerprint(\n resolver: PackageResolver,\n context: OpenApiInputContext,\n manifest: OpenApiInputManifest,\n): string {\n const rootDir = resolver.getRootDir()\n const appDir = resolver.getAppDir()\n const configPaths = [\n resolver.getModulesConfigPath(),\n path.join(rootDir, 'package.json'),\n path.join(rootDir, 'yarn.lock'),\n path.join(rootDir, 'package-lock.json'),\n path.join(rootDir, 'pnpm-lock.yaml'),\n path.join(rootDir, 'tsconfig.json'),\n path.join(rootDir, 'tsconfig.base.json'),\n path.join(appDir, 'package.json'),\n path.join(appDir, 'tsconfig.json'),\n ]\n const trackedRecords = [...manifest.inputPaths, ...configPaths]\n .map(trackedPathRecord)\n .sort((a, b) => a.localeCompare(b))\n return calculateChecksum(JSON.stringify({\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n modules: context.moduleIdentity,\n routeStructure: calculateStructureChecksum(context.apiRoots),\n trackedRecords,\n environment: {\n node: process.version,\n nodeEnv: process.env.NODE_ENV ?? '',\n publicAppUrl: process.env.NEXT_PUBLIC_APP_URL ?? '',\n },\n }))\n}\n\nfunction resolveExistingPath(paths: string[]): string | null {\n for (const candidate of paths) {\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n\n/**\n * Find all API route files and extract their OpenAPI specs.\n */\nasync function findApiRoutes(\n resolver: PackageResolver,\n enabled: ModuleEntry[],\n): Promise<ApiRouteInfo[]> {\n const routes: ApiRouteInfo[] = []\n\n for (const entry of enabled) {\n const modId = entry.id\n const roots = resolver.getModulePaths(entry)\n\n const apiApp = path.join(roots.appBase, 'api')\n const apiPkg = path.join(roots.pkgBase, 'api')\n\n // Scan route files\n const routeFiles: Array<{ relativePath: string; fullPath: string }> = []\n\n const walkDir = (dir: string, rel: string[] = []) => {\n if (!fs.existsSync(dir)) return\n for (const e of fs.readdirSync(dir, { withFileTypes: true })) {\n if (e.isDirectory()) {\n if (e.name === '__tests__' || e.name === '__mocks__') continue\n walkDir(path.join(dir, e.name), [...rel, e.name])\n } else if (e.isFile() && isModuleRouteFile(e.name)) {\n routeFiles.push({\n relativePath: [...rel].join('/'),\n fullPath: path.join(dir, e.name),\n })\n }\n }\n }\n\n // Scan package first, then app (app overrides)\n if (fs.existsSync(apiPkg)) walkDir(apiPkg)\n if (fs.existsSync(apiApp)) walkDir(apiApp)\n\n // Process unique routes (later app files overwrite earlier package files)\n const filesByRelativePath = new Map<string, string>()\n for (const { relativePath, fullPath } of routeFiles) {\n filesByRelativePath.set(relativePath, fullPath)\n }\n\n for (const [relativePath, fullPath] of filesByRelativePath) {\n\n // Build API path\n const routeSegs = relativePath ? relativePath.split('/') : []\n const apiPath = `/api/${modId}${routeSegs.length ? '/' + routeSegs.join('/') : ''}`\n // Convert [param] to {param} for OpenAPI format\n .replace(/\\[([^\\]]+)\\]/g, '{$1}')\n\n routes.push({\n path: fullPath,\n methods: await detectMethods(fullPath),\n openApiPath: apiPath,\n })\n }\n }\n\n return routes\n}\n\n/**\n * Detect which HTTP methods are exported from a route file.\n */\nasync function detectMethods(filePath: string): Promise<HttpMethod[]> {\n const methods: HttpMethod[] = []\n const content = fs.readFileSync(filePath, 'utf-8')\n\n const methodPatterns: HttpMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n for (const method of methodPatterns) {\n // Check for export { GET }, export const GET, export async function GET\n const patterns = [\n new RegExp(`export\\\\s+(const|async\\\\s+function|function)\\\\s+${method}\\\\b`),\n new RegExp(`export\\\\s*\\\\{[^}]*\\\\b${method}\\\\b[^}]*\\\\}`),\n ]\n if (patterns.some((p) => p.test(content))) {\n methods.push(method)\n }\n }\n\n return methods\n}\n\n/**\n * Parse openApi export from route file source code statically.\n * This extracts basic operation info without needing to compile the file.\n */\nfunction parseOpenApiFromSource(filePath: string): Record<string, any> | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8')\n\n // Check if file exports openApi\n if (!content.includes('export const openApi') && !content.includes('export { openApi')) {\n return null\n }\n\n // Extract operationId, summary, description from the source\n const result: Record<string, any> = {}\n const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n\n for (const method of methods) {\n // Look for method specs in the openApi object\n // Pattern: GET: { operationId: '...', summary: '...', ... }\n const methodPattern = new RegExp(\n `${method}\\\\s*:\\\\s*\\\\{([^}]+(?:\\\\{[^}]*\\\\}[^}]*)*)\\\\}`,\n 's'\n )\n const methodMatch = content.match(methodPattern)\n\n if (methodMatch) {\n const methodContent = methodMatch[1]\n const spec: Record<string, any> = {}\n\n // Extract operationId\n const opIdMatch = methodContent.match(/operationId\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (opIdMatch) spec.operationId = opIdMatch[1]\n\n // Extract summary\n const summaryMatch = methodContent.match(/summary\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (summaryMatch) spec.summary = summaryMatch[1]\n\n // Extract description\n const descMatch = methodContent.match(/description\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descMatch) spec.description = descMatch[1]\n\n // Extract tags\n const tagsMatch = methodContent.match(/tags\\s*:\\s*\\[([^\\]]*)\\]/)\n if (tagsMatch) {\n const tagsContent = tagsMatch[1]\n const tags = tagsContent.match(/['\"]([^'\"]+)['\"]/g)\n if (tags) {\n spec.tags = tags.map(t => t.replace(/['\"]/g, ''))\n }\n }\n\n if (Object.keys(spec).length > 0) {\n result[method] = spec\n }\n }\n }\n\n return Object.keys(result).length > 0 ? result : null\n } catch {\n return null\n }\n}\n\n/**\n * Generate a complete OpenAPI document by bundling route files with esbuild\n * and executing the bundle to call buildOpenApiDocument from @open-mercato/shared.\n *\n * esbuild compiles TypeScript with legacy decorator support (reads experimentalDecorators\n * from tsconfig.json), avoiding the TC39 decorator mismatch that breaks tsx-based imports.\n * External packages (zod, mikro-orm, etc.) are resolved from node_modules at runtime.\n */\nasync function generateOpenApiViaBundle(\n routes: ApiRouteInfo[],\n resolver: PackageResolver,\n quiet: boolean\n): Promise<OpenApiBundleResult> {\n let esbuild: typeof import('esbuild')\n try {\n esbuild = await import('esbuild')\n } catch {\n if (!quiet) console.log('[OpenAPI] esbuild not available, skipping bundle approach')\n return { doc: null, inputPaths: [] }\n }\n\n const { execFileSync } = await import('node:child_process')\n\n const rootDir = resolver.getRootDir()\n const appDir = resolver.getAppDir()\n const sharedPackageRoot = resolver.getPackageRoot('@open-mercato/shared')\n const corePackageRoot = resolver.getPackageRoot('@open-mercato/core')\n const tsconfigPath = resolveExistingPath([\n path.join(appDir, 'tsconfig.json'),\n path.join(rootDir, 'tsconfig.base.json'),\n path.join(rootDir, 'tsconfig.json'),\n ])\n const generatorPath = path.join(sharedPackageRoot, 'src', 'lib', 'openapi', 'generator.ts')\n const coreGeneratedRoot = path.join(corePackageRoot, 'generated')\n\n if (!fs.existsSync(generatorPath)) {\n if (!quiet) {\n console.log(`[OpenAPI] Generator source not found at ${generatorPath}, skipping bundle approach`)\n }\n return { doc: null, inputPaths: [] }\n }\n\n const cacheDir = path.join(rootDir, 'node_modules', '.cache')\n if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true })\n\n const bundlePath = path.join(cacheDir, '_openapi-bundle.mjs')\n let inputPaths: string[] = []\n\n // Build the entry script that imports all routes and calls buildOpenApiDocument\n const importLines: string[] = [\n `import { buildOpenApiDocument } from ${JSON.stringify(generatorPath)};`,\n ]\n const routeMapLines: string[] = []\n\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i]\n importLines.push(`import * as R${i} from ${JSON.stringify(route.path)};`)\n // Use [param] format so normalizePath in buildOpenApiDocument extracts path params\n const bracketPath = route.openApiPath.replace(/\\{([^}]+)\\}/g, '[$1]')\n routeMapLines.push(` [${JSON.stringify(bracketPath)}, R${i}],`)\n }\n\n const entryScript = `${importLines.join('\\n')}\n\nconst routeEntries = [\n${routeMapLines.join('\\n')}\n];\n\nconst modules = new Map();\nfor (const [apiPath, mod] of routeEntries) {\n const moduleId = apiPath.replace(/^\\\\/api\\\\//, '').split('/')[0];\n if (!modules.has(moduleId)) modules.set(moduleId, { id: moduleId, apis: [] });\n modules.get(moduleId).apis.push({\n path: apiPath,\n handlers: mod,\n metadata: mod.metadata,\n });\n}\n\nconst doc = buildOpenApiDocument([...modules.values()], {\n title: 'Open Mercato API',\n version: '1.0.0',\n description: 'Auto-generated OpenAPI specification',\n servers: [{ url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' }],\n});\n\n// Deep-clone to break shared object references before serializing.\n// The zodToJsonSchema memo cache returns the same object instance for\n// fields like currencyCode that appear on both parent and child schemas.\n// A naive WeakSet-based circular-ref guard would drop the second occurrence,\n// causing properties to vanish from the generated spec (while the field\n// still appears in the 'required' array, since those are plain strings).\nconst deepClone = (v, ancestors = []) => {\n if (v === null || typeof v !== 'object') return v;\n if (typeof v === 'bigint') return Number(v);\n if (typeof v === 'function') return undefined;\n if (ancestors.includes(v)) return undefined; // true circular ref\n const next = [...ancestors, v];\n if (Array.isArray(v)) return v.map((item) => deepClone(item, next));\n const out = {};\n for (const [k, val] of Object.entries(v)) {\n const cloned = deepClone(val, next);\n if (cloned !== undefined) out[k] = cloned;\n }\n return out;\n};\nprocess.stdout.write(JSON.stringify(deepClone(doc), (_, v) =>\n typeof v === 'bigint' ? Number(v) : v\n));\n`\n\n // Plugin: stub next/* imports (not available outside Next.js app context)\n const stubNextPlugin = {\n name: 'stub-next',\n setup(build: any) {\n build.onResolve({ filter: /^next($|\\/)/ }, () => ({\n path: 'next-stub',\n namespace: 'next-stub',\n }))\n build.onLoad({ filter: /.*/, namespace: 'next-stub' }, () => ({\n contents: [\n 'const p = new Proxy(function(){}, {',\n ' get(_, k) { return k === \"__esModule\" ? true : k === \"default\" ? p : p; },',\n ' apply() { return p; },',\n ' construct() { return p; },',\n '});',\n 'export default p;',\n 'export const NextRequest = p, NextResponse = p, headers = p, cookies = p;',\n 'export const redirect = p, notFound = p, useRouter = p, usePathname = p;',\n 'export const useSearchParams = p, permanentRedirect = p, revalidatePath = p;',\n ].join('\\n'),\n loader: 'js' as const,\n }))\n },\n }\n\n // Plugin: resolve workspace imports, aliases, and subpath imports\n const resolveProjectImportsPlugin = {\n name: 'resolve-project-imports',\n setup(build: any) {\n // @open-mercato/<pkg>/<path> \u2192 packageRoot/src/<path>.ts\n build.onResolve({ filter: /^@open-mercato\\// }, (args: any) => {\n const withoutScope = args.path.slice('@open-mercato/'.length)\n const slashIdx = withoutScope.indexOf('/')\n const pkg = slashIdx === -1 ? withoutScope : withoutScope.slice(0, slashIdx)\n const rest = slashIdx === -1 ? '' : withoutScope.slice(slashIdx + 1)\n const packageName = `@open-mercato/${pkg}`\n const packageRoot = resolver.getPackageRoot(packageName)\n\n const base = rest\n ? path.join(packageRoot, 'src', rest)\n : path.join(packageRoot, 'src', 'index')\n\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // @/.mercato/* \u2192 app/.mercato/* (tsconfig paths)\n build.onResolve({ filter: /^@\\/\\.mercato\\// }, (args: any) => {\n const rest = args.path.slice('@/'.length) // '.mercato/generated/...'\n const base = path.join(appDir, rest)\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx', '']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // @/* \u2192 app/src/* (tsconfig paths)\n build.onResolve({ filter: /^@\\// }, (args: any) => {\n const rest = args.path.slice('@/'.length)\n const base = path.join(appDir, 'src', rest)\n for (const ext of ['.ts', '.tsx', '/index.ts', '/index.tsx']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n\n // #generated/* \u2192 core package generated/* (Node subpath imports)\n build.onResolve({ filter: /^#generated\\// }, (args: any) => {\n const rest = args.path.slice('#generated/'.length)\n const base = path.join(coreGeneratedRoot, rest)\n for (const ext of ['.ts', '/index.ts']) {\n if (fs.existsSync(base + ext)) return { path: base + ext }\n }\n return undefined\n })\n },\n }\n\n // Plugin: externalize installed packages, stub missing ones\n const nodeBuiltins = new Set([\n 'assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',\n 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2',\n 'https', 'module', 'net', 'os', 'path', 'perf_hooks', 'process',\n 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder',\n 'sys', 'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'wasi',\n 'worker_threads', 'zlib', 'async_hooks', 'diagnostics_channel', 'inspector',\n 'trace_events',\n ])\n const externalNonWorkspacePlugin = {\n name: 'external-non-workspace',\n setup(build: any) {\n build.onResolve({ filter: /^[^./]/ }, (args: any) => {\n if (path.isAbsolute(args.path)) return undefined\n if (args.path.startsWith('@open-mercato/')) return undefined\n if (args.path.startsWith('@/')) return undefined\n if (args.path.startsWith('#generated/')) return undefined\n if (args.path.startsWith('next')) return undefined\n // Let esbuild handle Node builtins (with or without node: prefix)\n if (args.path.startsWith('node:')) return undefined\n const topLevel = args.path.split('/')[0]\n if (nodeBuiltins.has(topLevel)) return undefined\n\n // Extract package name (handle scoped packages like @mikro-orm/core)\n const pkgName = args.path.startsWith('@')\n ? args.path.split('/').slice(0, 2).join('/')\n : topLevel\n const pkgDir = path.join(rootDir, 'node_modules', pkgName)\n if (fs.existsSync(pkgDir)) return { external: true }\n\n // Package not installed \u2014 provide CJS stub (allows any named import)\n return { path: args.path, namespace: 'missing-pkg' }\n })\n build.onLoad({ filter: /.*/, namespace: 'missing-pkg' }, () => ({\n contents: 'var h={get:(_,k)=>k===\"__esModule\"?true:p};var p=new Proxy(function(){return p},{get:h.get,apply:()=>p,construct:()=>p});module.exports=p;',\n loader: 'js' as const,\n }))\n },\n }\n\n try {\n const buildResult = await esbuild.build({\n stdin: {\n contents: entryScript,\n resolveDir: appDir,\n sourcefile: 'openapi-entry.ts',\n loader: 'ts',\n },\n bundle: true,\n metafile: true,\n absWorkingDir: rootDir,\n format: 'esm',\n platform: 'node',\n target: 'node18',\n outfile: bundlePath,\n write: true,\n ...(tsconfigPath ? { tsconfig: tsconfigPath } : {}),\n logLevel: 'silent',\n jsx: 'automatic',\n plugins: [stubNextPlugin, resolveProjectImportsPlugin, externalNonWorkspacePlugin],\n })\n\n inputPaths = Object.keys(buildResult.metafile?.inputs ?? {})\n .filter((inputPath) => !inputPath.startsWith('<'))\n .map((inputPath) => path.resolve(rootDir, inputPath))\n .filter((inputPath) => fs.existsSync(inputPath))\n .sort((a, b) => a.localeCompare(b))\n\n const stdout = execFileSync(process.execPath, [bundlePath], {\n timeout: 60_000,\n maxBuffer: 20 * 1024 * 1024,\n encoding: 'utf-8',\n env: { ...process.env, NODE_NO_WARNINGS: '1' },\n cwd: rootDir,\n })\n\n const lastLine = stdout.trim().split('\\n').pop()!\n const doc = JSON.parse(lastLine) as Record<string, any>\n\n if (!quiet) {\n const pathCount = Object.keys(doc.paths || {}).length\n const withBody = Object.values(doc.paths || {}).reduce((n: number, methods: any) => {\n for (const m of Object.values(methods)) {\n if ((m as any)?.requestBody) n++\n }\n return n\n }, 0)\n console.log(`[OpenAPI] Bundle approach: ${pathCount} paths, ${withBody} with requestBody schemas`)\n }\n\n return { doc, inputPaths }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err)\n const stderr = (err as any)?.stderr\n const esbuildErrors = (err as any)?.errors as Array<{ text: string; location?: { file: string } }> | undefined\n if (!quiet) {\n console.log(`[OpenAPI] Bundle approach failed, will use static fallback: ${errMsg.split('\\n')[0]}`)\n if (esbuildErrors?.length) {\n const unique = new Map<string, string>()\n for (const e of esbuildErrors) {\n const key = e.text\n if (!unique.has(key)) unique.set(key, e.location?.file ?? '')\n }\n for (const [text, file] of [...unique.entries()].slice(0, 10)) {\n console.log(`[OpenAPI] ${text}${file ? ` (${path.basename(file)})` : ''}`)\n }\n if (unique.size > 10) console.log(`[OpenAPI] ... and ${unique.size - 10} more`)\n }\n if (stderr) {\n for (const line of String(stderr).trim().split('\\n').slice(0, 3)) {\n console.log(`[OpenAPI] ${line}`)\n }\n }\n }\n return { doc: null, inputPaths }\n } finally {\n // Shut down esbuild's persistent Go service so it does not deadlock at\n // process exit when a plugin request is still in flight.\n try { await esbuild.stop() } catch {}\n // Clean up old files from previous tsx-based approach\n for (const file of ['_openapi-register.mjs', '_openapi-loader.mjs', '_next-stub.cjs']) {\n try { fs.unlinkSync(path.join(cacheDir, file)) } catch {}\n }\n }\n}\n\n/**\n * Build OpenAPI paths from discovered routes.\n * Extracts basic operation info from route files statically.\n */\nfunction buildOpenApiPaths(routes: ApiRouteInfo[]): Record<string, any> {\n const paths: Record<string, any> = {}\n\n for (const route of routes) {\n const pathEntry: Record<string, any> = {}\n\n // Try to extract OpenAPI specs from source\n const openApiSpec = parseOpenApiFromSource(route.path)\n\n for (const method of route.methods) {\n const methodLower = method.toLowerCase()\n const spec = openApiSpec?.[method]\n\n // Generate a default operationId if not found\n const pathSegments = route.openApiPath\n .replace(/^\\/api\\//, '')\n .replace(/\\{[^}]+\\}/g, 'by_id')\n .split('/')\n .filter(Boolean)\n .join('_')\n const defaultOperationId = `${methodLower}_${pathSegments}`\n\n pathEntry[methodLower] = {\n operationId: spec?.operationId || defaultOperationId,\n summary: spec?.summary || `${method} ${route.openApiPath}`,\n description: spec?.description || `${method} operation for ${route.openApiPath}`,\n tags: spec?.tags || [route.openApiPath.split('/')[2] || 'api'],\n responses: {\n '200': {\n description: 'Successful response',\n },\n },\n }\n }\n\n if (Object.keys(pathEntry).length > 0) {\n paths[route.openApiPath] = pathEntry\n }\n }\n\n return paths\n}\n\n/**\n * Generate the OpenAPI JSON file.\n */\nexport async function generateOpenApi(options: GenerateOpenApiOptions): Promise<GeneratorResult> {\n const { resolver, quiet = false } = options\n const result = createGeneratorResult()\n\n const outputDir = resolver.getOutputDir()\n const outFile = path.join(outputDir, 'openapi.generated.json')\n const checksumFile = path.join(outputDir, 'openapi.generated.checksum')\n const inputManifestFile = path.join(outputDir, 'openapi.generated.inputs.json')\n\n getEnabledModuleIdentities(resolver, resolver.loadEnabledModules())\n\n // Ensure output directory exists\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n const inputContext = createOpenApiInputContext(resolver)\n const existingChecksums = readChecksumRecord(checksumFile)\n const existingManifest = readOpenApiInputManifest(inputManifestFile)\n\n if (\n existingChecksums?.structure\n && existingManifest\n && fs.existsSync(outFile)\n && calculateChecksum(fs.readFileSync(outFile, 'utf8')) === existingChecksums.content\n && calculateOpenApiInputFingerprint(resolver, inputContext, existingManifest) === existingChecksums.structure\n ) {\n result.filesUnchanged.push(outFile)\n if (!quiet) {\n console.log(`[OpenAPI] Skipped (inputs unchanged): ${outFile}`)\n }\n return result\n }\n\n // Find all API routes\n const routes = await findApiRoutes(resolver, inputContext.enabled)\n\n if (!quiet) {\n console.log(`[OpenAPI] Found ${routes.length} API route files`)\n }\n\n // Determine project root (cli package is at packages/cli/src/lib/generators/)\n // Try esbuild bundle approach first \u2014 produces full requestBody/response schemas\n const bundleResult = await generateOpenApiViaBundle(routes, resolver, quiet)\n let doc: Record<string, any> | null = bundleResult.doc\n\n // Fallback to static regex approach (extracts operationId/summary/tags but no schemas)\n if (!doc) {\n if (!quiet) {\n console.warn(\n '[OpenAPI] \u26A0 Bundling failed; falling back to static regex extraction \u2014 '\n + 'request/response schemas are OMITTED from the generated document. '\n + 'The usual cause is a route file importing a module specifier that does not resolve.',\n )\n }\n const paths = buildOpenApiPaths(routes)\n doc = {\n openapi: '3.1.0',\n info: {\n title: 'Open Mercato API',\n version: '1.0.0',\n description: 'Auto-generated OpenAPI specification',\n },\n servers: [\n { url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' },\n ],\n paths,\n components: {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: 'Send an `Authorization: Bearer <token>` header with a valid API token.',\n },\n },\n },\n }\n }\n\n const output = JSON.stringify(doc, null, 2)\n const checksum = calculateChecksum(output)\n let structureChecksum = ''\n\n if (bundleResult.doc && bundleResult.inputPaths.length > 0) {\n const manifest: OpenApiInputManifest = {\n version: OPENAPI_INPUT_MANIFEST_VERSION,\n inputPaths: Array.from(new Set(bundleResult.inputPaths)).sort((a, b) => a.localeCompare(b)),\n }\n fs.writeFileSync(inputManifestFile, `${JSON.stringify(manifest, null, 2)}\\n`)\n structureChecksum = calculateOpenApiInputFingerprint(resolver, inputContext, manifest)\n } else {\n try { fs.unlinkSync(inputManifestFile) } catch {}\n }\n\n // Check if unchanged\n const existingOutputMatches = fs.existsSync(outFile)\n && calculateChecksum(fs.readFileSync(outFile, 'utf8')) === checksum\n if (existingChecksums && existingChecksums.content === checksum && existingOutputMatches) {\n if (existingChecksums.structure !== structureChecksum) {\n writeChecksumRecord(checksumFile, { content: checksum, structure: structureChecksum })\n }\n result.filesUnchanged.push(outFile)\n if (!quiet) {\n console.log(`[OpenAPI] Skipped (unchanged): ${outFile}`)\n }\n return result\n }\n\n // Write the file\n fs.writeFileSync(outFile, output)\n writeChecksumRecord(checksumFile, { content: checksum, structure: structureChecksum })\n\n result.filesWritten.push(outFile)\n\n if (!quiet) {\n logGenerationResult(outFile, true)\n const pathCount = Object.keys(doc.paths || {}).length\n console.log(`[OpenAPI] Generated ${pathCount} API paths`)\n }\n\n return result\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import ts from "typescript-js";
|
|
2
|
+
function sourceHasDefaultExport(sourceFile, source) {
|
|
3
|
+
const parsed = ts.createSourceFile(
|
|
4
|
+
sourceFile,
|
|
5
|
+
source,
|
|
6
|
+
ts.ScriptTarget.Latest,
|
|
7
|
+
true,
|
|
8
|
+
sourceFile.endsWith(".tsx") ? ts.ScriptKind.TSX : sourceFile.endsWith(".jsx") ? ts.ScriptKind.JSX : sourceFile.endsWith(".js") ? ts.ScriptKind.JS : ts.ScriptKind.TS
|
|
9
|
+
);
|
|
10
|
+
for (const statement of parsed.statements) {
|
|
11
|
+
if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause) && statement.exportClause.elements.some(
|
|
15
|
+
(element) => element.name.text === "default" || element.propertyName?.text === "default"
|
|
16
|
+
)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
const modifiers = ts.canHaveModifiers(statement) ? ts.getModifiers(statement) : void 0;
|
|
20
|
+
if (modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword)) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
function sourceExportedHttpMethods(source) {
|
|
27
|
+
const knownMethods = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
28
|
+
const exportedMethods = /* @__PURE__ */ new Set();
|
|
29
|
+
const collectKnownMethods = (rawSpecifiers, opts) => {
|
|
30
|
+
for (const specifier of rawSpecifiers) {
|
|
31
|
+
const trimmed = specifier.trim();
|
|
32
|
+
if (!trimmed) continue;
|
|
33
|
+
let candidate = trimmed;
|
|
34
|
+
if (opts?.useExportedAlias) {
|
|
35
|
+
candidate = trimmed.split(/\s+as\s+/i).pop()?.trim() ?? trimmed;
|
|
36
|
+
}
|
|
37
|
+
if (opts?.useDestructuredProperty) {
|
|
38
|
+
candidate = trimmed.split(":")[0]?.trim() ?? trimmed;
|
|
39
|
+
}
|
|
40
|
+
if (knownMethods.includes(candidate)) {
|
|
41
|
+
exportedMethods.add(candidate);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
for (const method of knownMethods) {
|
|
46
|
+
const pattern = new RegExp(`export\\s+(?:async\\s+)?function\\s+${method}\\b|export\\s+(?:const|let|var)\\s+${method}\\b`);
|
|
47
|
+
if (pattern.test(source)) {
|
|
48
|
+
exportedMethods.add(method);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const reExportPattern = /export\s*{([^}]+)}/g;
|
|
52
|
+
for (const match of source.matchAll(reExportPattern)) {
|
|
53
|
+
const exportBlock = match[1] ?? "";
|
|
54
|
+
collectKnownMethods(
|
|
55
|
+
exportBlock.split(",").map((part) => part.trim()).filter((part) => part.length > 0),
|
|
56
|
+
{ useExportedAlias: true }
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const destructuredExportPattern = /export\s+(?:const|let|var)\s*{([^}]+)}/g;
|
|
60
|
+
for (const match of source.matchAll(destructuredExportPattern)) {
|
|
61
|
+
const exportBlock = match[1] ?? "";
|
|
62
|
+
collectKnownMethods(
|
|
63
|
+
exportBlock.split(",").map((part) => part.trim()).filter((part) => part.length > 0),
|
|
64
|
+
{ useDestructuredProperty: true }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return knownMethods.filter((method) => exportedMethods.has(method));
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
sourceExportedHttpMethods,
|
|
71
|
+
sourceHasDefaultExport
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=source-exports.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/generators/source-exports.ts"],
|
|
4
|
+
"sourcesContent": ["import ts from 'typescript-js'\n\nexport function sourceHasDefaultExport(sourceFile: string, source: string): boolean {\n const parsed = ts.createSourceFile(\n sourceFile,\n source,\n ts.ScriptTarget.Latest,\n true,\n sourceFile.endsWith('.tsx') ? ts.ScriptKind.TSX : sourceFile.endsWith('.jsx') ? ts.ScriptKind.JSX : sourceFile.endsWith('.js') ? ts.ScriptKind.JS : ts.ScriptKind.TS,\n )\n\n for (const statement of parsed.statements) {\n if (ts.isExportAssignment(statement) && !statement.isExportEquals) {\n return true\n }\n\n if (\n ts.isExportDeclaration(statement)\n && statement.exportClause\n && ts.isNamedExports(statement.exportClause)\n && statement.exportClause.elements.some(\n (element) => element.name.text === 'default' || element.propertyName?.text === 'default',\n )\n ) {\n return true\n }\n\n const modifiers = ts.canHaveModifiers(statement) ? ts.getModifiers(statement) : undefined\n if (modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword)) {\n return true\n }\n }\n\n return false\n}\n\ntype SourceHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\nexport function sourceExportedHttpMethods(source: string): SourceHttpMethod[] {\n const knownMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] as SourceHttpMethod[]\n const exportedMethods = new Set<SourceHttpMethod>()\n const collectKnownMethods = (rawSpecifiers: string[], opts?: { useExportedAlias?: boolean; useDestructuredProperty?: boolean }) => {\n for (const specifier of rawSpecifiers) {\n const trimmed = specifier.trim()\n if (!trimmed) continue\n\n let candidate = trimmed\n if (opts?.useExportedAlias) {\n candidate = trimmed.split(/\\s+as\\s+/i).pop()?.trim() ?? trimmed\n }\n if (opts?.useDestructuredProperty) {\n candidate = trimmed.split(':')[0]?.trim() ?? trimmed\n }\n\n if (knownMethods.includes(candidate as SourceHttpMethod)) {\n exportedMethods.add(candidate as SourceHttpMethod)\n }\n }\n }\n\n for (const method of knownMethods) {\n const pattern = new RegExp(`export\\\\s+(?:async\\\\s+)?function\\\\s+${method}\\\\b|export\\\\s+(?:const|let|var)\\\\s+${method}\\\\b`)\n if (pattern.test(source)) {\n exportedMethods.add(method)\n }\n }\n\n const reExportPattern = /export\\s*{([^}]+)}/g\n for (const match of source.matchAll(reExportPattern)) {\n const exportBlock = match[1] ?? ''\n collectKnownMethods(\n exportBlock\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part.length > 0),\n { useExportedAlias: true },\n )\n }\n\n const destructuredExportPattern = /export\\s+(?:const|let|var)\\s*{([^}]+)}/g\n for (const match of source.matchAll(destructuredExportPattern)) {\n const exportBlock = match[1] ?? ''\n collectKnownMethods(\n exportBlock\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part.length > 0),\n { useDestructuredProperty: true },\n )\n }\n\n return knownMethods.filter((method) => exportedMethods.has(method))\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,QAAQ;AAER,SAAS,uBAAuB,YAAoB,QAAyB;AAClF,QAAM,SAAS,GAAG;AAAA,IAChB;AAAA,IACA;AAAA,IACA,GAAG,aAAa;AAAA,IAChB;AAAA,IACA,WAAW,SAAS,MAAM,IAAI,GAAG,WAAW,MAAM,WAAW,SAAS,MAAM,IAAI,GAAG,WAAW,MAAM,WAAW,SAAS,KAAK,IAAI,GAAG,WAAW,KAAK,GAAG,WAAW;AAAA,EACpK;AAEA,aAAW,aAAa,OAAO,YAAY;AACzC,QAAI,GAAG,mBAAmB,SAAS,KAAK,CAAC,UAAU,gBAAgB;AACjE,aAAO;AAAA,IACT;AAEA,QACE,GAAG,oBAAoB,SAAS,KAC7B,UAAU,gBACV,GAAG,eAAe,UAAU,YAAY,KACxC,UAAU,aAAa,SAAS;AAAA,MACjC,CAAC,YAAY,QAAQ,KAAK,SAAS,aAAa,QAAQ,cAAc,SAAS;AAAA,IACjF,GACA;AACA,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,GAAG,iBAAiB,SAAS,IAAI,GAAG,aAAa,SAAS,IAAI;AAChF,QAAI,WAAW,KAAK,CAAC,aAAa,SAAS,SAAS,GAAG,WAAW,cAAc,GAAG;AACjF,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAIO,SAAS,0BAA0B,QAAoC;AAC5E,QAAM,eAAe,CAAC,OAAO,QAAQ,OAAO,SAAS,QAAQ;AAC7D,QAAM,kBAAkB,oBAAI,IAAsB;AAClD,QAAM,sBAAsB,CAAC,eAAyB,SAA6E;AACjI,eAAW,aAAa,eAAe;AACrC,YAAM,UAAU,UAAU,KAAK;AAC/B,UAAI,CAAC,QAAS;AAEd,UAAI,YAAY;AAChB,UAAI,MAAM,kBAAkB;AAC1B,oBAAY,QAAQ,MAAM,WAAW,EAAE,IAAI,GAAG,KAAK,KAAK;AAAA,MAC1D;AACA,UAAI,MAAM,yBAAyB;AACjC,oBAAY,QAAQ,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,KAAK;AAAA,MAC/C;AAEA,UAAI,aAAa,SAAS,SAA6B,GAAG;AACxD,wBAAgB,IAAI,SAA6B;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAEA,aAAW,UAAU,cAAc;AACjC,UAAM,UAAU,IAAI,OAAO,uCAAuC,MAAM,sCAAsC,MAAM,KAAK;AACzH,QAAI,QAAQ,KAAK,MAAM,GAAG;AACxB,sBAAgB,IAAI,MAAM;AAAA,IAC5B;AAAA,EACF;AAEA,QAAM,kBAAkB;AACxB,aAAW,SAAS,OAAO,SAAS,eAAe,GAAG;AACpD,UAAM,cAAc,MAAM,CAAC,KAAK;AAChC;AAAA,MACE,YACC,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AAAA,MACjC,EAAE,kBAAkB,KAAK;AAAA,IAC3B;AAAA,EACF;AAEA,QAAM,4BAA4B;AAClC,aAAW,SAAS,OAAO,SAAS,yBAAyB,GAAG;AAC9D,UAAM,cAAc,MAAM,CAAC,KAAK;AAChC;AAAA,MACE,YACG,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AAAA,MACnC,EAAE,yBAAyB,KAAK;AAAA,IAClC;AAAA,EACF;AAEA,SAAO,aAAa,OAAO,CAAC,WAAW,gBAAgB,IAAI,MAAM,CAAC;AACpE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/lib/init-secrets.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
|
|
2
|
+
import { getPasswordPolicy, validatePassword } from "@open-mercato/shared/lib/auth/passwordPolicy";
|
|
2
3
|
import { randomBytes } from "node:crypto";
|
|
4
|
+
import { createTranslator } from "@open-mercato/shared/lib/i18n/translate";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
const requireLocale = createRequire(import.meta.url);
|
|
7
|
+
function initTranslator(env) {
|
|
8
|
+
const locale = (env.LC_ALL || env.LC_MESSAGES || env.LANG || "en").split(/[_.-]/)[0].toLowerCase();
|
|
9
|
+
const supportedLocale = ["en", "pl", "es", "de", "ko"].includes(locale) ? locale : "en";
|
|
10
|
+
const dictionary = requireLocale(`../i18n/${supportedLocale}.json`);
|
|
11
|
+
return createTranslator(dictionary);
|
|
12
|
+
}
|
|
3
13
|
function readEnvValue(env, key) {
|
|
4
14
|
const value = env[key];
|
|
5
15
|
if (typeof value !== "string") return void 0;
|
|
@@ -40,7 +50,29 @@ function resolveInitDerivedSecrets(options) {
|
|
|
40
50
|
employeePassword: resolvePassword("OM_INIT_EMPLOYEE_PASSWORD", employeeEmail)
|
|
41
51
|
};
|
|
42
52
|
}
|
|
53
|
+
function resolveInitSuperadminCredentials(args, env = process.env) {
|
|
54
|
+
const argValue = (name) => args.find((arg) => arg.startsWith(`${name}=`))?.slice(name.length + 1) || void 0;
|
|
55
|
+
const email = argValue("--email") ?? readEnvValue(env, "OM_INIT_SUPERADMIN_EMAIL") ?? "superadmin@acme.com";
|
|
56
|
+
const suppliedPassword = argValue("--password") ?? readEnvValue(env, "OM_INIT_SUPERADMIN_PASSWORD");
|
|
57
|
+
const isProduction = (env.NODE_ENV ?? "").trim().toLowerCase() === "production";
|
|
58
|
+
const skipPolicyArg = args.find(
|
|
59
|
+
(arg) => arg === "--skip-password-policy" || arg.startsWith("--skip-password-policy=") || arg === "--allow-weak-password" || arg.startsWith("--allow-weak-password=")
|
|
60
|
+
);
|
|
61
|
+
const skipPasswordPolicy = !isProduction && (skipPolicyArg ? parseBooleanToken(skipPolicyArg.split("=")[1] ?? "true") ?? true : true);
|
|
62
|
+
if (isProduction) {
|
|
63
|
+
const t = initTranslator(env);
|
|
64
|
+
const placeholder = suppliedPassword?.trim().toLowerCase();
|
|
65
|
+
if (!suppliedPassword || !placeholder || ["secret", "password", "changeme", "change-me", "change_me", "replace-me", "replace_me"].includes(placeholder)) {
|
|
66
|
+
throw new Error(t("cli.init.errors.superadminPasswordRequired"));
|
|
67
|
+
}
|
|
68
|
+
if (!validatePassword(suppliedPassword, getPasswordPolicy(env)).ok) {
|
|
69
|
+
throw new Error(t("cli.init.errors.superadminPasswordPolicy"));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { email, password: suppliedPassword ?? "secret", skipPasswordPolicy };
|
|
73
|
+
}
|
|
43
74
|
export {
|
|
44
|
-
resolveInitDerivedSecrets
|
|
75
|
+
resolveInitDerivedSecrets,
|
|
76
|
+
resolveInitSuperadminCredentials
|
|
45
77
|
};
|
|
46
78
|
//# sourceMappingURL=init-secrets.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/init-secrets.ts"],
|
|
4
|
-
"sourcesContent": ["import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { randomBytes } from 'node:crypto'\n\ntype EnvReader = (key: string) => string | undefined\n\nfunction readEnvValue(env: NodeJS.ProcessEnv, key: string): string | undefined {\n const value = env[key]\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction resolveEmailFromDomain(domain: string | undefined, prefix: string): string | null {\n if (!domain) return null\n return `${prefix}@${domain}`\n}\n\nexport type InitDerivedSecrets = {\n adminEmail: string | null\n employeeEmail: string | null\n adminPassword: string | null\n employeePassword: string | null\n}\n\n// Well-known dev/demo password baked into local bootstrap flows so developers\n// keep the documented \"log in as admin@<domain> with password 'secret'\" UX.\n// Only used when NODE_ENV !== 'production' and the OM_INIT_*_PASSWORD env vars\n// are unset \u2014 production paths always use a random 96-bit secret.\nconst DEMO_DERIVED_PASSWORD = 'secret'\n\nlet warnedAboutDeprecatedRandomToggle = false\n\nexport function resolveInitDerivedSecrets(options: {\n email: string\n env?: NodeJS.ProcessEnv\n randomSource?: (size: number) => Buffer\n}): InitDerivedSecrets {\n const env = options.env ?? process.env\n const envRead: EnvReader = (key) => readEnvValue(env, key)\n const [, domain] = String(options.email ?? '').split('@')\n const adminEmail = envRead('OM_INIT_ADMIN_EMAIL') ?? resolveEmailFromDomain(domain, 'admin')\n const employeeEmail = envRead('OM_INIT_EMPLOYEE_EMAIL') ?? resolveEmailFromDomain(domain, 'employee')\n // OM_INIT_GENERATE_RANDOM_PASSWORD used to be an opt-in toggle for random\n // derived secrets; in production it is now the unconditional behaviour when\n // no override is set. Surface a one-time deprecation warning so existing\n // operators notice their config is no longer required.\n if (parseBooleanToken(envRead('OM_INIT_GENERATE_RANDOM_PASSWORD') ?? '') === true && !warnedAboutDeprecatedRandomToggle) {\n warnedAboutDeprecatedRandomToggle = true\n console.warn(\n '\u26A0\uFE0F OM_INIT_GENERATE_RANDOM_PASSWORD is deprecated and no longer required: derived admin/employee passwords are always randomized in production when overrides are unset.',\n )\n }\n const isProduction = (env.NODE_ENV ?? '').trim().toLowerCase() === 'production'\n const randomize = options.randomSource ?? randomBytes\n const randomSecret = () => randomize(12).toString('base64url')\n const resolvePassword = (key: string, emailValue: string | null) => {\n if (!emailValue) return null\n const envValue = envRead(key)\n if (envValue) return envValue\n // Non-production (dev/test/staging defaults): seed the documented demo\n // password so `yarn dev` / `mercato init` workflows stay predictable.\n // Production: generate a fresh random secret so credentials are never\n // hardcoded and the operator-facing CLI prints the value once.\n return isProduction ? randomSecret() : DEMO_DERIVED_PASSWORD\n }\n\n return {\n adminEmail,\n employeeEmail,\n adminPassword: resolvePassword('OM_INIT_ADMIN_PASSWORD', adminEmail),\n employeePassword: resolvePassword('OM_INIT_EMPLOYEE_PASSWORD', employeeEmail),\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;
|
|
4
|
+
"sourcesContent": ["import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { getPasswordPolicy, validatePassword } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { randomBytes } from 'node:crypto'\nimport { createTranslator } from '@open-mercato/shared/lib/i18n/translate'\nimport { createRequire } from 'node:module'\n\nconst requireLocale = createRequire(import.meta.url)\n\nfunction initTranslator(env: NodeJS.ProcessEnv) {\n const locale = (env.LC_ALL || env.LC_MESSAGES || env.LANG || 'en').split(/[_.-]/)[0].toLowerCase()\n const supportedLocale = ['en', 'pl', 'es', 'de', 'ko'].includes(locale) ? locale : 'en'\n const dictionary: Record<string, string> = requireLocale(`../i18n/${supportedLocale}.json`)\n return createTranslator(dictionary)\n}\n\ntype EnvReader = (key: string) => string | undefined\n\nfunction readEnvValue(env: NodeJS.ProcessEnv, key: string): string | undefined {\n const value = env[key]\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction resolveEmailFromDomain(domain: string | undefined, prefix: string): string | null {\n if (!domain) return null\n return `${prefix}@${domain}`\n}\n\nexport type InitDerivedSecrets = {\n adminEmail: string | null\n employeeEmail: string | null\n adminPassword: string | null\n employeePassword: string | null\n}\n\n// Well-known dev/demo password baked into local bootstrap flows so developers\n// keep the documented \"log in as admin@<domain> with password 'secret'\" UX.\n// Only used when NODE_ENV !== 'production' and the OM_INIT_*_PASSWORD env vars\n// are unset \u2014 production paths always use a random 96-bit secret.\nconst DEMO_DERIVED_PASSWORD = 'secret'\n\nlet warnedAboutDeprecatedRandomToggle = false\n\nexport function resolveInitDerivedSecrets(options: {\n email: string\n env?: NodeJS.ProcessEnv\n randomSource?: (size: number) => Buffer\n}): InitDerivedSecrets {\n const env = options.env ?? process.env\n const envRead: EnvReader = (key) => readEnvValue(env, key)\n const [, domain] = String(options.email ?? '').split('@')\n const adminEmail = envRead('OM_INIT_ADMIN_EMAIL') ?? resolveEmailFromDomain(domain, 'admin')\n const employeeEmail = envRead('OM_INIT_EMPLOYEE_EMAIL') ?? resolveEmailFromDomain(domain, 'employee')\n // OM_INIT_GENERATE_RANDOM_PASSWORD used to be an opt-in toggle for random\n // derived secrets; in production it is now the unconditional behaviour when\n // no override is set. Surface a one-time deprecation warning so existing\n // operators notice their config is no longer required.\n if (parseBooleanToken(envRead('OM_INIT_GENERATE_RANDOM_PASSWORD') ?? '') === true && !warnedAboutDeprecatedRandomToggle) {\n warnedAboutDeprecatedRandomToggle = true\n console.warn(\n '\u26A0\uFE0F OM_INIT_GENERATE_RANDOM_PASSWORD is deprecated and no longer required: derived admin/employee passwords are always randomized in production when overrides are unset.',\n )\n }\n const isProduction = (env.NODE_ENV ?? '').trim().toLowerCase() === 'production'\n const randomize = options.randomSource ?? randomBytes\n const randomSecret = () => randomize(12).toString('base64url')\n const resolvePassword = (key: string, emailValue: string | null) => {\n if (!emailValue) return null\n const envValue = envRead(key)\n if (envValue) return envValue\n // Non-production (dev/test/staging defaults): seed the documented demo\n // password so `yarn dev` / `mercato init` workflows stay predictable.\n // Production: generate a fresh random secret so credentials are never\n // hardcoded and the operator-facing CLI prints the value once.\n return isProduction ? randomSecret() : DEMO_DERIVED_PASSWORD\n }\n\n return {\n adminEmail,\n employeeEmail,\n adminPassword: resolvePassword('OM_INIT_ADMIN_PASSWORD', adminEmail),\n employeePassword: resolvePassword('OM_INIT_EMPLOYEE_PASSWORD', employeeEmail),\n }\n}\n\nexport function resolveInitSuperadminCredentials(args: string[], env: NodeJS.ProcessEnv = process.env) {\n const argValue = (name: string) => args.find((arg) => arg.startsWith(`${name}=`))?.slice(name.length + 1) || undefined\n const email = argValue('--email') ?? readEnvValue(env, 'OM_INIT_SUPERADMIN_EMAIL') ?? 'superadmin@acme.com'\n const suppliedPassword = argValue('--password') ?? readEnvValue(env, 'OM_INIT_SUPERADMIN_PASSWORD')\n const isProduction = (env.NODE_ENV ?? '').trim().toLowerCase() === 'production'\n const skipPolicyArg = args.find((arg) =>\n arg === '--skip-password-policy' || arg.startsWith('--skip-password-policy=') ||\n arg === '--allow-weak-password' || arg.startsWith('--allow-weak-password='),\n )\n const skipPasswordPolicy = !isProduction && (skipPolicyArg\n ? parseBooleanToken(skipPolicyArg.split('=')[1] ?? 'true') ?? true\n : true)\n if (isProduction) {\n const t = initTranslator(env)\n const placeholder = suppliedPassword?.trim().toLowerCase()\n if (!suppliedPassword || !placeholder || ['secret', 'password', 'changeme', 'change-me', 'change_me', 'replace-me', 'replace_me'].includes(placeholder)) {\n throw new Error(t('cli.init.errors.superadminPasswordRequired'))\n }\n if (!validatePassword(suppliedPassword, getPasswordPolicy(env)).ok) {\n throw new Error(t('cli.init.errors.superadminPasswordPolicy'))\n }\n }\n return { email, password: suppliedPassword ?? 'secret', skipPasswordPolicy }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
|
|
2
|
+
const panelStyle = "\x1B[48;2;57;62;70m\x1B[38;2;238;238;238m";
|
|
3
|
+
const reset = "\x1B[0m";
|
|
4
|
+
function cellWidth(value) {
|
|
5
|
+
if (new RegExp("\\p{Extended_Pictographic}|\\p{Regional_Indicator}|[\\u1100-\\u115f\\u2329\\u232a\\u2e80-\\ua4cf\\uac00-\\ud7a3\\uf900-\\ufaff\\ufe10-\\ufe19\\ufe30-\\ufe6f\\uff01-\\uff60\\uffe0-\\uffe6]", "u").test(value)) return 2;
|
|
6
|
+
return new RegExp("^\\p{Mark}+$", "u").test(value) ? 0 : 1;
|
|
7
|
+
}
|
|
8
|
+
function wrapLine(line, width) {
|
|
9
|
+
const wrapped = [];
|
|
10
|
+
let current = "";
|
|
11
|
+
let currentWidth = 0;
|
|
12
|
+
for (const { segment } of segmenter.segment(line)) {
|
|
13
|
+
const segmentWidth = cellWidth(segment);
|
|
14
|
+
if (currentWidth + segmentWidth > width && current) {
|
|
15
|
+
wrapped.push(current);
|
|
16
|
+
current = "";
|
|
17
|
+
currentWidth = 0;
|
|
18
|
+
}
|
|
19
|
+
current += segment;
|
|
20
|
+
currentWidth += segmentWidth;
|
|
21
|
+
}
|
|
22
|
+
wrapped.push(current);
|
|
23
|
+
return wrapped;
|
|
24
|
+
}
|
|
25
|
+
function formatInitSummary({ users, autoStart, columns = 80, color = false }) {
|
|
26
|
+
const width = Number.isFinite(columns) && columns >= 8 ? Math.floor(columns) : 80;
|
|
27
|
+
const lines = ["", "\u{1F511} DEVELOPMENT ACCOUNTS", ""];
|
|
28
|
+
for (const user of users) {
|
|
29
|
+
lines.push(`${user.icon} ${user.label}`, ` Email: ${user.email}`, ` Password: ${user.password}`, "");
|
|
30
|
+
}
|
|
31
|
+
lines.push(...autoStart ? ["\u{1F680} The dev server will start automatically.", " Next time, run: yarn dev"] : ["\u{1F680} Start the dev server: yarn dev"]);
|
|
32
|
+
lines.push("");
|
|
33
|
+
const rule = "\u2501".repeat(width);
|
|
34
|
+
const content = lines.flatMap((line) => wrapLine(line, width - 4).map((part) => ` ${part}`));
|
|
35
|
+
return [rule, ...content, rule].map((line) => {
|
|
36
|
+
if (!color) return line;
|
|
37
|
+
const visibleWidth = [...segmenter.segment(line)].reduce((total, { segment }) => total + cellWidth(segment), 0);
|
|
38
|
+
return `${panelStyle}${line}${" ".repeat(Math.max(0, width - visibleWidth))}${reset}`;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
formatInitSummary
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=init-summary.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/init-summary.ts"],
|
|
4
|
+
"sourcesContent": ["type InitSummaryUser = { icon: string; label: string; email: string; password: string }\n\ntype InitSummaryOptions = {\n users: InitSummaryUser[]\n autoStart: boolean\n columns?: number\n color?: boolean\n}\n\nconst segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' })\nconst panelStyle = '\\u001b[48;2;57;62;70m\\u001b[38;2;238;238;238m'\nconst reset = '\\u001b[0m'\n\nfunction cellWidth(value: string): number {\n if (/\\p{Extended_Pictographic}|\\p{Regional_Indicator}|[\\u1100-\\u115f\\u2329\\u232a\\u2e80-\\ua4cf\\uac00-\\ud7a3\\uf900-\\ufaff\\ufe10-\\ufe19\\ufe30-\\ufe6f\\uff01-\\uff60\\uffe0-\\uffe6]/u.test(value)) return 2\n return /^\\p{Mark}+$/u.test(value) ? 0 : 1\n}\n\nfunction wrapLine(line: string, width: number): string[] {\n const wrapped: string[] = []\n let current = ''\n let currentWidth = 0\n for (const { segment } of segmenter.segment(line)) {\n const segmentWidth = cellWidth(segment)\n if (currentWidth + segmentWidth > width && current) {\n wrapped.push(current)\n current = ''\n currentWidth = 0\n }\n current += segment\n currentWidth += segmentWidth\n }\n wrapped.push(current)\n return wrapped\n}\n\nexport function formatInitSummary({ users, autoStart, columns = 80, color = false }: InitSummaryOptions): string[] {\n const width = Number.isFinite(columns) && columns >= 8 ? Math.floor(columns) : 80\n const lines = ['', '\uD83D\uDD11 DEVELOPMENT ACCOUNTS', '']\n for (const user of users) {\n lines.push(`${user.icon} ${user.label}`, ` Email: ${user.email}`, ` Password: ${user.password}`, '')\n }\n lines.push(...(autoStart\n ? ['\uD83D\uDE80 The dev server will start automatically.', ' Next time, run: yarn dev']\n : ['\uD83D\uDE80 Start the dev server: yarn dev']))\n lines.push('')\n const rule = '\u2501'.repeat(width)\n const content = lines.flatMap((line) => wrapLine(line, width - 4).map((part) => ` ${part}`))\n return [rule, ...content, rule].map((line) => {\n if (!color) return line\n const visibleWidth = [...segmenter.segment(line)].reduce((total, { segment }) => total + cellWidth(segment), 0)\n return `${panelStyle}${line}${' '.repeat(Math.max(0, width - visibleWidth))}${reset}`\n })\n}\n"],
|
|
5
|
+
"mappings": "AASA,MAAM,YAAY,IAAI,KAAK,UAAU,MAAM,EAAE,aAAa,WAAW,CAAC;AACtE,MAAM,aAAa;AACnB,MAAM,QAAQ;AAEd,SAAS,UAAU,OAAuB;AACxC,MAAI,WAAC,+LAAwK,GAAC,EAAC,KAAK,KAAK,EAAG,QAAO;AACnM,SAAO,WAAC,gBAAY,GAAC,EAAC,KAAK,KAAK,IAAI,IAAI;AAC1C;AAEA,SAAS,SAAS,MAAc,OAAyB;AACvD,QAAM,UAAoB,CAAC;AAC3B,MAAI,UAAU;AACd,MAAI,eAAe;AACnB,aAAW,EAAE,QAAQ,KAAK,UAAU,QAAQ,IAAI,GAAG;AACjD,UAAM,eAAe,UAAU,OAAO;AACtC,QAAI,eAAe,eAAe,SAAS,SAAS;AAClD,cAAQ,KAAK,OAAO;AACpB,gBAAU;AACV,qBAAe;AAAA,IACjB;AACA,eAAW;AACX,oBAAgB;AAAA,EAClB;AACA,UAAQ,KAAK,OAAO;AACpB,SAAO;AACT;AAEO,SAAS,kBAAkB,EAAE,OAAO,WAAW,UAAU,IAAI,QAAQ,MAAM,GAAiC;AACjH,QAAM,QAAQ,OAAO,SAAS,OAAO,KAAK,WAAW,IAAI,KAAK,MAAM,OAAO,IAAI;AAC/E,QAAM,QAAQ,CAAC,IAAI,kCAA2B,EAAE;AAChD,aAAW,QAAQ,OAAO;AACxB,UAAM,KAAK,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,iBAAiB,KAAK,KAAK,IAAI,iBAAiB,KAAK,QAAQ,IAAI,EAAE;AAAA,EAC9G;AACA,QAAM,KAAK,GAAI,YACX,CAAC,sDAA+C,6BAA6B,IAC7E,CAAC,0CAAmC,CAAE;AAC1C,QAAM,KAAK,EAAE;AACb,QAAM,OAAO,SAAI,OAAO,KAAK;AAC7B,QAAM,UAAU,MAAM,QAAQ,CAAC,SAAS,SAAS,MAAM,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;AAC5F,SAAO,CAAC,MAAM,GAAG,SAAS,IAAI,EAAE,IAAI,CAAC,SAAS;AAC5C,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,eAAe,CAAC,GAAG,UAAU,QAAQ,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,QAAQ,MAAM,QAAQ,UAAU,OAAO,GAAG,CAAC;AAC9G,WAAO,GAAG,UAAU,GAAG,IAAI,GAAG,IAAI,OAAO,KAAK,IAAI,GAAG,QAAQ,YAAY,CAAC,CAAC,GAAG,KAAK;AAAA,EACrF,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { assertModulePackageExports, parsePackageNameFromSpec } from "./module-package.js";
|
|
3
|
+
function githubApi(endpoint, cwd) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(execFileSync("gh", ["api", endpoint], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 6e4, maxBuffer: 16 * 1024 * 1024 }));
|
|
6
|
+
} catch {
|
|
7
|
+
throw new Error(`Cannot read GitHub repository metadata at ${endpoint}. Check the locator and access with "gh auth login". No package was installed.`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function record(value) {
|
|
11
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
12
|
+
}
|
|
13
|
+
function resolveGithubModuleTarget(input, cwd, options = {}) {
|
|
14
|
+
let normalized = input.trim().replace(/^(?:(?:git\+)?https?:\/\/github\.com\/)+/i, "").replace(/^github\.com\//i, "").replace(/^github:/i, "").replace(/^git@github\.com:/i, "").replace(/^(?:git\+)?ssh:\/\/(?:git@)?github\.com\//i, "");
|
|
15
|
+
const hash = normalized.indexOf("#");
|
|
16
|
+
const separator = hash < 0 ? normalized.lastIndexOf("@") : hash;
|
|
17
|
+
const requestedRef = separator < 0 ? void 0 : normalized.slice(separator + 1);
|
|
18
|
+
if (requestedRef !== void 0 && !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/.test(requestedRef)) {
|
|
19
|
+
throw new Error("Invalid GitHub revision. No package was installed.");
|
|
20
|
+
}
|
|
21
|
+
normalized = (separator < 0 ? normalized : normalized.slice(0, separator)).replace(/\/$/, "").replace(/\.git$/i, "");
|
|
22
|
+
if (/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(normalized)) {
|
|
23
|
+
const login = record(githubApi("user", cwd)).login;
|
|
24
|
+
if (typeof login !== "string" || !/^[A-Za-z0-9][A-Za-z0-9-]*$/.test(login)) {
|
|
25
|
+
throw new Error("Cannot determine your GitHub account. Use owner/repository or a full GitHub URL.");
|
|
26
|
+
}
|
|
27
|
+
normalized = `${login}/${normalized}`;
|
|
28
|
+
}
|
|
29
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9-]*\/[A-Za-z0-9][A-Za-z0-9._-]*$/.test(normalized)) {
|
|
30
|
+
throw new Error("Unsupported GitHub locator. Use github:owner/repository, a repository URL, or owner/repository.");
|
|
31
|
+
}
|
|
32
|
+
const repository = normalized.toLowerCase();
|
|
33
|
+
const ref = requestedRef ?? record(githubApi(`repos/${repository}`, cwd)).default_branch;
|
|
34
|
+
if (typeof ref !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/.test(ref)) {
|
|
35
|
+
throw new Error("Cannot determine a valid GitHub revision. Use a repository locator with #branch, #tag, or #commit.");
|
|
36
|
+
}
|
|
37
|
+
const sha = record(githubApi(`repos/${repository}/commits/${encodeURIComponent(ref)}`, cwd)).sha;
|
|
38
|
+
if (typeof sha !== "string" || !/^[0-9a-f]{40}$/.test(sha)) {
|
|
39
|
+
throw new Error(`Cannot resolve ${repository} to an immutable commit. No package was installed.`);
|
|
40
|
+
}
|
|
41
|
+
const contents = record(githubApi(`repos/${repository}/contents/package.json?ref=${sha}`, cwd));
|
|
42
|
+
if (contents.encoding !== "base64" || typeof contents.content !== "string") {
|
|
43
|
+
throw new Error(`Repository ${repository} has no readable package.json. No package was installed.`);
|
|
44
|
+
}
|
|
45
|
+
let manifest;
|
|
46
|
+
try {
|
|
47
|
+
manifest = record(JSON.parse(Buffer.from(contents.content, "base64").toString("utf8")));
|
|
48
|
+
} catch {
|
|
49
|
+
throw new Error(`Repository ${repository} has invalid package.json. No package was installed.`);
|
|
50
|
+
}
|
|
51
|
+
const packageName = manifest.name;
|
|
52
|
+
if (typeof packageName !== "string" || !/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(packageName) || parsePackageNameFromSpec(packageName) !== packageName) {
|
|
53
|
+
throw new Error(`Repository ${repository} has no valid npm package name. No package was installed.`);
|
|
54
|
+
}
|
|
55
|
+
const tree = record(githubApi(`repos/${repository}/git/trees/${sha}?recursive=1`, cwd));
|
|
56
|
+
if (!Array.isArray(tree.tree) || tree.truncated === true) {
|
|
57
|
+
throw new Error(`Cannot enumerate modules in ${repository}. No package was installed.`);
|
|
58
|
+
}
|
|
59
|
+
const moduleIds = Array.from(new Set(tree.tree.flatMap((entry) => {
|
|
60
|
+
const filePath = record(entry).path;
|
|
61
|
+
const match = typeof filePath === "string" ? /^src\/modules\/([a-z0-9]+(?:_[a-z0-9]+)*)\/index\.ts$/.exec(filePath) : null;
|
|
62
|
+
return match ? [match[1]] : [];
|
|
63
|
+
})));
|
|
64
|
+
if (moduleIds.length === 0) throw new Error(`Repository ${repository} has no module descriptors in src/modules/. No package was installed.`);
|
|
65
|
+
const files = tree.tree.flatMap((entry) => {
|
|
66
|
+
const filePath = record(entry).path;
|
|
67
|
+
if (typeof filePath !== "string") return [];
|
|
68
|
+
const compiledPath = /^src\/modules\/.+\.tsx?$/.test(filePath) ? filePath.replace(/^src\//, "dist/").replace(/\.tsx?$/, ".js") : void 0;
|
|
69
|
+
return compiledPath ? [filePath, compiledPath] : [filePath];
|
|
70
|
+
});
|
|
71
|
+
const requiredModuleIds = /* @__PURE__ */ new Set([
|
|
72
|
+
...options.moduleId ? [options.moduleId] : moduleIds.length === 1 ? moduleIds : [],
|
|
73
|
+
...(options.enabledModules ?? []).filter((entry) => (entry.from ?? "@open-mercato/core") === packageName).map((entry) => entry.id)
|
|
74
|
+
]);
|
|
75
|
+
const sourceCache = /* @__PURE__ */ new Map();
|
|
76
|
+
const readSource = (relativePath) => {
|
|
77
|
+
const cached = sourceCache.get(relativePath);
|
|
78
|
+
if (cached !== void 0) return cached;
|
|
79
|
+
const encodedPath = relativePath.split("/").map(encodeURIComponent).join("/");
|
|
80
|
+
const file = record(githubApi(`repos/${repository}/contents/${encodedPath}?ref=${sha}`, cwd));
|
|
81
|
+
if (file.encoding !== "base64" || typeof file.content !== "string" || file.content.length > 2 * 1024 * 1024) {
|
|
82
|
+
throw new Error(`Cannot inspect module source in ${repository} at the selected commit. No package was installed.`);
|
|
83
|
+
}
|
|
84
|
+
const source = Buffer.from(file.content, "base64").toString("utf8");
|
|
85
|
+
if (Buffer.byteLength(source, "utf8") > 1024 * 1024) throw new Error(`Module source inspection limit exceeded in ${repository}. No package was installed.`);
|
|
86
|
+
sourceCache.set(relativePath, source);
|
|
87
|
+
return source;
|
|
88
|
+
};
|
|
89
|
+
for (const moduleId of requiredModuleIds) {
|
|
90
|
+
if (!moduleIds.includes(moduleId)) continue;
|
|
91
|
+
assertModulePackageExports(manifest, packageName, moduleId, files, readSource);
|
|
92
|
+
}
|
|
93
|
+
return { packageName, packageSpec: `${packageName}@github:${repository}#${sha}`, moduleIds, locator: `github:${repository}` };
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
resolveGithubModuleTarget
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=module-github.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/module-github.ts"],
|
|
4
|
+
"sourcesContent": ["import { execFileSync } from 'node:child_process'\nimport { assertModulePackageExports, parsePackageNameFromSpec } from './module-package'\n\nexport type GithubModuleTarget = {\n packageName: string\n packageSpec: string\n moduleIds: string[]\n locator: string\n}\n\nfunction githubApi(endpoint: string, cwd: string): unknown {\n try {\n return JSON.parse(execFileSync('gh', ['api', endpoint], { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 60_000, maxBuffer: 16 * 1024 * 1024 })) as unknown\n } catch {\n throw new Error(`Cannot read GitHub repository metadata at ${endpoint}. Check the locator and access with \"gh auth login\". No package was installed.`)\n }\n}\n\nfunction record(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\n\nexport function resolveGithubModuleTarget(input: string, cwd: string, options: { moduleId?: string; enabledModules?: readonly { id: string; from?: string }[] } = {}): GithubModuleTarget {\n let normalized = input.trim()\n .replace(/^(?:(?:git\\+)?https?:\\/\\/github\\.com\\/)+/i, '')\n .replace(/^github\\.com\\//i, '')\n .replace(/^github:/i, '')\n .replace(/^git@github\\.com:/i, '')\n .replace(/^(?:git\\+)?ssh:\\/\\/(?:git@)?github\\.com\\//i, '')\n const hash = normalized.indexOf('#')\n const separator = hash < 0 ? normalized.lastIndexOf('@') : hash\n const requestedRef = separator < 0 ? undefined : normalized.slice(separator + 1)\n if (requestedRef !== undefined && !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/.test(requestedRef)) {\n throw new Error('Invalid GitHub revision. No package was installed.')\n }\n normalized = (separator < 0 ? normalized : normalized.slice(0, separator)).replace(/\\/$/, '').replace(/\\.git$/i, '')\n if (/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(normalized)) {\n const login = record(githubApi('user', cwd)).login\n if (typeof login !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9-]*$/.test(login)) {\n throw new Error('Cannot determine your GitHub account. Use owner/repository or a full GitHub URL.')\n }\n normalized = `${login}/${normalized}`\n }\n if (!/^[A-Za-z0-9][A-Za-z0-9-]*\\/[A-Za-z0-9][A-Za-z0-9._-]*$/.test(normalized)) {\n throw new Error('Unsupported GitHub locator. Use github:owner/repository, a repository URL, or owner/repository.')\n }\n const repository = normalized.toLowerCase()\n const ref = requestedRef ?? record(githubApi(`repos/${repository}`, cwd)).default_branch\n if (typeof ref !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/.test(ref)) {\n throw new Error('Cannot determine a valid GitHub revision. Use a repository locator with #branch, #tag, or #commit.')\n }\n const sha = record(githubApi(`repos/${repository}/commits/${encodeURIComponent(ref)}`, cwd)).sha\n if (typeof sha !== 'string' || !/^[0-9a-f]{40}$/.test(sha)) {\n throw new Error(`Cannot resolve ${repository} to an immutable commit. No package was installed.`)\n }\n const contents = record(githubApi(`repos/${repository}/contents/package.json?ref=${sha}`, cwd))\n if (contents.encoding !== 'base64' || typeof contents.content !== 'string') {\n throw new Error(`Repository ${repository} has no readable package.json. No package was installed.`)\n }\n let manifest: Record<string, unknown>\n try {\n manifest = record(JSON.parse(Buffer.from(contents.content, 'base64').toString('utf8')))\n } catch {\n throw new Error(`Repository ${repository} has invalid package.json. No package was installed.`)\n }\n const packageName = manifest.name\n if (typeof packageName !== 'string' || !/^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/.test(packageName) || parsePackageNameFromSpec(packageName) !== packageName) {\n throw new Error(`Repository ${repository} has no valid npm package name. No package was installed.`)\n }\n const tree = record(githubApi(`repos/${repository}/git/trees/${sha}?recursive=1`, cwd))\n if (!Array.isArray(tree.tree) || tree.truncated === true) {\n throw new Error(`Cannot enumerate modules in ${repository}. No package was installed.`)\n }\n const moduleIds = Array.from(new Set(tree.tree.flatMap((entry: unknown) => {\n const filePath = record(entry).path\n const match = typeof filePath === 'string' ? /^src\\/modules\\/([a-z0-9]+(?:_[a-z0-9]+)*)\\/index\\.ts$/.exec(filePath) : null\n return match ? [match[1]] : []\n })))\n if (moduleIds.length === 0) throw new Error(`Repository ${repository} has no module descriptors in src/modules/. No package was installed.`)\n const files = tree.tree.flatMap((entry: unknown) => {\n const filePath = record(entry).path\n if (typeof filePath !== 'string') return []\n const compiledPath = /^src\\/modules\\/.+\\.tsx?$/.test(filePath) ? filePath.replace(/^src\\//, 'dist/').replace(/\\.tsx?$/, '.js') : undefined\n return compiledPath ? [filePath, compiledPath] : [filePath]\n })\n const requiredModuleIds = new Set([\n ...(options.moduleId ? [options.moduleId] : moduleIds.length === 1 ? moduleIds : []),\n ...(options.enabledModules ?? []).filter((entry) => (entry.from ?? '@open-mercato/core') === packageName).map((entry) => entry.id),\n ])\n const sourceCache = new Map<string, string>()\n const readSource = (relativePath: string): string => {\n const cached = sourceCache.get(relativePath)\n if (cached !== undefined) return cached\n const encodedPath = relativePath.split('/').map(encodeURIComponent).join('/')\n const file = record(githubApi(`repos/${repository}/contents/${encodedPath}?ref=${sha}`, cwd))\n if (file.encoding !== 'base64' || typeof file.content !== 'string' || file.content.length > 2 * 1024 * 1024) {\n throw new Error(`Cannot inspect module source in ${repository} at the selected commit. No package was installed.`)\n }\n const source = Buffer.from(file.content, 'base64').toString('utf8')\n if (Buffer.byteLength(source, 'utf8') > 1024 * 1024) throw new Error(`Module source inspection limit exceeded in ${repository}. No package was installed.`)\n sourceCache.set(relativePath, source)\n return source\n }\n for (const moduleId of requiredModuleIds) {\n if (!moduleIds.includes(moduleId)) continue\n assertModulePackageExports(manifest, packageName, moduleId, files, readSource)\n }\n return { packageName, packageSpec: `${packageName}@github:${repository}#${sha}`, moduleIds, locator: `github:${repository}` }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|