@voobase/cli 0.1.1-nonprod.2037 → 0.1.1-nonprod.2039
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-bundle/index.mjs +27 -24
- package/package.json +6 -6
package/dist-bundle/index.mjs
CHANGED
|
@@ -2402,30 +2402,33 @@ ${routeMarker}`)}return next}function buildAuthDebugPageSource(){return["export
|
|
|
2402
2402
|
- ${result.removedFiles.join(`
|
|
2403
2403
|
- `)}`:"\u5220\u9664\u6587\u4EF6: -",`lockfile: ${result.lockfilePath}`,`history: ${result.historyUpdated?"updated":"unchanged"}`,result.verify?formatPlatformBlocksVerifySummary(result.verify.output):"",""].join(`
|
|
2404
2404
|
`):["\u5E73\u53F0\u5757 dry-run \u7ED3\u679C",`\u5E94\u7528\u76EE\u5F55: ${result.appRoot}`,`\u6A21\u677F: ${result.templateKey}`,`target revision: ${result.targetRevision}`,`managed files: ${result.managedFiles}`,`lockfile: ${result.lockfilePresent?"present":"missing"}`,typeof result.adoptable=="boolean"?`adoptable: ${result.adoptable?"yes":"no"}`:"",typeof result.safeUpdates=="number"?`safe updates: ${result.safeUpdates}`:"",typeof result.safeRemovals=="number"?`safe removals: ${result.safeRemovals}`:"",typeof result.lockRefreshes=="number"?`lock refreshes: ${result.lockRefreshes}`:"",typeof result.conflicts=="number"?`conflicts: ${result.conflicts}`:"",typeof result.noopFiles=="number"?`noop files: ${result.noopFiles}`:"",hasLastPlatformBlocksHistory(result.appRoot)?"rollback last: available":"rollback last: unavailable",""].filter(Boolean).join(`
|
|
2405
|
-
`)}function buildTemplateFileMap(templateKey){let files=templateKey==="backend-app-node"?assembleBackendAppNodeTemplate():assembleFrontendAppViteTemplate();return new Map(files.map(file=>[file.path,file.content]))}function buildHistorySnapshot(appRoot,relativePath){let absolutePath=join9(appRoot,relativePath);return existsSync13(absolutePath)?{path:relativePath,existed_before:!0,content:readFileSync13(absolutePath,"utf8")}:{path:relativePath,existed_before:!1}}function writeManagedFile(appRoot,relativePath,content){let absolutePath=join9(appRoot,relativePath);mkdirSync7(dirname9(absolutePath),{recursive:!0}),writeFileSync8(absolutePath,content,"utf8")}function removeManagedFile(appRoot,relativePath){let absolutePath=resolve8(appRoot,relativePath);existsSync13(absolutePath)&&unlinkSync(absolutePath)}function assertSafeManagedRemovalPath(appRoot,templateKey,relativePath){let normalizedRoot=resolve8(appRoot),insideAppRoot=resolve8(normalizedRoot,relativePath).startsWith(`${normalizedRoot}${sep}`);if(isAbsolute(relativePath)||!insideAppRoot||!isManagedPlatformFilePath(templateKey,relativePath))throw new Error(`\u9501\u6587\u4EF6\u5305\u542B\u975E\u6CD5\u7684\u6258\u7BA1\u5220\u9664\u8DEF\u5F84\uFF0C\u5DF2\u62D2\u7EDD apply\uFF1A${relativePath}`)}function runPlatformBlocksVerify(appRoot){let workspaceRoot=findWorkspaceRoot(appRoot),scriptPath=process.env.PLATFORM_BLOCKS_VERIFY_SCRIPT?.trim()||join9(workspaceRoot,"scripts","validation","url","local-url-gate.sh");try{return{status:"passed",output:execFileSync("bash",[scriptPath,"--mode","inspect"],{cwd:workspaceRoot,encoding:"utf8",env:process.env,maxBuffer:4194304}).trim()}}catch(error){let detail=error instanceof Error?error.message:String(error);throw new Error(`\u5E73\u53F0\u5757 verify \u5931\u8D25\uFF1A${detail}`)}}function formatPlatformBlocksVerifySummary(output){try{let parsed=JSON.parse(output),checks=Array.isArray(parsed.checks)?parsed.checks:[],passed=checks.filter(check=>check.status==="passed").length;return`verify: ${parsed.status??"passed"} mode=${parsed.mode??"inspect"} checks=${passed}/${checks.length}`}catch{return"verify: passed"}}import{
|
|
2405
|
+
`)}function buildTemplateFileMap(templateKey){let files=templateKey==="backend-app-node"?assembleBackendAppNodeTemplate():assembleFrontendAppViteTemplate();return new Map(files.map(file=>[file.path,file.content]))}function buildHistorySnapshot(appRoot,relativePath){let absolutePath=join9(appRoot,relativePath);return existsSync13(absolutePath)?{path:relativePath,existed_before:!0,content:readFileSync13(absolutePath,"utf8")}:{path:relativePath,existed_before:!1}}function writeManagedFile(appRoot,relativePath,content){let absolutePath=join9(appRoot,relativePath);mkdirSync7(dirname9(absolutePath),{recursive:!0}),writeFileSync8(absolutePath,content,"utf8")}function removeManagedFile(appRoot,relativePath){let absolutePath=resolve8(appRoot,relativePath);existsSync13(absolutePath)&&unlinkSync(absolutePath)}function assertSafeManagedRemovalPath(appRoot,templateKey,relativePath){let normalizedRoot=resolve8(appRoot),insideAppRoot=resolve8(normalizedRoot,relativePath).startsWith(`${normalizedRoot}${sep}`);if(isAbsolute(relativePath)||!insideAppRoot||!isManagedPlatformFilePath(templateKey,relativePath))throw new Error(`\u9501\u6587\u4EF6\u5305\u542B\u975E\u6CD5\u7684\u6258\u7BA1\u5220\u9664\u8DEF\u5F84\uFF0C\u5DF2\u62D2\u7EDD apply\uFF1A${relativePath}`)}function runPlatformBlocksVerify(appRoot){let workspaceRoot=findWorkspaceRoot(appRoot),scriptPath=process.env.PLATFORM_BLOCKS_VERIFY_SCRIPT?.trim()||join9(workspaceRoot,"scripts","validation","url","local-url-gate.sh");try{return{status:"passed",output:execFileSync("bash",[scriptPath,"--mode","inspect"],{cwd:workspaceRoot,encoding:"utf8",env:process.env,maxBuffer:4194304}).trim()}}catch(error){let detail=error instanceof Error?error.message:String(error);throw new Error(`\u5E73\u53F0\u5757 verify \u5931\u8D25\uFF1A${detail}`)}}function formatPlatformBlocksVerifySummary(output){try{let parsed=JSON.parse(output),checks=Array.isArray(parsed.checks)?parsed.checks:[],passed=checks.filter(check=>check.status==="passed").length;return`verify: ${parsed.status??"passed"} mode=${parsed.mode??"inspect"} checks=${passed}/${checks.length}`}catch{return"verify: passed"}}import{randomUUID}from"node:crypto";import{copyFileSync,existsSync as existsSync15,lstatSync,mkdirSync as mkdirSync8,readFileSync as readFileSync15,readdirSync as readdirSync5,renameSync as renameSync2,rmSync as rmSync3,writeFileSync as writeFileSync9}from"node:fs";import{basename as basename4,dirname as dirname10,isAbsolute as isAbsolute2,join as join11,relative as relative3,resolve as resolve9}from"node:path";import{existsSync as existsSync14,readFileSync as readFileSync14}from"node:fs";import{join as join10}from"node:path";var SOURCE_CONTEXT_PATH=join10(".platform","source-context.json");function readJsonIfExists(filePath){return existsSync14(filePath)?JSON.parse(readFileSync14(filePath,"utf8")):null}function detectTemplateKeyFromWorkspace(workspaceDir){let sourceContext=readJsonIfExists(join10(workspaceDir,SOURCE_CONTEXT_PATH));if(sourceContext?.template_key){let normalized=normalizeAppTemplateKey(sourceContext.template_key);if(normalized==="frontend-app-vite"||normalized==="backend-app-node")return normalized}return existsSync14(join10(workspaceDir,"src","web","app.tsx"))||existsSync14(join10(workspaceDir,"src","server","entry.ts"))?"backend-app-node":(existsSync14(join10(workspaceDir,"src","app.tsx"))||existsSync14(join10(workspaceDir,"src","main.tsx")),"frontend-app-vite")}function resolveAppImportLayout(workspaceDir){let templateKey=detectTemplateKeyFromWorkspace(workspaceDir),frontendRoot=templateKey==="backend-app-node"?"src/web":"src",importedUpstreamRoot=join10(frontendRoot,"imported-upstream").replace(/\\/g,"/"),preservedWorkspaceFiles=["app.yaml","package.json","vite.config.ts","index.html",`${frontendRoot}/main.tsx`,`${frontendRoot}/app.tsx`,`${frontendRoot}/platform`,"public/auth/index.html","public/__app"];return templateKey==="backend-app-node"&&preservedWorkspaceFiles.push("Dockerfile","src/server"),{template_key:templateKey,frontend_root:frontendRoot,imported_upstream_root:importedUpstreamRoot,preserved_workspace_files:preservedWorkspaceFiles}}var REQUIRED_WORKSPACE_FILES=["app.yaml","package.json"],FRONTEND_MERGEABLE_SOURCE_DIRS=["pages","components","styles","lib","imports"];function printAppImportMergeUsage(){process.stdout.write(["platform app import merge","","\u7528\u6CD5\uFF1A"," platform app import merge [--workspace-dir <template-workspace-dir>] [--dry-run] [--json]","","\u4F5C\u7528\uFF1A"," \u5C06 `.design-import/upstream-clean-source/` \u7684\u53EF\u8FC1\u79FB\u76EE\u5F55\u5B89\u5168\u5E76\u5165\u6A21\u677F\u5DE5\u4F5C\u533A\u7684 imported-upstream \u843D\u70B9\uFF0C\u4FDD\u7559\u6A21\u677F\u5165\u53E3\u4E0E\u5E73\u53F0\u5951\u7EA6\u6587\u4EF6\u7531\u6A21\u677F\u4E3B\u5BFC\u3002","","\u8BF4\u660E\uFF1A"," - \u9ED8\u8BA4\u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4F5C\u4E3A\u6A21\u677F\u5DE5\u4F5C\u533A\uFF1B\u82E5\u672A\u4F20 `--workspace-dir`\uFF0C\u5C06\u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",""].join(`
|
|
2406
2406
|
`))}function parseArgs(argv){let result={workspaceDir:"",dryRun:!1,json:!1,help:!1};for(let index=0;index<argv.length;index+=1){let arg=argv[index];if(arg==="--help"||arg==="-h"){result.help=!0;continue}if(arg==="--dry-run"){result.dryRun=!0;continue}if(arg==="--json"){result.json=!0;continue}if(arg==="--workspace-dir"){result.workspaceDir=argv[index+1]??"",index+=1;continue}throw new Error(`\u672A\u77E5\u53C2\u6570: ${arg}`)}return result}function readJson(filePath){return JSON.parse(readFileSync15(filePath,"utf8"))}function writeJson(filePath,payload){writeFileSync9(filePath,`${JSON.stringify(payload,null,2)}
|
|
2407
|
-
`,"utf8")}function assertDirectory(pathValue,label){let stats=
|
|
2407
|
+
`,"utf8")}function assertDirectory(pathValue,label){let stats=lstatSync(pathValue,{throwIfNoEntry:!1});if(stats?.isSymbolicLink())throw new Error(`${label} \u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${pathValue}`);if(!stats||!stats.isDirectory())throw new Error(`${label} \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${pathValue}`)}function isSafeSourceDirectory(pathValue,label){let stats=lstatSync(pathValue,{throwIfNoEntry:!1});if(!stats)return!1;if(stats.isSymbolicLink())throw new Error(`${label} \u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${pathValue}`);return stats.isDirectory()}function validateMergeEntry(sourcePath){let sourceStats=lstatSync(sourcePath,{throwIfNoEntry:!1});if(!sourceStats)throw new Error(`merge \u6E90\u8DEF\u5F84\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${sourcePath}`);if(sourceStats.isSymbolicLink())throw new Error(`merge \u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${sourcePath}`);if(sourceStats.isDirectory()){for(let entry of readdirSync5(sourcePath,{withFileTypes:!0}))validateMergeEntry(join11(sourcePath,entry.name));return}if(!sourceStats.isFile())throw new Error(`merge \u4E0D\u652F\u6301\u590D\u5236\u8BE5\u7C7B\u578B\u7684\u6587\u4EF6: ${sourcePath}`)}function copyMergeEntry(sourcePath,targetPath){let sourceStats=lstatSync(sourcePath,{throwIfNoEntry:!1});if(!sourceStats)throw new Error(`merge \u6E90\u8DEF\u5F84\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${sourcePath}`);if(sourceStats.isSymbolicLink())throw new Error(`merge \u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${sourcePath}`);if(sourceStats.isDirectory()){mkdirSync8(targetPath,{recursive:!0});for(let entry of readdirSync5(sourcePath,{withFileTypes:!0}))copyMergeEntry(join11(sourcePath,entry.name),join11(targetPath,entry.name));return}if(sourceStats.isFile()){copyFileSync(sourcePath,targetPath);return}throw new Error(`merge \u4E0D\u652F\u6301\u590D\u5236\u8BE5\u7C7B\u578B\u7684\u6587\u4EF6: ${sourcePath}`)}function assertSafeTargetParent(workspaceDir,targetPath){let targetParent=dirname10(targetPath),relativeParent=relative3(workspaceDir,targetParent);if(relativeParent.startsWith("..")||isAbsolute2(relativeParent))throw new Error(`merge \u76EE\u6807\u8DEF\u5F84\u8D85\u51FA\u6A21\u677F\u5DE5\u4F5C\u533A: ${targetPath}`);let currentPath=workspaceDir;for(let segment of relativeParent.split(/[\\/]+/u).filter(Boolean)){currentPath=join11(currentPath,segment);let stats=lstatSync(currentPath,{throwIfNoEntry:!1});if(stats){if(stats.isSymbolicLink())throw new Error(`merge \u76EE\u6807\u7236\u8DEF\u5F84\u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${currentPath}`);if(!stats.isDirectory())throw new Error(`merge \u76EE\u6807\u7236\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${currentPath}`)}}if(lstatSync(targetPath,{throwIfNoEntry:!1})?.isSymbolicLink())throw new Error(`merge \u76EE\u6807\u8DEF\u5F84\u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${targetPath}`)}function describeError(error){return error instanceof Error?error.message:String(error)}function replaceMergeTargets(operations,deps={}){let renameEntry=deps.renameEntry??renameSync2,removeEntry=deps.removeEntry??rmSync3;try{for(let operation of operations)lstatSync(operation.targetPath,{throwIfNoEntry:!1})&&(renameEntry(operation.targetPath,operation.backupPath),operation.backedUp=!0),operation.tempPath&&(renameEntry(operation.tempPath,operation.targetPath),operation.installed=!0)}catch(error){let rollbackFailures=[],attemptRollback=(label,action)=>{try{action()}catch(rollbackError){rollbackFailures.push(`${label}: ${describeError(rollbackError)}`)}};for(let operation of[...operations].reverse())operation.installed&&attemptRollback(`remove installed target ${operation.targetPath}`,()=>removeEntry(operation.targetPath,{recursive:!0,force:!0})),operation.backedUp&&attemptRollback(`restore backup ${operation.backupPath} -> ${operation.targetPath}`,()=>renameEntry(operation.backupPath,operation.targetPath)),operation.tempPath&&attemptRollback(`remove temporary target ${operation.tempPath}`,()=>removeEntry(operation.tempPath,{recursive:!0,force:!0}));throw rollbackFailures.length>0?new Error(`merge \u76EE\u6807\u66FF\u6362\u5931\u8D25: ${describeError(error)}; \u56DE\u6EDA\u5F02\u5E38: ${rollbackFailures.join("; ")}`,{cause:error}):error}for(let operation of operations)if(operation.backedUp)try{removeEntry(operation.backupPath,{recursive:!0,force:!0})}catch(cleanupError){process.stderr.write(`[app import merge] warning: merge \u5DF2\u5B8C\u6210\uFF0C\u4F46\u65E7\u76EE\u6807\u5907\u4EFD\u6E05\u7406\u5931\u8D25: ${operation.backupPath}: ${describeError(cleanupError)}
|
|
2408
|
+
`)}}function cleanupMergeTemps(paths,removeEntry=rmSync3){for(let pathValue of paths.filter(Boolean))try{removeEntry(pathValue,{recursive:!0,force:!0})}catch(cleanupError){process.stderr.write(`[app import merge] warning: merge \u4E34\u65F6\u76EE\u5F55\u6E05\u7406\u5931\u8D25: ${pathValue}: ${describeError(cleanupError)}
|
|
2409
|
+
`)}}function validateWorkspace(workspaceDir){assertDirectory(workspaceDir,"\u6A21\u677F\u5DE5\u4F5C\u533A");let missing=REQUIRED_WORKSPACE_FILES.filter(file=>!existsSync15(join11(workspaceDir,file)));if(missing.length>0)throw new Error(`\u76EE\u6807\u76EE\u5F55\u4E0D\u662F\u6709\u6548\u6A21\u677F\u5DE5\u4F5C\u533A\uFF0C\u7F3A\u5C11: ${missing.join(", ")}`)}function buildMergeSummary(args,payload){let sourcePreprocessExecutionMode=payload.importSummary.source_preprocess_execution_mode||payload.importManifest.execution_mode||"unknown",warnings=[];return sourcePreprocessExecutionMode==="dry-run"&&warnings.push("\u5F53\u524D merge \u6765\u6E90\u4E8E dry-run \u9884\u5904\u7406\u4EA7\u7269\uFF1Bsrc/imported-upstream/ \u4E2D\u4ECD\u53EF\u80FD\u5305\u542B\u672A\u6E05\u7406\u7684\u672C\u5730\u7D20\u6750\u3002"),{tool:"merge-imported-upstream",version:1,mode:"merge-stage",execution_mode:args.dryRun?"dry-run":"apply",workspace_dir:payload.workspaceDir,import_summary:payload.importSummaryPath,source_preprocess_execution_mode:sourcePreprocessExecutionMode,target_template_key:payload.layout.template_key,frontend_root:payload.layout.frontend_root,upstream_clean_source_dir:payload.upstreamCleanSourceDir,merged_target_dir:payload.mergedTargetDir,merge_required:payload.mergeRequired,merged_paths:payload.mergedPaths,skipped_paths:payload.skippedPaths,preserved_workspace_files:payload.importSummary.preserved_workspace_files??[],warnings,next_steps:[`\u5728 ${payload.layout.imported_upstream_root}/ \u4E2D\u5BA1\u67E5\u4E0A\u6E38\u9875\u9762\u3001components\u3001styles\u3001lib\u3001imports`,payload.layout.template_key==="backend-app-node"?"\u4ECE src/web/app.tsx \u6216 src/web/pages/* \u4E2D\u9009\u62E9\u6027\u5F15\u7528 imported-upstream \u5185\u5BB9\uFF0C\u4FDD\u6301 src/server/* \u4E0E src/web/platform/* \u7531\u6A21\u677F\u4E3B\u5BFC":"\u4ECE src/app.tsx \u6216 src/pages/* \u4E2D\u9009\u62E9\u6027\u5F15\u7528 imported-upstream \u5185\u5BB9\uFF0C\u4FDD\u6301 src/platform/* \u7531\u6A21\u677F\u4E3B\u5BFC","\u9010\u6B65\u628A\u9700\u8981\u7684\u5E73\u53F0\u80FD\u529B\u63A5\u5165\u5230\u6A21\u677F\u4E3B\u5BFC\u7684\u8FD0\u884C\u5165\u53E3\u4E2D","\u5B8C\u6210\u63A5\u7EBF\u540E\uFF0C\u518D\u6267\u884C platform dev / verify / preview"]}}async function runAppImportMergeCli(argv,deps={}){let args=parseArgs(argv);if(args.help){printAppImportMergeUsage();return}if(!args.workspaceDir)throw new Error("\u7F3A\u5C11 `--workspace-dir <template-workspace-dir>`\u3002");let workspaceDir=resolve9(args.workspaceDir);validateWorkspace(workspaceDir);let designImportRoot=join11(workspaceDir,".design-import"),importSummaryPath=join11(designImportRoot,"import-summary.json"),importManifestPath=join11(designImportRoot,"reports","import-manifest.json"),upstreamCleanSourceDir=join11(designImportRoot,"upstream-clean-source");assertDirectory(designImportRoot,".design-import"),assertDirectory(upstreamCleanSourceDir,"upstream-clean-source");let importSummary=readJson(importSummaryPath),importManifest=existsSync15(importManifestPath)?readJson(importManifestPath):{},layout=resolveAppImportLayout(workspaceDir),mergedTargetDir=join11(workspaceDir,...layout.imported_upstream_root.split("/")),upstreamSrcDir=join11(upstreamCleanSourceDir,"src"),upstreamPublicDir=join11(upstreamCleanSourceDir,"public"),mergedPublicTargetDir=join11(workspaceDir,"public","imported-upstream"),mergeRequired=!0,upstreamSrcExists=isSafeSourceDirectory(upstreamSrcDir,"upstream clean-source/src"),upstreamPublicExists=isSafeSourceDirectory(upstreamPublicDir,"upstream clean-source/public");importSummary.source_detected_type==="frontend-app"&&assertDirectory(upstreamSrcDir,"upstream clean-source/src");let mergedPaths=[],skippedPaths=[],sourceMergeEntries=[];if(importSummary.source_detected_type==="frontend-app"&&upstreamSrcExists)for(let name of FRONTEND_MERGEABLE_SOURCE_DIRS){let sourcePath=join11(upstreamSrcDir,name);if(!isSafeSourceDirectory(sourcePath,`upstream clean-source/src/${name}`)){skippedPaths.push(`src/${name}`);continue}validateMergeEntry(sourcePath),sourceMergeEntries.push({name,sourcePath});let targetPath=join11(mergedTargetDir,name);mergedPaths.push({source:`src/${name}`,target:`${layout.imported_upstream_root}/${name}`})}else importSummary.source_detected_type==="frontend-app"?skippedPaths.push("src/: upstream clean-source does not contain mergeable frontend source"):skippedPaths.push("src/: static-site upstream does not require frontend source merge");if(upstreamPublicExists?(validateMergeEntry(upstreamPublicDir),mergedPaths.push({source:"public",target:"public/imported-upstream"})):skippedPaths.push("public"),!args.dryRun){assertSafeTargetParent(workspaceDir,mergedTargetDir),assertSafeTargetParent(workspaceDir,mergedPublicTargetDir),mkdirSync8(dirname10(mergedTargetDir),{recursive:!0}),mkdirSync8(dirname10(mergedPublicTargetDir),{recursive:!0});let runId=randomUUID(),mergedTempDir=join11(dirname10(mergedTargetDir),`.${basename4(mergedTargetDir)}.merge-${runId}.tmp`),publicTempDir=upstreamPublicExists?join11(dirname10(mergedPublicTargetDir),`.${basename4(mergedPublicTargetDir)}.merge-${runId}.tmp`):"",operations=[{targetPath:mergedTargetDir,tempPath:mergedTempDir,backupPath:join11(dirname10(mergedTargetDir),`.${basename4(mergedTargetDir)}.merge-${runId}.bak`),backedUp:!1,installed:!1},{targetPath:mergedPublicTargetDir,tempPath:publicTempDir,backupPath:join11(dirname10(mergedPublicTargetDir),`.${basename4(mergedPublicTargetDir)}.merge-${runId}.bak`),backedUp:!1,installed:!1}];try{mkdirSync8(mergedTempDir,{recursive:!1});for(let entry of sourceMergeEntries)copyMergeEntry(entry.sourcePath,join11(mergedTempDir,entry.name));upstreamPublicExists&©MergeEntry(upstreamPublicDir,publicTempDir),replaceMergeTargets(operations,deps)}catch(error){throw cleanupMergeTemps([mergedTempDir,publicTempDir],deps.removeEntry),error}}let summary=buildMergeSummary(args,{workspaceDir,importSummaryPath,importSummary,importManifest,layout,upstreamCleanSourceDir,mergedTargetDir,mergeRequired,mergedPaths,skippedPaths});if(args.dryRun||writeJson(join11(designImportRoot,"merge-summary.json"),summary),args.json){process.stdout.write(`${JSON.stringify(summary,null,2)}
|
|
2408
2410
|
`);return}process.stdout.write(["third-party design merge stage completed",`execution_mode: ${summary.execution_mode}`,`workspace_dir: ${summary.workspace_dir}`,`merged_target_dir: ${summary.merged_target_dir}`,`merged_paths: ${summary.merged_paths.length}`,`skipped_paths: ${summary.skipped_paths.length}`,`warnings: ${summary.warnings.length}`].join(`
|
|
2409
2411
|
`)+`
|
|
2410
|
-
`)}import{createHash as createHash5}from"node:crypto";import{copyFileSync,existsSync as existsSync16,lstatSync,mkdtempSync as mkdtempSync3,mkdirSync as mkdirSync9,readFileSync as readFileSync16,readdirSync as
|
|
2412
|
+
`)}import{createHash as createHash5}from"node:crypto";import{copyFileSync as copyFileSync2,existsSync as existsSync16,lstatSync as lstatSync2,mkdtempSync as mkdtempSync3,mkdirSync as mkdirSync9,readFileSync as readFileSync16,readdirSync as readdirSync6,rmSync as rmSync4,statSync as statSync4,unlinkSync as unlinkSync2,writeFileSync as writeFileSync10}from"node:fs";import{spawn}from"node:child_process";import{basename as basename5,dirname as dirname11,extname as extname3,join as join12,relative as relative4,resolve as resolve10}from"node:path";import{tmpdir as tmpdir2}from"node:os";var DEFAULT_INCLUDE_EXTENSIONS=new Set([".html",".css",".js",".jsx",".ts",".tsx",".vue",".svelte"]),DEFAULT_SKIP_DIRS=new Set([".git","node_modules","dist","build",".next",".nuxt","coverage",".platform",".sandbox",".design-preprocess",".third-party-design-reports"]),IMAGE_HOST_HINTS=["unsplash.com","images.unsplash.com","googleusercontent.com","lh3.googleusercontent.com"],IMAGE_EXTENSIONS=new Set([".png",".jpg",".jpeg",".gif",".webp",".svg",".avif",".bmp",".ico"]),VIDEO_EXTENSIONS=new Set([".mp4",".webm",".mov",".m4v",".avi",".mkv"]),HTTPS_FORCE_HOST_SUFFIXES=["21epub.com"],URL_PATTERN=/https?:\/\/[^\s"'`)>\]]+/giu,LOCAL_ASSET_REF_PATTERN=/["'`](\.{1,2}\/[^"'`]+?\.(?:png|jpg|jpeg|gif|webp|svg|avif|bmp|ico))["'`]/giu,CSS_URL_PATTERN=/url\((['"]?)(\.{1,2}\/[^)'"]+?\.(?:png|jpg|jpeg|gif|webp|svg|avif|bmp|ico))\1\)/giu,IMPORT_LOCAL_ASSET_PATTERN=/^(\s*)import\s+([A-Za-z_$][\w$]*)\s+from\s+(["'])(\.{1,2}\/[^"'`\n]+?\.(?:png|jpg|jpeg|gif|webp|svg|avif|bmp|ico))\3;?(\s*)$/gmu,LOCAL_IMAGE_UPLOAD_MAX_WIDTH=2048,PREFLIGHT_LOCAL_ASSET_WARN_BYTES=5*1024*1024,CACHE_VERSION=1,REMOTE_IMAGE_CONCURRENCY=3;function logProgress(message){process.stderr.write(`[app import preprocess] ${message}
|
|
2411
2413
|
`)}async function runWithConcurrency(items,concurrency,worker){let limit=Math.max(1,concurrency),results=new Array(items.length),nextIndex=0;async function consume(){for(;;){let currentIndex=nextIndex;if(nextIndex+=1,currentIndex>=items.length)return;results[currentIndex]=await worker(items[currentIndex],currentIndex)}}let runners=Array.from({length:Math.min(limit,items.length)},()=>consume());return await Promise.all(runners),results}function printAppImportPreprocessUsage(){process.stdout.write(["platform app import preprocess","","\u7528\u6CD5\uFF1A"," platform app import preprocess [--dir <third-party-source-dir>] [--dry-run] [--json]"," platform app import preprocess --dir <third-party-source-dir> --folder-id <asset-folder-id>","","\u4F5C\u7528\uFF1A"," \u626B\u63CF\u7B2C\u4E09\u65B9\u8BBE\u8BA1\u6E90\u7801\u5305\uFF0C\u505A\u7D20\u6750\u4E0A\u4F20\u56DE\u5199\u3001clean-source \u751F\u6210\u3001path-base \u57FA\u7840\u4FEE\u6B63\u4E0E\u9884\u5904\u7406\u62A5\u544A\u8F93\u51FA\u3002","","\u8BF4\u660E\uFF1A"," - \u9ED8\u8BA4\u7B49\u4EF7\u4E8E\u5728\u5F53\u524D\u76EE\u5F55\u6267\u884C\u9884\u5904\u7406\uFF1B\u82E5\u672A\u4F20 `--dir`\uFF0C\u5C06\u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002"," - \u9ED8\u8BA4\u4F1A\u590D\u7528 `.design-preprocess/cache/` \u4E2D\u5DF2\u6210\u529F\u4E0A\u4F20\u7684\u7D20\u6750\u6620\u5C04\uFF1B\u82E5\u9700\u5FFD\u7565\u7F13\u5B58\u91CD\u8DD1\uFF0C\u53EF\u663E\u5F0F\u4F20 `--reset-cache`\u3002",""].join(`
|
|
2412
|
-
`))}function parseArgs2(argv){let result={dir:"",include:new Set(DEFAULT_INCLUDE_EXTENSIONS),folderId:"",type:"auto",dryRun:!1,resume:!0,resetCache:!1,localReport:"",json:!1,help:!1};for(let index=0;index<argv.length;index+=1){let arg=argv[index];if(arg==="--help"||arg==="-h"){result.help=!0;continue}if(arg==="--json"){result.json=!0;continue}if(arg==="--dry-run"){result.dryRun=!0;continue}if(arg==="--resume"){result.resume=!0;continue}if(arg==="--reset-cache"){result.resetCache=!0;continue}if(arg==="--dir"){result.dir=argv[index+1]??"",index+=1;continue}if(arg==="--include"){let raw=argv[index+1]??"";index+=1,result.include=normalizeInclude(raw);continue}if(arg==="--folder-id"){result.folderId=argv[index+1]??"",index+=1;continue}if(arg==="--type"){result.type=argv[index+1]??result.type,index+=1;continue}if(arg==="--local-report"){result.localReport=argv[index+1]??"",index+=1;continue}throw new Error(`\u672A\u77E5\u53C2\u6570: ${arg}`)}return result}function normalizeInclude(raw){let values=raw.split(",").map(item=>item.trim().toLowerCase()).filter(Boolean).map(item=>item.startsWith(".")?item:`.${item}`);return values.length>0?new Set(values):new Set(DEFAULT_INCLUDE_EXTENSIONS)}function buildRemoteCacheKey(url){return`remote:${url}`}function buildLocalCacheKey(contentHash){return`local:${contentHash}`}function defaultAssetCache(sourceDir){return{version:CACHE_VERSION,source_dir:sourceDir,entries:{}}}function defaultLockState(){return{version:CACHE_VERSION,active_run_id:null,started_at:null,phase:null,in_progress_keys:[],last_interrupted_at:null}}function readJsonIfExists2(filePath,fallbackValue){if(!existsSync16(filePath))return fallbackValue;try{return JSON.parse(readFileSync16(filePath,"utf8"))}catch{return fallbackValue}}function loadAssetCache(cacheFile,sourceDir){let loaded=readJsonIfExists2(cacheFile,defaultAssetCache(sourceDir));return{version:CACHE_VERSION,source_dir:loaded.source_dir||sourceDir,entries:loaded.entries&&typeof loaded.entries=="object"?loaded.entries:{}}}function persistAssetCache(cacheFile,payload){ensureDir(dirname10(cacheFile)),writeJson2(cacheFile,payload)}function loadLockState(lockFile){let loaded=readJsonIfExists2(lockFile,defaultLockState());return{version:CACHE_VERSION,active_run_id:loaded.active_run_id??null,started_at:loaded.started_at??null,phase:loaded.phase??null,in_progress_keys:Array.isArray(loaded.in_progress_keys)?loaded.in_progress_keys:[],last_interrupted_at:loaded.last_interrupted_at??null}}function persistLockState(lockFile,payload){ensureDir(dirname10(lockFile)),writeJson2(lockFile,payload)}function beginLockRun(lockFile,previousLock){let interruptedItems=previousLock.active_run_id?previousLock.in_progress_keys.length:0,next={version:CACHE_VERSION,active_run_id:`preprocess-${Date.now()}`,started_at:new Date().toISOString(),phase:"scan",in_progress_keys:[],last_interrupted_at:previousLock.active_run_id?new Date().toISOString():previousLock.last_interrupted_at};return persistLockState(lockFile,next),{lock:next,interruptedItems}}function updateLockState(lockFile,currentLock,patch){let next={...currentLock,...patch};return persistLockState(lockFile,next),next}function completeLockRun(lockFile,currentLock){let next={...currentLock,active_run_id:null,phase:"completed",in_progress_keys:[]};return persistLockState(lockFile,next),next}function cacheEntryReusable(entry){return!!(entry&&typeof entry.final_url=="string"&&entry.final_url.trim()&&entry.asset_id&&entry.status!=="failed")}function updateCacheEntry(cache,cacheKey,patch){cache.entries[cacheKey]={...cache.entries[cacheKey]??{},...patch,updated_at:new Date().toISOString()}}function walkFiles(rootDir,includeExtensions){let files=[];function visit(currentDir){let entries=readdirSync5(currentDir,{withFileTypes:!0});for(let entry of entries){let fullPath=join12(currentDir,entry.name);if(entry.isDirectory()){if(DEFAULT_SKIP_DIRS.has(entry.name))continue;visit(fullPath);continue}if(!entry.isFile())continue;let extension=extname3(entry.name).toLowerCase();includeExtensions.has(extension)&&files.push(fullPath)}}return visit(rootDir),files.sort((left,right)=>left.localeCompare(right))}function walkAssetFiles(rootDir){let files=[];function visit(currentDir){let entries=readdirSync5(currentDir,{withFileTypes:!0});for(let entry of entries){let fullPath=join12(currentDir,entry.name);if(entry.isDirectory()){if(DEFAULT_SKIP_DIRS.has(entry.name))continue;visit(fullPath);continue}if(!entry.isFile())continue;let extension=extname3(entry.name).toLowerCase();IMAGE_EXTENSIONS.has(extension)&&files.push(fullPath)}}return visit(rootDir),files.sort((left,right)=>left.localeCompare(right))}function normalizeMatchedUrl(rawUrl){return rawUrl.replace(/[),.;]+$/u,"").replace(/^("?|"?|'?|'?)+/iu,"").replace(/("?|"?|'?|'?)+$/iu,"").replace(/&/giu,"&")}function findLineNumber(text2,offset){let line=1;for(let index=0;index<offset;index+=1)text2.charCodeAt(index)===10&&(line+=1);return line}function inferExtensionFromUrl(url){try{let parsed=new URL(url);return extname3(parsed.pathname).toLowerCase()}catch{return extname3(url).toLowerCase()}}function classifyUrl(url,surroundingText){let lowerUrl=url.toLowerCase(),extension=inferExtensionFromUrl(lowerUrl),lowerContext=surroundingText.toLowerCase(),nonImageContext=lowerContext.includes("<script")||lowerContext.includes("script src")||lowerContext.includes('rel="stylesheet"')||lowerContext.includes("rel='stylesheet'")||lowerContext.includes("xmlns="),nonImageUrl=lowerUrl.includes("cdn.tailwindcss.com")||lowerUrl.includes("fonts.googleapis.com")||lowerUrl.includes("fonts.gstatic.com")||lowerUrl.includes("w3.org/2000/svg");return lowerContext.includes("poster")?"poster":VIDEO_EXTENSIONS.has(extension)?"video":nonImageContext||nonImageUrl||extension===".js"||extension===".mjs"||extension===".css"?"unknown_remote":IMAGE_EXTENSIONS.has(extension)||IMAGE_HOST_HINTS.some(item=>lowerUrl.includes(item))||lowerContext.includes("<img")||lowerContext.includes("background-image")||lowerContext.includes("url(")?"image":"unknown_remote"}function computeRewriteSupported(kind){return kind==="image"}function compactContext(value){return value.replace(/\s+/gu," ").trim().slice(0,200)}function kindPriority(kind){switch(kind){case"video":return 4;case"poster":return 3;case"image":return 2;default:return 1}}function collectRemoteCandidates(rootDir,files){let byUrl=new Map;for(let filePath of files){let raw=readFileSync16(filePath,"utf8");for(let match2 of raw.matchAll(URL_PATTERN)){let matched=match2[0],offset=match2.index??0,url=normalizeMatchedUrl(matched),line=findLineNumber(raw,offset),surroundingText=raw.slice(Math.max(0,offset-80),Math.min(raw.length,offset+url.length+80)),kind=classifyUrl(url,surroundingText),occurrence={file:relative3(rootDir,filePath),line,kind,context:compactContext(surroundingText)},existing=byUrl.get(url);if(existing){existing.occurrences.push(occurrence),kindPriority(kind)>kindPriority(existing.kind)&&(existing.kind=kind,existing.rewrite_supported=computeRewriteSupported(kind));continue}byUrl.set(url,{url,kind,rewrite_supported:computeRewriteSupported(kind),occurrences:[occurrence],notes:kind==="video"?["\u5F53\u524D\u7B2C\u4E00\u7248\u4EC5\u626B\u63CF\uFF0C\u4E0D\u81EA\u52A8\u56DE\u5199\u89C6\u9891\u3002"]:[]})}}return[...byUrl.values()].sort((left,right)=>left.url.localeCompare(right.url))}function buildReport(rootDir,files,candidates,reportDir=join12(rootDir,".third-party-design-reports")){let byKind=candidates.reduce((accumulator,item)=>(accumulator[item.kind]=(accumulator[item.kind]??0)+1,accumulator),{}),pendingManualItems=candidates.filter(item=>item.rewrite_supported!==!0);return{tool:"assetize-project-urls",version:1,mode:"scan",project_dir:rootDir,scanned_files:files.map(file=>relative3(rootDir,file)),summary:{scanned_file_count:files.length,unique_remote_candidates:candidates.length,image_count:byKind.image??0,video_count:byKind.video??0,poster_count:byKind.poster??0,unknown_remote_count:byKind.unknown_remote??0},remote_candidates:candidates,pending_videos:candidates.filter(item=>item.kind==="video"),pending_manual_items:pendingManualItems,report_dir:reportDir}}function hashFileContent(filePath){let content=readFileSync16(filePath);return createHash5("sha256").update(content).digest("hex")}function collectReferencedLocalAssetPaths(sourceFilePath,sourceText){let found=new Set;for(let match2 of sourceText.matchAll(LOCAL_ASSET_REF_PATTERN))found.add(resolve10(dirname10(sourceFilePath),match2[1]));for(let match2 of sourceText.matchAll(CSS_URL_PATTERN))found.add(resolve10(dirname10(sourceFilePath),match2[2]));return found}function collectLocalAssetCandidates(rootDir,sourceFiles,assetFiles){let assetPathSet=new Set(assetFiles.map(filePath=>resolve10(filePath))),byHash=new Map,referencedAssets=new Map;for(let sourceFilePath of sourceFiles){let raw=readFileSync16(sourceFilePath,"utf8"),refs=collectReferencedLocalAssetPaths(sourceFilePath,raw);for(let absoluteRef of refs){if(!assetPathSet.has(absoluteRef))continue;let existing=referencedAssets.get(absoluteRef);if(existing){existing.referenced_by.push(relative3(rootDir,sourceFilePath));continue}referencedAssets.set(absoluteRef,{absolute_path:absoluteRef,relative_path:relative3(rootDir,absoluteRef),referenced_by:[relative3(rootDir,sourceFilePath)]})}}for(let asset of referencedAssets.values()){let stats=statSync5(asset.absolute_path),contentHash=hashFileContent(asset.absolute_path),existing=byHash.get(contentHash);if(existing){existing.source_paths.push(asset.relative_path),existing.referenced_by.push(...asset.referenced_by);continue}byHash.set(contentHash,{hash:contentHash,path:asset.relative_path,source_paths:[asset.relative_path],file_name:basename4(asset.absolute_path),size_bytes:stats.size,kind:"local_image",upload_supported:!0,referenced_by:[...asset.referenced_by]})}return[...byHash.values()].sort((left,right)=>left.path.localeCompare(right.path))}function detectProjectType(rootDir,requestedType="auto"){return requestedType==="static-site"||requestedType==="frontend-app"?requestedType:existsSync16(join12(rootDir,"package.json"))?"frontend-app":"static-site"}function collectPathBaseViolations(rootDir,files){let violations=[],textFilePattern=/\.(?:[cm]?[jt]sx?|html?|css)$/i,patterns=[{kind:"root_relative_fetch",regex:/\bfetch\(\s*['"`]\/(?!\/)/g},{kind:"root_relative_href",regex:/\bhref\s*=\s*['"]\/(?!\/)/g},{kind:"root_relative_src",regex:/\bsrc\s*=\s*['"]\/(?!\/)/g}];for(let filePath of files){let relativePath=relative3(rootDir,filePath);if(!textFilePattern.test(relativePath))continue;let lines=readFileSync16(filePath,"utf8").split(/\r?\n/u);for(let index=0;index<lines.length;index+=1){let line=lines[index];for(let pattern of patterns)pattern.regex.lastIndex=0,pattern.regex.test(line)&&violations.push({file:relativePath,line:index+1,kind:pattern.kind,snippet:line.trim().slice(0,180)})}}return violations}function toPosixPath(value){return value.replace(/\\/gu,"/")}function ensureDotRelativePath(value){return value===""||value==="."?"./":value.startsWith("./")||value.startsWith("../")?value:`./${value}`}function resolveRootRelativePathForFile(rootDir,filePath,rootRelativePath){let normalizedTarget=rootRelativePath.replace(/^\/+/u,""),targetPath=join12(rootDir,normalizedTarget),relativePath=relative3(dirname10(filePath),targetPath);return ensureDotRelativePath(toPosixPath(relativePath))}function rewritePathBaseRefsInContent(rootDir,filePath,content){let changed=!1,rewrites=[],patterns=[{regex:/\b(src|href)\s*=\s*(["'])\/(?!\/)([^"'`]+)\2/gu,buildReplacement(attrName,quote,rawPath){let nextPath=resolveRootRelativePathForFile(rootDir,filePath,rawPath);return rewrites.push({kind:"attribute",attr:attrName,from:`/${rawPath}`,to:nextPath}),`${attrName}=${quote}${nextPath}${quote}`}},{regex:/\bfetch\(\s*(["'])\/(?!\/)([^"'`]+)\1/gu,buildReplacement(quote,rawPath){let nextPath=resolveRootRelativePathForFile(rootDir,filePath,rawPath);return rewrites.push({kind:"fetch",from:`/${rawPath}`,to:nextPath}),`fetch(${quote}${nextPath}${quote}`}}],next=content;return next=next.replace(patterns[0].regex,(fullMatch,attrName,quote,rawPath)=>(changed=!0,patterns[0].buildReplacement(attrName,quote,rawPath))),next=next.replace(patterns[1].regex,(fullMatch,quote,rawPath)=>(changed=!0,patterns[1].buildReplacement(quote,rawPath))),{changed,content:next,rewrites}}async function runPathBaseRewrite(args,report,files){let rewrittenFiles=[],rewriteEntries=[],warnings=[];for(let absolutePath of files){let before=readFileSync16(absolutePath,"utf8"),rewritten=rewritePathBaseRefsInContent(report.project_dir,absolutePath,before);rewritten.changed&&(args.dryRun||writeFileSync10(absolutePath,rewritten.content,"utf8"),rewrittenFiles.push(relative3(report.project_dir,absolutePath)),rewriteEntries.push({file:relative3(report.project_dir,absolutePath),rewrites:rewritten.rewrites}))}return rewriteEntries.length>0&&warnings.push(`\u5DF2\u4FEE\u6B63 root-relative \u9759\u6001\u8D44\u6E90\u5F15\u7528: ${rewriteEntries.length} \u4E2A\u6587\u4EF6`),{rewritten_files:rewrittenFiles,rewrite_entries:rewriteEntries,warnings}}function collectSourcePackageBytes(rootDir){let total=0;function visit(currentDir){let entries=readdirSync5(currentDir,{withFileTypes:!0});for(let entry of entries){if(DEFAULT_SKIP_DIRS.has(entry.name))continue;let fullPath=join12(currentDir,entry.name);if(entry.isDirectory()){visit(fullPath);continue}entry.isFile()&&(total+=statSync5(fullPath).size)}}return visit(rootDir),total}function collectPreflightWarnings(rootDir,localAssetCandidates){let warnings=[];existsSync16(join12(rootDir,"pnpm-workspace.yaml"))&&warnings.push({kind:"workspace_like",file:"pnpm-workspace.yaml",message:"\u68C0\u6D4B\u5230 pnpm-workspace.yaml\uFF1B\u540E\u7EED\u6A21\u677F\u627F\u63A5\u6216\u4E91\u7AEF\u6784\u5EFA\u524D\u901A\u5E38\u9700\u8981\u5904\u7406 workspace-like \u7ED3\u6784\u3002"});for(let asset of localAssetCandidates)asset.size_bytes>=PREFLIGHT_LOCAL_ASSET_WARN_BYTES&&warnings.push({kind:"large_local_asset",file:asset.path,size_bytes:asset.size_bytes,message:"\u68C0\u6D4B\u5230\u5927\u4F53\u79EF\u672C\u5730\u56FE\u7247\uFF1B\u5EFA\u8BAE\u5728\u9884\u5904\u7406\u9636\u6BB5\u5B8C\u6210\u4E0A\u4F20\u3001\u56DE\u5199\u4E0E\u6E05\u7406\u3002"});return warnings}function inferExtensionFromMimeType2(mimeType){switch((mimeType||"").toLowerCase()){case"image/png":return".png";case"image/webp":return".webp";case"image/gif":return".gif";case"image/svg+xml":return".svg";case"image/avif":return".avif";case"image/jpeg":case"image/jpg":return".jpg";default:return".jpg"}}function sanitizeFileStem(value){return value.toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,80)}function sanitizeFileName(value){let trimmed=value.trim(),extension=extname3(trimmed).toLowerCase(),stem=trimmed.slice(0,Math.max(0,trimmed.length-extension.length));return`${sanitizeFileStem(stem)||"remote-image"}${extension||".jpg"}`}function inferRemoteFileName(url,mimeType){let extension=inferExtensionFromUrl(url),fallbackExtension=inferExtensionFromMimeType2(mimeType);if(extension)try{let segment=new URL(url).pathname.split("/").filter(Boolean).at(-1);if(segment)return sanitizeFileName(decodeURIComponent(segment))}catch{}try{let parsed=new URL(url),rawSegment=parsed.pathname.split("/").filter(Boolean).at(-1)||parsed.hostname,sanitizedBase=sanitizeFileStem(decodeURIComponent(rawSegment).replace(/\.[a-z0-9]+$/iu,"").trim());if(sanitizedBase)return`${sanitizedBase}${fallbackExtension}`}catch{}switch((mimeType||"").toLowerCase()){case"image/png":return"remote-image.png";case"image/webp":return"remote-image.webp";case"image/gif":return"remote-image.gif";case"image/svg+xml":return"remote-image.svg";case"image/avif":return"remote-image.avif";default:return"remote-image.jpg"}}async function downloadRemoteImage(url,deps={}){let fetchImpl=deps.fetchImpl??fetch,runCurl=deps.runCurl??runCurlProcess;try{return await downloadRemoteImageViaFetch(url,fetchImpl)}catch(error){if(!shouldRetryRemoteDownloadWithCurl(error))throw error;try{return await downloadRemoteImageViaCurl(url,runCurl)}catch(curlError){let fetchMessage=error instanceof Error?error.message:String(error),curlMessage=curlError instanceof Error?curlError.message:String(curlError),unavailable=curlError&&typeof curlError=="object"&&curlError.code==="ENOENT";throw new Error(`${fetchMessage}
|
|
2413
|
-
${unavailable?"[curl_unavailable] ":"[curl_failed] "}${curlMessage}`,{cause:error})}}}async function downloadRemoteImageViaFetch(url,fetchImpl=fetch){let response=await fetchImpl(url,{headers:{accept:"image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"}});if(!response.ok)throw new Error(`\u4E0B\u8F7D\u5931\u8D25\uFF08HTTP ${response.status}\uFF09`);let mimeType=String(response.headers.get("content-type")??"").split(";")[0].trim().toLowerCase();if(mimeType&&!mimeType.startsWith("image/"))throw new Error(`\u8FDC\u7A0B\u8D44\u6E90\u4E0D\u662F\u56FE\u7247\uFF1A${mimeType}`);let content=Buffer.from(await response.arrayBuffer());if(content.byteLength===0)throw new Error("\u8FDC\u7A0B\u56FE\u7247\u5185\u5BB9\u4E3A\u7A7A");return{mimeType,content,fileName:inferRemoteFileName(url,mimeType)}}function shouldRetryRemoteDownloadWithCurl(error){let message=error instanceof Error?error.message:String(error);return/fetch failed|timed?out|econnreset|socket|network|tls|und_err/iu.test(message)}function extractLastContentType(headerText){let matches=[...headerText.matchAll(/^content-type:\s*([^\r\n;]+)/gimu)];return matches.length>0?String(matches[matches.length-1][1]).trim().toLowerCase():""}async function runCurlProcess(executable,args){await new Promise((resolvePromise,reject)=>{let child=spawn(executable,args,{cwd:process.cwd(),env:process.env,stdio:["ignore","ignore","pipe"],shell:!1}),stderr="";child.stderr.on("data",chunk=>{stderr+=String(chunk)}),child.on("error",reject),child.on("close",code2=>{if(code2===0){resolvePromise();return}reject(new Error(stderr.trim()||`curl \u4E0B\u8F7D\u5931\u8D25\uFF08exit ${code2??"unknown"}\uFF09`))})})}async function downloadRemoteImageViaCurl(url,runCurl=runCurlProcess){let tempRoot=mkdtempSync3(join12(tmpdir2(),"platform-assetize-remote-")),outputPath=join12(tempRoot,"remote.bin"),headerPath=join12(tempRoot,"headers.txt");try{let injectedResult=await runCurl("curl",["-L","--fail","--silent","--show-error","-D",headerPath,"-o",outputPath,url]),headerText=typeof injectedResult?.headers=="string"?injectedResult.headers:existsSync16(headerPath)?readFileSync16(headerPath,"utf8"):"",mimeType=extractLastContentType(headerText);if(mimeType&&!mimeType.startsWith("image/"))throw new Error(`\u8FDC\u7A0B\u8D44\u6E90\u4E0D\u662F\u56FE\u7247\uFF1A${mimeType}`);let content=injectedResult?.content?Buffer.from(injectedResult.content):readFileSync16(outputPath);if(content.byteLength===0)throw new Error("\u8FDC\u7A0B\u56FE\u7247\u5185\u5BB9\u4E3A\u7A7A");return{mimeType,content,fileName:inferRemoteFileName(url,mimeType)}}finally{rmSync4(tempRoot,{recursive:!0,force:!0})}}function shouldRetryWithCompression(error){if(error&&typeof error=="object"&&"status"in error&&Number(error.status)===413)return!0;let message=error instanceof Error?error.message:String(error);return/\b413\b/u.test(message)}function buildCompressedFilePath(tempRoot,sourcePath){let safeStem=sanitizeFileStem(basename4(sourcePath,extname3(sourcePath)))||"compressed-image";return join12(tempRoot,`${safeStem}-${LOCAL_IMAGE_UPLOAD_MAX_WIDTH}.jpg`)}function resolveImageCompressionRetry(platform){return platform==="darwin"?{mode:"sips"}:platform==="win32"?{mode:"manual",code:"image_compression_unsupported_on_windows"}:{mode:"manual",code:"image_compression_unavailable"}}async function runSipsCompressor({sourcePath,outputPath}){return await new Promise((resolvePromise,reject)=>{let child=spawn("sips",["-s","format","jpeg","--resampleWidth",String(LOCAL_IMAGE_UPLOAD_MAX_WIDTH),sourcePath,"--out",outputPath],{cwd:process.cwd(),env:process.env,stdio:["ignore","ignore","pipe"],shell:!1}),stderr="";child.stderr.on("data",chunk=>{stderr+=String(chunk)}),child.on("error",reject),child.on("close",code2=>{if(code2===0){resolvePromise();return}reject(new Error(stderr.trim()||`sips \u538B\u7F29\u5931\u8D25\uFF08exit ${code2??"unknown"}\uFF09`))})}),outputPath}function shouldForceHttps(hostname){let lower=hostname.toLowerCase();return lower==="localhost"||lower==="127.0.0.1"||lower==="::1"?!1:HTTPS_FORCE_HOST_SUFFIXES.some(suffix=>lower===suffix||lower.endsWith(`.${suffix}`))}function normalizeUploadedAssetUrl(rawUrl){try{let parsed=new URL(rawUrl);return parsed.protocol==="http:"&&shouldForceHttps(parsed.hostname)?(parsed.protocol="https:",parsed.toString()):rawUrl}catch{return rawUrl}}function replaceUrlInContent(content,originalUrl,finalUrl){return content.split(originalUrl).join(finalUrl)}function normalizeLocalAssetReportPath(args,reportDir){return args.localReport?resolve10(args.localReport):join12(reportDir,"local-asset-report.json")}function loadLocalUploadMappings(reportPath){if(!existsSync16(reportPath))throw new Error(`\u672A\u627E\u5230\u672C\u5730\u7D20\u6750\u4E0A\u4F20\u62A5\u544A: ${reportPath}`);let payload=JSON.parse(readFileSync16(reportPath,"utf8"));if(!Array.isArray(payload.uploaded_local_assets))throw new Error(`\u672C\u5730\u7D20\u6750\u4E0A\u4F20\u62A5\u544A\u683C\u5F0F\u65E0\u6548\uFF0C\u7F3A\u5C11 uploaded_local_assets: ${reportPath}`);let bySourcePath=new Map;for(let item of payload.uploaded_local_assets){if(!item||typeof item.final_url!="string"||!item.final_url.trim()||item.status!=="uploaded"&&item.status!=="uploaded_after_compress"&&item.status!=="reused_from_cache")continue;let allSourcePaths=Array.isArray(item.source_paths)&&item.source_paths.length>0?item.source_paths:[item.source_path];for(let sourcePath of allSourcePaths)typeof sourcePath=="string"&&sourcePath.trim()&&bySourcePath.set(sourcePath,item.final_url)}return{reportPath,bySourcePath}}function rewriteImportedLocalAssets(rootDir,filePath,content,relativePathToUrl){let changed=!1,next=content.replace(IMPORT_LOCAL_ASSET_PATTERN,(fullMatch,leading,identifier,quote,rawRef,trailing)=>{let resolved=relative3(rootDir,resolve10(dirname10(filePath),rawRef)),finalUrl=relativePathToUrl.get(resolved);return finalUrl?(changed=!0,`${leading}const ${identifier} = ${quote}${finalUrl}${quote};${trailing}`):fullMatch});return{changed,content:next}}function rewriteLiteralLocalAssetRefs(rootDir,filePath,content,relativePathToUrl){let changed=!1,next=content.replace(LOCAL_ASSET_REF_PATTERN,(fullMatch,rawRef)=>{let resolved=relative3(rootDir,resolve10(dirname10(filePath),rawRef)),finalUrl=relativePathToUrl.get(resolved);return finalUrl?(changed=!0,fullMatch.replace(rawRef,finalUrl)):fullMatch});return{changed,content:next}}async function runRewriteLocal(args,report,files,cacheContext){let warnings=[];if(!Array.isArray(report.local_asset_candidates)||report.local_asset_candidates.length===0)return{rewritten_files:[],deleted_clean_source_assets:[],warnings};let localReportPath=normalizeLocalAssetReportPath(args,report.report_dir),loaded=loadLocalUploadMappings(localReportPath),relativePathToUrl=loaded.bySourcePath;if(relativePathToUrl.size===0){let message=report.local_asset_candidates.length===0?`\u5F53\u524D\u6E90\u7801\u5305\u672A\u68C0\u6D4B\u5230\u9700\u8981\u56DE\u5199\u7684\u672C\u5730\u7D20\u6750: ${loaded.reportPath}`:`\u672C\u5730\u7D20\u6750\u4E0A\u4F20\u62A5\u544A\u91CC\u6CA1\u6709\u53EF\u56DE\u5199\u7684\u6210\u529F\u4E0A\u4F20\u8BB0\u5F55: ${loaded.reportPath}`;return args.dryRun?{rewritten_files:[],deleted_clean_source_assets:[],warnings:[`dry-run \u6A21\u5F0F\u4E0B\u672A\u751F\u6210\u672C\u5730\u7D20\u6750\u56DE\u5199\u6620\u5C04: ${loaded.reportPath}`]}:{rewritten_files:[],deleted_clean_source_assets:[],warnings:[message]}}let rewrittenFiles=[],deletedLocalAssets=[],hashBySourcePath=new Map;for(let asset of report.local_asset_candidates)for(let sourcePath of asset.source_paths)hashBySourcePath.set(sourcePath,asset.hash);for(let absolutePath of files){let before=readFileSync16(absolutePath,"utf8"),after=before;after=rewriteImportedLocalAssets(report.project_dir,absolutePath,after,relativePathToUrl).content,after=rewriteLiteralLocalAssetRefs(report.project_dir,absolutePath,after,relativePathToUrl).content,after!==before&&(args.dryRun||writeFileSync10(absolutePath,after,"utf8"),rewrittenFiles.push(relative3(report.project_dir,absolutePath)))}if(cacheContext?.enabled&&rewrittenFiles.length>0){cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"rewrite_local_refs"});for(let sourcePath of[...relativePathToUrl.keys()]){let contentHash=hashBySourcePath.get(sourcePath);if(!contentHash)continue;let cacheKey=buildLocalCacheKey(contentHash),cached=cacheContext.cache.entries[cacheKey];cacheEntryReusable(cached)&&updateCacheEntry(cacheContext.cache,cacheKey,{status:"rewritten"})}persistAssetCache(cacheContext.cacheFile,cacheContext.cache)}for(let sourcePath of[...relativePathToUrl.keys()].sort((left,right)=>left.localeCompare(right))){let absolutePath=join12(report.project_dir,sourcePath);if(!existsSync16(absolutePath))continue;let contentHash=hashBySourcePath.get(sourcePath),cacheKey=contentHash?buildLocalCacheKey(contentHash):null;if(cacheContext?.enabled&&cacheKey){cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"cleanup_local_assets",in_progress_keys:[...new Set([...cacheContext.lock.in_progress_keys,cacheKey])]});let cached=cacheContext.cache.entries[cacheKey];cacheEntryReusable(cached)&&(updateCacheEntry(cacheContext.cache,cacheKey,{status:"cleaning"}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache))}args.dryRun||unlinkSync2(absolutePath),deletedLocalAssets.push(sourcePath),cacheContext?.enabled&&cacheKey&&(cacheContext.cache.entries[cacheKey]&&(updateCacheEntry(cacheContext.cache,cacheKey,{status:"cleaned"}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache)),cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{in_progress_keys:cacheContext.lock.in_progress_keys.filter(item=>item!==cacheKey)}))}return warnings.push(`\u5DF2\u57FA\u4E8E\u4E0A\u4F20\u62A5\u544A\u56DE\u5199\u672C\u5730\u56FE\u7247\u5F15\u7528: ${loaded.reportPath}`),{rewritten_files:rewrittenFiles,deleted_clean_source_assets:deletedLocalAssets,warnings}}function copyWorkspaceForPreprocess(sourceDir,cleanSourceDir){rmSync4(cleanSourceDir,{recursive:!0,force:!0}),ensureDir(cleanSourceDir);let entries=readdirSync5(sourceDir,{withFileTypes:!0});for(let entry of entries)DEFAULT_SKIP_DIRS.has(entry.name)||copyWorkspaceEntry(join12(sourceDir,entry.name),join12(cleanSourceDir,entry.name))}function copyWorkspaceEntry(sourcePath,targetPath){let sourceStats=lstatSync(sourcePath,{throwIfNoEntry:!1});if(!sourceStats)throw new Error(`\u9884\u5904\u7406\u590D\u5236\u6E90\u4E0D\u5B58\u5728: ${sourcePath}`);if(sourceStats.isSymbolicLink())throw new Error(`\u9884\u5904\u7406\u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5\uFF0C\u8BF7\u5148\u8F6C\u6362\u4E3A\u666E\u901A\u6587\u4EF6\u6216\u76EE\u5F55: ${sourcePath}`);if(sourceStats.isDirectory()){ensureDir(targetPath);for(let entry of readdirSync5(sourcePath,{withFileTypes:!0}))copyWorkspaceEntry(join12(sourcePath,entry.name),join12(targetPath,entry.name));return}if(sourceStats.isFile()){ensureDir(dirname10(targetPath)),copyFileSync(sourcePath,targetPath);return}throw new Error(`\u9884\u5904\u7406\u4E0D\u652F\u6301\u590D\u5236\u6B64\u6587\u4EF6\u7C7B\u578B: ${sourcePath}`)}function buildPreflightPayload(report,sourceDir,cleanSourceDir,options){return{tool:report.tool,version:report.version,mode:"preprocess",execution_mode:report.execution_mode??"apply",source_dir:sourceDir,clean_source_dir:cleanSourceDir,detected_type:options.detectedType,upstream_source_package_bytes:options.upstreamSourcePackageBytes,clean_source_package_bytes_before_rewrite:options.cleanSourcePackageBytesBeforeRewrite,summary:report.summary,path_base_violations_detected:options.pathBaseViolationsDetected,path_base_rewrites:options.pathBaseRewrites,path_base_violations_remaining:options.pathBaseViolationsRemaining,preflight_warnings:options.preflightWarnings,remote_candidates:report.remote_candidates,local_asset_candidates:report.local_asset_candidates,pending_videos:report.pending_videos,pending_manual_items:report.pending_manual_items}}function buildAssetInventoryPayload(report,rewriteResult,localUploadResult,sourceDir,cleanSourceDir){return{tool:report.tool,version:report.version,mode:"preprocess",execution_mode:report.execution_mode??"apply",source_dir:sourceDir,clean_source_dir:cleanSourceDir,remote_candidates:report.remote_candidates,local_asset_candidates:report.local_asset_candidates,uploaded_assets:rewriteResult.uploaded_assets,uploaded_local_assets:localUploadResult.uploaded_local_assets}}function countAppliedRemoteUploads(rewriteResult){return rewriteResult.uploaded_assets.filter(item=>item.status==="uploaded").length}function countAppliedLocalUploads(localUploadResult){return localUploadResult.uploaded_local_assets.filter(item=>item.status==="uploaded"||item.status==="uploaded_after_compress").length}function buildPlannedActions(report,rewriteResult,localUploadResult,localRewriteResult,pathBaseRewriteResult){return{remote_upload_candidates:rewriteResult.uploaded_assets.length,local_upload_candidates:localUploadResult.uploaded_local_assets.length,path_base_rewrite_candidates:pathBaseRewriteResult.rewritten_files.length,local_cleanup_candidates:localRewriteResult.deleted_clean_source_assets.length,file_rewrite_candidates:rewriteResult.rewritten_files.length+localRewriteResult.rewritten_files.length+pathBaseRewriteResult.rewritten_files.length,pending_video_candidates:report.pending_videos.length}}function buildWarningsPayload(report,importManifest,reportsDir,cacheContext){return{tool:report.tool,version:report.version,mode:"preprocess",execution_mode:report.execution_mode??"apply",source_dir:importManifest.source_dir,clean_source_dir:importManifest.clean_source_dir,warnings:importManifest.warnings,pending_manual_items:report.pending_manual_items,pending_videos:report.pending_videos,cache_warnings:cacheContext?.warnings??[],recovery_actions:{resumed_from_cache:cacheContext?.stats?.resumed_from_cache??!1,reused_uploaded_assets_count:cacheContext?.stats?.remote_reused??0,reused_uploaded_local_assets_count:cacheContext?.stats?.local_reused??0,interrupted_items_count:cacheContext?.stats?.interrupted_items_count??0},report_files:{preflight_report:join12(reportsDir,"preflight-report.json"),asset_inventory:join12(reportsDir,"asset-inventory.json"),import_manifest:join12(reportsDir,"import-manifest.json"),pending_videos:join12(reportsDir,"pending-videos.json")}}}function buildImportManifest(report,rewriteResult,localUploadResult,localRewriteResult,pathBaseRewriteResult,sourceDir,cleanSourceDir,cacheContext){return{tool:report.tool,version:report.version,generated_at:new Date().toISOString(),mode:"preprocess",execution_mode:report.execution_mode??"apply",source_dir:sourceDir,clean_source_dir:cleanSourceDir,cache_dir:cacheContext?.cacheDir??null,cache_enabled:cacheContext?.enabled??!1,resumed_from_cache:cacheContext?.stats?.resumed_from_cache??!1,reused_uploaded_assets_count:cacheContext?.stats?.remote_reused??0,reused_uploaded_local_assets_count:cacheContext?.stats?.local_reused??0,interrupted_items_count:cacheContext?.stats?.interrupted_items_count??0,clean_source_package_bytes:collectSourcePackageBytes(cleanSourceDir),summary:report.summary,planned_actions:buildPlannedActions(report,rewriteResult,localUploadResult,localRewriteResult,pathBaseRewriteResult),asset_mappings:{remote:rewriteResult.uploaded_assets,local:localUploadResult.uploaded_local_assets},rewritten_files:[...rewriteResult.rewritten_files,...localRewriteResult.rewritten_files,...pathBaseRewriteResult.rewritten_files],deleted_clean_source_assets:localRewriteResult.deleted_clean_source_assets,path_base_rewrites:pathBaseRewriteResult.rewrite_entries,pending_videos:report.pending_videos,warnings:[...rewriteResult.warnings,...localUploadResult.warnings,...localRewriteResult.warnings,...pathBaseRewriteResult.warnings]}}async function runRewrite(args,report,cacheContext,deps){let imageCandidates=report.remote_candidates.filter(item=>item.kind==="image"&&item.rewrite_supported===!0),warnings=[],uploads=[],replacements=new Map;if(args.dryRun)return{uploaded_assets:imageCandidates.map(item=>({original_url:item.url,final_url:item.url,status:"dry-run"})),rewritten_files:[],warnings};let tempRoot=mkdtempSync3(join12(tmpdir2(),"platform-assetize-project-"));try{let total=imageCandidates.length,uploadResults=await runWithConcurrency(imageCandidates,REMOTE_IMAGE_CONCURRENCY,async(candidate,index)=>{let itemLabel=`remote image ${index+1}/${total}`,cacheKey=buildRemoteCacheKey(candidate.url),cached=cacheContext?.cache?.entries?.[cacheKey];if(cacheContext?.enabled&&cacheEntryReusable(cached))return logProgress(`${itemLabel} reused from cache: ${candidate.url}`),cacheContext.stats.remote_reused+=1,{candidate,finalUrl:cached.final_url,assetId:cached.asset_id??null,status:"reused_from_cache"};try{cacheContext?.enabled&&(cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"upload_remote",in_progress_keys:[...new Set([...cacheContext.lock.in_progress_keys,cacheKey])]}),updateCacheEntry(cacheContext.cache,cacheKey,{kind:"remote_image",status:"uploading",original_ref:candidate.url}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache));let downloadStart=Date.now();logProgress(`${itemLabel} downloading: ${candidate.url}`);let downloaded=await downloadRemoteImage(candidate.url,{fetchImpl:deps.fetchImpl,runCurl:deps.runCurl}),downloadMs=Date.now()-downloadStart,tempFilePath=join12(tempRoot,`${index+1}-${downloaded.fileName}`);writeFileSync10(tempFilePath,downloaded.content),logProgress(`${itemLabel} downloaded in ${downloadMs}ms, uploading asset`);let uploadStart=Date.now(),uploaded=await deps.uploadAsset({filePath:tempFilePath,title:downloaded.fileName,folderId:args.folderId||void 0}),uploadMs=Date.now()-uploadStart,finalUrl=normalizeUploadedAssetUrl(uploaded.original_url);return logProgress(`${itemLabel} uploaded in ${uploadMs}ms`),finalUrl!==uploaded.original_url&&warnings.push(`\u5DF2\u5C06\u7D20\u6750 URL \u534F\u8BAE\u89C4\u8303\u5316\u4E3A HTTPS: ${uploaded.original_url} -> ${finalUrl}`),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"remote_image",status:"uploaded",original_ref:candidate.url,final_url:finalUrl,asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null,content_digest:`sha256:${createHash5("sha256").update(downloaded.content).digest("hex")}`}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache),cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{in_progress_keys:cacheContext.lock.in_progress_keys.filter(item=>item!==cacheKey)})),{candidate,finalUrl,assetId:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null,status:"uploaded"}}catch(error){let message=error instanceof Error?error.message:String(error);return logProgress(`${itemLabel} failed: ${message}`),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"remote_image",status:"failed",original_ref:candidate.url,last_error:message}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache)),{candidate,error:message,status:"fallback"}}});for(let result of uploadResults){if(result.error){warnings.push(`\u56FE\u7247\u4E0A\u4F20\u5931\u8D25: ${result.candidate.url} (${result.error})`),uploads.push({original_url:result.candidate.url,final_url:result.candidate.url,status:"fallback"});continue}replacements.set(result.candidate.url,result.finalUrl),uploads.push({original_url:result.candidate.url,final_url:result.finalUrl,asset_id:result.assetId??null,status:result.status})}let targetFiles=new Set(imageCandidates.flatMap(candidate=>candidate.occurrences.map(occurrence=>occurrence.file))),rewrittenFiles=[];for(let relativePath of[...targetFiles].sort((left,right)=>left.localeCompare(right))){let absolutePath=join12(report.project_dir,relativePath),before=readFileSync16(absolutePath,"utf8"),after=before;for(let[originalUrl,finalUrl]of replacements)after=replaceUrlInContent(after,originalUrl,finalUrl);after!==before&&(writeFileSync10(absolutePath,after,"utf8"),rewrittenFiles.push(relativePath))}if(cacheContext?.enabled&&rewrittenFiles.length>0){cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"rewrite_remote_refs"});for(let candidate of imageCandidates){let cacheKey=buildRemoteCacheKey(candidate.url),cached=cacheContext.cache.entries[cacheKey];cacheEntryReusable(cached)&&updateCacheEntry(cacheContext.cache,cacheKey,{status:"rewritten"})}persistAssetCache(cacheContext.cacheFile,cacheContext.cache)}return{uploaded_assets:uploads,rewritten_files:rewrittenFiles,warnings}}finally{rmSync4(tempRoot,{recursive:!0,force:!0})}}async function runUploadLocal(args,report,cacheContext,deps){let warnings=[],uploads=[],tempRoot=mkdtempSync3(join12(tmpdir2(),"platform-assetize-local-"));try{if(args.dryRun)return{uploaded_local_assets:report.local_asset_candidates.map(item=>({source_path:item.path,title:item.file_name,status:"dry-run"})),warnings};for(let asset of report.local_asset_candidates){let absolutePath=join12(report.project_dir,asset.path),cacheKey=buildLocalCacheKey(asset.hash),cached=cacheContext?.cache?.entries?.[cacheKey];if(cacheContext?.enabled&&cacheEntryReusable(cached)){uploads.push({source_path:asset.path,source_paths:asset.source_paths,content_hash:asset.hash,title:cached.title??asset.file_name,final_url:cached.final_url,asset_id:cached.asset_id??null,status:"reused_from_cache"}),cacheContext.stats.local_reused+=1;continue}try{cacheContext?.enabled&&(cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"upload_local",in_progress_keys:[...new Set([...cacheContext.lock.in_progress_keys,cacheKey])]}),updateCacheEntry(cacheContext.cache,cacheKey,{kind:"local_image",status:"uploading",source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache));let uploaded=await deps.uploadAsset({filePath:absolutePath,title:asset.file_name,folderId:args.folderId||void 0});uploads.push({source_path:asset.path,source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name,final_url:normalizeUploadedAssetUrl(uploaded.original_url),asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null,status:"uploaded"}),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"local_image",status:"uploaded",source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name,final_url:normalizeUploadedAssetUrl(uploaded.original_url),asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache),cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{in_progress_keys:cacheContext.lock.in_progress_keys.filter(item=>item!==cacheKey)}))}catch(error){if(shouldRetryWithCompression(error)){let hostPlatform=deps.platform??process.platform,retry=resolveImageCompressionRetry(hostPlatform);if(retry.mode==="manual")warnings.push(`[${retry.code}] \u672C\u5730\u56FE\u7247\u8D85\u8FC7\u4E0A\u4F20\u9650\u5236\uFF08HTTP 413\uFF09\uFF0C${hostPlatform==="win32"?"Windows \u6682\u4E0D\u652F\u6301\u81EA\u52A8\u538B\u7F29":"\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u81EA\u52A8\u538B\u7F29"}: ${asset.path}\u3002\u8BF7\u5C06\u56FE\u7247\u5BBD\u5EA6\u538B\u7F29\u81F3\u4E0D\u8D85\u8FC7 ${LOCAL_IMAGE_UPLOAD_MAX_WIDTH}px \u5E76\u51CF\u5C0F\u6587\u4EF6\u4F53\u79EF\uFF0C\u7136\u540E\u6267\u884C\uFF1Aplatform app import preprocess --dir "${report.project_dir}" --reset-cache`);else try{let outputPath=buildCompressedFilePath(tempRoot,absolutePath),compressedPath=await(deps.runCompressor??runSipsCompressor)({sourcePath:absolutePath,outputPath}),uploaded=await deps.uploadAsset({filePath:compressedPath,title:basename4(compressedPath),folderId:args.folderId||void 0});warnings.push(`\u672C\u5730\u56FE\u7247\u8FC7\u5927\uFF0C\u5DF2\u81EA\u52A8\u538B\u7F29\u540E\u4E0A\u4F20: ${asset.path}`),uploads.push({source_path:asset.path,source_paths:asset.source_paths,content_hash:asset.hash,title:basename4(compressedPath),final_url:normalizeUploadedAssetUrl(uploaded.original_url),asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null,status:"uploaded_after_compress"}),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"local_image",status:"uploaded",source_paths:asset.source_paths,content_hash:asset.hash,title:basename4(compressedPath),final_url:normalizeUploadedAssetUrl(uploaded.original_url),asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache),cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{in_progress_keys:cacheContext.lock.in_progress_keys.filter(item=>item!==cacheKey)}));continue}catch(compressionError){warnings.push(`\u672C\u5730\u56FE\u7247\u538B\u7F29\u91CD\u8BD5\u5931\u8D25: ${asset.path} (${compressionError instanceof Error?compressionError.message:String(compressionError)})`)}}warnings.push(`\u672C\u5730\u56FE\u7247\u4E0A\u4F20\u5931\u8D25: ${asset.path} (${error instanceof Error?error.message:String(error)})`),uploads.push({source_path:asset.path,source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name,status:"failed"}),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"local_image",status:"failed",source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name,last_error:error instanceof Error?error.message:String(error)}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache))}}return{uploaded_local_assets:uploads,warnings}}finally{rmSync4(tempRoot,{recursive:!0,force:!0})}}function renderMarkdown(report){let lines=[];if(lines.push("# Scan Report",""),lines.push(`- Project: \`${report.project_dir}\``),lines.push(`- Mode: \`${report.mode}\``),lines.push(`- Scanned files: ${report.summary.scanned_file_count}`),lines.push(`- Unique remote candidates: ${report.summary.unique_remote_candidates}`),lines.push(`- Images: ${report.summary.image_count}`),lines.push(`- Videos: ${report.summary.video_count}`),lines.push(`- Posters: ${report.summary.poster_count}`),lines.push(`- Unknown remote: ${report.summary.unknown_remote_count}`),lines.push(`- Local images: ${report.summary.local_asset_count??0}`,""),report.remote_candidates.length===0&&(!Array.isArray(report.local_asset_candidates)||report.local_asset_candidates.length===0))return lines.push("No candidates found.",""),lines.join(`
|
|
2414
|
+
`))}function parseArgs2(argv){let result={dir:"",include:new Set(DEFAULT_INCLUDE_EXTENSIONS),folderId:"",type:"auto",dryRun:!1,resume:!0,resetCache:!1,localReport:"",json:!1,help:!1};for(let index=0;index<argv.length;index+=1){let arg=argv[index];if(arg==="--help"||arg==="-h"){result.help=!0;continue}if(arg==="--json"){result.json=!0;continue}if(arg==="--dry-run"){result.dryRun=!0;continue}if(arg==="--resume"){result.resume=!0;continue}if(arg==="--reset-cache"){result.resetCache=!0;continue}if(arg==="--dir"){result.dir=argv[index+1]??"",index+=1;continue}if(arg==="--include"){let raw=argv[index+1]??"";index+=1,result.include=normalizeInclude(raw);continue}if(arg==="--folder-id"){result.folderId=argv[index+1]??"",index+=1;continue}if(arg==="--type"){result.type=argv[index+1]??result.type,index+=1;continue}if(arg==="--local-report"){result.localReport=argv[index+1]??"",index+=1;continue}throw new Error(`\u672A\u77E5\u53C2\u6570: ${arg}`)}return result}function normalizeInclude(raw){let values=raw.split(",").map(item=>item.trim().toLowerCase()).filter(Boolean).map(item=>item.startsWith(".")?item:`.${item}`);return values.length>0?new Set(values):new Set(DEFAULT_INCLUDE_EXTENSIONS)}function buildRemoteCacheKey(url){return`remote:${url}`}function buildLocalCacheKey(contentHash){return`local:${contentHash}`}function defaultAssetCache(sourceDir){return{version:CACHE_VERSION,source_dir:sourceDir,entries:{}}}function defaultLockState(){return{version:CACHE_VERSION,active_run_id:null,started_at:null,phase:null,in_progress_keys:[],last_interrupted_at:null}}function readJsonIfExists2(filePath,fallbackValue){if(!existsSync16(filePath))return fallbackValue;try{return JSON.parse(readFileSync16(filePath,"utf8"))}catch{return fallbackValue}}function loadAssetCache(cacheFile,sourceDir){let loaded=readJsonIfExists2(cacheFile,defaultAssetCache(sourceDir));return{version:CACHE_VERSION,source_dir:loaded.source_dir||sourceDir,entries:loaded.entries&&typeof loaded.entries=="object"?loaded.entries:{}}}function persistAssetCache(cacheFile,payload){ensureDir(dirname11(cacheFile)),writeJson2(cacheFile,payload)}function loadLockState(lockFile){let loaded=readJsonIfExists2(lockFile,defaultLockState());return{version:CACHE_VERSION,active_run_id:loaded.active_run_id??null,started_at:loaded.started_at??null,phase:loaded.phase??null,in_progress_keys:Array.isArray(loaded.in_progress_keys)?loaded.in_progress_keys:[],last_interrupted_at:loaded.last_interrupted_at??null}}function persistLockState(lockFile,payload){ensureDir(dirname11(lockFile)),writeJson2(lockFile,payload)}function beginLockRun(lockFile,previousLock){let interruptedItems=previousLock.active_run_id?previousLock.in_progress_keys.length:0,next={version:CACHE_VERSION,active_run_id:`preprocess-${Date.now()}`,started_at:new Date().toISOString(),phase:"scan",in_progress_keys:[],last_interrupted_at:previousLock.active_run_id?new Date().toISOString():previousLock.last_interrupted_at};return persistLockState(lockFile,next),{lock:next,interruptedItems}}function updateLockState(lockFile,currentLock,patch){let next={...currentLock,...patch};return persistLockState(lockFile,next),next}function completeLockRun(lockFile,currentLock){let next={...currentLock,active_run_id:null,phase:"completed",in_progress_keys:[]};return persistLockState(lockFile,next),next}function cacheEntryReusable(entry){return!!(entry&&typeof entry.final_url=="string"&&entry.final_url.trim()&&entry.asset_id&&entry.status!=="failed")}function updateCacheEntry(cache,cacheKey,patch){cache.entries[cacheKey]={...cache.entries[cacheKey]??{},...patch,updated_at:new Date().toISOString()}}function walkFiles(rootDir,includeExtensions){let files=[];function visit(currentDir){let entries=readdirSync6(currentDir,{withFileTypes:!0});for(let entry of entries){let fullPath=join12(currentDir,entry.name);if(entry.isDirectory()){if(DEFAULT_SKIP_DIRS.has(entry.name))continue;visit(fullPath);continue}if(!entry.isFile())continue;let extension=extname3(entry.name).toLowerCase();includeExtensions.has(extension)&&files.push(fullPath)}}return visit(rootDir),files.sort((left,right)=>left.localeCompare(right))}function walkAssetFiles(rootDir){let files=[];function visit(currentDir){let entries=readdirSync6(currentDir,{withFileTypes:!0});for(let entry of entries){let fullPath=join12(currentDir,entry.name);if(entry.isDirectory()){if(DEFAULT_SKIP_DIRS.has(entry.name))continue;visit(fullPath);continue}if(!entry.isFile())continue;let extension=extname3(entry.name).toLowerCase();IMAGE_EXTENSIONS.has(extension)&&files.push(fullPath)}}return visit(rootDir),files.sort((left,right)=>left.localeCompare(right))}function normalizeMatchedUrl(rawUrl){return rawUrl.replace(/[),.;]+$/u,"").replace(/^("?|"?|'?|'?)+/iu,"").replace(/("?|"?|'?|'?)+$/iu,"").replace(/&/giu,"&")}function findLineNumber(text2,offset){let line=1;for(let index=0;index<offset;index+=1)text2.charCodeAt(index)===10&&(line+=1);return line}function inferExtensionFromUrl(url){try{let parsed=new URL(url);return extname3(parsed.pathname).toLowerCase()}catch{return extname3(url).toLowerCase()}}function classifyUrl(url,surroundingText){let lowerUrl=url.toLowerCase(),extension=inferExtensionFromUrl(lowerUrl),lowerContext=surroundingText.toLowerCase(),nonImageContext=lowerContext.includes("<script")||lowerContext.includes("script src")||lowerContext.includes('rel="stylesheet"')||lowerContext.includes("rel='stylesheet'")||lowerContext.includes("xmlns="),nonImageUrl=lowerUrl.includes("cdn.tailwindcss.com")||lowerUrl.includes("fonts.googleapis.com")||lowerUrl.includes("fonts.gstatic.com")||lowerUrl.includes("w3.org/2000/svg");return lowerContext.includes("poster")?"poster":VIDEO_EXTENSIONS.has(extension)?"video":nonImageContext||nonImageUrl||extension===".js"||extension===".mjs"||extension===".css"?"unknown_remote":IMAGE_EXTENSIONS.has(extension)||IMAGE_HOST_HINTS.some(item=>lowerUrl.includes(item))||lowerContext.includes("<img")||lowerContext.includes("background-image")||lowerContext.includes("url(")?"image":"unknown_remote"}function computeRewriteSupported(kind){return kind==="image"}function compactContext(value){return value.replace(/\s+/gu," ").trim().slice(0,200)}function kindPriority(kind){switch(kind){case"video":return 4;case"poster":return 3;case"image":return 2;default:return 1}}function collectRemoteCandidates(rootDir,files){let byUrl=new Map;for(let filePath of files){let raw=readFileSync16(filePath,"utf8");for(let match2 of raw.matchAll(URL_PATTERN)){let matched=match2[0],offset=match2.index??0,url=normalizeMatchedUrl(matched),line=findLineNumber(raw,offset),surroundingText=raw.slice(Math.max(0,offset-80),Math.min(raw.length,offset+url.length+80)),kind=classifyUrl(url,surroundingText),occurrence={file:relative4(rootDir,filePath),line,kind,context:compactContext(surroundingText)},existing=byUrl.get(url);if(existing){existing.occurrences.push(occurrence),kindPriority(kind)>kindPriority(existing.kind)&&(existing.kind=kind,existing.rewrite_supported=computeRewriteSupported(kind));continue}byUrl.set(url,{url,kind,rewrite_supported:computeRewriteSupported(kind),occurrences:[occurrence],notes:kind==="video"?["\u5F53\u524D\u7B2C\u4E00\u7248\u4EC5\u626B\u63CF\uFF0C\u4E0D\u81EA\u52A8\u56DE\u5199\u89C6\u9891\u3002"]:[]})}}return[...byUrl.values()].sort((left,right)=>left.url.localeCompare(right.url))}function buildReport(rootDir,files,candidates,reportDir=join12(rootDir,".third-party-design-reports")){let byKind=candidates.reduce((accumulator,item)=>(accumulator[item.kind]=(accumulator[item.kind]??0)+1,accumulator),{}),pendingManualItems=candidates.filter(item=>item.rewrite_supported!==!0);return{tool:"assetize-project-urls",version:1,mode:"scan",project_dir:rootDir,scanned_files:files.map(file=>relative4(rootDir,file)),summary:{scanned_file_count:files.length,unique_remote_candidates:candidates.length,image_count:byKind.image??0,video_count:byKind.video??0,poster_count:byKind.poster??0,unknown_remote_count:byKind.unknown_remote??0},remote_candidates:candidates,pending_videos:candidates.filter(item=>item.kind==="video"),pending_manual_items:pendingManualItems,report_dir:reportDir}}function hashFileContent(filePath){let content=readFileSync16(filePath);return createHash5("sha256").update(content).digest("hex")}function collectReferencedLocalAssetPaths(sourceFilePath,sourceText){let found=new Set;for(let match2 of sourceText.matchAll(LOCAL_ASSET_REF_PATTERN))found.add(resolve10(dirname11(sourceFilePath),match2[1]));for(let match2 of sourceText.matchAll(CSS_URL_PATTERN))found.add(resolve10(dirname11(sourceFilePath),match2[2]));return found}function collectLocalAssetCandidates(rootDir,sourceFiles,assetFiles){let assetPathSet=new Set(assetFiles.map(filePath=>resolve10(filePath))),byHash=new Map,referencedAssets=new Map;for(let sourceFilePath of sourceFiles){let raw=readFileSync16(sourceFilePath,"utf8"),refs=collectReferencedLocalAssetPaths(sourceFilePath,raw);for(let absoluteRef of refs){if(!assetPathSet.has(absoluteRef))continue;let existing=referencedAssets.get(absoluteRef);if(existing){existing.referenced_by.push(relative4(rootDir,sourceFilePath));continue}referencedAssets.set(absoluteRef,{absolute_path:absoluteRef,relative_path:relative4(rootDir,absoluteRef),referenced_by:[relative4(rootDir,sourceFilePath)]})}}for(let asset of referencedAssets.values()){let stats=statSync4(asset.absolute_path),contentHash=hashFileContent(asset.absolute_path),existing=byHash.get(contentHash);if(existing){existing.source_paths.push(asset.relative_path),existing.referenced_by.push(...asset.referenced_by);continue}byHash.set(contentHash,{hash:contentHash,path:asset.relative_path,source_paths:[asset.relative_path],file_name:basename5(asset.absolute_path),size_bytes:stats.size,kind:"local_image",upload_supported:!0,referenced_by:[...asset.referenced_by]})}return[...byHash.values()].sort((left,right)=>left.path.localeCompare(right.path))}function detectProjectType(rootDir,requestedType="auto"){return requestedType==="static-site"||requestedType==="frontend-app"?requestedType:existsSync16(join12(rootDir,"package.json"))?"frontend-app":"static-site"}function collectPathBaseViolations(rootDir,files){let violations=[],textFilePattern=/\.(?:[cm]?[jt]sx?|html?|css)$/i,patterns=[{kind:"root_relative_fetch",regex:/\bfetch\(\s*['"`]\/(?!\/)/g},{kind:"root_relative_href",regex:/\bhref\s*=\s*['"]\/(?!\/)/g},{kind:"root_relative_src",regex:/\bsrc\s*=\s*['"]\/(?!\/)/g}];for(let filePath of files){let relativePath=relative4(rootDir,filePath);if(!textFilePattern.test(relativePath))continue;let lines=readFileSync16(filePath,"utf8").split(/\r?\n/u);for(let index=0;index<lines.length;index+=1){let line=lines[index];for(let pattern of patterns)pattern.regex.lastIndex=0,pattern.regex.test(line)&&violations.push({file:relativePath,line:index+1,kind:pattern.kind,snippet:line.trim().slice(0,180)})}}return violations}function toPosixPath(value){return value.replace(/\\/gu,"/")}function ensureDotRelativePath(value){return value===""||value==="."?"./":value.startsWith("./")||value.startsWith("../")?value:`./${value}`}function resolveRootRelativePathForFile(rootDir,filePath,rootRelativePath){let normalizedTarget=rootRelativePath.replace(/^\/+/u,""),targetPath=join12(rootDir,normalizedTarget),relativePath=relative4(dirname11(filePath),targetPath);return ensureDotRelativePath(toPosixPath(relativePath))}function rewritePathBaseRefsInContent(rootDir,filePath,content){let changed=!1,rewrites=[],patterns=[{regex:/\b(src|href)\s*=\s*(["'])\/(?!\/)([^"'`]+)\2/gu,buildReplacement(attrName,quote,rawPath){let nextPath=resolveRootRelativePathForFile(rootDir,filePath,rawPath);return rewrites.push({kind:"attribute",attr:attrName,from:`/${rawPath}`,to:nextPath}),`${attrName}=${quote}${nextPath}${quote}`}},{regex:/\bfetch\(\s*(["'])\/(?!\/)([^"'`]+)\1/gu,buildReplacement(quote,rawPath){let nextPath=resolveRootRelativePathForFile(rootDir,filePath,rawPath);return rewrites.push({kind:"fetch",from:`/${rawPath}`,to:nextPath}),`fetch(${quote}${nextPath}${quote}`}}],next=content;return next=next.replace(patterns[0].regex,(fullMatch,attrName,quote,rawPath)=>(changed=!0,patterns[0].buildReplacement(attrName,quote,rawPath))),next=next.replace(patterns[1].regex,(fullMatch,quote,rawPath)=>(changed=!0,patterns[1].buildReplacement(quote,rawPath))),{changed,content:next,rewrites}}async function runPathBaseRewrite(args,report,files){let rewrittenFiles=[],rewriteEntries=[],warnings=[];for(let absolutePath of files){let before=readFileSync16(absolutePath,"utf8"),rewritten=rewritePathBaseRefsInContent(report.project_dir,absolutePath,before);rewritten.changed&&(args.dryRun||writeFileSync10(absolutePath,rewritten.content,"utf8"),rewrittenFiles.push(relative4(report.project_dir,absolutePath)),rewriteEntries.push({file:relative4(report.project_dir,absolutePath),rewrites:rewritten.rewrites}))}return rewriteEntries.length>0&&warnings.push(`\u5DF2\u4FEE\u6B63 root-relative \u9759\u6001\u8D44\u6E90\u5F15\u7528: ${rewriteEntries.length} \u4E2A\u6587\u4EF6`),{rewritten_files:rewrittenFiles,rewrite_entries:rewriteEntries,warnings}}function collectSourcePackageBytes(rootDir){let total=0;function visit(currentDir){let entries=readdirSync6(currentDir,{withFileTypes:!0});for(let entry of entries){if(DEFAULT_SKIP_DIRS.has(entry.name))continue;let fullPath=join12(currentDir,entry.name);if(entry.isDirectory()){visit(fullPath);continue}entry.isFile()&&(total+=statSync4(fullPath).size)}}return visit(rootDir),total}function collectPreflightWarnings(rootDir,localAssetCandidates){let warnings=[];existsSync16(join12(rootDir,"pnpm-workspace.yaml"))&&warnings.push({kind:"workspace_like",file:"pnpm-workspace.yaml",message:"\u68C0\u6D4B\u5230 pnpm-workspace.yaml\uFF1B\u540E\u7EED\u6A21\u677F\u627F\u63A5\u6216\u4E91\u7AEF\u6784\u5EFA\u524D\u901A\u5E38\u9700\u8981\u5904\u7406 workspace-like \u7ED3\u6784\u3002"});for(let asset of localAssetCandidates)asset.size_bytes>=PREFLIGHT_LOCAL_ASSET_WARN_BYTES&&warnings.push({kind:"large_local_asset",file:asset.path,size_bytes:asset.size_bytes,message:"\u68C0\u6D4B\u5230\u5927\u4F53\u79EF\u672C\u5730\u56FE\u7247\uFF1B\u5EFA\u8BAE\u5728\u9884\u5904\u7406\u9636\u6BB5\u5B8C\u6210\u4E0A\u4F20\u3001\u56DE\u5199\u4E0E\u6E05\u7406\u3002"});return warnings}function inferExtensionFromMimeType2(mimeType){switch((mimeType||"").toLowerCase()){case"image/png":return".png";case"image/webp":return".webp";case"image/gif":return".gif";case"image/svg+xml":return".svg";case"image/avif":return".avif";case"image/bmp":case"image/x-ms-bmp":return".bmp";case"image/x-icon":case"image/vnd.microsoft.icon":return".ico";case"image/jpeg":case"image/jpg":return".jpg";default:return".jpg"}}function sanitizeFileStem(value){return value.toLowerCase().replace(/[^a-z0-9]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,80)}function sanitizeFileName(value){let trimmed=value.trim(),extension=extname3(trimmed).toLowerCase(),stem=trimmed.slice(0,Math.max(0,trimmed.length-extension.length));return`${sanitizeFileStem(stem)||"remote-image"}${extension||".jpg"}`}function inferRemoteFileName(url,mimeType){let extension=inferExtensionFromUrl(url),fallbackExtension=inferExtensionFromMimeType2(mimeType);if(extension)try{let segment=new URL(url).pathname.split("/").filter(Boolean).at(-1);if(segment)return sanitizeFileName(decodeURIComponent(segment))}catch{}try{let parsed=new URL(url),rawSegment=parsed.pathname.split("/").filter(Boolean).at(-1)||parsed.hostname,sanitizedBase=sanitizeFileStem(decodeURIComponent(rawSegment).replace(/\.[a-z0-9]+$/iu,"").trim());if(sanitizedBase)return`${sanitizedBase}${fallbackExtension}`}catch{}switch((mimeType||"").toLowerCase()){case"image/png":return"remote-image.png";case"image/webp":return"remote-image.webp";case"image/gif":return"remote-image.gif";case"image/svg+xml":return"remote-image.svg";case"image/avif":return"remote-image.avif";case"image/bmp":case"image/x-ms-bmp":return"remote-image.bmp";case"image/x-icon":case"image/vnd.microsoft.icon":return"remote-image.ico";default:return"remote-image.jpg"}}async function downloadRemoteImage(url,deps={}){let fetchImpl=deps.fetchImpl??fetch,runCurl=deps.runCurl??runCurlProcess;try{return await downloadRemoteImageViaFetch(url,fetchImpl)}catch(error){if(!shouldRetryRemoteDownloadWithCurl(error))throw error;try{return await downloadRemoteImageViaCurl(url,runCurl)}catch(curlError){let fetchMessage=error instanceof Error?error.message:String(error),curlMessage=curlError instanceof Error?curlError.message:String(curlError),unavailable=curlError&&typeof curlError=="object"&&curlError.code==="ENOENT";throw new Error(`${fetchMessage}
|
|
2415
|
+
${unavailable?"[curl_unavailable] ":"[curl_failed] "}${curlMessage}`,{cause:error})}}}async function downloadRemoteImageViaFetch(url,fetchImpl=fetch){let response=await fetchImpl(url,{headers:{accept:"image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"}});if(!response.ok)throw new Error(`\u4E0B\u8F7D\u5931\u8D25\uFF08HTTP ${response.status}\uFF09`);let mimeType=String(response.headers.get("content-type")??"").split(";")[0].trim().toLowerCase();if(mimeType&&!mimeType.startsWith("image/"))throw new Error(`\u8FDC\u7A0B\u8D44\u6E90\u4E0D\u662F\u56FE\u7247\uFF1A${mimeType}`);let content=Buffer.from(await response.arrayBuffer());if(content.byteLength===0)throw new Error("\u8FDC\u7A0B\u56FE\u7247\u5185\u5BB9\u4E3A\u7A7A");return{mimeType,content,fileName:inferRemoteFileName(url,mimeType)}}function shouldRetryRemoteDownloadWithCurl(error){let message=error instanceof Error?error.message:String(error);return/fetch failed|timed?out|econnreset|socket|network|tls|und_err/iu.test(message)}function extractLastContentType(headerText){let matches=[...headerText.matchAll(/^content-type:\s*([^\r\n;]+)/gimu)];return matches.length>0?String(matches[matches.length-1][1]).trim().toLowerCase():""}async function runCurlProcess(executable,args){await new Promise((resolvePromise,reject)=>{let child=spawn(executable,args,{cwd:process.cwd(),env:process.env,stdio:["ignore","ignore","pipe"],shell:!1}),stderr="";child.stderr.on("data",chunk=>{stderr+=String(chunk)}),child.on("error",reject),child.on("close",code2=>{if(code2===0){resolvePromise();return}reject(new Error(stderr.trim()||`curl \u4E0B\u8F7D\u5931\u8D25\uFF08exit ${code2??"unknown"}\uFF09`))})})}async function downloadRemoteImageViaCurl(url,runCurl=runCurlProcess){let tempRoot=mkdtempSync3(join12(tmpdir2(),"platform-assetize-remote-")),outputPath=join12(tempRoot,"remote.bin"),headerPath=join12(tempRoot,"headers.txt");try{let injectedResult=await runCurl("curl",["-L","--fail","--silent","--show-error","-D",headerPath,"-o",outputPath,url]),headerText=typeof injectedResult?.headers=="string"?injectedResult.headers:existsSync16(headerPath)?readFileSync16(headerPath,"utf8"):"",mimeType=extractLastContentType(headerText);if(mimeType&&!mimeType.startsWith("image/"))throw new Error(`\u8FDC\u7A0B\u8D44\u6E90\u4E0D\u662F\u56FE\u7247\uFF1A${mimeType}`);let content=injectedResult?.content?Buffer.from(injectedResult.content):readFileSync16(outputPath);if(content.byteLength===0)throw new Error("\u8FDC\u7A0B\u56FE\u7247\u5185\u5BB9\u4E3A\u7A7A");return{mimeType,content,fileName:inferRemoteFileName(url,mimeType)}}finally{rmSync4(tempRoot,{recursive:!0,force:!0})}}function shouldRetryWithCompression(error){if(error&&typeof error=="object"&&"status"in error&&Number(error.status)===413)return!0;let message=error instanceof Error?error.message:String(error);return/\b413\b/u.test(message)}function buildCompressedFilePath(tempRoot,sourcePath){let safeStem=sanitizeFileStem(basename5(sourcePath,extname3(sourcePath)))||"compressed-image";return join12(tempRoot,`${safeStem}-${LOCAL_IMAGE_UPLOAD_MAX_WIDTH}.jpg`)}function resolveImageCompressionRetry(platform){return platform==="darwin"?{mode:"sips"}:platform==="win32"?{mode:"manual",code:"image_compression_unsupported_on_windows"}:{mode:"manual",code:"image_compression_unavailable"}}async function runSipsCompressor({sourcePath,outputPath}){return await new Promise((resolvePromise,reject)=>{let child=spawn("sips",["-s","format","jpeg","--resampleWidth",String(LOCAL_IMAGE_UPLOAD_MAX_WIDTH),sourcePath,"--out",outputPath],{cwd:process.cwd(),env:process.env,stdio:["ignore","ignore","pipe"],shell:!1}),stderr="";child.stderr.on("data",chunk=>{stderr+=String(chunk)}),child.on("error",reject),child.on("close",code2=>{if(code2===0){resolvePromise();return}reject(new Error(stderr.trim()||`sips \u538B\u7F29\u5931\u8D25\uFF08exit ${code2??"unknown"}\uFF09`))})}),outputPath}function shouldForceHttps(hostname){let lower=hostname.toLowerCase();return lower==="localhost"||lower==="127.0.0.1"||lower==="::1"?!1:HTTPS_FORCE_HOST_SUFFIXES.some(suffix=>lower===suffix||lower.endsWith(`.${suffix}`))}function normalizeUploadedAssetUrl(rawUrl){try{let parsed=new URL(rawUrl);return parsed.protocol==="http:"&&shouldForceHttps(parsed.hostname)?(parsed.protocol="https:",parsed.toString()):rawUrl}catch{return rawUrl}}function replaceUrlInContent(content,originalUrl,finalUrl){return content.split(originalUrl).join(finalUrl)}function normalizeLocalAssetReportPath(args,reportDir){return args.localReport?resolve10(args.localReport):join12(reportDir,"local-asset-report.json")}function loadLocalUploadMappings(reportPath){if(!existsSync16(reportPath))throw new Error(`\u672A\u627E\u5230\u672C\u5730\u7D20\u6750\u4E0A\u4F20\u62A5\u544A: ${reportPath}`);let payload=JSON.parse(readFileSync16(reportPath,"utf8"));if(!Array.isArray(payload.uploaded_local_assets))throw new Error(`\u672C\u5730\u7D20\u6750\u4E0A\u4F20\u62A5\u544A\u683C\u5F0F\u65E0\u6548\uFF0C\u7F3A\u5C11 uploaded_local_assets: ${reportPath}`);let bySourcePath=new Map;for(let item of payload.uploaded_local_assets){if(!item||typeof item.final_url!="string"||!item.final_url.trim()||item.status!=="uploaded"&&item.status!=="uploaded_after_compress"&&item.status!=="reused_from_cache")continue;let allSourcePaths=Array.isArray(item.source_paths)&&item.source_paths.length>0?item.source_paths:[item.source_path];for(let sourcePath of allSourcePaths)typeof sourcePath=="string"&&sourcePath.trim()&&bySourcePath.set(sourcePath,item.final_url)}return{reportPath,bySourcePath}}function rewriteImportedLocalAssets(rootDir,filePath,content,relativePathToUrl){let changed=!1,next=content.replace(IMPORT_LOCAL_ASSET_PATTERN,(fullMatch,leading,identifier,quote,rawRef,trailing)=>{let resolved=relative4(rootDir,resolve10(dirname11(filePath),rawRef)),finalUrl=relativePathToUrl.get(resolved);return finalUrl?(changed=!0,`${leading}const ${identifier} = ${quote}${finalUrl}${quote};${trailing}`):fullMatch});return{changed,content:next}}function rewriteLiteralLocalAssetRefs(rootDir,filePath,content,relativePathToUrl){let changed=!1,next=content.replace(LOCAL_ASSET_REF_PATTERN,(fullMatch,rawRef)=>{let resolved=relative4(rootDir,resolve10(dirname11(filePath),rawRef)),finalUrl=relativePathToUrl.get(resolved);return finalUrl?(changed=!0,fullMatch.replace(rawRef,finalUrl)):fullMatch});return{changed,content:next}}async function runRewriteLocal(args,report,files,cacheContext){let warnings=[];if(!Array.isArray(report.local_asset_candidates)||report.local_asset_candidates.length===0)return{rewritten_files:[],deleted_clean_source_assets:[],warnings};let localReportPath=normalizeLocalAssetReportPath(args,report.report_dir),loaded=loadLocalUploadMappings(localReportPath),relativePathToUrl=loaded.bySourcePath;if(relativePathToUrl.size===0){let message=report.local_asset_candidates.length===0?`\u5F53\u524D\u6E90\u7801\u5305\u672A\u68C0\u6D4B\u5230\u9700\u8981\u56DE\u5199\u7684\u672C\u5730\u7D20\u6750: ${loaded.reportPath}`:`\u672C\u5730\u7D20\u6750\u4E0A\u4F20\u62A5\u544A\u91CC\u6CA1\u6709\u53EF\u56DE\u5199\u7684\u6210\u529F\u4E0A\u4F20\u8BB0\u5F55: ${loaded.reportPath}`;return args.dryRun?{rewritten_files:[],deleted_clean_source_assets:[],warnings:[`dry-run \u6A21\u5F0F\u4E0B\u672A\u751F\u6210\u672C\u5730\u7D20\u6750\u56DE\u5199\u6620\u5C04: ${loaded.reportPath}`]}:{rewritten_files:[],deleted_clean_source_assets:[],warnings:[message]}}let rewrittenFiles=[],deletedLocalAssets=[],hashBySourcePath=new Map;for(let asset of report.local_asset_candidates)for(let sourcePath of asset.source_paths)hashBySourcePath.set(sourcePath,asset.hash);for(let absolutePath of files){let before=readFileSync16(absolutePath,"utf8"),after=before;after=rewriteImportedLocalAssets(report.project_dir,absolutePath,after,relativePathToUrl).content,after=rewriteLiteralLocalAssetRefs(report.project_dir,absolutePath,after,relativePathToUrl).content,after!==before&&(args.dryRun||writeFileSync10(absolutePath,after,"utf8"),rewrittenFiles.push(relative4(report.project_dir,absolutePath)))}if(cacheContext?.enabled&&rewrittenFiles.length>0){cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"rewrite_local_refs"});for(let sourcePath of[...relativePathToUrl.keys()]){let contentHash=hashBySourcePath.get(sourcePath);if(!contentHash)continue;let cacheKey=buildLocalCacheKey(contentHash),cached=cacheContext.cache.entries[cacheKey];cacheEntryReusable(cached)&&updateCacheEntry(cacheContext.cache,cacheKey,{status:"rewritten"})}persistAssetCache(cacheContext.cacheFile,cacheContext.cache)}for(let sourcePath of[...relativePathToUrl.keys()].sort((left,right)=>left.localeCompare(right))){let absolutePath=join12(report.project_dir,sourcePath);if(!existsSync16(absolutePath))continue;let contentHash=hashBySourcePath.get(sourcePath),cacheKey=contentHash?buildLocalCacheKey(contentHash):null;if(cacheContext?.enabled&&cacheKey){cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"cleanup_local_assets",in_progress_keys:[...new Set([...cacheContext.lock.in_progress_keys,cacheKey])]});let cached=cacheContext.cache.entries[cacheKey];cacheEntryReusable(cached)&&(updateCacheEntry(cacheContext.cache,cacheKey,{status:"cleaning"}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache))}args.dryRun||unlinkSync2(absolutePath),deletedLocalAssets.push(sourcePath),cacheContext?.enabled&&cacheKey&&(cacheContext.cache.entries[cacheKey]&&(updateCacheEntry(cacheContext.cache,cacheKey,{status:"cleaned"}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache)),cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{in_progress_keys:cacheContext.lock.in_progress_keys.filter(item=>item!==cacheKey)}))}return warnings.push(`\u5DF2\u57FA\u4E8E\u4E0A\u4F20\u62A5\u544A\u56DE\u5199\u672C\u5730\u56FE\u7247\u5F15\u7528: ${loaded.reportPath}`),{rewritten_files:rewrittenFiles,deleted_clean_source_assets:deletedLocalAssets,warnings}}function copyWorkspaceForPreprocess(sourceDir,cleanSourceDir){rmSync4(cleanSourceDir,{recursive:!0,force:!0}),ensureDir(cleanSourceDir);let entries=readdirSync6(sourceDir,{withFileTypes:!0});for(let entry of entries)DEFAULT_SKIP_DIRS.has(entry.name)||copyWorkspaceEntry(join12(sourceDir,entry.name),join12(cleanSourceDir,entry.name))}function copyWorkspaceEntry(sourcePath,targetPath){let sourceStats=lstatSync2(sourcePath,{throwIfNoEntry:!1});if(!sourceStats)throw new Error(`\u9884\u5904\u7406\u590D\u5236\u6E90\u4E0D\u5B58\u5728: ${sourcePath}`);if(sourceStats.isSymbolicLink())throw new Error(`\u9884\u5904\u7406\u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5\uFF0C\u8BF7\u5148\u8F6C\u6362\u4E3A\u666E\u901A\u6587\u4EF6\u6216\u76EE\u5F55: ${sourcePath}`);if(sourceStats.isDirectory()){ensureDir(targetPath);for(let entry of readdirSync6(sourcePath,{withFileTypes:!0}))copyWorkspaceEntry(join12(sourcePath,entry.name),join12(targetPath,entry.name));return}if(sourceStats.isFile()){ensureDir(dirname11(targetPath)),copyFileSync2(sourcePath,targetPath);return}throw new Error(`\u9884\u5904\u7406\u4E0D\u652F\u6301\u590D\u5236\u6B64\u6587\u4EF6\u7C7B\u578B: ${sourcePath}`)}function buildPreflightPayload(report,sourceDir,cleanSourceDir,options){return{tool:report.tool,version:report.version,mode:"preprocess",execution_mode:report.execution_mode??"apply",source_dir:sourceDir,clean_source_dir:cleanSourceDir,detected_type:options.detectedType,upstream_source_package_bytes:options.upstreamSourcePackageBytes,clean_source_package_bytes_before_rewrite:options.cleanSourcePackageBytesBeforeRewrite,summary:report.summary,path_base_violations_detected:options.pathBaseViolationsDetected,path_base_rewrites:options.pathBaseRewrites,path_base_violations_remaining:options.pathBaseViolationsRemaining,preflight_warnings:options.preflightWarnings,remote_candidates:report.remote_candidates,local_asset_candidates:report.local_asset_candidates,pending_videos:report.pending_videos,pending_manual_items:report.pending_manual_items}}function buildAssetInventoryPayload(report,rewriteResult,localUploadResult,sourceDir,cleanSourceDir){return{tool:report.tool,version:report.version,mode:"preprocess",execution_mode:report.execution_mode??"apply",source_dir:sourceDir,clean_source_dir:cleanSourceDir,remote_candidates:report.remote_candidates,local_asset_candidates:report.local_asset_candidates,uploaded_assets:rewriteResult.uploaded_assets,uploaded_local_assets:localUploadResult.uploaded_local_assets}}function countAppliedRemoteUploads(rewriteResult){return rewriteResult.uploaded_assets.filter(item=>item.status==="uploaded").length}function countAppliedLocalUploads(localUploadResult){return localUploadResult.uploaded_local_assets.filter(item=>item.status==="uploaded"||item.status==="uploaded_after_compress").length}function buildPlannedActions(report,rewriteResult,localUploadResult,localRewriteResult,pathBaseRewriteResult){return{remote_upload_candidates:rewriteResult.uploaded_assets.length,local_upload_candidates:localUploadResult.uploaded_local_assets.length,path_base_rewrite_candidates:pathBaseRewriteResult.rewritten_files.length,local_cleanup_candidates:localRewriteResult.deleted_clean_source_assets.length,file_rewrite_candidates:rewriteResult.rewritten_files.length+localRewriteResult.rewritten_files.length+pathBaseRewriteResult.rewritten_files.length,pending_video_candidates:report.pending_videos.length}}function buildWarningsPayload(report,importManifest,reportsDir,cacheContext){return{tool:report.tool,version:report.version,mode:"preprocess",execution_mode:report.execution_mode??"apply",source_dir:importManifest.source_dir,clean_source_dir:importManifest.clean_source_dir,warnings:importManifest.warnings,pending_manual_items:report.pending_manual_items,pending_videos:report.pending_videos,cache_warnings:cacheContext?.warnings??[],recovery_actions:{resumed_from_cache:cacheContext?.stats?.resumed_from_cache??!1,reused_uploaded_assets_count:cacheContext?.stats?.remote_reused??0,reused_uploaded_local_assets_count:cacheContext?.stats?.local_reused??0,interrupted_items_count:cacheContext?.stats?.interrupted_items_count??0},report_files:{preflight_report:join12(reportsDir,"preflight-report.json"),asset_inventory:join12(reportsDir,"asset-inventory.json"),import_manifest:join12(reportsDir,"import-manifest.json"),pending_videos:join12(reportsDir,"pending-videos.json")}}}function buildImportManifest(report,rewriteResult,localUploadResult,localRewriteResult,pathBaseRewriteResult,sourceDir,cleanSourceDir,cacheContext){return{tool:report.tool,version:report.version,generated_at:new Date().toISOString(),mode:"preprocess",execution_mode:report.execution_mode??"apply",source_dir:sourceDir,clean_source_dir:cleanSourceDir,cache_dir:cacheContext?.cacheDir??null,cache_enabled:cacheContext?.enabled??!1,resumed_from_cache:cacheContext?.stats?.resumed_from_cache??!1,reused_uploaded_assets_count:cacheContext?.stats?.remote_reused??0,reused_uploaded_local_assets_count:cacheContext?.stats?.local_reused??0,interrupted_items_count:cacheContext?.stats?.interrupted_items_count??0,clean_source_package_bytes:collectSourcePackageBytes(cleanSourceDir),summary:report.summary,planned_actions:buildPlannedActions(report,rewriteResult,localUploadResult,localRewriteResult,pathBaseRewriteResult),asset_mappings:{remote:rewriteResult.uploaded_assets,local:localUploadResult.uploaded_local_assets},rewritten_files:[...rewriteResult.rewritten_files,...localRewriteResult.rewritten_files,...pathBaseRewriteResult.rewritten_files],deleted_clean_source_assets:localRewriteResult.deleted_clean_source_assets,path_base_rewrites:pathBaseRewriteResult.rewrite_entries,pending_videos:report.pending_videos,warnings:[...rewriteResult.warnings,...localUploadResult.warnings,...localRewriteResult.warnings,...pathBaseRewriteResult.warnings]}}async function runRewrite(args,report,cacheContext,deps){let imageCandidates=report.remote_candidates.filter(item=>item.kind==="image"&&item.rewrite_supported===!0),warnings=[],uploads=[],replacements=new Map;if(args.dryRun)return{uploaded_assets:imageCandidates.map(item=>({original_url:item.url,final_url:item.url,status:"dry-run"})),rewritten_files:[],warnings};let tempRoot=mkdtempSync3(join12(tmpdir2(),"platform-assetize-project-"));try{let total=imageCandidates.length,uploadResults=await runWithConcurrency(imageCandidates,REMOTE_IMAGE_CONCURRENCY,async(candidate,index)=>{let itemLabel=`remote image ${index+1}/${total}`,cacheKey=buildRemoteCacheKey(candidate.url),cached=cacheContext?.cache?.entries?.[cacheKey];if(cacheContext?.enabled&&cacheEntryReusable(cached))return logProgress(`${itemLabel} reused from cache: ${candidate.url}`),cacheContext.stats.remote_reused+=1,{candidate,finalUrl:cached.final_url,assetId:cached.asset_id??null,status:"reused_from_cache"};try{cacheContext?.enabled&&(cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"upload_remote",in_progress_keys:[...new Set([...cacheContext.lock.in_progress_keys,cacheKey])]}),updateCacheEntry(cacheContext.cache,cacheKey,{kind:"remote_image",status:"uploading",original_ref:candidate.url}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache));let downloadStart=Date.now();logProgress(`${itemLabel} downloading: ${candidate.url}`);let downloaded=await downloadRemoteImage(candidate.url,{fetchImpl:deps.fetchImpl,runCurl:deps.runCurl}),downloadMs=Date.now()-downloadStart,tempFilePath=join12(tempRoot,`${index+1}-${downloaded.fileName}`);writeFileSync10(tempFilePath,downloaded.content),logProgress(`${itemLabel} downloaded in ${downloadMs}ms, uploading asset`);let uploadStart=Date.now(),uploaded=await deps.uploadAsset({filePath:tempFilePath,title:downloaded.fileName,folderId:args.folderId||void 0}),uploadMs=Date.now()-uploadStart,finalUrl=normalizeUploadedAssetUrl(uploaded.original_url);return logProgress(`${itemLabel} uploaded in ${uploadMs}ms`),finalUrl!==uploaded.original_url&&warnings.push(`\u5DF2\u5C06\u7D20\u6750 URL \u534F\u8BAE\u89C4\u8303\u5316\u4E3A HTTPS: ${uploaded.original_url} -> ${finalUrl}`),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"remote_image",status:"uploaded",original_ref:candidate.url,final_url:finalUrl,asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null,content_digest:`sha256:${createHash5("sha256").update(downloaded.content).digest("hex")}`}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache),cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{in_progress_keys:cacheContext.lock.in_progress_keys.filter(item=>item!==cacheKey)})),{candidate,finalUrl,assetId:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null,status:"uploaded"}}catch(error){let message=error instanceof Error?error.message:String(error);return logProgress(`${itemLabel} failed: ${message}`),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"remote_image",status:"failed",original_ref:candidate.url,last_error:message}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache)),{candidate,error:message,status:"fallback"}}});for(let result of uploadResults){if(result.error){warnings.push(`\u56FE\u7247\u4E0A\u4F20\u5931\u8D25: ${result.candidate.url} (${result.error})`),uploads.push({original_url:result.candidate.url,final_url:result.candidate.url,status:"fallback"});continue}replacements.set(result.candidate.url,result.finalUrl),uploads.push({original_url:result.candidate.url,final_url:result.finalUrl,asset_id:result.assetId??null,status:result.status})}let targetFiles=new Set(imageCandidates.flatMap(candidate=>candidate.occurrences.map(occurrence=>occurrence.file))),rewrittenFiles=[];for(let relativePath of[...targetFiles].sort((left,right)=>left.localeCompare(right))){let absolutePath=join12(report.project_dir,relativePath),before=readFileSync16(absolutePath,"utf8"),after=before;for(let[originalUrl,finalUrl]of replacements)after=replaceUrlInContent(after,originalUrl,finalUrl);after!==before&&(writeFileSync10(absolutePath,after,"utf8"),rewrittenFiles.push(relativePath))}if(cacheContext?.enabled&&rewrittenFiles.length>0){cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"rewrite_remote_refs"});for(let candidate of imageCandidates){let cacheKey=buildRemoteCacheKey(candidate.url),cached=cacheContext.cache.entries[cacheKey];cacheEntryReusable(cached)&&updateCacheEntry(cacheContext.cache,cacheKey,{status:"rewritten"})}persistAssetCache(cacheContext.cacheFile,cacheContext.cache)}return{uploaded_assets:uploads,rewritten_files:rewrittenFiles,warnings}}finally{rmSync4(tempRoot,{recursive:!0,force:!0})}}async function runUploadLocal(args,report,cacheContext,deps){let warnings=[],uploads=[],tempRoot=mkdtempSync3(join12(tmpdir2(),"platform-assetize-local-"));try{if(args.dryRun)return{uploaded_local_assets:report.local_asset_candidates.map(item=>({source_path:item.path,title:item.file_name,status:"dry-run"})),warnings};for(let asset of report.local_asset_candidates){let absolutePath=join12(report.project_dir,asset.path),cacheKey=buildLocalCacheKey(asset.hash),cached=cacheContext?.cache?.entries?.[cacheKey];if(cacheContext?.enabled&&cacheEntryReusable(cached)){uploads.push({source_path:asset.path,source_paths:asset.source_paths,content_hash:asset.hash,title:cached.title??asset.file_name,final_url:cached.final_url,asset_id:cached.asset_id??null,status:"reused_from_cache"}),cacheContext.stats.local_reused+=1;continue}try{cacheContext?.enabled&&(cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{phase:"upload_local",in_progress_keys:[...new Set([...cacheContext.lock.in_progress_keys,cacheKey])]}),updateCacheEntry(cacheContext.cache,cacheKey,{kind:"local_image",status:"uploading",source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache));let uploaded=await deps.uploadAsset({filePath:absolutePath,title:asset.file_name,folderId:args.folderId||void 0});uploads.push({source_path:asset.path,source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name,final_url:normalizeUploadedAssetUrl(uploaded.original_url),asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null,status:"uploaded"}),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"local_image",status:"uploaded",source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name,final_url:normalizeUploadedAssetUrl(uploaded.original_url),asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache),cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{in_progress_keys:cacheContext.lock.in_progress_keys.filter(item=>item!==cacheKey)}))}catch(error){if(shouldRetryWithCompression(error)){let hostPlatform=deps.platform??process.platform,retry=resolveImageCompressionRetry(hostPlatform);if(retry.mode==="manual")warnings.push(`[${retry.code}] \u672C\u5730\u56FE\u7247\u8D85\u8FC7\u4E0A\u4F20\u9650\u5236\uFF08HTTP 413\uFF09\uFF0C${hostPlatform==="win32"?"Windows \u6682\u4E0D\u652F\u6301\u81EA\u52A8\u538B\u7F29":"\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u81EA\u52A8\u538B\u7F29"}: ${asset.path}\u3002\u8BF7\u5C06\u56FE\u7247\u5BBD\u5EA6\u538B\u7F29\u81F3\u4E0D\u8D85\u8FC7 ${LOCAL_IMAGE_UPLOAD_MAX_WIDTH}px \u5E76\u51CF\u5C0F\u6587\u4EF6\u4F53\u79EF\uFF0C\u7136\u540E\u6267\u884C\uFF1Aplatform app import preprocess --dir "${report.project_dir}" --reset-cache`);else try{let outputPath=buildCompressedFilePath(tempRoot,absolutePath),compressedPath=await(deps.runCompressor??runSipsCompressor)({sourcePath:absolutePath,outputPath}),uploaded=await deps.uploadAsset({filePath:compressedPath,title:basename5(compressedPath),folderId:args.folderId||void 0});warnings.push(`\u672C\u5730\u56FE\u7247\u8FC7\u5927\uFF0C\u5DF2\u81EA\u52A8\u538B\u7F29\u540E\u4E0A\u4F20: ${asset.path}`),uploads.push({source_path:asset.path,source_paths:asset.source_paths,content_hash:asset.hash,title:basename5(compressedPath),final_url:normalizeUploadedAssetUrl(uploaded.original_url),asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null,status:"uploaded_after_compress"}),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"local_image",status:"uploaded",source_paths:asset.source_paths,content_hash:asset.hash,title:basename5(compressedPath),final_url:normalizeUploadedAssetUrl(uploaded.original_url),asset_id:uploaded.asset?.asset_id??uploaded.asset?.asset?.asset_id??null}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache),cacheContext.lock=updateLockState(cacheContext.lockFile,cacheContext.lock,{in_progress_keys:cacheContext.lock.in_progress_keys.filter(item=>item!==cacheKey)}));continue}catch(compressionError){warnings.push(`\u672C\u5730\u56FE\u7247\u538B\u7F29\u91CD\u8BD5\u5931\u8D25: ${asset.path} (${compressionError instanceof Error?compressionError.message:String(compressionError)})`)}}warnings.push(`\u672C\u5730\u56FE\u7247\u4E0A\u4F20\u5931\u8D25: ${asset.path} (${error instanceof Error?error.message:String(error)})`),uploads.push({source_path:asset.path,source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name,status:"failed"}),cacheContext?.enabled&&(updateCacheEntry(cacheContext.cache,cacheKey,{kind:"local_image",status:"failed",source_paths:asset.source_paths,content_hash:asset.hash,title:asset.file_name,last_error:error instanceof Error?error.message:String(error)}),persistAssetCache(cacheContext.cacheFile,cacheContext.cache))}}return{uploaded_local_assets:uploads,warnings}}finally{rmSync4(tempRoot,{recursive:!0,force:!0})}}function renderMarkdown(report){let lines=[];if(lines.push("# Scan Report",""),lines.push(`- Project: \`${report.project_dir}\``),lines.push(`- Mode: \`${report.mode}\``),lines.push(`- Scanned files: ${report.summary.scanned_file_count}`),lines.push(`- Unique remote candidates: ${report.summary.unique_remote_candidates}`),lines.push(`- Images: ${report.summary.image_count}`),lines.push(`- Videos: ${report.summary.video_count}`),lines.push(`- Posters: ${report.summary.poster_count}`),lines.push(`- Unknown remote: ${report.summary.unknown_remote_count}`),lines.push(`- Local images: ${report.summary.local_asset_count??0}`,""),report.remote_candidates.length===0&&(!Array.isArray(report.local_asset_candidates)||report.local_asset_candidates.length===0))return lines.push("No candidates found.",""),lines.join(`
|
|
2414
2416
|
`);if(report.remote_candidates.length>0){lines.push("## Remote Candidates","","| Kind | Rewrite | URL | Refs |","|---|---|---|---:|");for(let item of report.remote_candidates)lines.push(`| ${item.kind} | ${item.rewrite_supported?"yes":"no"} | ${escapeMdCell(item.url)} | ${item.occurrences.length} |`);lines.push("")}if(report.pending_videos.length>0){lines.push("## Pending Videos","");for(let item of report.pending_videos)lines.push(`- ${item.url}`);lines.push("")}if(Array.isArray(report.local_asset_candidates)&&report.local_asset_candidates.length>0){lines.push("## Local Images","","| File | Dedupe Refs | Size (bytes) | Upload |","|---|---:|---:|---|");for(let item of report.local_asset_candidates)lines.push(`| ${escapeMdCell(item.path)} | ${item.source_paths.length} | ${item.size_bytes} | ${item.upload_supported?"yes":"no"} |`);lines.push("")}if(report.remote_candidates.length>0){lines.push("## Occurrences","");for(let item of report.remote_candidates){lines.push(`### ${item.url}`,"",`- kind: \`${item.kind}\``,`- rewrite_supported: \`${item.rewrite_supported}\``),Array.isArray(item.notes)&&item.notes.length>0&&lines.push(`- notes: ${item.notes.join(" / ")}`);for(let occurrence of item.occurrences)lines.push(`- ${occurrence.file}:${occurrence.line} (${occurrence.kind})`);lines.push("")}}return lines.join(`
|
|
2415
2417
|
`)}function escapeMdCell(value){return value.replace(/\|/gu,"\\|")}function ensureDir(dirPath){mkdirSync9(dirPath,{recursive:!0})}function writeJson2(filePath,payload){writeFileSync10(filePath,`${JSON.stringify(payload,null,2)}
|
|
2416
2418
|
`,"utf8")}async function runPreprocess(args,sourceDir,deps){let preprocessRoot=join12(sourceDir,".design-preprocess"),cleanSourceDir=join12(preprocessRoot,"clean-source"),reportsDir=join12(preprocessRoot,"reports"),cacheDir=join12(preprocessRoot,"cache"),cacheFile=join12(cacheDir,"assets.json"),lockFile=join12(cacheDir,"locks.json");args.resetCache&&!args.dryRun&&rmSync4(cacheDir,{recursive:!0,force:!0}),rmSync4(cleanSourceDir,{recursive:!0,force:!0}),rmSync4(reportsDir,{recursive:!0,force:!0}),ensureDir(reportsDir),ensureDir(cacheDir),copyWorkspaceForPreprocess(sourceDir,cleanSourceDir);let cache=loadAssetCache(cacheFile,sourceDir),previousLock=loadLockState(lockFile),lockRun=args.dryRun?{lock:defaultLockState(),interruptedItems:0}:beginLockRun(lockFile,previousLock),lock=lockRun.lock,cacheContext={enabled:!args.dryRun&&args.resume!==!1,cacheDir,cacheFile,cache,lockFile,lock,warnings:[],stats:{resumed_from_cache:!1,remote_reused:0,local_reused:0,interrupted_items_count:lockRun.interruptedItems}};cacheContext.stats.interrupted_items_count>0&&(cacheContext.stats.resumed_from_cache=!0,cacheContext.warnings.push(`\u68C0\u6D4B\u5230\u4E0A\u6B21\u9884\u5904\u7406\u53EF\u80FD\u4E2D\u65AD\uFF1B\u5C06\u5C1D\u8BD5\u4ECE\u672C\u5730 cache \u6062\u590D\uFF08\u4E2D\u65AD\u9879: ${cacheContext.stats.interrupted_items_count}\uFF09\u3002`));let files=walkFiles(cleanSourceDir,args.include),assetFiles=walkAssetFiles(cleanSourceDir),candidates=collectRemoteCandidates(cleanSourceDir,files),localAssetCandidates=collectLocalAssetCandidates(cleanSourceDir,files,assetFiles),report=buildReport(cleanSourceDir,files,candidates,reportsDir);report.execution_mode=args.dryRun?"dry-run":"apply",report.local_asset_candidates=localAssetCandidates,report.summary.local_asset_count=localAssetCandidates.length;let detectedType=detectProjectType(sourceDir,args.type),upstreamSourcePackageBytes=collectSourcePackageBytes(sourceDir),cleanSourcePackageBytesBeforeRewrite=collectSourcePackageBytes(cleanSourceDir),pathBaseViolationsDetected=collectPathBaseViolations(cleanSourceDir,files),preflightWarnings=collectPreflightWarnings(cleanSourceDir,localAssetCandidates);cacheContext.enabled&&(lock=updateLockState(lockFile,lock,{phase:"rewrite_path_base"}),cacheContext.lock=lock);let pathBaseRewriteResult=await runPathBaseRewrite(args,report,files),pathBaseViolationsRemaining=collectPathBaseViolations(cleanSourceDir,files);writeJson2(join12(reportsDir,"preflight-report.json"),buildPreflightPayload(report,sourceDir,cleanSourceDir,{detectedType,upstreamSourcePackageBytes,cleanSourcePackageBytesBeforeRewrite,pathBaseViolationsDetected,pathBaseRewrites:pathBaseRewriteResult.rewrite_entries,pathBaseViolationsRemaining,preflightWarnings})),writeFileSync10(join12(reportsDir,"preflight-report.md"),`${renderMarkdown(report)}
|
|
2417
2419
|
`,"utf8");let rewriteResult=await runRewrite(args,report,cacheContext,deps),localUploadResult=await runUploadLocal(args,report,cacheContext,deps),localUploadFullReport={...report,mode:"upload-local",uploaded_assets:[],uploaded_local_assets:localUploadResult.uploaded_local_assets,rewritten_files:[],warnings:[...localUploadResult.warnings]};writeJson2(join12(reportsDir,"local-asset-report.json"),localUploadFullReport),writeFileSync10(join12(reportsDir,"local-asset-report.md"),`${renderMarkdown(localUploadFullReport)}
|
|
2418
2420
|
`,"utf8");let localRewriteResult=await runRewriteLocal({...args,localReport:join12(reportsDir,"local-asset-report.json")},report,files,cacheContext);(cacheContext.stats.remote_reused>0||cacheContext.stats.local_reused>0)&&(cacheContext.stats.resumed_from_cache=!0);let assetInventory=buildAssetInventoryPayload(report,rewriteResult,localUploadResult,sourceDir,cleanSourceDir),importManifestWithCache=buildImportManifest(report,rewriteResult,localUploadResult,localRewriteResult,pathBaseRewriteResult,sourceDir,cleanSourceDir,cacheContext),warningsPayload=buildWarningsPayload(report,importManifestWithCache,reportsDir,cacheContext);return writeJson2(join12(reportsDir,"asset-inventory.json"),assetInventory),writeJson2(join12(reportsDir,"import-manifest.json"),importManifestWithCache),writeJson2(join12(reportsDir,"warnings.json"),warningsPayload),writeJson2(join12(reportsDir,"pending-videos.json"),{pending_videos:report.pending_videos}),writeFileSync10(join12(reportsDir,"import-manifest.md"),`${renderMarkdown({...report,mode:"preprocess",uploaded_assets:rewriteResult.uploaded_assets,uploaded_local_assets:localUploadResult.uploaded_local_assets,rewritten_files:importManifestWithCache.rewritten_files,deleted_clean_source_assets:importManifestWithCache.deleted_clean_source_assets,warnings:importManifestWithCache.warnings})}
|
|
2419
|
-
`,"utf8"),cacheContext.enabled&&(cacheContext.lock=completeLockRun(lockFile,cacheContext.lock)),{preprocess_root:preprocessRoot,clean_source_dir:cleanSourceDir,reports_dir:reportsDir,cache_dir:cacheDir,report,pathBaseRewriteResult,rewriteResult,localUploadResult,localRewriteResult,importManifest:importManifestWithCache,cacheContext}}async function runAppImportPreprocess(argv,deps={}){let args=parseArgs2(argv);if(args.help)throw new Error("\u5E2E\u52A9\u8BF7\u6C42\u5E94\u7531 runAppImportPreprocessCli \u5904\u7406\u3002");let rootDir=resolve10(args.dir||process.env.PLATFORM_INVOCATION_CWD||process.env.INIT_CWD||process.cwd()),stats=
|
|
2421
|
+
`,"utf8"),cacheContext.enabled&&(cacheContext.lock=completeLockRun(lockFile,cacheContext.lock)),{preprocess_root:preprocessRoot,clean_source_dir:cleanSourceDir,reports_dir:reportsDir,cache_dir:cacheDir,report,pathBaseRewriteResult,rewriteResult,localUploadResult,localRewriteResult,importManifest:importManifestWithCache,cacheContext}}async function runAppImportPreprocess(argv,deps={}){let args=parseArgs2(argv);if(args.help)throw new Error("\u5E2E\u52A9\u8BF7\u6C42\u5E94\u7531 runAppImportPreprocessCli \u5904\u7406\u3002");let rootDir=resolve10(args.dir||process.env.PLATFORM_INVOCATION_CWD||process.env.INIT_CWD||process.cwd()),stats=statSync4(rootDir,{throwIfNoEntry:!1});if(!stats||!stats.isDirectory())throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${rootDir}`);let uploadAsset=deps.uploadAsset??(async()=>{throw new Error("app import preprocess \u7F3A\u5C11\u8FDB\u7A0B\u5185\u7D20\u6750\u4E0A\u4F20\u4F9D\u8D56\u3002")}),result=await runPreprocess(args,rootDir,{...deps,uploadAsset,platform:deps.platform??process.platform}),warnings=result.importManifest.warnings;return{tool:"assetize-project-urls",version:1,mode:"preprocess",execution_mode:args.dryRun?"dry-run":"apply",source_dir:rootDir,clean_source_dir:result.clean_source_dir,reports_dir:result.reports_dir,cache_dir:result.cache_dir,summary:result.report.summary,planned_actions:result.importManifest.planned_actions,path_base_rewritten_files:result.pathBaseRewriteResult.rewritten_files.length,uploaded_assets:countAppliedRemoteUploads(result.rewriteResult),uploaded_local_assets:countAppliedLocalUploads(result.localUploadResult),resumed_from_cache:result.importManifest.resumed_from_cache,reused_uploaded_assets:result.importManifest.reused_uploaded_assets_count,reused_uploaded_local_assets:result.importManifest.reused_uploaded_local_assets_count,interrupted_items_count:result.importManifest.interrupted_items_count,rewritten_files:args.dryRun?0:result.importManifest.rewritten_files.length,deleted_clean_source_assets:args.dryRun?0:result.importManifest.deleted_clean_source_assets.length,warnings,report_files:{preflight_report:join12(result.reports_dir,"preflight-report.json"),asset_inventory:join12(result.reports_dir,"asset-inventory.json"),import_manifest:join12(result.reports_dir,"import-manifest.json"),warnings:join12(result.reports_dir,"warnings.json"),pending_videos:join12(result.reports_dir,"pending-videos.json")}}}async function runAppImportPreprocessCli(argv,deps={}){let args=parseArgs2(argv);if(args.help){printAppImportPreprocessUsage();return}let output=await runAppImportPreprocess(argv,deps);if(args.json){process.stdout.write(`${JSON.stringify(output,null,2)}
|
|
2420
2422
|
`);return}process.stdout.write(["third-party design preprocess completed",`mode: ${output.mode}`,`execution_mode: ${output.execution_mode}`,`source_dir: ${output.source_dir}`,`clean_source_dir: ${output.clean_source_dir}`,`cache_dir: ${output.cache_dir}`,`scanned_files: ${output.summary.scanned_file_count}`,`unique_remote_candidates: ${output.summary.unique_remote_candidates}`,`local_images: ${output.summary.local_asset_count}`,`planned_remote_upload_candidates: ${output.planned_actions.remote_upload_candidates}`,`planned_local_upload_candidates: ${output.planned_actions.local_upload_candidates}`,`planned_file_rewrite_candidates: ${output.planned_actions.file_rewrite_candidates}`,`planned_local_cleanup_candidates: ${output.planned_actions.local_cleanup_candidates}`,`path_base_rewritten_files: ${output.path_base_rewritten_files}`,`uploaded_assets: ${output.uploaded_assets}`,`uploaded_local_assets: ${output.uploaded_local_assets}`,`resumed_from_cache: ${output.resumed_from_cache}`,`reused_uploaded_assets: ${output.reused_uploaded_assets}`,`reused_uploaded_local_assets: ${output.reused_uploaded_local_assets}`,`interrupted_items_count: ${output.interrupted_items_count}`,`rewritten_files: ${output.rewritten_files}`,`deleted_clean_source_assets: ${output.deleted_clean_source_assets}`,`warnings: ${output.warnings.length}`,`preflight_report: ${output.report_files.preflight_report}`,`import_manifest: ${output.report_files.import_manifest}`].join(`
|
|
2421
2423
|
`)+`
|
|
2422
|
-
`)}import{
|
|
2423
|
-
`))}function parseArgs3(argv){let result={workspaceDir:"",preprocess:"",dryRun:!1,json:!1,help:!1};for(let index=0;index<argv.length;index+=1){let arg=argv[index];if(arg==="--help"||arg==="-h"){result.help=!0;continue}if(arg==="--dry-run"){result.dryRun=!0;continue}if(arg==="--json"){result.json=!0;continue}if(arg==="--workspace-dir"){result.workspaceDir=argv[index+1]??"",index+=1;continue}if(arg==="--preprocess"){result.preprocess=argv[index+1]??"",index+=1;continue}throw new Error(`\u672A\u77E5\u53C2\u6570: ${arg}`)}return result}function ensureDir2(dirPath){mkdirSync10(dirPath,{recursive:!0})}function
|
|
2424
|
-
|
|
2424
|
+
`)}import{copyFileSync as copyFileSync3,existsSync as existsSync17,lstatSync as lstatSync3,mkdirSync as mkdirSync10,mkdtempSync as mkdtempSync4,readFileSync as readFileSync17,readdirSync as readdirSync7,renameSync as renameSync3,rmSync as rmSync5,statSync as statSync5,writeFileSync as writeFileSync11}from"node:fs";import{basename as basename6,dirname as dirname12,isAbsolute as isAbsolute3,join as join13,relative as relative5,resolve as resolve11,sep as sep2}from"node:path";var WORKSPACE_REQUIRED_FILES=["app.yaml","package.json"],REPORT_FILE_NAMES=["import-manifest.json","preflight-report.json","asset-inventory.json","warnings.json","pending-videos.json"],TOP_LEVEL_IMPORT_CANDIDATES=["src","public","_videos","guidelines","index.html","README.md","ATTRIBUTIONS.md"],SKIP_DIRS=new Set([".git","node_modules","dist","build",".platform",".sandbox",".design-preprocess",".third-party-design-reports"]);function printAppImportStageUsage(){process.stdout.write(["platform app import stage","","\u7528\u6CD5\uFF1A"," platform app import stage [--workspace-dir <template-workspace-dir>] --preprocess <source-dir|.design-preprocess|reports|import-manifest.json> [--dry-run] [--json]","","\u4F5C\u7528\uFF1A"," \u5C06\u9884\u5904\u7406\u4EA7\u7269\u4EE5\u975E\u7834\u574F\u65B9\u5F0F stage \u5230\u6A21\u677F\u5DE5\u4F5C\u533A `.design-import/`\uFF0C\u4E0D\u76F4\u63A5\u8986\u76D6\u6A21\u677F\u5165\u53E3\u4E0E\u8FD0\u884C\u5951\u7EA6\u6587\u4EF6\u3002","","\u8BF4\u660E\uFF1A"," - \u9ED8\u8BA4\u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4F5C\u4E3A\u6A21\u677F\u5DE5\u4F5C\u533A\uFF1B\u82E5\u672A\u4F20 `--workspace-dir`\uFF0C\u5C06\u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",""].join(`
|
|
2425
|
+
`))}function parseArgs3(argv){let result={workspaceDir:"",preprocess:"",dryRun:!1,json:!1,help:!1};for(let index=0;index<argv.length;index+=1){let arg=argv[index];if(arg==="--help"||arg==="-h"){result.help=!0;continue}if(arg==="--dry-run"){result.dryRun=!0;continue}if(arg==="--json"){result.json=!0;continue}if(arg==="--workspace-dir"){result.workspaceDir=argv[index+1]??"",index+=1;continue}if(arg==="--preprocess"){result.preprocess=argv[index+1]??"",index+=1;continue}throw new Error(`\u672A\u77E5\u53C2\u6570: ${arg}`)}return result}function ensureDir2(dirPath){mkdirSync10(dirPath,{recursive:!0})}function assertPathWithinTrustedRoot(trustedRoot,pathValue,label,options={}){let absoluteRoot=resolve11(trustedRoot),absolutePath=resolve11(pathValue),relativePath=relative5(absoluteRoot,absolutePath);if(relativePath===".."||relativePath.startsWith(`..${sep2}`)||isAbsolute3(relativePath))throw new Error(`${label} \u8D85\u51FA\u53D7\u4FE1\u6839\u76EE\u5F55: ${absolutePath}`);let componentPath=absoluteRoot;if(!options.trustRoot){let rootStats=lstatSync3(componentPath,{throwIfNoEntry:!1});if(!rootStats)throw new Error(`${label} \u53D7\u4FE1\u6839\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${absoluteRoot}`);if(rootStats.isSymbolicLink())throw new Error(`${label} \u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${componentPath}`)}for(let component of relativePath?relativePath.split(sep2).filter(Boolean):[]){componentPath=join13(componentPath,component);let stats=lstatSync3(componentPath,{throwIfNoEntry:!1});if(!stats)break;if(stats.isSymbolicLink())throw new Error(`${label} \u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${componentPath}`)}}function validateImportEntry(sourcePath){let sourceStats=lstatSync3(sourcePath,{throwIfNoEntry:!1});if(!sourceStats)throw new Error(`\u5F85\u590D\u5236\u7684\u5BFC\u5165\u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${sourcePath}`);if(sourceStats.isSymbolicLink())throw new Error(`\u5BFC\u5165\u4EA7\u7269\u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${sourcePath}`);if(sourceStats.isDirectory()){for(let entry of readdirSync7(sourcePath,{withFileTypes:!0}))validateImportEntry(join13(sourcePath,entry.name));return}if(!sourceStats.isFile())throw new Error(`\u5BFC\u5165\u4EA7\u7269\u5305\u542B\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B: ${sourcePath}`)}function copyImportEntry(sourcePath,targetPath){let sourceStats=lstatSync3(sourcePath,{throwIfNoEntry:!1});if(!sourceStats)throw new Error(`\u5F85\u590D\u5236\u7684\u5BFC\u5165\u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${sourcePath}`);if(sourceStats.isSymbolicLink())throw new Error(`\u5BFC\u5165\u4EA7\u7269\u4E0D\u652F\u6301\u7B26\u53F7\u94FE\u63A5\u6216\u76EE\u5F55\u8054\u63A5: ${sourcePath}`);if(sourceStats.isDirectory()){ensureDir2(targetPath);for(let entry of readdirSync7(sourcePath,{withFileTypes:!0}))copyImportEntry(join13(sourcePath,entry.name),join13(targetPath,entry.name));return}if(sourceStats.isFile()){ensureDir2(dirname12(targetPath)),copyFileSync3(sourcePath,targetPath);return}throw new Error(`\u5BFC\u5165\u4EA7\u7269\u5305\u542B\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B: ${sourcePath}`)}function assertReplaceableImportRoot(designImportRoot){assertPathWithinTrustedRoot(dirname12(designImportRoot),designImportRoot,"stage \u76EE\u6807\u8DEF\u5F84",{trustRoot:!0});let existingStats=lstatSync3(designImportRoot,{throwIfNoEntry:!1});if(existingStats&&!existingStats.isDirectory())throw new Error(`stage \u76EE\u6807\u5FC5\u987B\u662F\u76EE\u5F55: ${designImportRoot}`)}function replaceImportRoot(stagedRoot,designImportRoot,deps={}){let rename=deps.rename??renameSync3,remove=deps.remove??rmSync5,warn=deps.warn??(message=>process.stderr.write(`${message}
|
|
2426
|
+
`));if(assertReplaceableImportRoot(designImportRoot),!lstatSync3(designImportRoot,{throwIfNoEntry:!1})){rename(stagedRoot,designImportRoot);return}let backupRoot=`${designImportRoot}.backup-${process.pid}-${Date.now()}`;if(existsSync17(backupRoot))throw new Error(`stage \u5907\u4EFD\u76EE\u5F55\u5DF2\u5B58\u5728: ${backupRoot}`);rename(designImportRoot,backupRoot);try{rename(stagedRoot,designImportRoot)}catch(error){try{rename(backupRoot,designImportRoot)}catch(rollbackError){throw new Error(`stage \u66FF\u6362\u5931\u8D25\u4E14\u65E7\u4EA7\u7269\u56DE\u6EDA\u5931\u8D25: ${error.message}; rollback: ${rollbackError.message}`)}throw error}try{remove(backupRoot,{recursive:!0,force:!0})}catch(error){warn(`[app import stage] \u65B0\u4EA7\u7269\u5DF2\u751F\u6548\uFF0C\u4F46\u65E7\u4EA7\u7269\u5907\u4EFD\u6E05\u7406\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u624B\u52A8\u5220\u9664: ${backupRoot} (${error.message})`)}}function writeJson3(filePath,payload){writeFileSync11(filePath,`${JSON.stringify(payload,null,2)}
|
|
2427
|
+
`,"utf8")}function readJson2(filePath){return JSON.parse(readFileSync17(filePath,"utf8"))}function assertDirectory2(pathValue,label){let stats=statSync5(pathValue,{throwIfNoEntry:!1});if(!stats||!stats.isDirectory())throw new Error(`${label} \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${pathValue}`)}function resolveManifestPath(inputPath){let absolute=resolve11(inputPath),stats=statSync5(absolute,{throwIfNoEntry:!1});if(!stats)throw new Error(`\u672A\u627E\u5230\u9884\u5904\u7406\u8F93\u5165: ${absolute}`);if(stats.isFile()){if(basename6(absolute)!=="import-manifest.json")throw new Error(`\u9884\u5904\u7406\u8F93\u5165\u6587\u4EF6\u5FC5\u987B\u662F import-manifest.json: ${absolute}`);return absolute}let candidates=[join13(absolute,"reports","import-manifest.json"),join13(absolute,"import-manifest.json"),join13(absolute,".design-preprocess","reports","import-manifest.json")];for(let candidate of candidates)if(existsSync17(candidate))return candidate;throw new Error(`\u65E0\u6CD5\u4ECE\u9884\u5904\u7406\u8F93\u5165\u89E3\u6790 import-manifest.json: ${absolute}`)}function validateWorkspace2(workspaceDir){assertDirectory2(workspaceDir,"\u6A21\u677F\u5DE5\u4F5C\u533A");let missing=WORKSPACE_REQUIRED_FILES.filter(file=>!existsSync17(join13(workspaceDir,file)));if(missing.length>0)throw new Error(`\u76EE\u6807\u76EE\u5F55\u4E0D\u662F\u6709\u6548\u6A21\u677F\u5DE5\u4F5C\u533A\uFF0C\u7F3A\u5C11: ${missing.join(", ")}`)}function topLevelEntries(rootDir){return readdirSync7(rootDir,{withFileTypes:!0}).filter(entry=>!SKIP_DIRS.has(entry.name)).map(entry=>({name:entry.name,kind:entry.isDirectory()?"dir":entry.isFile()?"file":"other"})).sort((left,right)=>left.name.localeCompare(right.name))}function collectImportCandidates(cleanSourceDir,layout,sourceDetectedType){return topLevelEntries(cleanSourceDir).filter(entry=>TOP_LEVEL_IMPORT_CANDIDATES.includes(entry.name)).map(entry=>({path:entry.name,kind:entry.kind,suggested_target:entry.name==="src"?sourceDetectedType==="frontend-app"?`workspace/${layout.imported_upstream_root}/ (\u6309 pages/components/styles/lib/imports \u53D7\u63A7\u5E76\u5165)`:`workspace/.design-import/upstream-clean-source/${entry.name}`:entry.name==="_videos"?"workspace/public/imported-upstream/_videos/ \u6216\u6A21\u677F\u9759\u6001\u8D44\u6E90\u76EE\u5F55":entry.name==="public"?"workspace/public/imported-upstream/ (\u9700\u4EBA\u5DE5\u5BA1\u67E5\u51B2\u7A81)":`workspace/.design-import/upstream-clean-source/${entry.name}`}))}function collectPreservedWorkspaceFiles(workspaceDir,layout){return layout.preserved_workspace_files.filter(file=>existsSync17(join13(workspaceDir,file)))}function buildImportSummary(args,payload){let sourcePreprocessExecutionMode=payload.importManifest.execution_mode??"unknown",warnings=[];return sourcePreprocessExecutionMode==="dry-run"&&warnings.push("\u5F53\u524D\u9884\u5904\u7406\u4EA7\u7269\u6765\u81EA dry-run\uFF1Bstaged clean source \u4ECD\u53EF\u80FD\u5305\u542B\u672A\u771F\u5B9E\u56DE\u5199\u6216\u672A\u6E05\u7406\u7684\u672C\u5730\u7D20\u6750\u3002"),{tool:"import-clean-source",version:1,mode:"import-stage",execution_mode:args.dryRun?"dry-run":"apply",workspace_dir:payload.workspaceDir,preprocess_manifest:payload.manifestPath,source_dir:payload.importManifest.source_dir,clean_source_dir:payload.importManifest.clean_source_dir,source_preprocess_execution_mode:sourcePreprocessExecutionMode,target_template_key:payload.layout.template_key,frontend_root:payload.layout.frontend_root,imported_upstream_root:payload.layout.imported_upstream_root,staged_clean_source_dir:payload.stagedCleanSourceDir,staged_reports_dir:payload.stagedReportsDir,source_detected_type:payload.preflightReport.detected_type??"unknown",clean_source_package_bytes:payload.importManifest.clean_source_package_bytes??null,upstream_source_package_bytes:payload.preflightReport.upstream_source_package_bytes??null,import_candidates:collectImportCandidates(payload.importManifest.clean_source_dir,payload.layout,payload.preflightReport.detected_type??"unknown"),preserved_workspace_files:collectPreservedWorkspaceFiles(payload.workspaceDir,payload.layout),pending_videos_count:Array.isArray(payload.importManifest.pending_videos)?payload.importManifest.pending_videos.length:0,pending_manual_items_count:Array.isArray(payload.warningsReport.pending_manual_items)?payload.warningsReport.pending_manual_items.length:0,warnings,next_steps:["\u5148\u5728 .design-import/upstream-clean-source \u4E2D\u5BA1\u67E5\u4E0A\u6E38 clean source",`\u518D\u6309 import_candidates \u9009\u62E9\u6027\u5408\u5E76\u5230\u6A21\u677F\u5DE5\u4F5C\u533A\u7684 ${payload.layout.frontend_root}/public \u7B49\u76EE\u5F55`,"\u4FDD\u7559\u6A21\u677F\u4E3B\u5BFC\u6587\u4EF6\uFF08app.yaml / package.json / vite.config.ts / \u8FD0\u884C\u5165\u53E3 / platform \u5C42\uFF09\u4E0D\u88AB\u8986\u76D6","\u5B8C\u6210\u9875\u9762\u5408\u5E76\u540E\uFF0C\u518D\u6267\u884C platform dev / verify / preview"]}}function collectReportFiles(sourceReportsDir){return REPORT_FILE_NAMES.filter(fileName=>existsSync17(join13(sourceReportsDir,fileName)))}function stageReports(sourceReportsDir,stagedReportsDir,reportFiles){for(let fileName of reportFiles){let sourcePath=join13(sourceReportsDir,fileName);copyImportEntry(sourcePath,join13(stagedReportsDir,fileName))}}async function runAppImportStageCli(argv){let args=parseArgs3(argv);if(args.help){printAppImportStageUsage();return}if(!args.workspaceDir)throw new Error("\u7F3A\u5C11 `--workspace-dir <template-workspace-dir>`\u3002");if(!args.preprocess)throw new Error("\u7F3A\u5C11 `--preprocess <source-dir|.design-preprocess|reports|import-manifest.json>`\u3002");let workspaceDir=resolve11(args.workspaceDir);validateWorkspace2(workspaceDir);let manifestPath=resolveManifestPath(args.preprocess),reportsDir=resolve11(dirname12(manifestPath)),preprocessInput=resolve11(args.preprocess),preprocessInputRoot=statSync5(preprocessInput,{throwIfNoEntry:!1})?.isFile()?dirname12(preprocessInput):preprocessInput;assertPathWithinTrustedRoot(preprocessInputRoot,manifestPath,"\u9884\u5904\u7406 manifest \u8DEF\u5F84");let copiedReports=collectReportFiles(reportsDir);for(let reportFile of copiedReports)validateImportEntry(join13(reportsDir,reportFile));let importManifest=readJson2(manifestPath),preflightReport=readJson2(join13(reportsDir,"preflight-report.json")),warningsReport=readJson2(join13(reportsDir,"warnings.json")),sourceRoot=resolve11(importManifest.source_dir),cleanSourceDir=resolve11(importManifest.clean_source_dir);assertPathWithinTrustedRoot(sourceRoot,reportsDir,"\u9884\u5904\u7406 reports \u8DEF\u5F84"),assertPathWithinTrustedRoot(sourceRoot,cleanSourceDir,"clean-source \u8DEF\u5F84"),assertDirectory2(cleanSourceDir,"clean-source"),validateImportEntry(cleanSourceDir);let layout=resolveAppImportLayout(workspaceDir),designImportRoot=join13(workspaceDir,".design-import");assertReplaceableImportRoot(designImportRoot);let stagedCleanSourceDir=join13(designImportRoot,"upstream-clean-source"),stagedReportsDir=join13(designImportRoot,"reports"),summary=buildImportSummary(args,{workspaceDir,manifestPath,importManifest,preflightReport,warningsReport,layout,stagedCleanSourceDir,stagedReportsDir});if(!args.dryRun){let temporaryRoot=mkdtempSync4(join13(workspaceDir,".design-import.stage-"));try{let temporaryReportsDir=join13(temporaryRoot,"reports");ensureDir2(temporaryReportsDir),copyImportEntry(cleanSourceDir,join13(temporaryRoot,"upstream-clean-source")),stageReports(reportsDir,temporaryReportsDir,copiedReports),writeJson3(join13(temporaryRoot,"import-summary.json"),summary),replaceImportRoot(temporaryRoot,designImportRoot)}catch(error){throw rmSync5(temporaryRoot,{recursive:!0,force:!0}),error}}let output={...summary,copied_report_files:copiedReports};if(args.json){process.stdout.write(`${JSON.stringify(output,null,2)}
|
|
2425
2428
|
`);return}process.stdout.write(["third-party design import stage completed",`execution_mode: ${output.execution_mode}`,`workspace_dir: ${output.workspace_dir}`,`source_detected_type: ${output.source_detected_type}`,`staged_clean_source_dir: ${output.staged_clean_source_dir}`,`staged_reports_dir: ${output.staged_reports_dir}`,`import_candidates: ${output.import_candidates.length}`,`preserved_workspace_files: ${output.preserved_workspace_files.length}`,`pending_videos_count: ${output.pending_videos_count}`,`pending_manual_items_count: ${output.pending_manual_items_count}`].join(`
|
|
2426
2429
|
`)+`
|
|
2427
|
-
`)}import{existsSync as existsSync18,readFileSync as readFileSync18,statSync as
|
|
2428
|
-
`))}function parseArgs4(argv){let result={workspaceDir:"",json:!1,help:!1};for(let index=0;index<argv.length;index+=1){let arg=argv[index];if(arg==="--help"||arg==="-h"){result.help=!0;continue}if(arg==="--json"){result.json=!0;continue}if(arg==="--workspace-dir"){result.workspaceDir=argv[index+1]??"",index+=1;continue}throw new Error(`\u672A\u77E5\u53C2\u6570: ${arg}`)}return result}function readJsonIfExists3(filePath,fallbackValue=null){return existsSync18(filePath)?JSON.parse(readFileSync18(filePath,"utf8")):fallbackValue}function assertDirectory3(pathValue,label){let stats=
|
|
2430
|
+
`)}import{existsSync as existsSync18,readFileSync as readFileSync18,statSync as statSync6}from"node:fs";import{join as join14,resolve as resolve12}from"node:path";var REQUIRED_WORKSPACE_FILES2=["app.yaml","package.json"];function printAppImportVerifyUsage(){process.stdout.write(["platform app import verify","","\u7528\u6CD5\uFF1A"," platform app import verify [--workspace-dir <template-workspace-dir>] [--json]","","\u4F5C\u7528\uFF1A"," \u6821\u9A8C\u6A21\u677F\u5DE5\u4F5C\u533A\u662F\u5426\u5DF2\u5177\u5907 preprocess / stage / merge \u7684\u57FA\u7840\u4EA7\u7269\uFF0C\u5E76\u8F93\u51FA\u4E0B\u4E00\u6B65\u5EFA\u8BAE\u3002","","\u8BF4\u660E\uFF1A"," - \u9ED8\u8BA4\u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4F5C\u4E3A\u6A21\u677F\u5DE5\u4F5C\u533A\uFF1B\u82E5\u672A\u4F20 `--workspace-dir`\uFF0C\u5C06\u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002"," - verify \u53EA\u505A\u72B6\u6001\u6821\u9A8C\uFF0C\u4E0D\u4F1A\u6267\u884C\u7D20\u6750\u4E0A\u4F20\u3001\u6587\u4EF6\u642C\u8FD0\u6216\u6A21\u677F\u63A5\u7EBF\u3002",""].join(`
|
|
2431
|
+
`))}function parseArgs4(argv){let result={workspaceDir:"",json:!1,help:!1};for(let index=0;index<argv.length;index+=1){let arg=argv[index];if(arg==="--help"||arg==="-h"){result.help=!0;continue}if(arg==="--json"){result.json=!0;continue}if(arg==="--workspace-dir"){result.workspaceDir=argv[index+1]??"",index+=1;continue}throw new Error(`\u672A\u77E5\u53C2\u6570: ${arg}`)}return result}function readJsonIfExists3(filePath,fallbackValue=null){return existsSync18(filePath)?JSON.parse(readFileSync18(filePath,"utf8")):fallbackValue}function assertDirectory3(pathValue,label){let stats=statSync6(pathValue,{throwIfNoEntry:!1});if(!stats||!stats.isDirectory())throw new Error(`${label} \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${pathValue}`)}function validateWorkspace3(workspaceDir){assertDirectory3(workspaceDir,"\u6A21\u677F\u5DE5\u4F5C\u533A");let missing=REQUIRED_WORKSPACE_FILES2.filter(file=>!existsSync18(join14(workspaceDir,file)));if(missing.length>0)throw new Error(`\u76EE\u6807\u76EE\u5F55\u4E0D\u662F\u6709\u6548\u6A21\u677F\u5DE5\u4F5C\u533A\uFF0C\u7F3A\u5C11: ${missing.join(", ")}`)}function listMissingItems(state){let missing=[];return state.hasPreprocessManifest||missing.push(".design-import/reports/import-manifest.json"),state.hasPreflightReport||missing.push(".design-import/reports/preflight-report.json"),state.hasWarningsReport||missing.push(".design-import/reports/warnings.json"),state.hasImportSummary||missing.push(".design-import/import-summary.json"),state.mergeRequired&&(state.hasMergeSummary||missing.push(".design-import/merge-summary.json"),state.hasImportedUpstreamDir||missing.push(`${state.importedUpstreamRoot}/`)),missing}function deriveStatus(state){return state.hasImportSummary?state.mergeRequired&&(!state.hasMergeSummary||!state.hasImportedUpstreamDir)?"needs_merge":state.sourcePreprocessExecutionMode==="dry-run"?"needs_apply_preprocess":"ready_for_manual_wiring":"needs_stage"}function buildNextSteps(status,state){switch(status){case"needs_stage":return["\u5148\u6267\u884C platform app import stage --preprocess <source-dir|.design-preprocess|reports|import-manifest.json>","\u786E\u8BA4 .design-import/upstream-clean-source/ \u4E0E .design-import/reports/ \u5DF2\u751F\u6210"];case"needs_merge":return["\u6267\u884C platform app import merge",`\u786E\u8BA4 ${state.importedUpstreamRoot}/ \u5DF2\u751F\u6210\uFF0C\u518D\u5F00\u59CB\u4EBA\u5DE5\u63A5\u7EBF`];case"needs_apply_preprocess":return["\u5F53\u524D\u4E0A\u6E38\u9884\u5904\u7406\u4EA7\u7269\u6765\u81EA dry-run\uFF1B\u8BF7\u91CD\u65B0\u6267\u884C platform app import preprocess\uFF08\u975E --dry-run\uFF09","\u91CD\u65B0 stage / merge \u540E\u518D\u7EE7\u7EED\u6A21\u677F\u63A5\u7EBF"];default:return state.templateKey==="backend-app-node"?["\u5728 src/web/app.tsx \u6216 src/web/pages/* \u4E2D\u9009\u62E9\u6027\u5F15\u7528 imported-upstream \u5185\u5BB9","\u4FDD\u6301 src/server/* \u4E0E src/web/platform/* \u7531\u6A21\u677F\u4E3B\u5BFC\uFF0C\u518D\u7EE7\u7EED\u505A CMS / DB / Auth \u63A5\u5165","\u63A5\u7EBF\u5B8C\u6210\u540E\u518D\u6267\u884C platform dev / preview"]:["\u5728 src/app.tsx \u6216 src/pages/* \u4E2D\u9009\u62E9\u6027\u5F15\u7528 imported-upstream \u5185\u5BB9","\u4FDD\u6301 src/platform/* \u7531\u6A21\u677F\u4E3B\u5BFC\uFF0C\u518D\u7EE7\u7EED\u505A\u54CD\u5E94\u5F0F\u4FEE\u6B63\u4E0E CMS / DB / Auth \u63A5\u5165","\u63A5\u7EBF\u5B8C\u6210\u540E\u518D\u6267\u884C platform dev / preview"]}}async function runAppImportVerifyCli(argv){let args=parseArgs4(argv);if(args.help){printAppImportVerifyUsage();return}if(!args.workspaceDir)throw new Error("\u7F3A\u5C11 `--workspace-dir <template-workspace-dir>`\u3002");let workspaceDir=resolve12(args.workspaceDir);validateWorkspace3(workspaceDir);let layout=resolveAppImportLayout(workspaceDir),designImportRoot=join14(workspaceDir,".design-import"),reportsDir=join14(designImportRoot,"reports"),importManifestPath=join14(reportsDir,"import-manifest.json"),preflightReportPath=join14(reportsDir,"preflight-report.json"),warningsReportPath=join14(reportsDir,"warnings.json"),importSummaryPath=join14(designImportRoot,"import-summary.json"),mergeSummaryPath=join14(designImportRoot,"merge-summary.json"),importedUpstreamDir=join14(workspaceDir,...layout.imported_upstream_root.split("/")),sourceContextPath=join14(workspaceDir,".platform","source-context.json"),importManifest=readJsonIfExists3(importManifestPath,{}),preflightReport=readJsonIfExists3(preflightReportPath,{}),warningsReport=readJsonIfExists3(warningsReportPath,{}),importSummary=readJsonIfExists3(importSummaryPath,{}),mergeSummary=readJsonIfExists3(mergeSummaryPath,{}),state={hasPreprocessManifest:existsSync18(importManifestPath),hasPreflightReport:existsSync18(preflightReportPath),hasWarningsReport:existsSync18(warningsReportPath),hasImportSummary:existsSync18(importSummaryPath),hasMergeSummary:existsSync18(mergeSummaryPath),hasImportedUpstreamDir:existsSync18(importedUpstreamDir),mergeRequired:!0,templateKey:layout.template_key,frontendRoot:layout.frontend_root,importedUpstreamRoot:layout.imported_upstream_root,hasSourceContext:existsSync18(sourceContextPath),sourcePreprocessExecutionMode:importSummary.source_preprocess_execution_mode||importManifest.execution_mode||"unknown",pendingVideosCount:Array.isArray(importManifest.pending_videos)?importManifest.pending_videos.length:Array.isArray(warningsReport.pending_videos)?warningsReport.pending_videos.length:0,pendingManualItemsCount:Array.isArray(warningsReport.pending_manual_items)?warningsReport.pending_manual_items.length:0,pathBaseViolationsRemaining:Array.isArray(preflightReport.path_base_violations_remaining)?preflightReport.path_base_violations_remaining.length:0,cleanSourcePackageBytes:importManifest.clean_source_package_bytes??null,upstreamSourcePackageBytes:preflightReport.upstream_source_package_bytes??null,mergedPathsCount:Array.isArray(mergeSummary.merged_paths)?mergeSummary.merged_paths.length:0},status=deriveStatus(state),output={tool:"app-import-verify",version:1,mode:"verify",workspace_dir:workspaceDir,design_import_dir:designImportRoot,target_template_key:layout.template_key,frontend_root:layout.frontend_root,imported_upstream_dir:layout.imported_upstream_root,status,state,missing_items:listMissingItems(state),next_steps:buildNextSteps(status,state)};if(args.json){process.stdout.write(`${JSON.stringify(output,null,2)}
|
|
2429
2432
|
`);return}process.stdout.write(["third-party design verify completed",`workspace_dir: ${output.workspace_dir}`,`status: ${output.status}`,`source_preprocess_execution_mode: ${output.state.sourcePreprocessExecutionMode}`,`has_import_summary: ${output.state.hasImportSummary}`,`has_merge_summary: ${output.state.hasMergeSummary}`,`has_imported_upstream_dir: ${output.state.hasImportedUpstreamDir}`,`pending_videos: ${output.state.pendingVideosCount}`,`pending_manual_items: ${output.state.pendingManualItemsCount}`,`path_base_violations_remaining: ${output.state.pathBaseViolationsRemaining}`,`missing_items: ${output.missing_items.length}`].join(`
|
|
2430
2433
|
`)+`
|
|
2431
2434
|
`)}function hasFlag(args,key){return args.options[key]===!0}function readOption(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}function currentWorkspaceDir(){return process.env.PLATFORM_INVOCATION_CWD||process.env.INIT_CWD||process.cwd()}function printAppImportHelp(subcommand){switch(subcommand){case"preprocess":printAppImportPreprocessUsage();return;case"stage":printAppImportStageUsage();return;case"merge":printAppImportMergeUsage();return;case"verify":printAppImportVerifyUsage();return;default:process.stdout.write(["platform app import","","\u53EF\u7528\u5B50\u547D\u4EE4\uFF1A"," platform app import preprocess \u751F\u6210 clean-source \u4E0E\u9884\u5904\u7406\u62A5\u544A"," platform app import stage \u628A clean-source \u4E0E reports stage \u5230\u6A21\u677F\u5DE5\u4F5C\u533A"," platform app import merge \u6309\u6A21\u677F\u524D\u7AEF\u6839\u76EE\u5F55\u628A\u4E0A\u6E38\u5185\u5BB9\u5B89\u5168\u5E76\u5165 imported-upstream \u843D\u70B9"," platform app import verify \u6821\u9A8C preprocess / stage / merge \u4EA7\u7269\u72B6\u6001","","\u8BF4\u660E\uFF1A"," \u5F53\u524D P0 \u81EA\u52A8\u5316\u53EA\u8986\u76D6\u6700\u8017\u65F6\u3001\u6700\u673A\u68B0\u7684\u4E09\u6BB5\uFF1Apreprocess / stage / merge\u3002"," create / wiring / CMS-DB-Auth \u63A5\u7EBF\u4ECD\u7531\u6A21\u677F\u5DE5\u4F5C\u533A\u4E0E\u4EBA\u5DE5\u5DE5\u7A0B\u5316\u627F\u63A5\u3002",""].join(`
|
|
@@ -2455,8 +2458,8 @@ detail: ${JSON.stringify(error.detail)}`:"";return new Error([`platform build ${
|
|
|
2455
2458
|
detail: ${JSON.stringify(error.detail)}`:"";return new Error([`platform build validate \u5931\u8D25: ${appId}/${sourceVersionId}`,`code: ${error.code}`,`message: ${error.message}${suffix}`].join(`
|
|
2456
2459
|
`))}return error instanceof Error?error:new Error(`platform build validate \u5931\u8D25: ${appId}/${sourceVersionId}`)}function formatBuildRunError(error,appId,sourceVersionId){if(error instanceof PlatformApiError){let suffix=error.detail?`
|
|
2457
2460
|
detail: ${JSON.stringify(error.detail)}`:"";return new Error([`platform build run \u5931\u8D25: ${appId}/${sourceVersionId}`,`code: ${error.code}`,`message: ${error.message}${suffix}`].join(`
|
|
2458
|
-
`))}return error instanceof Error?error:new Error(`platform build run \u5931\u8D25: ${appId}/${sourceVersionId}`)}import{readFileSync as readFileSync19}from"node:fs";import{basename as
|
|
2459
|
-
`))}async function runBlobUpload(args,deps){let filePathArg=args.rest[1];if(!filePathArg)throw new Error("`platform blob upload` \u9700\u8981 <file-path>\u3002");let filePath=resolve13(filePathArg),fileName=
|
|
2461
|
+
`))}return error instanceof Error?error:new Error(`platform build run \u5931\u8D25: ${appId}/${sourceVersionId}`)}import{readFileSync as readFileSync19}from"node:fs";import{basename as basename7,extname as extname4,resolve as resolve13}from"node:path";async function runBlobCommand(args,deps){if(hasHelpFlag4(args)||args.rest.length===0){printBlobHelp();return}let subcommand=args.rest[0];if(subcommand==="upload"){await runBlobUpload(args,deps);return}if(subcommand==="list"){await runBlobList(args,deps);return}if(subcommand==="get"){await runBlobGet(args,deps);return}if(subcommand==="url"){await runBlobUrl(args,deps);return}throw new Error("`platform blob` \u4EC5\u652F\u6301 `upload`\u3001`list`\u3001`get`\u3001`url`\u3002")}function isBlobHelpRequest(args){return hasHelpFlag4(args)||args.rest.length===0}function printBlobHelp(){process.stdout.write(["platform blob <command>","","Commands:"," platform blob upload <file-path> [--app <app-id>] [--content-type <mime>] [--client-request-id <id>] [--json]"," platform blob list [--app <app-id>] [--q <keyword>] [--cursor <cursor>] [--limit <n>] [--json]"," platform blob get <blob-id> [--json]"," platform blob url <blob-id> [--ttl-seconds <n>] [--json]","","Notes:"," - Object Storage \u5F53\u524D\u8D70 tenant \u63A7\u5236\u9762\uFF0C\u4E0D\u8D70 public/runtime SDK"," - `upload` \u590D\u7528\u4E09\u6B65\u5F0F\u4E0A\u4F20\uFF1Acreate session -> upload binary -> complete"," - `url` \u9ED8\u8BA4\u7B7E\u53D1 1 \u5C0F\u65F6\u4E0B\u8F7D\u94FE\u63A5",""].join(`
|
|
2462
|
+
`))}async function runBlobUpload(args,deps){let filePathArg=args.rest[1];if(!filePathArg)throw new Error("`platform blob upload` \u9700\u8981 <file-path>\u3002");let filePath=resolve13(filePathArg),fileName=basename7(filePath),content=new Uint8Array(readFileSync19(filePath)),contentType=readStringOption4(args,"content-type")?.trim()||inferMimeType(fileName),appId=readStringOption4(args,"app")?.trim(),clientRequestId=readStringOption4(args,"client-request-id")?.trim(),session=await deps.sdk.createTenantBlobUploadSession({original_filename:fileName,content_type:contentType,size_bytes:content.byteLength,...appId?{app_id:appId}:{},...clientRequestId?{client_request_id:clientRequestId}:{}}).catch(error=>{throw formatBlobError(error,"upload(create session)")});await deps.sdk.uploadTenantBlobBinary(session.upload_session_id,{content,content_type:contentType,upload_url:session.upload_url,headers:session.headers}).catch(error=>{throw formatBlobError(error,"upload(content)")});let response=await deps.sdk.completeTenantBlobUpload(session.upload_session_id,{size_bytes:content.byteLength}).catch(error=>{throw formatBlobError(error,"upload(complete)")});if(args.options.json===!0){process.stdout.write(`${JSON.stringify({upload_session:session,result:response},null,2)}
|
|
2460
2463
|
`);return}process.stdout.write(["Blob \u5DF2\u4E0A\u4F20\u3002",`tenant: ${deps.tenantId}`,`blob: ${response.blob_id}`,`upload_session: ${response.upload_session_id}`,`file: ${fileName}`,`content_type: ${contentType}`,`size: ${content.byteLength} bytes`,`source: ${appId?`app:${appId}`:"tenant_workbench"}`,""].join(`
|
|
2461
2464
|
`))}async function runBlobList(args,deps){let response=await deps.sdk.listTenantBlobs({...readStringOption4(args,"app")?{app_id:readStringOption4(args,"app")}:{},...readStringOption4(args,"q")?{q:readStringOption4(args,"q")}:{},...readStringOption4(args,"cursor")?{cursor:readStringOption4(args,"cursor")}:{},...readNumberOption2(args,"limit")!==void 0?{limit:readNumberOption2(args,"limit")}:{}}).catch(error=>{throw formatBlobError(error,"list")});if(args.options.json===!0){process.stdout.write(`${JSON.stringify(response,null,2)}
|
|
2462
2465
|
`);return}process.stdout.write([`tenant: ${deps.tenantId}`,`items: ${response.items.length}`,`next_cursor: ${response.next_cursor??"-"}`,...response.items.map(item=>[item.blob_id,item.original_filename,`source=${item.source_type}`,`mime=${item.content_type??"-"}`,`size=${item.size_bytes}`,`created_at=${item.created_at}`].join(" ")),""].join(`
|
|
@@ -2465,15 +2468,15 @@ detail: ${JSON.stringify(error.detail)}`:"";return new Error([`platform build ru
|
|
|
2465
2468
|
`))}async function runBlobUrl(args,deps){let blobId=args.rest[1];if(!blobId)throw new Error("`platform blob url` \u9700\u8981 <blob-id>\u3002");let ttlSeconds=readNumberOption2(args,"ttl-seconds")??3600,response=await deps.sdk.issueTenantBlobDownloadUrl(blobId,{ttl_seconds:ttlSeconds}).catch(error=>{throw formatBlobError(error,"url")});if(args.options.json===!0){process.stdout.write(`${JSON.stringify(response,null,2)}
|
|
2466
2469
|
`);return}process.stdout.write([response.url,`expires_at: ${response.expires_at}`,`ttl_seconds: ${ttlSeconds}`,`tenant: ${deps.tenantId}`,""].join(`
|
|
2467
2470
|
`))}function readStringOption4(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}function readNumberOption2(args,key){let value=readStringOption4(args,key);if(value===void 0)return;let parsed=Number(value);if(!Number.isFinite(parsed)||parsed<=0)throw new Error(`\`--${key}\` \u9700\u8981\u6B63\u6574\u6570\u3002`);return Math.trunc(parsed)}function hasHelpFlag4(args){return args.options.help===!0||args.options.h===!0}function inferMimeType(fileName){switch(extname4(fileName).toLowerCase()){case".json":return"application/json";case".pdf":return"application/pdf";case".txt":return"text/plain";case".csv":return"text/csv";case".html":return"text/html";case".md":return"text/markdown";case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".gif":return"image/gif";case".webp":return"image/webp";case".svg":return"image/svg+xml";case".mp4":return"video/mp4";case".mov":return"video/quicktime";case".webm":return"video/webm";case".zip":return"application/zip";default:return"application/octet-stream"}}function formatBlobError(error,action){return error instanceof PlatformApiError?new Error([`Blob ${action} \u5931\u8D25\u3002`,`\u72B6\u6001\u7801: ${error.status}`,`\u9519\u8BEF\u7801: ${error.code??"-"}`,error.message].join(`
|
|
2468
|
-
`)):error instanceof Error?error:new Error(`Blob ${action} \u5931\u8D25\u3002`)}function buildTenantAssetReference2(asset){return{asset_id:asset.asset.asset_id,title:asset.asset.title,media_type:asset.asset.media_type,mime_type:asset.asset.mime_type,size_bytes:asset.original_file.size_bytes,folder_id:asset.asset.folder_id,original_url:asset.original_url,variant_urls:asset.variant_urls}}function resolveCmsAttachAssetField(fields,fieldName){let field=fields.find(entry=>entry.name===fieldName);if(!field)throw new Error(`Collection does not contain field \`${fieldName}\`.`);if(field.type!=="image"&&field.type!=="images")throw new Error(`\u5B57\u6BB5 \`${fieldName}\` \u4E0D\u662F\u53EF\u6302\u8F7D\u7D20\u6750\u7684\u56FE\u7247\u5B57\u6BB5\u3002`);return field}function isAssetReferenceRecord(value){return typeof value=="object"&&value!==null&&typeof value.asset_id=="string"}function dedupeAssetReferences(values){let seen=new Set,deduped=[];for(let value of values)seen.has(value.asset_id)||(seen.add(value.asset_id),deduped.push(value));return deduped}function buildCmsAttachAssetPayload(args){let assetReferences=args.assets.map(buildTenantAssetReference2),nextContent=normalizeCmsContentForWrite2(args.item.content,args.fields);if(args.field.type==="image"){if(assetReferences.length!==1)throw new Error("\u5355\u56FE\u5B57\u6BB5\u4E00\u6B21\u53EA\u80FD\u6302\u8F7D\u4E00\u4E2A\u7D20\u6750\u3002");nextContent[args.field.name]=assetReferences[0]}else if(args.field.type==="images"){let currentValues=Array.isArray(args.item.content[args.field.name])?args.item.content[args.field.name].filter(isAssetReferenceRecord):[];nextContent[args.field.name]=dedupeAssetReferences(args.replace?assetReferences:[...currentValues,...assetReferences])}else throw new Error(`\u5B57\u6BB5 \`${args.field.name}\` \u4E0D\u662F\u53EF\u6302\u8F7D\u7D20\u6750\u7684\u56FE\u7247\u5B57\u6BB5\u3002`);return{collection:args.item.collection,system:{...args.item.system.publish_status?{publish_status:args.item.system.publish_status}:{},...args.item.system.slug?{slug:args.item.system.slug}:{},...args.item.system.tags?{tags:[...args.item.system.tags]}:{},...Object.prototype.hasOwnProperty.call(args.item.system,"category_id")?{category_id:args.item.system.category_id??null}:{},...args.item.system.content_format?{content_format:args.item.system.content_format}:{},...args.item.system.source?{source:{...args.item.system.source}}:{}},content:nextContent}}function normalizeCmsContentForWrite2(content,fields){let normalized={...content};for(let field of fields){let currentValue=normalized[field.name];if(field.type==="relation"){typeof currentValue=="object"&¤tValue!==null&&typeof currentValue.id=="string"&&(normalized[field.name]=currentValue.id);continue}field.type==="relations"&&Array.isArray(currentValue)&&(normalized[field.name]=currentValue.map(item=>typeof item=="string"?item:typeof item=="object"&&item!==null&&typeof item.id=="string"?item.id:null).filter(item=>typeof item=="string"))}return normalized}import{existsSync as existsSync19,readFileSync as readFileSync20}from"node:fs";import{createConnection}from"node:net";import{dirname as
|
|
2471
|
+
`)):error instanceof Error?error:new Error(`Blob ${action} \u5931\u8D25\u3002`)}function buildTenantAssetReference2(asset){return{asset_id:asset.asset.asset_id,title:asset.asset.title,media_type:asset.asset.media_type,mime_type:asset.asset.mime_type,size_bytes:asset.original_file.size_bytes,folder_id:asset.asset.folder_id,original_url:asset.original_url,variant_urls:asset.variant_urls}}function resolveCmsAttachAssetField(fields,fieldName){let field=fields.find(entry=>entry.name===fieldName);if(!field)throw new Error(`Collection does not contain field \`${fieldName}\`.`);if(field.type!=="image"&&field.type!=="images")throw new Error(`\u5B57\u6BB5 \`${fieldName}\` \u4E0D\u662F\u53EF\u6302\u8F7D\u7D20\u6750\u7684\u56FE\u7247\u5B57\u6BB5\u3002`);return field}function isAssetReferenceRecord(value){return typeof value=="object"&&value!==null&&typeof value.asset_id=="string"}function dedupeAssetReferences(values){let seen=new Set,deduped=[];for(let value of values)seen.has(value.asset_id)||(seen.add(value.asset_id),deduped.push(value));return deduped}function buildCmsAttachAssetPayload(args){let assetReferences=args.assets.map(buildTenantAssetReference2),nextContent=normalizeCmsContentForWrite2(args.item.content,args.fields);if(args.field.type==="image"){if(assetReferences.length!==1)throw new Error("\u5355\u56FE\u5B57\u6BB5\u4E00\u6B21\u53EA\u80FD\u6302\u8F7D\u4E00\u4E2A\u7D20\u6750\u3002");nextContent[args.field.name]=assetReferences[0]}else if(args.field.type==="images"){let currentValues=Array.isArray(args.item.content[args.field.name])?args.item.content[args.field.name].filter(isAssetReferenceRecord):[];nextContent[args.field.name]=dedupeAssetReferences(args.replace?assetReferences:[...currentValues,...assetReferences])}else throw new Error(`\u5B57\u6BB5 \`${args.field.name}\` \u4E0D\u662F\u53EF\u6302\u8F7D\u7D20\u6750\u7684\u56FE\u7247\u5B57\u6BB5\u3002`);return{collection:args.item.collection,system:{...args.item.system.publish_status?{publish_status:args.item.system.publish_status}:{},...args.item.system.slug?{slug:args.item.system.slug}:{},...args.item.system.tags?{tags:[...args.item.system.tags]}:{},...Object.prototype.hasOwnProperty.call(args.item.system,"category_id")?{category_id:args.item.system.category_id??null}:{},...args.item.system.content_format?{content_format:args.item.system.content_format}:{},...args.item.system.source?{source:{...args.item.system.source}}:{}},content:nextContent}}function normalizeCmsContentForWrite2(content,fields){let normalized={...content};for(let field of fields){let currentValue=normalized[field.name];if(field.type==="relation"){typeof currentValue=="object"&¤tValue!==null&&typeof currentValue.id=="string"&&(normalized[field.name]=currentValue.id);continue}field.type==="relations"&&Array.isArray(currentValue)&&(normalized[field.name]=currentValue.map(item=>typeof item=="string"?item:typeof item=="object"&&item!==null&&typeof item.id=="string"?item.id:null).filter(item=>typeof item=="string"))}return normalized}import{existsSync as existsSync19,readFileSync as readFileSync20}from"node:fs";import{createConnection}from"node:net";import{dirname as dirname13,resolve as resolve14}from"node:path";import process2 from"node:process";function isLikelyControlApiConnectionError(error){if(!(error instanceof Error))return!1;let message=error.message.toLowerCase();if(message.includes("fetch failed")||message.includes("econnrefused")||message.includes("failed to fetch"))return!0;let cause=error.cause;if(cause&&typeof cause=="object"&&"code"in cause){let code2=String(cause.code).toLowerCase();return code2==="econnrefused"||code2==="enotfound"||code2==="econnreset"}return!1}function isControlApiDiagnosticError(error){return error instanceof PlatformApiError&&(error.category==="capability_health"||error.category==="runtime_binding"||error.code==="capability_unavailable"||error.code==="runtime_binding_missing")}function formatControlApiDiagnosticErrorText(error){let lines=["control-api diagnostic error:",`- code: ${error.code??"unknown"}`,`- category: ${error.category??"unknown"}`,`- capability: ${error.capability??"unknown"}`,`- message: ${error.message}`];return error.requestId&&lines.push(`- request_id: ${error.requestId}`),error.remediation&&lines.push(`- action: ${error.remediation}`),`${lines.join(`
|
|
2469
2472
|
`)}
|
|
2470
2473
|
`}async function collectControlApiFailureDiagnostics(baseUrl=getControlApiBaseUrl(),startDir=process2.cwd()){let parsedBaseUrl=new URL(baseUrl),isLocal=isLocalControlApiUrl(parsedBaseUrl),healthz=await probeEndpoint(new URL("/healthz",parsedBaseUrl)),readyz=healthz.status==="ok"||healthz.status==="failed"?await probeEndpoint(new URL("/readyz",parsedBaseUrl)):{status:"skipped",httpStatus:null},port=Number.parseInt(parsedBaseUrl.port||(parsedBaseUrl.protocol==="https:"?"443":"80"),10),host=normalizeProbeHost(parsedBaseUrl.hostname),lock=isLocal?readControlApiDevLock(startDir,port):emptyLock(),listening=isLocal?await isPortListening(host,port):null,diagnosis=buildDiagnosis({healthz,readyz,isLocal,lockExists:lock.exists,pidAlive:lock.pid_alive,portListening:listening}),endpoints=await collectEndpointDiagnostics(baseUrl,healthz),capabilityHealth=extractCapabilityHealthDiagnostics(healthz.body);return{control_api:{base_url:baseUrl,reachable:healthz.status==="ok"||healthz.status==="failed",healthz:{status:healthz.status==="not_ready"?"failed":healthz.status,http_status:healthz.httpStatus},readyz:{status:readyz.status,http_status:readyz.httpStatus}},capability_health:capabilityHealth,endpoints,local_dev:{is_local_base_url:isLocal,lock,port:{host,port,listening}},diagnosis,recommendations:buildRecommendations(diagnosis.code,isLocal)}}function formatControlApiFailureDiagnosticsText(diagnostics){return formatControlApiDiagnosticsText(diagnostics,"control-api unreachable:")}function formatControlApiDiagnosticsText(diagnostics,title="control-api diagnostics:"){let lines=[title,`- base_url: ${diagnostics.control_api.base_url}`,`- healthz: ${diagnostics.control_api.healthz.status}${diagnostics.control_api.healthz.http_status==null?"":` (${diagnostics.control_api.healthz.http_status})`}`,`- readyz: ${diagnostics.control_api.readyz.status}${diagnostics.control_api.readyz.http_status==null?"":` (${diagnostics.control_api.readyz.http_status})`}`];return lines.push(`- endpoint control: ${diagnostics.endpoints.control.healthz.status}`,`- endpoint runtime: ${formatEndpointState(diagnostics.endpoints.runtime)}`,`- endpoint public: ${formatEndpointState(diagnostics.endpoints.public)}`),diagnostics.capability_health.degraded.length>0&&lines.push(`- degraded capabilities: ${formatHealthItems(diagnostics.capability_health.degraded)}`),diagnostics.capability_health.workers.length>0&&lines.push(`- degraded workers: ${formatHealthItems(diagnostics.capability_health.workers)}`),diagnostics.local_dev.is_local_base_url&&lines.push(`- lock: ${diagnostics.local_dev.lock.exists?`exists pid=${diagnostics.local_dev.lock.pid??"-"} alive=${diagnostics.local_dev.lock.pid_alive??"-"}`:"missing"}`,`- port: ${diagnostics.local_dev.port.listening?"listening":"not listening"}`),lines.push(`- likely_cause: ${diagnostics.diagnosis.code}`,...diagnostics.recommendations.map(item=>`- action: ${item}`)),`${lines.join(`
|
|
2471
2474
|
`)}
|
|
2472
|
-
`}async function collectEndpointDiagnostics(controlBaseUrl,controlHealthz){let endpoints=listResolvedControlApiEndpoints({...process2.env,CONTROL_API_BASE_URL:controlBaseUrl}),results=await Promise.all(endpoints.map(async endpoint=>{if(endpoint.role==="control")return{role:endpoint.role,base_url:endpoint.baseUrl,enabled:!0,capabilities:endpoint.capabilities,request_class:endpoint.requestClass,healthz:{status:controlHealthz.status,http_status:controlHealthz.httpStatus}};if(!endpoint.enabled||endpoint.baseUrl==null)return{role:endpoint.role,base_url:endpoint.baseUrl,enabled:!1,capabilities:endpoint.capabilities,request_class:endpoint.requestClass,reason:endpoint.reason,healthz:{status:"skipped",http_status:null}};let healthz=await probeEndpoint(new URL("/healthz",endpoint.baseUrl));return{role:endpoint.role,base_url:endpoint.baseUrl,enabled:!0,capabilities:endpoint.capabilities,request_class:endpoint.requestClass,healthz:{status:healthz.status,http_status:healthz.httpStatus}}}));return{control:results.find(endpoint=>endpoint.role==="control"),runtime:results.find(endpoint=>endpoint.role==="runtime"),public:results.find(endpoint=>endpoint.role==="public")}}function formatEndpointState(endpoint){return endpoint.enabled?`${endpoint.healthz.status}${endpoint.healthz.http_status==null?"":` (${endpoint.healthz.http_status})`}`:`${endpoint.reason??"disabled"}${endpoint.base_url?` (${endpoint.base_url})`:""}`}async function probeEndpoint(url){try{let response=await fetch(url,{signal:AbortSignal.timeout(1200)}),body=await readJsonBody(response);return response.ok?{status:"ok",httpStatus:response.status,body}:{status:response.status===503?"not_ready":"failed",httpStatus:response.status,body}}catch{return{status:"unreachable",httpStatus:null}}}async function readJsonBody(response){let text2=await response.text().catch(()=>"");if(text2)try{return JSON.parse(text2)}catch{return}}function extractCapabilityHealthDiagnostics(body){if(!body||typeof body!="object")return{status:null,degraded:[],workers:[]};let record=body;return{status:typeof record.status=="string"?record.status:null,degraded:extractDegradedHealthItems(record.capabilities),workers:extractDegradedHealthItems(record.workers)}}function extractDegradedHealthItems(input){return!input||typeof input!="object"?[]:Object.entries(input).map(([key,value])=>toHealthDiagnostic(key,value)).filter(item=>!!item)}function toHealthDiagnostic(key,value){if(!value||typeof value!="object")return null;let record=value,status=typeof record.status=="string"?record.status:"unknown";return status!=="degraded"&&status!=="unavailable"?null:{key,status,summary:typeof record.summary=="string"?record.summary:"",issues:Array.isArray(record.issues)?record.issues.filter(item=>typeof item=="string"):[],...typeof record.check_level=="string"?{check_level:record.check_level}:{}}}function formatHealthItems(items){return items.map(item=>{let issueText=item.issues.length>0?` issues=${item.issues.join(",")}`:"",levelText=item.check_level?` level=${item.check_level}`:"";return`${item.key}:${item.status}${levelText}${issueText}`}).join("; ")}function isLocalControlApiUrl(url){return url.hostname==="localhost"||url.hostname==="127.0.0.1"||url.hostname==="0.0.0.0"}function normalizeProbeHost(host){return host==="0.0.0.0"?"127.0.0.1":host}function readControlApiDevLock(startDir,port){let path2=findControlApiLockPath(startDir,port);if(!path2||!existsSync19(path2))return{path:path2,exists:!1,pid:null,pid_alive:null};let raw=readFileSync20(path2,"utf8").trim(),pid=parseLockPid(raw);return{path:path2,exists:!0,pid,pid_alive:pid==null?null:isPidRunning(pid)}}function emptyLock(){return{path:null,exists:!1,pid:null,pid_alive:null}}function findControlApiLockPath(startDir,port){let current=resolve14(startDir);for(;;){let candidate=resolve14(current,"services","control-api",`.dev-server.${port}.lock`);if(existsSync19(resolve14(current,"services","control-api")))return candidate;let parent=
|
|
2473
|
-
`)}function computeChecksum2(input){return`sha256:${createHash6("sha256").update(input).digest("hex")}`}function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function toStringArray(value){if(Array.isArray(value))return value.filter(item=>typeof item=="string").map(item=>item.trim()).filter(Boolean);if(typeof value=="string")return value.split(",").map(item=>item.trim()).filter(Boolean)}function toOptionalString(value){return typeof value=="string"&&value.trim().length>0?value.trim():void 0}function isMarkdownFilePath(filePath){let extension=extname5(filePath).toLowerCase();return extension===".md"||extension===".markdown"}function normalizeSourcePath(filePath){let normalized=
|
|
2475
|
+
`}async function collectEndpointDiagnostics(controlBaseUrl,controlHealthz){let endpoints=listResolvedControlApiEndpoints({...process2.env,CONTROL_API_BASE_URL:controlBaseUrl}),results=await Promise.all(endpoints.map(async endpoint=>{if(endpoint.role==="control")return{role:endpoint.role,base_url:endpoint.baseUrl,enabled:!0,capabilities:endpoint.capabilities,request_class:endpoint.requestClass,healthz:{status:controlHealthz.status,http_status:controlHealthz.httpStatus}};if(!endpoint.enabled||endpoint.baseUrl==null)return{role:endpoint.role,base_url:endpoint.baseUrl,enabled:!1,capabilities:endpoint.capabilities,request_class:endpoint.requestClass,reason:endpoint.reason,healthz:{status:"skipped",http_status:null}};let healthz=await probeEndpoint(new URL("/healthz",endpoint.baseUrl));return{role:endpoint.role,base_url:endpoint.baseUrl,enabled:!0,capabilities:endpoint.capabilities,request_class:endpoint.requestClass,healthz:{status:healthz.status,http_status:healthz.httpStatus}}}));return{control:results.find(endpoint=>endpoint.role==="control"),runtime:results.find(endpoint=>endpoint.role==="runtime"),public:results.find(endpoint=>endpoint.role==="public")}}function formatEndpointState(endpoint){return endpoint.enabled?`${endpoint.healthz.status}${endpoint.healthz.http_status==null?"":` (${endpoint.healthz.http_status})`}`:`${endpoint.reason??"disabled"}${endpoint.base_url?` (${endpoint.base_url})`:""}`}async function probeEndpoint(url){try{let response=await fetch(url,{signal:AbortSignal.timeout(1200)}),body=await readJsonBody(response);return response.ok?{status:"ok",httpStatus:response.status,body}:{status:response.status===503?"not_ready":"failed",httpStatus:response.status,body}}catch{return{status:"unreachable",httpStatus:null}}}async function readJsonBody(response){let text2=await response.text().catch(()=>"");if(text2)try{return JSON.parse(text2)}catch{return}}function extractCapabilityHealthDiagnostics(body){if(!body||typeof body!="object")return{status:null,degraded:[],workers:[]};let record=body;return{status:typeof record.status=="string"?record.status:null,degraded:extractDegradedHealthItems(record.capabilities),workers:extractDegradedHealthItems(record.workers)}}function extractDegradedHealthItems(input){return!input||typeof input!="object"?[]:Object.entries(input).map(([key,value])=>toHealthDiagnostic(key,value)).filter(item=>!!item)}function toHealthDiagnostic(key,value){if(!value||typeof value!="object")return null;let record=value,status=typeof record.status=="string"?record.status:"unknown";return status!=="degraded"&&status!=="unavailable"?null:{key,status,summary:typeof record.summary=="string"?record.summary:"",issues:Array.isArray(record.issues)?record.issues.filter(item=>typeof item=="string"):[],...typeof record.check_level=="string"?{check_level:record.check_level}:{}}}function formatHealthItems(items){return items.map(item=>{let issueText=item.issues.length>0?` issues=${item.issues.join(",")}`:"",levelText=item.check_level?` level=${item.check_level}`:"";return`${item.key}:${item.status}${levelText}${issueText}`}).join("; ")}function isLocalControlApiUrl(url){return url.hostname==="localhost"||url.hostname==="127.0.0.1"||url.hostname==="0.0.0.0"}function normalizeProbeHost(host){return host==="0.0.0.0"?"127.0.0.1":host}function readControlApiDevLock(startDir,port){let path2=findControlApiLockPath(startDir,port);if(!path2||!existsSync19(path2))return{path:path2,exists:!1,pid:null,pid_alive:null};let raw=readFileSync20(path2,"utf8").trim(),pid=parseLockPid(raw);return{path:path2,exists:!0,pid,pid_alive:pid==null?null:isPidRunning(pid)}}function emptyLock(){return{path:null,exists:!1,pid:null,pid_alive:null}}function findControlApiLockPath(startDir,port){let current=resolve14(startDir);for(;;){let candidate=resolve14(current,"services","control-api",`.dev-server.${port}.lock`);if(existsSync19(resolve14(current,"services","control-api")))return candidate;let parent=dirname13(current);if(parent===current)return null;current=parent}}function parseLockPid(raw){if(!raw)return null;try{let parsed=JSON.parse(raw),pid=Number.parseInt(String(parsed.pid??""),10);return Number.isFinite(pid)&&pid>0?pid:null}catch{let pid=Number.parseInt(raw,10);return Number.isFinite(pid)&&pid>0?pid:null}}function isPidRunning(pid){try{return process2.kill(pid,0),!0}catch{return!1}}function isPortListening(host,port){return new Promise(resolvePromise=>{let socket=createConnection({host,port});socket.setTimeout(800),socket.once("connect",()=>{socket.destroy(),resolvePromise(!0)}),socket.once("timeout",()=>{socket.destroy(),resolvePromise(!1)}),socket.once("error",()=>{socket.destroy(),resolvePromise(!1)})})}function buildDiagnosis(args){return args.healthz.status==="ok"&&args.readyz.status==="ok"?{category:"control_api_infrastructure",code:"control_api_ok",message:"control-api is reachable and ready"}:args.readyz.status==="not_ready"?{category:"control_api_infrastructure",code:"readyz_not_ready",message:"control-api is reachable but not ready"}:args.isLocal&&args.lockExists&&args.pidAlive===!0&&args.portListening===!1?{category:"control_api_infrastructure",code:"dev_manager_alive_but_http_not_ready",message:"control-api dev manager is alive but HTTP server is not listening"}:args.isLocal&&args.lockExists&&args.portListening===!1?{category:"control_api_infrastructure",code:"dev_lock_exists_port_not_listening",message:"control-api dev lock exists but HTTP port is not listening"}:{category:"control_api_infrastructure",code:args.healthz.status==="unreachable"?"healthz_unreachable":"control_api_unreachable",message:"control-api is unreachable"}}function buildRecommendations(code2,isLocal){return code2==="control_api_ok"?[]:isLocal?code2==="dev_manager_alive_but_http_not_ready"||code2==="dev_lock_exists_port_not_listening"?["restart `pnpm --filter @platform/control-api dev`"]:["start `pnpm --filter @platform/control-api dev`"]:["check CONTROL_API_BASE_URL, network connectivity, and environment configuration"]}function normalizeCategorySlug(value){return value.trim().toLowerCase().replace(/[\/\\]+/g,"-").replace(/\s+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"category"}function parseCmsCategoryPath(path2){let segments=path2.split("/").map(segment=>segment.trim()).filter(Boolean);if(segments.length===0)throw new Error("\u5206\u7C7B\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A\u3002");return segments.map(name=>({name,slug:normalizeCategorySlug(name)}))}function findCmsCategoryPathMatch(categories,parentId,segment){return categories.find(node=>(node.parent_id??null)===parentId&&node.slug===segment.slug)??categories.find(node=>(node.parent_id??null)===parentId&&node.name===segment.name)??null}async function ensureCmsCategoryPath(args){let categories=[...args.categories],parentId=null,finalNode=null,ensuredNodes=[];for(let segment of args.segments){let existing=findCmsCategoryPathMatch(categories,parentId,segment);if(existing){finalNode=existing,parentId=existing.id,ensuredNodes.push({id:existing.id,name:existing.name,slug:existing.slug,parent_id:existing.parent_id??null,action:"reused"});continue}let created=await args.createCategory(segment,parentId);categories.push(created),finalNode=created,parentId=created.id,ensuredNodes.push({id:created.id,name:created.name,slug:created.slug,parent_id:created.parent_id??null,action:"created"})}if(!finalNode)throw new Error("\u5206\u7C7B\u8DEF\u5F84\u89E3\u6790\u5931\u8D25\uFF0C\u672A\u751F\u6210\u76EE\u6807\u5206\u7C7B\u3002");return{categories,finalNode,ensuredNodes}}function planCmsCategoryPath(args){let categories=[...args.categories],parentId=null,finalNode=null,plannedNodeCounter=0,plannedNodes=[];for(let segment of args.segments){let existing=findCmsCategoryPathMatch(categories,parentId,segment);if(existing){finalNode=existing,parentId=existing.id,plannedNodes.push({id:existing.id,name:existing.name,slug:existing.slug,parent_id:existing.parent_id??null,action:"reused"});continue}plannedNodes.push({id:null,name:segment.name,slug:segment.slug,parent_id:parentId,action:"created"}),finalNode=null,plannedNodeCounter+=1,parentId=`__planned_category_${plannedNodeCounter}`}return{finalNode,plannedNodes}}import{createHash as createHash6}from"node:crypto";import{readdirSync as readdirSync8,statSync as statSync7}from"node:fs";import{basename as basename8,extname as extname5,join as join15,relative as relative6,resolve as resolve15}from"node:path";import YAML3 from"yaml";function normalizeLineEndings(input){return input.replace(/\r\n/g,`
|
|
2476
|
+
`)}function computeChecksum2(input){return`sha256:${createHash6("sha256").update(input).digest("hex")}`}function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function toStringArray(value){if(Array.isArray(value))return value.filter(item=>typeof item=="string").map(item=>item.trim()).filter(Boolean);if(typeof value=="string")return value.split(",").map(item=>item.trim()).filter(Boolean)}function toOptionalString(value){return typeof value=="string"&&value.trim().length>0?value.trim():void 0}function isMarkdownFilePath(filePath){let extension=extname5(filePath).toLowerCase();return extension===".md"||extension===".markdown"}function normalizeSourcePath(filePath){let normalized=relative6(process.cwd(),filePath).replace(/\\/g,"/");return normalized.length>0&&!normalized.startsWith("..")?normalized:filePath.replace(/\\/g,"/")}function inferDefaultTitleFromPath(filePath){let title=basename8(filePath,extname5(filePath)).trim();return title.length>0?title:void 0}function inferDefaultSlugFromPath(filePath){let slug=basename8(filePath,extname5(filePath)).trim().toLowerCase().replace(/[\/\\]+/g,"-").replace(/\s+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"").slice(0,120);return slug.length>0?slug:void 0}function normalizeItemIdSegment(value){return value.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function inferItemIdFromPrefix(prefix,filePath){let normalizedPrefix=normalizeItemIdSegment(prefix)||"cms-item",normalizedSource=filePath.replace(/\.[^.]+$/,""),pathSegment=normalizeItemIdSegment(normalizedSource),hash=createHash6("sha256").update(filePath).digest("hex").slice(0,8),readableSegment=pathSegment.length>0?pathSegment.slice(0,64):"item";return`${normalizedPrefix}-${readableSegment}-${hash}`}function collectMarkdownImportSources(targetPath,recursive){let absoluteTargetPath=resolve15(targetPath),stats=statSync7(absoluteTargetPath);if(stats.isFile()){if(!isMarkdownFilePath(absoluteTargetPath))throw new Error(`\u4EC5\u652F\u6301\u5BFC\u5165 Markdown \u6587\u4EF6\uFF1A${targetPath}`);return[{absolutePath:absoluteTargetPath,sourcePath:normalizeSourcePath(absoluteTargetPath)}]}if(!stats.isDirectory())throw new Error(`\u4EC5\u652F\u6301\u5BFC\u5165 Markdown \u6587\u4EF6\u6216\u76EE\u5F55\uFF1A${targetPath}`);let collected=[],visitDirectory=directoryPath=>{let entries=readdirSync8(directoryPath,{withFileTypes:!0}).sort((left,right)=>left.name.localeCompare(right.name));for(let entry of entries){let entryPath=join15(directoryPath,entry.name);if(entry.isDirectory()){recursive&&visitDirectory(entryPath);continue}!entry.isFile()||!isMarkdownFilePath(entryPath)||collected.push({absolutePath:entryPath,sourcePath:normalizeSourcePath(entryPath)})}};return visitDirectory(absoluteTargetPath),collected}function parseMarkdownWithFrontmatter(input){let raw=normalizeLineEndings(input),checksum3=computeChecksum2(raw);if(!raw.startsWith(`---
|
|
2474
2477
|
`))return{frontmatter:{},body:raw.trim(),raw,checksum:checksum3};let closingIndex=raw.indexOf(`
|
|
2475
2478
|
---
|
|
2476
|
-
`,4);if(closingIndex===-1)return{frontmatter:{},body:raw.trim(),raw,checksum:checksum3};let frontmatterSource=raw.slice(4,closingIndex),body=raw.slice(closingIndex+5).trim(),parsed=YAML3.parse(frontmatterSource);return{frontmatter:isPlainObject(parsed)?parsed:{},body,raw,checksum:checksum3}}function buildMarkdownItemPayload(args){let parsed=parseMarkdownWithFrontmatter(args.markdownContent),frontmatter={...parsed.frontmatter},title=args.title??toOptionalString(frontmatter.title)??inferDefaultTitleFromPath(args.markdownPath),slug=args.slug??toOptionalString(frontmatter.slug)??inferDefaultSlugFromPath(args.markdownPath),summary=args.summary??toOptionalString(frontmatter.summary),tags=args.tags??toStringArray(frontmatter.tags),categoryId=args.categoryId??toOptionalString(frontmatter.category_id)??null,publishStatus=args.publishStatus??toOptionalString(frontmatter.publish_status)??"draft";delete frontmatter.title,delete frontmatter.slug,delete frontmatter.summary,delete frontmatter.tags,delete frontmatter.category_id,delete frontmatter.publish_status;let content={...frontmatter,body:parsed.body};return title&&(content.title=title),summary&&(content.summary=summary),{...args.itemId?{item_id:args.itemId}:{},collection:args.collection,system:{publish_status:publishStatus,...slug?{slug}:{},...tags!==void 0?{tags}:{},...categoryId?{category_id:categoryId}:{},content_format:"markdown",source:{source_type:"markdown",source_url:null,source_path:args.markdownPath,source_raw:parsed.raw,checksum:parsed.checksum,imported_by:args.importedBy??"ide-agent",parser_version:"markdown-importer.v1"}},content}}function resolveMarkdownImportLookupKey(payload){return typeof payload.item_id=="string"&&payload.item_id.trim().length>0?{kind:"item_id",value:payload.item_id}:typeof payload.system.slug=="string"&&payload.system.slug.trim().length>0?{kind:"slug",value:payload.system.slug}:null}function summarizeMarkdownImportResults(items){let importedOrPlanned=0,skipped=0,draft=0,published=0,archived=0;for(let item of items){if(item.state==="skipped"?skipped+=1:importedOrPlanned+=1,item.publish_status==="draft"){draft+=1;continue}if(item.publish_status==="published"){published+=1;continue}item.publish_status==="archived"&&(archived+=1)}return{total:items.length,imported_or_planned:importedOrPlanned,skipped,draft,published,archived}}function normalizeSlugCandidate(value){return value.trim().slice(0,120)}function applySlugSuffix(baseSlug,suffix){let suffixText=`-${suffix}`;return`${baseSlug.slice(0,Math.max(1,120-suffixText.length))}${suffixText}`}async function findTenantCmsItemByExactSlug(args){let normalizedSlug=normalizeSlugCandidate(args.slug);if(!normalizedSlug)return null;let page=1,pageSize=100;for(;;){let response=await args.sdk.listTenantCmsItems({collection:args.collection,page,pageSize,query:normalizedSlug}),matched=response.items.find(item=>item.system.slug===normalizedSlug);if(matched)return matched;if(page*pageSize>=response.total||response.items.length===0)return null;page+=1}}async function resolveUniqueTenantCmsSlug(args){let normalizedSlug=args.slug?normalizeSlugCandidate(args.slug):void 0;if(!normalizedSlug)return{slug:void 0,adjusted:!1};let candidate=normalizedSlug,suffix=2;for(;;){let conflictsInBatch=args.reservedSlugs?.has(candidate)??!1,existing=conflictsInBatch?null:await findTenantCmsItemByExactSlug({sdk:args.sdk,collection:args.collection,slug:candidate});if(!conflictsInBatch&&(!existing||existing.system.id===args.itemId))return{slug:candidate,adjusted:candidate!==normalizedSlug,originalSlug:candidate!==normalizedSlug?normalizedSlug:void 0};candidate=applySlugSuffix(normalizedSlug,suffix),suffix+=1}}import{createHash as createHash7}from"node:crypto";import{URL as URL3}from"node:url";import{Readability}from"@mozilla/readability";import{JSDOM}from"jsdom";import sanitizeHtml from"sanitize-html";function computeChecksum3(input){return`sha256:${createHash7("sha256").update(input).digest("hex")}`}function stripUnsupportedJsonChars(value){return value.replace(/\u0000/g,"")}function trimToUndefined2(value){let normalized=value?.trim();return normalized||void 0}function getMetaContent(document,key){let selectors=[`meta[property="${key}"]`,`meta[name="${key}"]`,`meta[itemprop="${key}"]`];for(let selector of selectors){let value=trimToUndefined2(document.querySelector(selector)?.getAttribute("content"));if(value)return value}}function getFirstText(document,selectors){for(let selector of selectors){let value=trimToUndefined2(document.querySelector(selector)?.textContent);if(value)return value}}function normalizeUrl2(value,baseUrl){if(!value)return;let trimmed=value.trim();if(trimmed)try{return new URL3(trimmed,baseUrl).toString()}catch{return}}function escapeHtmlAttribute(value){return value.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function inferMimeTypeFromUrl2(value){if(!value)return;let pathname=(()=>{try{return new URL3(value).pathname.toLowerCase()}catch{return value.toLowerCase()}})();if(pathname.endsWith(".png"))return"image/png";if(pathname.endsWith(".webp"))return"image/webp";if(pathname.endsWith(".gif"))return"image/gif";if(pathname.endsWith(".svg"))return"image/svg+xml";if(pathname.endsWith(".jpg")||pathname.endsWith(".jpeg"))return"image/jpeg"}function extractArticleImageCandidates(document,baseUrl){let selectors=[".news-detail .image.parbase img",".news-detail .news-img img",".news-detail .richtext img","article img","main img"],results=[],seen=new Set;for(let selector of selectors)for(let image2 of document.querySelectorAll(selector)){let className=image2.getAttribute("class")?.toLowerCase()??"",parentClassName=image2.parentElement?.getAttribute("class")?.toLowerCase()??"";if(className.includes("qrcode")||className.includes("qr-code")||parentClassName.includes("qrcode")||parentClassName.includes("qr-code"))continue;let rawSrc=image2.getAttribute("src")??image2.getAttribute("data-src")??image2.getAttribute("data-original")??image2.getAttribute("data-original-src")??image2.getAttribute("data-lazy-src")??void 0,absoluteUrl=normalizeUrl2(rawSrc??void 0,baseUrl);!absoluteUrl||seen.has(absoluteUrl)||absoluteUrl.startsWith("data:")||(seen.add(absoluteUrl),results.push({url:absoluteUrl,alt:trimToUndefined2(image2.getAttribute("alt")??image2.getAttribute("title")??void 0)}))}return results}function normalizePublishedAt(value){if(!value)return;let timestamp=Date.parse(value);if(!Number.isNaN(timestamp))return new Date(timestamp).toISOString()}function inferDefaultTitleFromUrl(value){try{let parsed=new URL3(value),segment=parsed.pathname.replace(/\/+$/,"").split("/").filter(Boolean).at(-1)?.trim();return segment&&segment.length>0?decodeURIComponent(segment):parsed.hostname}catch{return}}function stripPageExtension(value){if(value)return value.replace(/\.(html?|xhtml|shtml)$/i,"")}function inferDefaultSlug(args){let candidates=[stripPageExtension(inferDefaultTitleFromUrl(args.resolvedUrl)),stripPageExtension(inferDefaultTitleFromUrl(args.requestedUrl)),args.title];for(let candidate of candidates){let normalized=candidate?.trim().toLowerCase().replace(/[\/\\]+/g,"-").replace(/\s+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"").slice(0,120);if(normalized)return normalized}}function absolutizeRichTextHtml(html,baseUrl){let body=new JSDOM(`<body>${html}</body>`,{url:baseUrl}).window.document.body;for(let anchor of body.querySelectorAll("a[href]")){let href=anchor.getAttribute("href"),absoluteHref=normalizeUrl2(href??void 0,baseUrl);absoluteHref&&anchor.setAttribute("href",absoluteHref)}let firstImageUrl;for(let image2 of body.querySelectorAll("img[src]")){let src=image2.getAttribute("src"),absoluteSrc=normalizeUrl2(src??void 0,baseUrl);absoluteSrc&&(image2.setAttribute("src",absoluteSrc),firstImageUrl??=absoluteSrc)}return{html:body.innerHTML,firstImageUrl}}function sanitizeArticleHtml(html){return sanitizeHtml(html,{allowedTags:["h1","h2","h3","h4","h5","h6","p","br","hr","blockquote","pre","code","ul","ol","li","strong","em","b","i","del","a","img","table","thead","tbody","tr","th","td"],allowedAttributes:{a:["href","title"],img:["src","alt","title"],code:["class"],pre:["class"]},allowedSchemes:["http","https","mailto"],disallowedTagsMode:"discard"})}async function fetchUrlImportSource(url,fetchImpl=fetch){let response=await fetchImpl(url,{redirect:"follow",headers:{"user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8","accept-language":"zh-CN,zh;q=0.9,en;q=0.8","cache-control":"no-cache",pragma:"no-cache"}});if(!response.ok)throw new Error(`URL \u6293\u53D6\u5931\u8D25\uFF1AHTTP ${response.status}`);let raw=stripUnsupportedJsonChars(await response.text());if(!trimToUndefined2(raw))throw new Error("URL \u9875\u9762\u5185\u5BB9\u4E3A\u7A7A\u3002");return{requestedUrl:url,resolvedUrl:response.url||url,raw,checksum:computeChecksum3(raw)}}function parseUrlImportHtml(args){let metadataDocument=new JSDOM(args.raw,{url:args.resolvedUrl}).window.document,articleImageCandidates=extractArticleImageCandidates(metadataDocument,args.resolvedUrl),readabilityDom=new JSDOM(args.raw,{url:args.resolvedUrl}),article=new Readability(readabilityDom.window.document).parse();if(!article?.content||!trimToUndefined2(article.textContent))throw new Error("\u672A\u80FD\u4ECE\u9875\u9762\u4E2D\u63D0\u53D6\u6B63\u6587\u3002");let{html:articleHtml,firstImageUrl}=absolutizeRichTextHtml(article.content,args.resolvedUrl),cleanedHtml=sanitizeArticleHtml(articleHtml).trim();if(!cleanedHtml)throw new Error("\u9875\u9762\u6B63\u6587\u5728\u6E05\u6D17\u540E\u4E3A\u7A7A\u3002");let leadImage=articleImageCandidates[0];if(!firstImageUrl&&leadImage){let altText=leadImage.alt?` alt="${escapeHtmlAttribute(leadImage.alt)}"`:' alt=""';cleanedHtml=`<p><img src="${escapeHtmlAttribute(leadImage.url)}"${altText} /></p>${cleanedHtml}`}let title=getMetaContent(metadataDocument,"og:title")??getMetaContent(metadataDocument,"twitter:title")??trimToUndefined2(metadataDocument.title)??trimToUndefined2(article.title)??getFirstText(metadataDocument,["h1"]),summary=getMetaContent(metadataDocument,"og:description")??getMetaContent(metadataDocument,"description")??trimToUndefined2(article.excerpt),metaCoverUrl=normalizeUrl2(getMetaContent(metadataDocument,"og:image"),args.resolvedUrl)??normalizeUrl2(getMetaContent(metadataDocument,"twitter:image"),args.resolvedUrl),bodyCoverUrl=firstImageUrl,coverUrl=leadImage?.url??bodyCoverUrl??metaCoverUrl,coverMimeType=coverUrl===metaCoverUrl?getMetaContent(metadataDocument,"og:image:type")??inferMimeTypeFromUrl2(coverUrl):inferMimeTypeFromUrl2(coverUrl)??getMetaContent(metadataDocument,"og:image:type"),sourceAuthor=getMetaContent(metadataDocument,"article:author")??getMetaContent(metadataDocument,"author")??getMetaContent(metadataDocument,"parsely-author")??getFirstText(metadataDocument,['[rel="author"]','[itemprop="author"]',".author",".ArticleAuthor-name"]),sourceSite=getMetaContent(metadataDocument,"og:site_name")??(()=>{try{return new URL3(args.resolvedUrl).hostname.replace(/^www\./,"")}catch{return}})(),sourcePublishedAt=normalizePublishedAt(getMetaContent(metadataDocument,"article:published_time")??getMetaContent(metadataDocument,"publishdate")??trimToUndefined2(metadataDocument.querySelector("time[datetime]")?.getAttribute("datetime")));return{requestedUrl:args.requestedUrl,resolvedUrl:args.resolvedUrl,title,summary,coverUrl,coverMimeType,sourceAuthor,sourceSite,sourcePublishedAt,body:cleanedHtml,contentFormat:"html",raw:args.raw,checksum:args.checksum??computeChecksum3(args.raw),warnings:[]}}function buildUrlItemPayload(args){let title=args.title??args.parsed.title??inferDefaultTitleFromUrl(args.parsed.resolvedUrl),slug=args.slug??inferDefaultSlug(args.parsed),summary=args.summary??args.parsed.summary,content={body:args.parsed.body,source_url:args.parsed.resolvedUrl};title&&(content.title=title),summary&&(content.summary=summary),args.parsed.sourceAuthor&&(content.source_author=args.parsed.sourceAuthor),args.parsed.sourceSite&&(content.source_site=args.parsed.sourceSite),args.parsed.sourcePublishedAt&&(content.source_published_at=args.parsed.sourcePublishedAt);let cover=resolveImportedUrlCover({parsed:args.parsed,cover:args.cover,title});return cover&&(content.cover=cover),{...args.itemId?{item_id:args.itemId}:{},collection:args.collection,system:{publish_status:args.publishStatus??"draft",...slug?{slug}:{},...args.tags&&args.tags.length>0?{tags:args.tags}:{},...args.categoryId!==void 0?{category_id:args.categoryId}:{},content_format:args.parsed.contentFormat,source:{source_type:"url",source_url:args.parsed.resolvedUrl,source_path:null,source_raw:args.parsed.raw,checksum:args.parsed.checksum,imported_by:args.importedBy??"ide-agent",parser_version:"url-importer.v1"}},content}}function resolveImportedUrlCover(args){if(args.cover?.mode==="asset"||args.cover?.mode==="remote")return args.cover.value;if(args.cover?.mode!=="none"&&args.parsed.coverUrl)return{title:args.title??"Remote cover",...args.parsed.coverMimeType?{mime_type:args.parsed.coverMimeType}:{},original_url:args.parsed.coverUrl}}async function assetizeParsedUrlImages(args){if(!args.includeBody&&!args.includeCover)return{parsed:args.parsed,cover:{mode:"none"},warnings:[]};let assetization=await assetizeExternalImagesInHtml({sdk:args.sdk,html:args.includeBody?args.parsed.body:"",baseUrl:args.parsed.resolvedUrl,coverUrl:args.includeCover?args.parsed.coverUrl:void 0,coverTitle:args.parsed.title,coverMimeType:args.parsed.coverMimeType,bodyTitle:args.parsed.title});return{parsed:{...args.parsed,body:args.includeBody?assetization.html:args.parsed.body},cover:assetization.cover,warnings:assetization.warnings}}function restrictItemPayloadToSchemaFields(payload,fields){let allowedFieldNames=new Set(fields.map(field=>field.name)),nextContent=Object.fromEntries(Object.entries(payload.content).filter(([key])=>allowedFieldNames.has(key))),droppedFields=Object.keys(payload.content).filter(key=>!allowedFieldNames.has(key));return{payload:{...payload,content:nextContent},droppedFields}}import process3 from"node:process";import{existsSync as existsSync21,readFileSync as readFileSync22}from"node:fs";import{join as join17}from"node:path";import{createHash as createHash9}from"node:crypto";import{existsSync as existsSync20,readdirSync as readdirSync8,readFileSync as readFileSync21}from"node:fs";import{basename as basename8,join as join16,relative as relative5}from"node:path";function assertNonEmptyString(value,field){if(typeof value!="string"||value.trim().length===0)throw new Error(`Auth policy field \`${field}\` must be a non-empty string.`);return value.trim()}function normalizePermissions(value){if(!Array.isArray(value))throw new Error("Auth policy field `permissions` must be an array.");let permissions=value.map((item,index)=>assertNonEmptyString(item,`permissions[${index}]`));return[...new Set(permissions)]}function normalizeAuthPolicy(input){if(typeof input!="object"||input===null)throw new Error("Auth policy must be an object.");let record=input;return{version:assertNonEmptyString(record.version,"version"),role:assertNonEmptyString(record.role,"role"),permissions:normalizePermissions(record.permissions)}}function deriveAuthResourceKey(policy,fallbackName){if(typeof policy=="object"&&policy!==null){let record=policy;if(typeof record.role=="string"&&record.role.trim().length>0)return`auth/${record.role.trim()}`;if(typeof record.policy=="string"&&record.policy.trim().length>0)return`auth/${record.policy.trim()}`}return`auth/${fallbackName}`}var DATA_FORM_ACCESS_SCOPES=["public","own","admin"];var DATA_FORM_GENERATED_SOURCE_TAG="data_form_generated";function buildSourceTagComment(source){return`-- source: ${source}`}function renderColumn(column){let parts=[`${column.column_name} ${column.data_type}`];return parts.push(column.nullable?"NULL":"NOT NULL"),column.default_sql!==void 0&&parts.push(`DEFAULT ${column.default_sql}`),parts.join(" ")}function renderCreateTable(tableName,columns){return[`CREATE TABLE IF NOT EXISTS ${tableName} (`,columns.map(column=>` ${renderColumn(column)}`).join(`,
|
|
2479
|
+
`,4);if(closingIndex===-1)return{frontmatter:{},body:raw.trim(),raw,checksum:checksum3};let frontmatterSource=raw.slice(4,closingIndex),body=raw.slice(closingIndex+5).trim(),parsed=YAML3.parse(frontmatterSource);return{frontmatter:isPlainObject(parsed)?parsed:{},body,raw,checksum:checksum3}}function buildMarkdownItemPayload(args){let parsed=parseMarkdownWithFrontmatter(args.markdownContent),frontmatter={...parsed.frontmatter},title=args.title??toOptionalString(frontmatter.title)??inferDefaultTitleFromPath(args.markdownPath),slug=args.slug??toOptionalString(frontmatter.slug)??inferDefaultSlugFromPath(args.markdownPath),summary=args.summary??toOptionalString(frontmatter.summary),tags=args.tags??toStringArray(frontmatter.tags),categoryId=args.categoryId??toOptionalString(frontmatter.category_id)??null,publishStatus=args.publishStatus??toOptionalString(frontmatter.publish_status)??"draft";delete frontmatter.title,delete frontmatter.slug,delete frontmatter.summary,delete frontmatter.tags,delete frontmatter.category_id,delete frontmatter.publish_status;let content={...frontmatter,body:parsed.body};return title&&(content.title=title),summary&&(content.summary=summary),{...args.itemId?{item_id:args.itemId}:{},collection:args.collection,system:{publish_status:publishStatus,...slug?{slug}:{},...tags!==void 0?{tags}:{},...categoryId?{category_id:categoryId}:{},content_format:"markdown",source:{source_type:"markdown",source_url:null,source_path:args.markdownPath,source_raw:parsed.raw,checksum:parsed.checksum,imported_by:args.importedBy??"ide-agent",parser_version:"markdown-importer.v1"}},content}}function resolveMarkdownImportLookupKey(payload){return typeof payload.item_id=="string"&&payload.item_id.trim().length>0?{kind:"item_id",value:payload.item_id}:typeof payload.system.slug=="string"&&payload.system.slug.trim().length>0?{kind:"slug",value:payload.system.slug}:null}function summarizeMarkdownImportResults(items){let importedOrPlanned=0,skipped=0,draft=0,published=0,archived=0;for(let item of items){if(item.state==="skipped"?skipped+=1:importedOrPlanned+=1,item.publish_status==="draft"){draft+=1;continue}if(item.publish_status==="published"){published+=1;continue}item.publish_status==="archived"&&(archived+=1)}return{total:items.length,imported_or_planned:importedOrPlanned,skipped,draft,published,archived}}function normalizeSlugCandidate(value){return value.trim().slice(0,120)}function applySlugSuffix(baseSlug,suffix){let suffixText=`-${suffix}`;return`${baseSlug.slice(0,Math.max(1,120-suffixText.length))}${suffixText}`}async function findTenantCmsItemByExactSlug(args){let normalizedSlug=normalizeSlugCandidate(args.slug);if(!normalizedSlug)return null;let page=1,pageSize=100;for(;;){let response=await args.sdk.listTenantCmsItems({collection:args.collection,page,pageSize,query:normalizedSlug}),matched=response.items.find(item=>item.system.slug===normalizedSlug);if(matched)return matched;if(page*pageSize>=response.total||response.items.length===0)return null;page+=1}}async function resolveUniqueTenantCmsSlug(args){let normalizedSlug=args.slug?normalizeSlugCandidate(args.slug):void 0;if(!normalizedSlug)return{slug:void 0,adjusted:!1};let candidate=normalizedSlug,suffix=2;for(;;){let conflictsInBatch=args.reservedSlugs?.has(candidate)??!1,existing=conflictsInBatch?null:await findTenantCmsItemByExactSlug({sdk:args.sdk,collection:args.collection,slug:candidate});if(!conflictsInBatch&&(!existing||existing.system.id===args.itemId))return{slug:candidate,adjusted:candidate!==normalizedSlug,originalSlug:candidate!==normalizedSlug?normalizedSlug:void 0};candidate=applySlugSuffix(normalizedSlug,suffix),suffix+=1}}import{createHash as createHash7}from"node:crypto";import{URL as URL3}from"node:url";import{Readability}from"@mozilla/readability";import{JSDOM}from"jsdom";import sanitizeHtml from"sanitize-html";function computeChecksum3(input){return`sha256:${createHash7("sha256").update(input).digest("hex")}`}function stripUnsupportedJsonChars(value){return value.replace(/\u0000/g,"")}function trimToUndefined2(value){let normalized=value?.trim();return normalized||void 0}function getMetaContent(document,key){let selectors=[`meta[property="${key}"]`,`meta[name="${key}"]`,`meta[itemprop="${key}"]`];for(let selector of selectors){let value=trimToUndefined2(document.querySelector(selector)?.getAttribute("content"));if(value)return value}}function getFirstText(document,selectors){for(let selector of selectors){let value=trimToUndefined2(document.querySelector(selector)?.textContent);if(value)return value}}function normalizeUrl2(value,baseUrl){if(!value)return;let trimmed=value.trim();if(trimmed)try{return new URL3(trimmed,baseUrl).toString()}catch{return}}function escapeHtmlAttribute(value){return value.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function inferMimeTypeFromUrl2(value){if(!value)return;let pathname=(()=>{try{return new URL3(value).pathname.toLowerCase()}catch{return value.toLowerCase()}})();if(pathname.endsWith(".png"))return"image/png";if(pathname.endsWith(".webp"))return"image/webp";if(pathname.endsWith(".gif"))return"image/gif";if(pathname.endsWith(".svg"))return"image/svg+xml";if(pathname.endsWith(".jpg")||pathname.endsWith(".jpeg"))return"image/jpeg"}function extractArticleImageCandidates(document,baseUrl){let selectors=[".news-detail .image.parbase img",".news-detail .news-img img",".news-detail .richtext img","article img","main img"],results=[],seen=new Set;for(let selector of selectors)for(let image2 of document.querySelectorAll(selector)){let className=image2.getAttribute("class")?.toLowerCase()??"",parentClassName=image2.parentElement?.getAttribute("class")?.toLowerCase()??"";if(className.includes("qrcode")||className.includes("qr-code")||parentClassName.includes("qrcode")||parentClassName.includes("qr-code"))continue;let rawSrc=image2.getAttribute("src")??image2.getAttribute("data-src")??image2.getAttribute("data-original")??image2.getAttribute("data-original-src")??image2.getAttribute("data-lazy-src")??void 0,absoluteUrl=normalizeUrl2(rawSrc??void 0,baseUrl);!absoluteUrl||seen.has(absoluteUrl)||absoluteUrl.startsWith("data:")||(seen.add(absoluteUrl),results.push({url:absoluteUrl,alt:trimToUndefined2(image2.getAttribute("alt")??image2.getAttribute("title")??void 0)}))}return results}function normalizePublishedAt(value){if(!value)return;let timestamp=Date.parse(value);if(!Number.isNaN(timestamp))return new Date(timestamp).toISOString()}function inferDefaultTitleFromUrl(value){try{let parsed=new URL3(value),segment=parsed.pathname.replace(/\/+$/,"").split("/").filter(Boolean).at(-1)?.trim();return segment&&segment.length>0?decodeURIComponent(segment):parsed.hostname}catch{return}}function stripPageExtension(value){if(value)return value.replace(/\.(html?|xhtml|shtml)$/i,"")}function inferDefaultSlug(args){let candidates=[stripPageExtension(inferDefaultTitleFromUrl(args.resolvedUrl)),stripPageExtension(inferDefaultTitleFromUrl(args.requestedUrl)),args.title];for(let candidate of candidates){let normalized=candidate?.trim().toLowerCase().replace(/[\/\\]+/g,"-").replace(/\s+/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"").slice(0,120);if(normalized)return normalized}}function absolutizeRichTextHtml(html,baseUrl){let body=new JSDOM(`<body>${html}</body>`,{url:baseUrl}).window.document.body;for(let anchor of body.querySelectorAll("a[href]")){let href=anchor.getAttribute("href"),absoluteHref=normalizeUrl2(href??void 0,baseUrl);absoluteHref&&anchor.setAttribute("href",absoluteHref)}let firstImageUrl;for(let image2 of body.querySelectorAll("img[src]")){let src=image2.getAttribute("src"),absoluteSrc=normalizeUrl2(src??void 0,baseUrl);absoluteSrc&&(image2.setAttribute("src",absoluteSrc),firstImageUrl??=absoluteSrc)}return{html:body.innerHTML,firstImageUrl}}function sanitizeArticleHtml(html){return sanitizeHtml(html,{allowedTags:["h1","h2","h3","h4","h5","h6","p","br","hr","blockquote","pre","code","ul","ol","li","strong","em","b","i","del","a","img","table","thead","tbody","tr","th","td"],allowedAttributes:{a:["href","title"],img:["src","alt","title"],code:["class"],pre:["class"]},allowedSchemes:["http","https","mailto"],disallowedTagsMode:"discard"})}async function fetchUrlImportSource(url,fetchImpl=fetch){let response=await fetchImpl(url,{redirect:"follow",headers:{"user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8","accept-language":"zh-CN,zh;q=0.9,en;q=0.8","cache-control":"no-cache",pragma:"no-cache"}});if(!response.ok)throw new Error(`URL \u6293\u53D6\u5931\u8D25\uFF1AHTTP ${response.status}`);let raw=stripUnsupportedJsonChars(await response.text());if(!trimToUndefined2(raw))throw new Error("URL \u9875\u9762\u5185\u5BB9\u4E3A\u7A7A\u3002");return{requestedUrl:url,resolvedUrl:response.url||url,raw,checksum:computeChecksum3(raw)}}function parseUrlImportHtml(args){let metadataDocument=new JSDOM(args.raw,{url:args.resolvedUrl}).window.document,articleImageCandidates=extractArticleImageCandidates(metadataDocument,args.resolvedUrl),readabilityDom=new JSDOM(args.raw,{url:args.resolvedUrl}),article=new Readability(readabilityDom.window.document).parse();if(!article?.content||!trimToUndefined2(article.textContent))throw new Error("\u672A\u80FD\u4ECE\u9875\u9762\u4E2D\u63D0\u53D6\u6B63\u6587\u3002");let{html:articleHtml,firstImageUrl}=absolutizeRichTextHtml(article.content,args.resolvedUrl),cleanedHtml=sanitizeArticleHtml(articleHtml).trim();if(!cleanedHtml)throw new Error("\u9875\u9762\u6B63\u6587\u5728\u6E05\u6D17\u540E\u4E3A\u7A7A\u3002");let leadImage=articleImageCandidates[0];if(!firstImageUrl&&leadImage){let altText=leadImage.alt?` alt="${escapeHtmlAttribute(leadImage.alt)}"`:' alt=""';cleanedHtml=`<p><img src="${escapeHtmlAttribute(leadImage.url)}"${altText} /></p>${cleanedHtml}`}let title=getMetaContent(metadataDocument,"og:title")??getMetaContent(metadataDocument,"twitter:title")??trimToUndefined2(metadataDocument.title)??trimToUndefined2(article.title)??getFirstText(metadataDocument,["h1"]),summary=getMetaContent(metadataDocument,"og:description")??getMetaContent(metadataDocument,"description")??trimToUndefined2(article.excerpt),metaCoverUrl=normalizeUrl2(getMetaContent(metadataDocument,"og:image"),args.resolvedUrl)??normalizeUrl2(getMetaContent(metadataDocument,"twitter:image"),args.resolvedUrl),bodyCoverUrl=firstImageUrl,coverUrl=leadImage?.url??bodyCoverUrl??metaCoverUrl,coverMimeType=coverUrl===metaCoverUrl?getMetaContent(metadataDocument,"og:image:type")??inferMimeTypeFromUrl2(coverUrl):inferMimeTypeFromUrl2(coverUrl)??getMetaContent(metadataDocument,"og:image:type"),sourceAuthor=getMetaContent(metadataDocument,"article:author")??getMetaContent(metadataDocument,"author")??getMetaContent(metadataDocument,"parsely-author")??getFirstText(metadataDocument,['[rel="author"]','[itemprop="author"]',".author",".ArticleAuthor-name"]),sourceSite=getMetaContent(metadataDocument,"og:site_name")??(()=>{try{return new URL3(args.resolvedUrl).hostname.replace(/^www\./,"")}catch{return}})(),sourcePublishedAt=normalizePublishedAt(getMetaContent(metadataDocument,"article:published_time")??getMetaContent(metadataDocument,"publishdate")??trimToUndefined2(metadataDocument.querySelector("time[datetime]")?.getAttribute("datetime")));return{requestedUrl:args.requestedUrl,resolvedUrl:args.resolvedUrl,title,summary,coverUrl,coverMimeType,sourceAuthor,sourceSite,sourcePublishedAt,body:cleanedHtml,contentFormat:"html",raw:args.raw,checksum:args.checksum??computeChecksum3(args.raw),warnings:[]}}function buildUrlItemPayload(args){let title=args.title??args.parsed.title??inferDefaultTitleFromUrl(args.parsed.resolvedUrl),slug=args.slug??inferDefaultSlug(args.parsed),summary=args.summary??args.parsed.summary,content={body:args.parsed.body,source_url:args.parsed.resolvedUrl};title&&(content.title=title),summary&&(content.summary=summary),args.parsed.sourceAuthor&&(content.source_author=args.parsed.sourceAuthor),args.parsed.sourceSite&&(content.source_site=args.parsed.sourceSite),args.parsed.sourcePublishedAt&&(content.source_published_at=args.parsed.sourcePublishedAt);let cover=resolveImportedUrlCover({parsed:args.parsed,cover:args.cover,title});return cover&&(content.cover=cover),{...args.itemId?{item_id:args.itemId}:{},collection:args.collection,system:{publish_status:args.publishStatus??"draft",...slug?{slug}:{},...args.tags&&args.tags.length>0?{tags:args.tags}:{},...args.categoryId!==void 0?{category_id:args.categoryId}:{},content_format:args.parsed.contentFormat,source:{source_type:"url",source_url:args.parsed.resolvedUrl,source_path:null,source_raw:args.parsed.raw,checksum:args.parsed.checksum,imported_by:args.importedBy??"ide-agent",parser_version:"url-importer.v1"}},content}}function resolveImportedUrlCover(args){if(args.cover?.mode==="asset"||args.cover?.mode==="remote")return args.cover.value;if(args.cover?.mode!=="none"&&args.parsed.coverUrl)return{title:args.title??"Remote cover",...args.parsed.coverMimeType?{mime_type:args.parsed.coverMimeType}:{},original_url:args.parsed.coverUrl}}async function assetizeParsedUrlImages(args){if(!args.includeBody&&!args.includeCover)return{parsed:args.parsed,cover:{mode:"none"},warnings:[]};let assetization=await assetizeExternalImagesInHtml({sdk:args.sdk,html:args.includeBody?args.parsed.body:"",baseUrl:args.parsed.resolvedUrl,coverUrl:args.includeCover?args.parsed.coverUrl:void 0,coverTitle:args.parsed.title,coverMimeType:args.parsed.coverMimeType,bodyTitle:args.parsed.title});return{parsed:{...args.parsed,body:args.includeBody?assetization.html:args.parsed.body},cover:assetization.cover,warnings:assetization.warnings}}function restrictItemPayloadToSchemaFields(payload,fields){let allowedFieldNames=new Set(fields.map(field=>field.name)),nextContent=Object.fromEntries(Object.entries(payload.content).filter(([key])=>allowedFieldNames.has(key))),droppedFields=Object.keys(payload.content).filter(key=>!allowedFieldNames.has(key));return{payload:{...payload,content:nextContent},droppedFields}}import process3 from"node:process";import{existsSync as existsSync21,readFileSync as readFileSync22}from"node:fs";import{join as join17}from"node:path";import{createHash as createHash9}from"node:crypto";import{existsSync as existsSync20,readdirSync as readdirSync9,readFileSync as readFileSync21}from"node:fs";import{basename as basename9,join as join16,relative as relative7}from"node:path";function assertNonEmptyString(value,field){if(typeof value!="string"||value.trim().length===0)throw new Error(`Auth policy field \`${field}\` must be a non-empty string.`);return value.trim()}function normalizePermissions(value){if(!Array.isArray(value))throw new Error("Auth policy field `permissions` must be an array.");let permissions=value.map((item,index)=>assertNonEmptyString(item,`permissions[${index}]`));return[...new Set(permissions)]}function normalizeAuthPolicy(input){if(typeof input!="object"||input===null)throw new Error("Auth policy must be an object.");let record=input;return{version:assertNonEmptyString(record.version,"version"),role:assertNonEmptyString(record.role,"role"),permissions:normalizePermissions(record.permissions)}}function deriveAuthResourceKey(policy,fallbackName){if(typeof policy=="object"&&policy!==null){let record=policy;if(typeof record.role=="string"&&record.role.trim().length>0)return`auth/${record.role.trim()}`;if(typeof record.policy=="string"&&record.policy.trim().length>0)return`auth/${record.policy.trim()}`}return`auth/${fallbackName}`}var DATA_FORM_ACCESS_SCOPES=["public","own","admin"];var DATA_FORM_GENERATED_SOURCE_TAG="data_form_generated";function buildSourceTagComment(source){return`-- source: ${source}`}function renderColumn(column){let parts=[`${column.column_name} ${column.data_type}`];return parts.push(column.nullable?"NULL":"NOT NULL"),column.default_sql!==void 0&&parts.push(`DEFAULT ${column.default_sql}`),parts.join(" ")}function renderCreateTable(tableName,columns){return[`CREATE TABLE IF NOT EXISTS ${tableName} (`,columns.map(column=>` ${renderColumn(column)}`).join(`,
|
|
2477
2480
|
`),");"].join(`
|
|
2478
2481
|
`)}function renderAlterColumn(tableName,columnName,nullable,defaultSql){let statements=[];return nullable!==void 0&&statements.push(`ALTER TABLE ${tableName} ALTER COLUMN ${columnName} ${nullable?"DROP NOT NULL":"SET NOT NULL"};`),defaultSql!==void 0&&statements.push(`ALTER TABLE ${tableName} ALTER COLUMN ${columnName} SET DEFAULT ${defaultSql};`),statements}function renderDataFormDiffSql(diff){let statements=[buildSourceTagComment(diff.source),`-- resource_key: ${diff.resource_key}`,`-- table_name: ${diff.table_name}`,""];for(let operation of diff.operations)switch(operation.kind){case"create_table":statements.push(renderCreateTable(operation.table_name,operation.columns));break;case"add_column":statements.push(`ALTER TABLE ${operation.table_name} ADD COLUMN ${renderColumn(operation.column)};`);break;case"alter_column":statements.push(...renderAlterColumn(operation.table_name,operation.column_name,operation.nullable,operation.default_sql));break}return`${statements.filter(item=>item.length>0).join(`
|
|
2479
2482
|
`)}
|
|
@@ -2500,11 +2503,11 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2500
2503
|
`)}var DATA_FORM_RUNTIME_ROUTE_PREFIX="/api/public/apps";function buildDataFormRuntimeBasePath(appId){return`${DATA_FORM_RUNTIME_ROUTE_PREFIX}/${encodeURIComponent(appId)}/data-form`}function buildDataFormRuntimeResourcesPath(appId){return`${buildDataFormRuntimeBasePath(appId)}/resources`}function buildDataFormRuntimeRecordsPath(appId,resourceKey){return`${buildDataFormRuntimeResourcesPath(appId)}/${encodeURIComponent(resourceKey)}/records`}function buildDataFormRuntimeRecordPath(appId,resourceKey,recordId){return`${buildDataFormRuntimeRecordsPath(appId,resourceKey)}/${encodeURIComponent(recordId)}`}function normalizeDataFormRuntimeListQuery(query){return{page:normalizePositiveInteger(query.page,1),page_size:normalizePositiveInteger(query.page_size,20),owner_scope:query.owner_scope==="all"?"all":"me",q:typeof query.q=="string"?query.q.trim():""}}function normalizePositiveInteger(value,fallback){if(!Number.isFinite(value)||value===void 0)return fallback;let normalized=Math.floor(value);return normalized>0?normalized:fallback}function buildWorkflowObjectModelSummary(args){let objectTypes=new Set;for(let definition of args.definitions)definition.object_type&&objectTypes.add(definition.object_type);for(let binding of args.bindings)binding.object_type&&objectTypes.add(binding.object_type);return Array.from(objectTypes).sort((left,right)=>left.localeCompare(right)).map(objectType=>{let definitions=args.definitions.filter(item=>item.object_type===objectType),bindings=args.bindings.filter(item=>item.object_type===objectType),bindingDefinitionKeys=Array.from(new Set(bindings.map(item=>item.definition_key))).sort((left,right)=>left.localeCompare(right)),definitionKeys=Array.from(new Set([...definitions.map(item=>item.definition_key),...bindingDefinitionKeys])).sort((left,right)=>left.localeCompare(right)),relatedRoleBindings=args.roleBindings.filter(item=>bindingDefinitionKeys.includes(item.definition_key));return{object_type:objectType,default_definition_key:bindingDefinitionKeys.length===1?bindingDefinitionKeys[0]:definitions.length===1?definitions[0]?.definition_key:void 0,definition_keys:definitionKeys,binding_definition_keys:bindingDefinitionKeys,role_keys:Array.from(new Set(relatedRoleBindings.map(item=>item.role_key))).sort((left,right)=>left.localeCompare(right)),principal_role_keys:Array.from(new Set(relatedRoleBindings.map(item=>item.principal_role_key))).sort((left,right)=>left.localeCompare(right)),target_scopes:Array.from(new Set(bindings.map(item=>item.target_scope))).sort((left,right)=>left.localeCompare(right))}})}async function syncLocalControlPlaneSummary(args){try{let summary=await collectControlPlaneSummary(args);updateSourceContext(args.startDir??process.cwd(),{tenant_id:args.tenantId,app_id:args.appId,control_plane:summary})}catch{}}async function collectControlPlaneSummary(args){let[authInspect,dbPreview,dbProd,workflowDefinitions,workflowBindings,deploymentTimeline,cmsCollections]=await Promise.all([args.sdk.getTenantAppEndUserAuthInspect(args.appId).catch(()=>null),args.sdk.getTenantAppDbInstance(args.appId,"preview").catch(()=>null),args.sdk.getTenantAppDbInstance(args.appId,"prod").catch(()=>null),args.sdk.listWorkflowDefinitions({target_id:args.appId,status:"active"}).catch(()=>[]),args.sdk.listWorkflowBindings({target_id:args.appId}).catch(()=>[]),args.sdk.listTenantAppDeploymentTimeline(args.appId,{limit:10}).catch(()=>({items:[]})),args.sdk.listTenantCmsCollections().catch(()=>({items:[]}))]),previewDeployment=deploymentTimeline.items.find(item=>item.env==="preview"&&item.is_current_release),prodDeployment=deploymentTimeline.items.find(item=>item.env==="prod"&&item.is_current_release),previewAuth=authInspect?.environments.find(item=>item.env==="preview"),prodAuth=authInspect?.environments.find(item=>item.env==="prod"),workflowRoleBindings=(await Promise.all(workflowBindings.map(binding=>args.sdk.listWorkflowRoleBindings({target_scope:binding.target_scope,target_id:binding.target_id,definition_key:binding.definition_key}).catch(()=>[])))).flat(),cmsCollectionDetails=await Promise.all(cmsCollections.items.map(async item=>{let discovered=await args.sdk.discoverTenantCmsCollection(item.collection).catch(()=>null);return{...item,has_active_schema:!!discovered?.active_schema,has_draft_schema:!!discovered?.draft_schema,categories_count:discovered?.categories.length??0}}));return{synced_at:new Date().toISOString(),auth:{inspect_status:authInspect?.inspect_status??null,issues:authInspect?.issues??[],environments:{preview:previewAuth?{status:previewAuth.status,missing_binding_keys:previewAuth.missing_binding_keys,issues:previewAuth.issues}:void 0,prod:prodAuth?{status:prodAuth.status,missing_binding_keys:prodAuth.missing_binding_keys,issues:prodAuth.issues}:void 0}},db:{preview:dbPreview?{bound:dbPreview.bound,status:dbPreview.status,schema_name:dbPreview.schema_name??null,database_name:dbPreview.database_name??null,tables_count:typeof dbPreview.tables_count=="number"?dbPreview.tables_count:null,latest_migration:dbPreview.latest_migration?.migration_path??null}:void 0,prod:dbProd?{bound:dbProd.bound,status:dbProd.status,schema_name:dbProd.schema_name??null,database_name:dbProd.database_name??null,tables_count:typeof dbProd.tables_count=="number"?dbProd.tables_count:null,latest_migration:dbProd.latest_migration?.migration_path??null}:void 0},workflow:{active_definition_count:workflowDefinitions.length,binding_count:workflowBindings.length,definition_keys:workflowDefinitions.map(item=>item.definition_key),definitions:workflowDefinitions.map(item=>({definition_key:item.definition_key,object_type:item.object_type,status:item.status})),bindings:workflowBindings.map(item=>({definition_key:item.definition_key,target_scope:item.target_scope,target_id:item.target_id,object_type:item.object_type,status:item.status,role_binding_count:workflowRoleBindings.filter(binding=>binding.definition_key===item.definition_key&&binding.target_id===item.target_id).length})),role_bindings:workflowRoleBindings.map(item=>({definition_key:item.definition_key,role_key:item.role_key,actor_scope:item.actor_scope,principal_role_key:item.principal_role_key})),object_models:buildWorkflowObjectModelSummary({definitions:workflowDefinitions,bindings:workflowBindings,roleBindings:workflowRoleBindings})},cms:{collection_count:cmsCollectionDetails.length,collections:cmsCollectionDetails.map(item=>({collection:item.collection,label:item.label,template:item.template,collection_status:item.collection_status,item_count:item.item_count,has_draft:item.has_draft,schema_status:item.schema_status,schema_version:item.schema_version,has_active_schema:item.has_active_schema,has_draft_schema:item.has_draft_schema,categories_count:item.categories_count}))},runtime:{preview:previewDeployment?{health:previewDeployment.health??null,source_version_id:previewDeployment.source_version_id??null,preview_url:previewDeployment.preview_url??null}:void 0,prod:prodDeployment?{health:prodDeployment.health??null,source_version_id:prodDeployment.source_version_id??null}:void 0}}}import YAML4 from"yaml";var GENERATED_AUTH_MANIFEST_PATH=".platform/generated/auth/end-user-auth.json",GENERATED_AUTH_POLICY={version:"0.1.0",role:"end-user-auth",permissions:["auth:enabled"]};async function runResourcesCommand(args){let subcommand=args.rest[0];if(subcommand!=="diff"&&subcommand!=="apply"&&subcommand!=="rollback")throw new Error("`platform resources` \u4EC5\u652F\u6301 `diff`\u3001`apply` \u6216 `rollback` \u5B50\u547D\u4EE4\u3002");let credentials=await loadStoredCredentialsEnsuringFresh();if(!credentials)throw new Error("\u672A\u627E\u5230\u672C\u5730\u51ED\u636E\uFF0C\u8BF7\u5148\u6267\u884C `platform login`\u3002");let appRoot=findAppRoot(process.cwd()),binding=readBinding(appRoot)?.binding,tenantId=readStringOption5(args,"tenant")??binding?.tenant_id,appId=readStringOption5(args,"app")??binding?.app_id,env=readStringOption5(args,"env")??binding?.env??"preview",baseSnapshotId=readStringOption5(args,"base-snapshot"),targetSnapshotId=args.rest[1]??readStringOption5(args,"target-snapshot");if(!tenantId||!appId)throw new Error("`platform resources` \u9700\u8981\u5DF2\u7ED1\u5B9A\u9879\u76EE\uFF0C\u6216\u663E\u5F0F\u4F20\u5165 `--tenant` \u4E0E `--app`\u3002");if(subcommand==="rollback"&&!targetSnapshotId)throw new Error("`platform resources rollback` \u9700\u8981 `<snapshot-id>` \u6216 `--target-snapshot <snapshot-id>`\u3002");let requestedBy=await resolveRequestedBy2({accessToken:selectApiToken(credentials),tenantId});subcommand!=="rollback"&&readAppManifest(appRoot);let sdk=createControlApiSdk({accessToken:selectApiToken(credentials),tenantId,capability:"m1",requestClass:"control"}),localResources=await collectEffectiveResources(appRoot,{sdk,appId});if(subcommand==="rollback"){let approveId=readStringOption5(args,"approve-id"),rollbackPayload={operation:"rollback",tenant_id:tenantId,app_id:appId,env,target_snapshot_id:targetSnapshotId,requested_by:requestedBy,reason:readStringOption5(args,"reason")??"manual_resource_rollback",...approveId?{approve_id:approveId}:{}},result2=await withPendingFeedback(args.options.json===!0,`\u6B63\u5728\u6267\u884C\u8D44\u6E90\u56DE\u9000: ${appId}/${env} -> ${targetSnapshotId}`,"\u8D44\u6E90\u56DE\u9000\u4ECD\u5728\u8FDB\u884C\uFF0C\u8BF7\u7EE7\u7EED\u7B49\u5F85\u63A7\u5236\u9762\u5B8C\u6210\u5BA1\u6279\u6821\u9A8C\u3001\u5FEB\u7167\u88C5\u8F7D\u4E0E\u8D44\u6E90\u5E94\u7528...",()=>sdk.rollbackResources(rollbackPayload)).catch(error=>{throw formatResourceCommandError({error,appId,env,subcommand,targetSnapshotId,approveId})});if(args.options.json===!0){process.stdout.write(`${JSON.stringify(result2,null,2)}
|
|
2501
2504
|
`);return}printRollback(result2,appRoot,env);return}let payload={operation:subcommand==="apply"?"apply":"diff",tenant_id:tenantId,app_id:appId,env,requested_by:requestedBy,...subcommand==="apply"&&args.options["dry-run"]===!0?{dry_run:!0}:{},...baseSnapshotId?{base_snapshot_id:baseSnapshotId}:{},local_resources:localResources};if(subcommand==="diff"){let result2=await sdk.diffResources(payload).catch(error=>{throw formatResourceCommandError({error,appId,env,subcommand,baseSnapshotId})});if(await syncLocalControlPlaneSummary({sdk,startDir:appRoot,tenantId,appId}),args.options.json===!0){process.stdout.write(`${JSON.stringify(result2,null,2)}
|
|
2502
2505
|
`);return}printDiff(result2,appRoot,{baseSnapshotSource:baseSnapshotId?"explicit":"auto"});return}let result=await withPendingFeedback(args.options.json===!0,`\u6B63\u5728\u6267\u884C\u8D44\u6E90\u53D8\u66F4: ${appId}/${env}${baseSnapshotId?`\uFF0C\u57FA\u7EBF ${baseSnapshotId}`:"\uFF0C\u57FA\u7EBF\u5C06\u81EA\u52A8\u89E3\u6790"}`,"\u8D44\u6E90 Apply \u4ECD\u5728\u8FDB\u884C\uFF0C\u8BF7\u7EE7\u7EED\u7B49\u5F85\u63A7\u5236\u9762\u5B8C\u6210\u57FA\u7EBF\u89E3\u6790\u3001diff\u3001\u9501\u6821\u9A8C\u4E0E\u8D44\u6E90\u7F16\u6392...",()=>sdk.applyResources(payload)).catch(error=>{throw formatResourceCommandError({error,appId,env,subcommand,baseSnapshotId})});if(await syncLocalControlPlaneSummary({sdk,startDir:appRoot,tenantId,appId}),args.options.json===!0){process.stdout.write(`${JSON.stringify(result,null,2)}
|
|
2503
|
-
`);return}printApply(result,appRoot,{baseSnapshotSource:baseSnapshotId?"explicit":"auto"})}async function resolveRequestedBy2(args){return(await createControlApiSdk({accessToken:args.accessToken,tenantId:args.tenantId,capability:"auth",requestClass:"control"}).getWhoAmI()).subject_id}function readStringOption5(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}async function collectEffectiveResources(appRoot,options){let dbResources=collectDbResources(appRoot),authResources=collectAuthResources(appRoot);if(authResources.length>0||!options?.sdk||!options.appId)return[...dbResources,...authResources].sort((left,right)=>left.manifest_path.localeCompare(right.manifest_path));let bridgedAuthResources=await collectBridgedAuthResources(options.sdk,options.appId);return[...dbResources,...authResources,...bridgedAuthResources].sort((left,right)=>left.manifest_path.localeCompare(right.manifest_path))}function collectDbResources(appRoot){let directory=join16(appRoot,"resources","db","migrations"),sqlResources=existsSync20(directory)?
|
|
2506
|
+
`);return}printApply(result,appRoot,{baseSnapshotSource:baseSnapshotId?"explicit":"auto"})}async function resolveRequestedBy2(args){return(await createControlApiSdk({accessToken:args.accessToken,tenantId:args.tenantId,capability:"auth",requestClass:"control"}).getWhoAmI()).subject_id}function readStringOption5(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}async function collectEffectiveResources(appRoot,options){let dbResources=collectDbResources(appRoot),authResources=collectAuthResources(appRoot);if(authResources.length>0||!options?.sdk||!options.appId)return[...dbResources,...authResources].sort((left,right)=>left.manifest_path.localeCompare(right.manifest_path));let bridgedAuthResources=await collectBridgedAuthResources(options.sdk,options.appId);return[...dbResources,...authResources,...bridgedAuthResources].sort((left,right)=>left.manifest_path.localeCompare(right.manifest_path))}function collectDbResources(appRoot){let directory=join16(appRoot,"resources","db","migrations"),sqlResources=existsSync20(directory)?readdirSync9(directory).filter(entry=>entry.endsWith(".sql")).sort((left,right)=>left.localeCompare(right)).map(entry=>{let filePath=join16(directory,entry),sql=readFileSync21(filePath,"utf8"),manifestPath=toWorkspaceRelative(appRoot,filePath);return{resource_type:"db",resource_key:`db/${basename9(entry,".sql")}`,manifest_path:manifestPath,checksum:checksum2(sql),spec:{kind:"migration",sql,statements_count:sql.split(";").map(part=>part.trim()).filter(Boolean).length}}}):[],dataFormDirectory=join16(appRoot,"resources","data-forms"),dataFormResources=existsSync20(dataFormDirectory)?readdirSync9(dataFormDirectory).filter(entry=>entry.endsWith(".yaml")||entry.endsWith(".yml")).sort((left,right)=>left.localeCompare(right)).map(entry=>{let filePath=join16(dataFormDirectory,entry),raw=YAML4.parse(readFileSync21(filePath,"utf8")),schema=normalizeDataFormResourceSchema(raw),manifestPath=toWorkspaceRelative(appRoot,filePath),artifact=buildDataFormMigrationArtifact({schema,sourceManifestPath:manifestPath});return{resource_type:"db",resource_key:artifact.resource_key,manifest_path:manifestPath,checksum:artifact.checksum,spec:{kind:"migration",sql:artifact.sql,statements_count:artifact.statements_count,source:artifact.source,table_name:artifact.table_name,source_manifest_path:artifact.source_manifest_path,source_of_truth:"data_form_schema",data_form_resource:schema}}}):[];return[...sqlResources,...dataFormResources].sort((left,right)=>left.manifest_path.localeCompare(right.manifest_path))}function collectAuthResources(appRoot){let directory=join16(appRoot,"resources","auth","policies");return existsSync20(directory)?readdirSync9(directory).filter(entry=>entry.endsWith(".json")).sort((left,right)=>left.localeCompare(right)).map(entry=>{let filePath=join16(directory,entry),raw=readFileSync21(filePath,"utf8"),policy=normalizeAuthPolicy(JSON.parse(raw)),manifestPath=toWorkspaceRelative(appRoot,filePath);return{resource_type:"auth",resource_key:deriveAuthResourceKey(policy,basename9(entry,".json")),manifest_path:manifestPath,checksum:checksum2(raw),spec:{kind:"policy",policy}}}):[]}async function collectBridgedAuthResources(sdk,appId){if((await sdk.getTenantAppEndUserAuthConfig(appId)).auth_enabled!==!0)return[];let policy=normalizeAuthPolicy(GENERATED_AUTH_POLICY),raw=JSON.stringify(policy,null,2);return[{resource_type:"auth",resource_key:deriveAuthResourceKey(policy,"end-user-auth"),manifest_path:GENERATED_AUTH_MANIFEST_PATH,checksum:checksum2(raw),spec:{kind:"policy",policy}}]}function toWorkspaceRelative(appRoot,filePath){return relative7(appRoot,filePath).split("\\").join("/")}function checksum2(value){return createHash9("sha256").update(value).digest("hex")}function printDiff(result,appRoot,options){let lines=[`\u8D44\u6E90 Diff \u5DF2\u5B8C\u6210\uFF0C\u57FA\u7EBF\u5FEB\u7167: ${result.base_snapshot_id}`,`\u57FA\u7EBF\u6765\u6E90: ${options.baseSnapshotSource==="auto"?"\u81EA\u52A8\u89E3\u6790":"\u624B\u52A8\u6307\u5B9A"}`,`\u672C\u5730\u8D44\u6E90: ${result.resources.local_count}\uFF0C\u8FDC\u7AEF\u8D44\u6E90: ${result.resources.remote_count}`,`\u65B0\u589E ${result.summary.added}\uFF0C\u4FEE\u6539 ${result.summary.modified}\uFF0C\u5220\u9664 ${result.summary.deleted}`];if(result.changes.length>0){lines.push("");for(let change of result.changes)lines.push(`- ${formatChangePrefix(change.change_type)} ${relative7(appRoot,join16(appRoot,change.manifest_path)).split("\\").join("/")}`+(change.previous_checksum?` (${change.previous_checksum} -> ${change.checksum??"deleted"})`:""))}process.stdout.write(`${lines.join(`
|
|
2504
2507
|
`)}
|
|
2505
|
-
`)}function printApply(result,appRoot,options){let lines=[`\u8D44\u6E90 Apply ${result.status==="failed"?"\u5931\u8D25":"\u5B8C\u6210"}${result.dry_run?"\uFF08dry-run\uFF09":""}`,`\u57FA\u7EBF\u5FEB\u7167: ${result.base_snapshot_id}`,`\u57FA\u7EBF\u6765\u6E90: ${options.baseSnapshotSource==="auto"?"\u81EA\u52A8\u89E3\u6790":"\u624B\u52A8\u6307\u5B9A"}`,`status: ${result.status}`,`\u65B0\u589E ${result.summary.added}\uFF0C\u4FEE\u6539 ${result.summary.modified}\uFF0C\u5220\u9664 ${result.summary.deleted}`,`\u6267\u884C\u8D44\u6E90: ${result.summary.applied}\uFF0CDB ${result.summary.db_resources}\uFF0CAuth ${result.summary.auth_resources}`];if(result.result_snapshot_id&&lines.push(`\u7ED3\u679C\u5FEB\u7167: ${result.result_snapshot_id}`),result.db_skill&&lines.push(`DB Skill: ${result.db_skill.binding_key} -> ${result.db_skill.tenant_database_id} (schema=${result.db_skill.schema_name})`),result.auth_skill&&lines.push(`Auth Skill: ${result.auth_skill.binding_key} -> ${result.auth_skill.skill_instance_id}`),result.errors&&result.errors.length>0&&lines.push(`errors: ${result.errors.join(" | ")}`),result.status==="succeeded"&&result.result_snapshot_id&&lines.push(`\u4E0B\u4E00\u6B21 diff/apply \u53EF\u76F4\u63A5\u4F7F\u7528: --base-snapshot ${result.result_snapshot_id}`),result.status==="dry_run"&&lines.push("\u4E0B\u4E00\u6B65: \u786E\u8BA4\u7ED3\u679C\u65E0\u8BEF\u540E\uFF0C\u53BB\u6389 `--dry-run` \u518D\u6267\u884C\u4E00\u6B21 apply\u3002"),result.changes.length>0){lines.push("");for(let change of result.changes)lines.push(`- ${formatChangePrefix(change.change_type)} ${
|
|
2508
|
+
`)}function printApply(result,appRoot,options){let lines=[`\u8D44\u6E90 Apply ${result.status==="failed"?"\u5931\u8D25":"\u5B8C\u6210"}${result.dry_run?"\uFF08dry-run\uFF09":""}`,`\u57FA\u7EBF\u5FEB\u7167: ${result.base_snapshot_id}`,`\u57FA\u7EBF\u6765\u6E90: ${options.baseSnapshotSource==="auto"?"\u81EA\u52A8\u89E3\u6790":"\u624B\u52A8\u6307\u5B9A"}`,`status: ${result.status}`,`\u65B0\u589E ${result.summary.added}\uFF0C\u4FEE\u6539 ${result.summary.modified}\uFF0C\u5220\u9664 ${result.summary.deleted}`,`\u6267\u884C\u8D44\u6E90: ${result.summary.applied}\uFF0CDB ${result.summary.db_resources}\uFF0CAuth ${result.summary.auth_resources}`];if(result.result_snapshot_id&&lines.push(`\u7ED3\u679C\u5FEB\u7167: ${result.result_snapshot_id}`),result.db_skill&&lines.push(`DB Skill: ${result.db_skill.binding_key} -> ${result.db_skill.tenant_database_id} (schema=${result.db_skill.schema_name})`),result.auth_skill&&lines.push(`Auth Skill: ${result.auth_skill.binding_key} -> ${result.auth_skill.skill_instance_id}`),result.errors&&result.errors.length>0&&lines.push(`errors: ${result.errors.join(" | ")}`),result.status==="succeeded"&&result.result_snapshot_id&&lines.push(`\u4E0B\u4E00\u6B21 diff/apply \u53EF\u76F4\u63A5\u4F7F\u7528: --base-snapshot ${result.result_snapshot_id}`),result.status==="dry_run"&&lines.push("\u4E0B\u4E00\u6B65: \u786E\u8BA4\u7ED3\u679C\u65E0\u8BEF\u540E\uFF0C\u53BB\u6389 `--dry-run` \u518D\u6267\u884C\u4E00\u6B21 apply\u3002"),result.changes.length>0){lines.push("");for(let change of result.changes)lines.push(`- ${formatChangePrefix(change.change_type)} ${relative7(appRoot,join16(appRoot,change.manifest_path)).split("\\").join("/")}`)}process.stdout.write(`${lines.join(`
|
|
2506
2509
|
`)}
|
|
2507
|
-
`)}function printRollback(result,appRoot,env){let lines=[`\u8D44\u6E90 Rollback ${result.status==="failed"?"\u5931\u8D25":"\u5B8C\u6210"}\uFF0C\u76EE\u6807\u5FEB\u7167: ${result.target_snapshot_id}`,`status: ${result.status}`,`\u65B0\u589E ${result.summary.added}\uFF0C\u4FEE\u6539 ${result.summary.modified}\uFF0C\u5220\u9664 ${result.summary.deleted}`,`\u6267\u884C\u8D44\u6E90: ${result.summary.applied}\uFF0CDB ${result.summary.db_resources}\uFF0CAuth ${result.summary.auth_resources}`];result.failure_stage&&lines.push(`failure_stage: ${result.failure_stage}`),result.result_snapshot_id&&lines.push(`\u7ED3\u679C\u5FEB\u7167: ${result.result_snapshot_id}`),result.errors&&result.errors.length>0&&lines.push(`errors: ${result.errors.join(" | ")}`),result.status==="succeeded"&&result.result_snapshot_id&&(lines.push(`\u56DE\u9000\u5B8C\u6210\u540E\u65B0\u7684\u7ED3\u679C\u5FEB\u7167: ${result.result_snapshot_id}`),lines.push(`\u540E\u7EED\u82E5\u7EE7\u7EED\u8D44\u6E90\u8FED\u4EE3\uFF0C\u8BF7\u6539\u7528: --base-snapshot ${result.result_snapshot_id}`));for(let hint of buildRollbackHints(result,env))lines.push(hint);if(result.changes.length>0){lines.push("");for(let change of result.changes)lines.push(`- ${formatChangePrefix(change.change_type)} ${
|
|
2510
|
+
`)}function printRollback(result,appRoot,env){let lines=[`\u8D44\u6E90 Rollback ${result.status==="failed"?"\u5931\u8D25":"\u5B8C\u6210"}\uFF0C\u76EE\u6807\u5FEB\u7167: ${result.target_snapshot_id}`,`status: ${result.status}`,`\u65B0\u589E ${result.summary.added}\uFF0C\u4FEE\u6539 ${result.summary.modified}\uFF0C\u5220\u9664 ${result.summary.deleted}`,`\u6267\u884C\u8D44\u6E90: ${result.summary.applied}\uFF0CDB ${result.summary.db_resources}\uFF0CAuth ${result.summary.auth_resources}`];result.failure_stage&&lines.push(`failure_stage: ${result.failure_stage}`),result.result_snapshot_id&&lines.push(`\u7ED3\u679C\u5FEB\u7167: ${result.result_snapshot_id}`),result.errors&&result.errors.length>0&&lines.push(`errors: ${result.errors.join(" | ")}`),result.status==="succeeded"&&result.result_snapshot_id&&(lines.push(`\u56DE\u9000\u5B8C\u6210\u540E\u65B0\u7684\u7ED3\u679C\u5FEB\u7167: ${result.result_snapshot_id}`),lines.push(`\u540E\u7EED\u82E5\u7EE7\u7EED\u8D44\u6E90\u8FED\u4EE3\uFF0C\u8BF7\u6539\u7528: --base-snapshot ${result.result_snapshot_id}`));for(let hint of buildRollbackHints(result,env))lines.push(hint);if(result.changes.length>0){lines.push("");for(let change of result.changes)lines.push(`- ${formatChangePrefix(change.change_type)} ${relative7(appRoot,join16(appRoot,change.manifest_path)).split("\\").join("/")}`)}process.stdout.write(`${lines.join(`
|
|
2508
2511
|
`)}
|
|
2509
2512
|
`)}function formatChangePrefix(changeType){switch(changeType){case"added":return"+";case"modified":return"~";case"deleted":return"-"}return"?"}async function withPendingFeedback(jsonOutput,startMessage,waitingMessage,action){if(jsonOutput)return action();process.stderr.write(`${startMessage}
|
|
2510
2513
|
`);let timer=setTimeout(()=>{process.stderr.write(`${waitingMessage}
|
|
@@ -2521,7 +2524,7 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2521
2524
|
`);return}let origin=deriveWorkbenchOrigin();process3.stdout.write(["\u5DE5\u4F5C\u53F0\u6570\u636E\u9875\u5165\u53E3\uFF1A",`${origin}/#apps`,`\u5E94\u7528: ${context.appId}`,`\u73AF\u5883: ${env}`,""].join(`
|
|
2522
2525
|
`))}function buildDbStatusWarnings(result,startDir){if(!result.bound)return[];let warnings=[];if((result.tables_count??0)===0){let latestMigrationPath=result.latest_migration?.migration_path,looksLikeScaffold=latestMigrationPath?isLikelyEmptyMigrationScaffold(startDir,latestMigrationPath):!1;warnings.push(looksLikeScaffold?"\u63D0\u793A: \u5F53\u524D schema \u4ECD\u4E3A 0 \u8868\uFF0C\u4E14\u672C\u5730\u6700\u65B0 migration \u770B\u8D77\u6765\u8FD8\u662F\u7A7A scaffold\u3002\u82E5\u4F60\u8BA1\u5212\u63A5\u5165\u4E1A\u52A1 DB\uFF0C\u8BF7\u5148\u628A resources/db/migrations/ \u4E0B\u7684\u793A\u4F8B\u6CE8\u91CA\u6539\u6210\u771F\u5B9E\u5EFA\u8868 SQL\uFF0C\u518D\u6267\u884C `platform db migrate`\u3002":"\u63D0\u793A: \u5F53\u524D schema \u4ECD\u4E3A 0 \u8868\u3002\u82E5\u4F60\u8BA1\u5212\u63A5\u5165\u4E1A\u52A1 DB\uFF0C\u8BF7\u5148\u8865\u771F\u5B9E migration\uFF0C\u518D\u6267\u884C `platform db migrate` \u548C `platform db tables`\u3002")}return warnings}function isLikelyEmptyMigrationScaffold(startDir,migrationPath){try{let appRoot=findAppRoot(startDir),absolutePath=join17(appRoot,migrationPath);return existsSync21(absolutePath)?readFileSync22(absolutePath,"utf8").split(`
|
|
2523
2526
|
`).map(line=>line.replace(/--.*$/,"").trim()).filter(Boolean).join(`
|
|
2524
|
-
`).trim().length===0:!1}catch{return!1}}function resolveDbContext(args){let storedContext=loadStoredCliContext(),binding;try{binding=readBinding(findAppRoot(process3.cwd()))?.binding}catch{binding=void 0}let tenantId=readStringOption6(args,"tenant")??binding?.tenant_id??storedContext?.selected_app_tenant_id,appId=readStringOption6(args,"app")??binding?.app_id??storedContext?.selected_app_id,env=readStringOption6(args,"env")??binding?.env??storedContext?.selected_app_env??"preview";return{tenantId,appId,env}}function readStringOption6(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}function deriveWorkbenchOrigin(){let redirectUri=process3.env.AUTH_TENANT_REDIRECT_URI?.trim()||process3.env.LOGTO_TENANT_REDIRECT_URI?.trim()||"http://localhost:7102/callback";try{return new URL(redirectUri).origin}catch{return"http://localhost:7102"}}import{existsSync as existsSync22,readdirSync as
|
|
2527
|
+
`).trim().length===0:!1}catch{return!1}}function resolveDbContext(args){let storedContext=loadStoredCliContext(),binding;try{binding=readBinding(findAppRoot(process3.cwd()))?.binding}catch{binding=void 0}let tenantId=readStringOption6(args,"tenant")??binding?.tenant_id??storedContext?.selected_app_tenant_id,appId=readStringOption6(args,"app")??binding?.app_id??storedContext?.selected_app_id,env=readStringOption6(args,"env")??binding?.env??storedContext?.selected_app_env??"preview";return{tenantId,appId,env}}function readStringOption6(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}function deriveWorkbenchOrigin(){let redirectUri=process3.env.AUTH_TENANT_REDIRECT_URI?.trim()||process3.env.LOGTO_TENANT_REDIRECT_URI?.trim()||"http://localhost:7102/callback";try{return new URL(redirectUri).origin}catch{return"http://localhost:7102"}}import{existsSync as existsSync22,readdirSync as readdirSync10,readFileSync as readFileSync23}from"node:fs";import{join as join18}from"node:path";import YAML5 from"yaml";async function runDataFormCommand(args){let subcommand=args.rest[0]??"help";if(args.options.help===!0||args.options.h===!0||subcommand==="help"){printDataFormHelp(args.rest[1]);return}if(!["validate","compile","inspect","apply","records"].includes(subcommand))throw new Error(`\u672A\u77E5 data-form \u5B50\u547D\u4EE4: ${subcommand}`);if(subcommand==="records"){await runDataFormRecordsCommand(args);return}if(subcommand==="apply"){if(readStringOption7(args.options,"resource"))throw new Error("`platform data-form apply` \u4E0D\u652F\u6301 `--resource`\u3002\u8BF7\u5148\u7528 validate/compile/inspect \u68C0\u67E5\u5355\u4E2A\u8D44\u6E90\uFF0C\u518D\u6267\u884C\u6574\u5E94\u7528\u8D44\u6E90 apply\u3002");await runResourcesCommand({rest:["apply"],options:args.options});return}let appRoot=findAppRoot(process.cwd()),loaded=loadDataFormSchemas(appRoot,readStringOption7(args.options,"resource"));if(loaded.length===0)throw new Error("\u672A\u627E\u5230 `resources/data-forms/*.yaml`\u3002");if(subcommand==="validate"){let result=loaded.map(item=>({manifest_path:item.manifestPath,resource_key:item.schema.resource_key,field_count:item.schema.fields.length,valid:validateDataFormResourceSchema(item.schema)}));if(args.options.json===!0){process.stdout.write(`${JSON.stringify({items:result},null,2)}
|
|
2525
2528
|
`);return}process.stdout.write(`${result.map(item=>`OK ${item.resource_key} ${item.manifest_path} fields=${item.field_count}`).join(`
|
|
2526
2529
|
`)}
|
|
2527
2530
|
`);return}if(subcommand==="inspect"){let inspected=loaded.map(item=>({manifest_path:item.manifestPath,schema:item.schema,artifact:buildDataFormMigrationArtifact({schema:item.schema,sourceManifestPath:item.manifestPath})}));if(args.options.json===!0){process.stdout.write(`${JSON.stringify({items:inspected.map(item=>({manifest_path:item.manifest_path,schema:item.schema,generated_migration:{source:item.artifact.source,source_manifest_path:item.artifact.source_manifest_path,resource_key:item.artifact.resource_key,table_name:item.artifact.table_name,checksum:item.artifact.checksum,statements_count:item.artifact.statements_count,sql:item.artifact.sql}}))},null,2)}
|
|
@@ -2541,7 +2544,7 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2541
2544
|
`))])}async function requestDataFormRuntime(fetchImpl,url,headers){let response=await fetchImpl(url,{method:"GET",headers}),text2=await response.text(),payload=text2.trim()?JSON.parse(text2):{};if(!response.ok){let error=payload.error;throw new Error(error?.message??`Request failed: ${response.status}`)}return payload}function writeJsonOrText2(json,payload,lines){if(json){process.stdout.write(`${JSON.stringify(payload,null,2)}
|
|
2542
2545
|
`);return}process.stdout.write(`${lines.join(`
|
|
2543
2546
|
`)}
|
|
2544
|
-
`)}function loadDataFormSchemas(appRoot,resourceKey){let directory=join18(appRoot,"resources","data-forms");if(!existsSync22(directory))return[];let targetResourceKey=typeof resourceKey=="string"?resourceKey.trim():"";return
|
|
2547
|
+
`)}function loadDataFormSchemas(appRoot,resourceKey){let directory=join18(appRoot,"resources","data-forms");if(!existsSync22(directory))return[];let targetResourceKey=typeof resourceKey=="string"?resourceKey.trim():"";return readdirSync10(directory).filter(entry=>entry.endsWith(".yaml")||entry.endsWith(".yml")).sort((left,right)=>left.localeCompare(right)).map(entry=>{let manifestPath=join18("resources","data-forms",entry),raw=YAML5.parse(readFileSync23(join18(directory,entry),"utf8")),schema=normalizeDataFormResourceSchema(raw);return validateDataFormResourceSchema(schema),{manifestPath,schema}}).filter(item=>!targetResourceKey||item.schema.resource_key===targetResourceKey)}function serializeCompileResult(item){return{manifest_path:item.manifest_path,resource_key:item.resource_key,table_name:item.result.table.table_name,operations:item.result.diff.operations,sql:item.result.sql}}function readStringOption7(options,key){let value=options[key];return typeof value=="string"?value:void 0}function parseOptionalInteger(value){if(!value)return;let parsed=Number.parseInt(value,10);return Number.isFinite(parsed)?parsed:void 0}function normalizeOwnerScope(value){return value==="all"?"all":value==="me"?"me":void 0}function normalizeRuntimeEnv(value){return value==="prod"?"prod":"preview"}function printDataFormHelp(subcommand){if(subcommand==="validate"){process.stdout.write(["platform data-form validate",""," platform data-form validate [--resource <resource-key>] [--json]",""," \u6821\u9A8C\u5F53\u524D\u5E94\u7528\u76EE\u5F55\u4E0B\u7684 `resources/data-forms/*.yaml`\u3002"].join(`
|
|
2545
2548
|
`)+`
|
|
2546
2549
|
`);return}if(subcommand==="compile"){process.stdout.write(["platform data-form compile",""," platform data-form compile [--resource <resource-key>] [--json]",""," \u628A `Data Form schema` \u7F16\u8BD1\u6210\u9996\u671F DB migration SQL \u4EA7\u7269\u9884\u89C8\u3002"].join(`
|
|
2547
2550
|
`)+`
|
|
@@ -2553,8 +2556,8 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2553
2556
|
`)+`
|
|
2554
2557
|
`);return}process.stdout.write(["platform data-form",""," platform data-form validate [--resource <resource-key>] [--json]"," platform data-form compile [--resource <resource-key>] [--json]"," platform data-form inspect [--resource <resource-key>] [--json]"," platform data-form apply [--env preview|prod] [--dry-run] [--json]"," platform data-form records --resource <resource-key> [--record <record-id>] [--env preview|prod] [--page <n>] [--page-size <n>] [--owner-scope me|all] [--q <keyword>] [--json]",""," \u672C\u5730\u6821\u9A8C\u3001\u67E5\u770B\u751F\u6210 migration\u3001\u901A\u8FC7\u73B0\u6709\u8D44\u6E90\u4E3B\u94FE\u5E94\u7528 `resources/data-forms/*.yaml`\uFF0C\u5E76\u901A\u8FC7 runtime API \u67E5\u8BE2\u8BB0\u5F55\u3002"].join(`
|
|
2555
2558
|
`)+`
|
|
2556
|
-
`)}import{spawn as spawn2}from"node:child_process";import net from"node:net";import WebSocket from"ws";async function prepareLocalDevDatabaseBindings(runtimeBindings,options={}){let databaseUrl=runtimeBindings.DATABASE_URL?.trim();if(!databaseUrl)return{bindings:runtimeBindings,warnings:[],cleanup:null};let proxyTransport=runtimeBindings.DATABASE_PROXY_TRANSPORT?.trim(),proxyWsUrl=runtimeBindings.DATABASE_PROXY_WS_URL?.trim();if(proxyTransport==="ws_tunnel"&&proxyWsUrl)return await prepareWebSocketDatabaseTunnel(runtimeBindings,databaseUrl,proxyWsUrl);if(!shouldTunnelDatabaseUrl(databaseUrl))return{bindings:runtimeBindings,warnings:[],cleanup:null};if(!((process.env.PLATFORM_INTERNAL_ENABLE_DB_SSH_TUNNEL||"").trim()==="1"))throw new Error(["dev_runtime_binding_not_available","\u5F53\u524D\u73AF\u5883\u5C1A\u672A\u63D0\u4F9B\u5F00\u53D1\u673A\u53EF\u8FBE\u7684 DB binding\uFF0C`platform dev --remote-bindings` \u5DF2\u62D2\u7EDD\u4F7F\u7528\u79C1\u7F51\u6570\u636E\u5E93\u5730\u5740\u3002","\u8BF7\u5148\u6539\u7528 `platform preview` \u9A8C\u8BC1\u771F\u5B9E\u5199\u5E93\u94FE\u8DEF\uFF1B\u5982\u4E3A\u5E73\u53F0\u7BA1\u7406\u5458\u5185\u90E8\u6392\u969C\uFF0C\u53EF\u663E\u5F0F\u8BBE\u7F6E `PLATFORM_INTERNAL_ENABLE_DB_SSH_TUNNEL=1` \u540E\u91CD\u8BD5\u3002"].join(" "));let sshHost=(options.sshHost||process.env.TEST_ENV_SSH_HOST||"").trim();if(!sshHost)throw new Error("\u5F53\u524D\u5DF2\u663E\u5F0F\u542F\u7528\u5185\u90E8 SSH \u515C\u5E95\uFF0C\u4F46\u672A\u914D\u7F6E TEST_ENV_SSH_HOST\uFF0C\u65E0\u6CD5\u5EFA\u7ACB\u672C\u5730 SSH \u96A7\u9053\u3002");let parsed=new URL(databaseUrl),remoteHost=parsed.hostname,remotePort=Number(parsed.port||"5432"),localPort=await allocateLocalPort(),child=spawn2("ssh",["-o","ExitOnForwardFailure=yes","-o","BatchMode=yes","-o","ConnectTimeout=8","-N","-L",`127.0.0.1:${localPort}:${remoteHost}:${remotePort}`,sshHost],{stdio:"ignore"});try{await waitForTunnelReady(localPort,child)}catch(error){throw child.kill("SIGTERM"),await waitForChildExit(child),error}let localUrl=rewriteDatabaseUrlForLocalPort(databaseUrl,localPort);return{bindings:{...runtimeBindings,DATABASE_URL:localUrl},warnings:[`\u68C0\u6D4B\u5230\u79C1\u7F51 DB host\uFF08${remoteHost}:${remotePort}\uFF09\uFF0C\u5DF2\u901A\u8FC7 SSH \u96A7\u9053\u6620\u5C04\u5230\u672C\u5730 127.0.0.1:${localPort}\u3002`],cleanup:async()=>{child.kill("SIGTERM"),await waitForChildExit(child)}}}async function prepareWebSocketDatabaseTunnel(runtimeBindings,databaseUrl,wsUrl){let localPort=await allocateLocalPort(),sockets=new Set,bridges=new Set,server=net.createServer(clientSocket=>{clientSocket.setNoDelay(!0),sockets.add(clientSocket);let bridge=new WebSocket(wsUrl);bridges.add(bridge);let closeBoth=()=>{sockets.delete(clientSocket),bridges.delete(bridge),clientSocket.destroyed||clientSocket.destroy(),(bridge.readyState===WebSocket.OPEN||bridge.readyState===WebSocket.CONNECTING)&&bridge.close()};bridge.on("open",()=>{clientSocket.on("data",chunk=>{bridge.readyState===WebSocket.OPEN&&bridge.send(chunk)}),clientSocket.resume()}),bridge.on("message",payload=>{clientSocket.write(Buffer.isBuffer(payload)?payload:Buffer.from(payload))}),bridge.on("close",closeBoth),bridge.on("error",closeBoth),clientSocket.on("close",closeBoth),clientSocket.on("error",closeBoth),clientSocket.pause()});return await listenLocalServer(server,localPort),{bindings:{...runtimeBindings,DATABASE_URL:rewriteDatabaseUrlForLocalPort(databaseUrl,localPort)},warnings:[`\u68C0\u6D4B\u5230\u6B63\u5F0F dev proxy WebSocket \u6570\u636E\u9762\uFF0C\u5DF2\u6620\u5C04\u5230\u672C\u5730 127.0.0.1:${localPort}\u3002`],cleanup:async()=>{for(let socket of sockets)socket.destroyed||socket.destroy();for(let bridge of bridges)(bridge.readyState===WebSocket.OPEN||bridge.readyState===WebSocket.CONNECTING)&&bridge.close();await closeServer(server)}}}function shouldTunnelDatabaseUrl(databaseUrl){try{let url=new URL(databaseUrl);return shouldTunnelHostname(url.hostname)}catch{return!1}}function rewriteDatabaseUrlForLocalPort(databaseUrl,localPort){let url=new URL(databaseUrl);return url.hostname="127.0.0.1",url.port=String(localPort),url.toString()}function shouldTunnelHostname(hostname){let value=hostname.trim().toLowerCase();return!value||["localhost","127.0.0.1"].includes(value)?!1:!!(["host.docker.internal","host.containers.internal"].includes(value)||isPrivateIpv4(value))}function isPrivateIpv4(hostname){let parts=hostname.split(".");if(parts.length!==4||parts.some(part=>!/^\d+$/.test(part)))return!1;let[a,b]=parts.map(part=>Number(part));return a===10||a===192&&b===168||a===172&&b>=16&&b<=31}async function allocateLocalPort(){return await new Promise((resolve19,reject)=>{let server=net.createServer();server.once("error",reject),server.listen(0,"127.0.0.1",()=>{let address=server.address();if(!address||typeof address=="string"){server.close(()=>reject(new Error("\u65E0\u6CD5\u5206\u914D\u672C\u5730\u7AEF\u53E3\u3002")));return}let port=address.port;server.close(error=>{if(error){reject(error);return}resolve19(port)})})})}async function listenLocalServer(server,port){await new Promise((resolve19,reject)=>{server.once("error",reject),server.listen(port,"127.0.0.1",()=>{server.off("error",reject),resolve19()})})}async function closeServer(server){await new Promise(resolve19=>{server.close(()=>resolve19())})}async function waitForTunnelReady(localPort,child){let startedAt=Date.now();for(;Date.now()-startedAt<1e4;){if(child.exitCode!==null)throw new Error(`SSH \u96A7\u9053\u8FDB\u7A0B\u63D0\u524D\u9000\u51FA\uFF08code=${child.exitCode}\uFF09\u3002`);if(await canConnect("127.0.0.1",localPort))return;await sleep3(200)}throw new Error(`SSH \u96A7\u9053\u672A\u5728\u9884\u671F\u65F6\u95F4\u5185\u5C31\u7EEA\uFF1A127.0.0.1:${localPort}`)}async function canConnect(host,port){return await new Promise(resolve19=>{let socket=net.createConnection({host,port}),done=value=>{socket.removeAllListeners(),socket.destroyed||socket.destroy(),resolve19(value)};socket.once("connect",()=>done(!0)),socket.once("error",()=>done(!1)),socket.setTimeout(500,()=>done(!1))})}async function waitForChildExit(child){await new Promise(resolve19=>{if(child.exitCode!==null){resolve19();return}child.once("exit",()=>resolve19()),setTimeout(()=>resolve19(),1e3)})}function sleep3(ms){return new Promise(resolve19=>{setTimeout(resolve19,ms)})}import{spawn as spawn3}from"node:child_process";import{watch}from"node:fs";import process4 from"node:process";var IGNORED_PATH_SEGMENTS=new Set(["node_modules",".git",".platform","dist",".next"]),RESTART_DEBOUNCE_MS=250;async function runDevSupervisor(options){let platform=options.platform??process4.platform,spawnImpl=options.spawnImpl??spawn3,terminateProcessTreeImpl=options.terminateProcessTreeImpl??terminateProcessTree,signalSource=options.signalSource??process4,restartDebounceMs=options.restartDebounceMs??RESTART_DEBOUNCE_MS,expectedStops=new WeakSet,state={child:null,watcher:null,restartTimer:null,stopping:!1,restarting:!1,restartPending:!1,cleanupPromise:null},runPromise=new Promise((resolve19,reject)=>{state.resolveRun=resolve19,state.rejectRun=reject}),stopChild=async()=>{let child=state.child;if(!child)return;expectedStops.add(child);let exitPromise=waitForChildExit2(child);if(typeof child.pid=="number"){try{await terminateProcessTreeImpl(child.pid,{platform})}catch(error){if(child.exitCode===null&&child.signalCode===null)throw error}await exitPromise}else child.kill("SIGTERM");state.child===child&&(state.child=null)},cleanup=()=>(state.cleanupPromise||(state.stopping=!0,state.restartTimer&&(clearTimeout(state.restartTimer),state.restartTimer=null),state.watcher?.close(),state.watcher=null,state.cleanupPromise=stopChild()),state.cleanupPromise),handleSignal=signal=>{cleanup().then(()=>{let exitCode=signal==="SIGINT"?130:143;(options.setExitCode??(code2=>{process4.exitCode=code2}))(exitCode),state.resolveRun?.()}).catch(error=>{state.rejectRun?.(error instanceof Error?error:new Error(String(error)))})},handleSigint=()=>handleSignal("SIGINT"),handleSigterm=()=>handleSignal("SIGTERM");signalSource.once("SIGINT",handleSigint),signalSource.once("SIGTERM",handleSigterm);let startChild=()=>{let child=spawnImpl(options.command,{cwd:options.cwd,env:options.env,stdio:"inherit",shell:!0,detached:platform!=="win32"});state.child=child,child.on("exit",(code2,signal)=>{if(state.child===child&&(state.child=null),!(expectedStops.has(child)||state.stopping||state.restarting)){if(signal){state.rejectRun?.(new Error(`dev \u547D\u4EE4\u88AB\u4FE1\u53F7 ${signal} \u7EC8\u6B62`));return}if(code2&&code2!==0){state.rejectRun?.(new Error(`dev \u547D\u4EE4\u9000\u51FA\uFF0C\u72B6\u6001\u7801 ${code2}`));return}state.resolveRun?.()}}),child.on("error",error=>{state.rejectRun?.(error instanceof Error?error:new Error(String(error)))})},performPendingRestarts=async()=>{if(!(state.restarting||state.stopping)){state.restarting=!0;try{for(;state.restartPending&&!state.stopping;)state.restartPending=!1,await stopChild(),state.stopping||startChild()}finally{state.restarting=!1}}},scheduleRestart=changedPath=>{let normalized=typeof changedPath=="string"?changedPath:changedPath?.toString("utf8");normalized&&normalized.split(/[\\/]+/u).filter(Boolean).some(segment=>IGNORED_PATH_SEGMENTS.has(segment))||(state.restartTimer&&clearTimeout(state.restartTimer),state.restartTimer=setTimeout(()=>{state.restartTimer=null,state.restartPending=!0,options.onWatching?.(`\u68C0\u6D4B\u5230\u6587\u4EF6\u53D8\u66F4${normalized?`\uFF1A${normalized}`:""}\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u542F dev \u5B50\u8FDB\u7A0B...`),performPendingRestarts().catch(error=>{state.rejectRun?.(error instanceof Error?error:new Error(String(error)))})},restartDebounceMs))};if(options.watchRoot)try{state.watcher=watch(options.watchRoot,{recursive:!0},(_eventType,filename)=>{scheduleRestart(filename)}),options.onWatching?.("\u5DF2\u542F\u7528\u6587\u4EF6\u76D1\u542C\uFF1B\u6E90\u7801\u53D8\u66F4\u540E\u5C06\u81EA\u52A8\u91CD\u542F dev \u5B50\u8FDB\u7A0B\u3002")}catch{options.onWatching?.("\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u4E0D\u652F\u6301\u9012\u5F52\u6587\u4EF6\u76D1\u542C\uFF1Bdev \u5B50\u8FDB\u7A0B\u5C06\u4FDD\u6301\u5355\u6B21\u542F\u52A8\u3002")}startChild();try{await runPromise}finally{try{await cleanup()}finally{signalSource.removeListener("SIGINT",handleSigint),signalSource.removeListener("SIGTERM",handleSigterm)}}}function waitForChildExit2(child){return child.exitCode!==null||child.signalCode!==null?Promise.resolve():new Promise(resolve19=>{child.once("exit",()=>resolve19())})}import{chmodSync as chmodSync2,existsSync as existsSync23,mkdirSync as mkdirSync11,readFileSync as readFileSync24,rmSync as rmSync6,writeFileSync as writeFileSync12}from"node:fs";import{dirname as dirname13,resolve as resolve16}from"node:path";import{fileURLToPath as fileURLToPath5}from"node:url";import YAML6 from"yaml";var MANAGED_ENV_KEYS=["CONTROL_API_BASE_URL","PUBLIC_API_BASE_URL","RUNTIME_API_BASE_URL","OIDC_ISSUER","OIDC_AUDIENCE","LOGTO_CLI_APP_ID","LOGTO_CLI_REDIRECT_URI","LOGTO_TENANT_APP_ID","LOGTO_TENANT_REDIRECT_URI","TEST_ENV_PROFILE"];function getEnvironmentProfilePath(){return resolveCliStateFilePath("environment.json")}function loadStoredEnvironmentProfile(){let envProfilePath=getEnvironmentProfilePath();return existsSync23(envProfilePath)?JSON.parse(readFileSync24(envProfilePath,"utf8")):null}function persistStoredEnvironmentProfile(input){withCliStateFileWriteFallback({fileName:"environment.json",operation:"\u5199\u5165",write:({filePath,stateDir})=>{mkdirSync11(stateDir,{recursive:!0}),writeFileSync12(filePath,`${JSON.stringify({active_profile:input.active_profile,values:normalizeProfileValues(input.values),updated_at:new Date().toISOString()},null,2)}
|
|
2557
|
-
`,"utf8"),chmodSync2(filePath,384)}})}function clearStoredEnvironmentProfile(){let envProfilePath=getEnvironmentProfilePath();existsSync23(envProfilePath)&&rmSync6(envProfilePath)}function applyStoredEnvironmentProfile(env=process.env){let stored=loadStoredEnvironmentProfile();if(!stored)return null;for(let key of MANAGED_ENV_KEYS){let current=env[key];if(typeof current=="string"&¤t.trim().length>0)continue;let nextValue=stored.values[key];typeof nextValue=="string"&&nextValue.trim().length>0&&(env[key]=nextValue)}return stored}function listKnownEnvironmentProfiles(startDir=getInvocationCwd()){return loadEnvironmentProfileRegistry(startDir).map(profile=>({name:profile.name,values:resolveProfileValues(profile)}))}function resolveKnownEnvironmentProfile(profileName,startDir=getInvocationCwd()){let matched=loadEnvironmentProfileRegistry(startDir).find(profile=>profile.name===profileName);return matched?{name:matched.name,values:resolveProfileValues(matched)}:null}function normalizeProfileValues(values){let normalized={};for(let key of MANAGED_ENV_KEYS){let value=values[key];if(typeof value!="string")continue;let trimmed=value.trim();trimmed.length>0&&(normalized[key]=trimmed)}return normalized}function resolveProfileValues(profile){let values={},scheme=profile.topology?.scheme?.trim(),controlHost=profile.hosts?.control?.trim(),publicHost=profile.hosts?.public?.trim(),runtimeHost=profile.hosts?.runtime?.trim(),authHost=profile.hosts?.auth?.trim(),tenantHost=profile.hosts?.tenant?.trim(),issuer=profile.auth?.issuer?.trim(),audience=profile.auth?.audience?.trim();return scheme&&controlHost&&(values.CONTROL_API_BASE_URL=`${scheme}://${controlHost}`),scheme&&publicHost&&(values.PUBLIC_API_BASE_URL=`${scheme}://${publicHost}`),scheme&&runtimeHost&&(values.RUNTIME_API_BASE_URL=`${scheme}://${runtimeHost}`),issuer&&(values.OIDC_ISSUER=issuer),audience&&(values.OIDC_AUDIENCE=audience),tenantHost&&scheme&&(values.LOGTO_TENANT_REDIRECT_URI=`${scheme}://${tenantHost}/callback`),authHost&&profile.name==="local"?values.LOGTO_CLI_REDIRECT_URI="http://localhost:7300/callback":authHost&&(values.LOGTO_CLI_REDIRECT_URI="http://127.0.0.1:7300/callback"),values.TEST_ENV_PROFILE=profile.name,values}function loadEnvironmentProfileRegistry(startDir){let registryPath=resolveEnvironmentRegistryPath(startDir);if(!existsSync23(registryPath))return[];let parsed=YAML6.parse(readFileSync24(registryPath,"utf8"));return Array.isArray(parsed?.profiles)?parsed.profiles:[]}function resolveEnvironmentRegistryPath(startDir){let invocationWorkspaceRoot=findWorkspaceRoot(startDir),invocationCandidate=resolve16(invocationWorkspaceRoot,"deploy","registry","environment-profiles.yaml");if(existsSync23(invocationCandidate))return invocationCandidate;let cliModuleRoot=resolve16(
|
|
2559
|
+
`)}import{spawn as spawn2}from"node:child_process";import net from"node:net";import WebSocket from"ws";async function prepareLocalDevDatabaseBindings(runtimeBindings,options={}){let databaseUrl=runtimeBindings.DATABASE_URL?.trim();if(!databaseUrl)return{bindings:runtimeBindings,warnings:[],cleanup:null};let proxyTransport=runtimeBindings.DATABASE_PROXY_TRANSPORT?.trim(),proxyWsUrl=runtimeBindings.DATABASE_PROXY_WS_URL?.trim();if(proxyTransport==="ws_tunnel"&&proxyWsUrl)return await prepareWebSocketDatabaseTunnel(runtimeBindings,databaseUrl,proxyWsUrl);if(!shouldTunnelDatabaseUrl(databaseUrl))return{bindings:runtimeBindings,warnings:[],cleanup:null};if(!((process.env.PLATFORM_INTERNAL_ENABLE_DB_SSH_TUNNEL||"").trim()==="1"))throw new Error(["dev_runtime_binding_not_available","\u5F53\u524D\u73AF\u5883\u5C1A\u672A\u63D0\u4F9B\u5F00\u53D1\u673A\u53EF\u8FBE\u7684 DB binding\uFF0C`platform dev --remote-bindings` \u5DF2\u62D2\u7EDD\u4F7F\u7528\u79C1\u7F51\u6570\u636E\u5E93\u5730\u5740\u3002","\u8BF7\u5148\u6539\u7528 `platform preview` \u9A8C\u8BC1\u771F\u5B9E\u5199\u5E93\u94FE\u8DEF\uFF1B\u5982\u4E3A\u5E73\u53F0\u7BA1\u7406\u5458\u5185\u90E8\u6392\u969C\uFF0C\u53EF\u663E\u5F0F\u8BBE\u7F6E `PLATFORM_INTERNAL_ENABLE_DB_SSH_TUNNEL=1` \u540E\u91CD\u8BD5\u3002"].join(" "));let sshHost=(options.sshHost||process.env.TEST_ENV_SSH_HOST||"").trim();if(!sshHost)throw new Error("\u5F53\u524D\u5DF2\u663E\u5F0F\u542F\u7528\u5185\u90E8 SSH \u515C\u5E95\uFF0C\u4F46\u672A\u914D\u7F6E TEST_ENV_SSH_HOST\uFF0C\u65E0\u6CD5\u5EFA\u7ACB\u672C\u5730 SSH \u96A7\u9053\u3002");let parsed=new URL(databaseUrl),remoteHost=parsed.hostname,remotePort=Number(parsed.port||"5432"),localPort=await allocateLocalPort(),child=spawn2("ssh",["-o","ExitOnForwardFailure=yes","-o","BatchMode=yes","-o","ConnectTimeout=8","-N","-L",`127.0.0.1:${localPort}:${remoteHost}:${remotePort}`,sshHost],{stdio:"ignore"});try{await waitForTunnelReady(localPort,child)}catch(error){throw child.kill("SIGTERM"),await waitForChildExit(child),error}let localUrl=rewriteDatabaseUrlForLocalPort(databaseUrl,localPort);return{bindings:{...runtimeBindings,DATABASE_URL:localUrl},warnings:[`\u68C0\u6D4B\u5230\u79C1\u7F51 DB host\uFF08${remoteHost}:${remotePort}\uFF09\uFF0C\u5DF2\u901A\u8FC7 SSH \u96A7\u9053\u6620\u5C04\u5230\u672C\u5730 127.0.0.1:${localPort}\u3002`],cleanup:async()=>{child.kill("SIGTERM"),await waitForChildExit(child)}}}async function prepareWebSocketDatabaseTunnel(runtimeBindings,databaseUrl,wsUrl){let localPort=await allocateLocalPort(),sockets=new Set,bridges=new Set,server=net.createServer(clientSocket=>{clientSocket.setNoDelay(!0),sockets.add(clientSocket);let bridge=new WebSocket(wsUrl);bridges.add(bridge);let closeBoth=()=>{sockets.delete(clientSocket),bridges.delete(bridge),clientSocket.destroyed||clientSocket.destroy(),(bridge.readyState===WebSocket.OPEN||bridge.readyState===WebSocket.CONNECTING)&&bridge.close()};bridge.on("open",()=>{clientSocket.on("data",chunk=>{bridge.readyState===WebSocket.OPEN&&bridge.send(chunk)}),clientSocket.resume()}),bridge.on("message",payload=>{clientSocket.write(Buffer.isBuffer(payload)?payload:Buffer.from(payload))}),bridge.on("close",closeBoth),bridge.on("error",closeBoth),clientSocket.on("close",closeBoth),clientSocket.on("error",closeBoth),clientSocket.pause()});return await listenLocalServer(server,localPort),{bindings:{...runtimeBindings,DATABASE_URL:rewriteDatabaseUrlForLocalPort(databaseUrl,localPort)},warnings:[`\u68C0\u6D4B\u5230\u6B63\u5F0F dev proxy WebSocket \u6570\u636E\u9762\uFF0C\u5DF2\u6620\u5C04\u5230\u672C\u5730 127.0.0.1:${localPort}\u3002`],cleanup:async()=>{for(let socket of sockets)socket.destroyed||socket.destroy();for(let bridge of bridges)(bridge.readyState===WebSocket.OPEN||bridge.readyState===WebSocket.CONNECTING)&&bridge.close();await closeServer(server)}}}function shouldTunnelDatabaseUrl(databaseUrl){try{let url=new URL(databaseUrl);return shouldTunnelHostname(url.hostname)}catch{return!1}}function rewriteDatabaseUrlForLocalPort(databaseUrl,localPort){let url=new URL(databaseUrl);return url.hostname="127.0.0.1",url.port=String(localPort),url.toString()}function shouldTunnelHostname(hostname){let value=hostname.trim().toLowerCase();return!value||["localhost","127.0.0.1"].includes(value)?!1:!!(["host.docker.internal","host.containers.internal"].includes(value)||isPrivateIpv4(value))}function isPrivateIpv4(hostname){let parts=hostname.split(".");if(parts.length!==4||parts.some(part=>!/^\d+$/.test(part)))return!1;let[a,b]=parts.map(part=>Number(part));return a===10||a===192&&b===168||a===172&&b>=16&&b<=31}async function allocateLocalPort(){return await new Promise((resolve19,reject)=>{let server=net.createServer();server.once("error",reject),server.listen(0,"127.0.0.1",()=>{let address=server.address();if(!address||typeof address=="string"){server.close(()=>reject(new Error("\u65E0\u6CD5\u5206\u914D\u672C\u5730\u7AEF\u53E3\u3002")));return}let port=address.port;server.close(error=>{if(error){reject(error);return}resolve19(port)})})})}async function listenLocalServer(server,port){await new Promise((resolve19,reject)=>{server.once("error",reject),server.listen(port,"127.0.0.1",()=>{server.off("error",reject),resolve19()})})}async function closeServer(server){await new Promise(resolve19=>{server.close(()=>resolve19())})}async function waitForTunnelReady(localPort,child){let startedAt=Date.now();for(;Date.now()-startedAt<1e4;){if(child.exitCode!==null)throw new Error(`SSH \u96A7\u9053\u8FDB\u7A0B\u63D0\u524D\u9000\u51FA\uFF08code=${child.exitCode}\uFF09\u3002`);if(await canConnect("127.0.0.1",localPort))return;await sleep3(200)}throw new Error(`SSH \u96A7\u9053\u672A\u5728\u9884\u671F\u65F6\u95F4\u5185\u5C31\u7EEA\uFF1A127.0.0.1:${localPort}`)}async function canConnect(host,port){return await new Promise(resolve19=>{let socket=net.createConnection({host,port}),done=value=>{socket.removeAllListeners(),socket.destroyed||socket.destroy(),resolve19(value)};socket.once("connect",()=>done(!0)),socket.once("error",()=>done(!1)),socket.setTimeout(500,()=>done(!1))})}async function waitForChildExit(child){await new Promise(resolve19=>{if(child.exitCode!==null){resolve19();return}child.once("exit",()=>resolve19()),setTimeout(()=>resolve19(),1e3)})}function sleep3(ms){return new Promise(resolve19=>{setTimeout(resolve19,ms)})}import{spawn as spawn3}from"node:child_process";import{watch}from"node:fs";import process4 from"node:process";var IGNORED_PATH_SEGMENTS=new Set(["node_modules",".git",".platform","dist",".next"]),RESTART_DEBOUNCE_MS=250;async function runDevSupervisor(options){let platform=options.platform??process4.platform,spawnImpl=options.spawnImpl??spawn3,terminateProcessTreeImpl=options.terminateProcessTreeImpl??terminateProcessTree,signalSource=options.signalSource??process4,restartDebounceMs=options.restartDebounceMs??RESTART_DEBOUNCE_MS,expectedStops=new WeakSet,state={child:null,watcher:null,restartTimer:null,stopping:!1,restarting:!1,restartPending:!1,cleanupPromise:null},runPromise=new Promise((resolve19,reject)=>{state.resolveRun=resolve19,state.rejectRun=reject}),stopChild=async()=>{let child=state.child;if(!child)return;expectedStops.add(child);let exitPromise=waitForChildExit2(child);if(typeof child.pid=="number"){try{await terminateProcessTreeImpl(child.pid,{platform})}catch(error){if(child.exitCode===null&&child.signalCode===null)throw error}await exitPromise}else child.kill("SIGTERM");state.child===child&&(state.child=null)},cleanup=()=>(state.cleanupPromise||(state.stopping=!0,state.restartTimer&&(clearTimeout(state.restartTimer),state.restartTimer=null),state.watcher?.close(),state.watcher=null,state.cleanupPromise=stopChild()),state.cleanupPromise),handleSignal=signal=>{cleanup().then(()=>{let exitCode=signal==="SIGINT"?130:143;(options.setExitCode??(code2=>{process4.exitCode=code2}))(exitCode),state.resolveRun?.()}).catch(error=>{state.rejectRun?.(error instanceof Error?error:new Error(String(error)))})},handleSigint=()=>handleSignal("SIGINT"),handleSigterm=()=>handleSignal("SIGTERM");signalSource.once("SIGINT",handleSigint),signalSource.once("SIGTERM",handleSigterm);let startChild=()=>{let child=spawnImpl(options.command,{cwd:options.cwd,env:options.env,stdio:"inherit",shell:!0,detached:platform!=="win32"});state.child=child,child.on("exit",(code2,signal)=>{if(state.child===child&&(state.child=null),!(expectedStops.has(child)||state.stopping||state.restarting)){if(signal){state.rejectRun?.(new Error(`dev \u547D\u4EE4\u88AB\u4FE1\u53F7 ${signal} \u7EC8\u6B62`));return}if(code2&&code2!==0){state.rejectRun?.(new Error(`dev \u547D\u4EE4\u9000\u51FA\uFF0C\u72B6\u6001\u7801 ${code2}`));return}state.resolveRun?.()}}),child.on("error",error=>{state.rejectRun?.(error instanceof Error?error:new Error(String(error)))})},performPendingRestarts=async()=>{if(!(state.restarting||state.stopping)){state.restarting=!0;try{for(;state.restartPending&&!state.stopping;)state.restartPending=!1,await stopChild(),state.stopping||startChild()}finally{state.restarting=!1}}},scheduleRestart=changedPath=>{let normalized=typeof changedPath=="string"?changedPath:changedPath?.toString("utf8");normalized&&normalized.split(/[\\/]+/u).filter(Boolean).some(segment=>IGNORED_PATH_SEGMENTS.has(segment))||(state.restartTimer&&clearTimeout(state.restartTimer),state.restartTimer=setTimeout(()=>{state.restartTimer=null,state.restartPending=!0,options.onWatching?.(`\u68C0\u6D4B\u5230\u6587\u4EF6\u53D8\u66F4${normalized?`\uFF1A${normalized}`:""}\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u542F dev \u5B50\u8FDB\u7A0B...`),performPendingRestarts().catch(error=>{state.rejectRun?.(error instanceof Error?error:new Error(String(error)))})},restartDebounceMs))};if(options.watchRoot)try{state.watcher=watch(options.watchRoot,{recursive:!0},(_eventType,filename)=>{scheduleRestart(filename)}),options.onWatching?.("\u5DF2\u542F\u7528\u6587\u4EF6\u76D1\u542C\uFF1B\u6E90\u7801\u53D8\u66F4\u540E\u5C06\u81EA\u52A8\u91CD\u542F dev \u5B50\u8FDB\u7A0B\u3002")}catch{options.onWatching?.("\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u4E0D\u652F\u6301\u9012\u5F52\u6587\u4EF6\u76D1\u542C\uFF1Bdev \u5B50\u8FDB\u7A0B\u5C06\u4FDD\u6301\u5355\u6B21\u542F\u52A8\u3002")}startChild();try{await runPromise}finally{try{await cleanup()}finally{signalSource.removeListener("SIGINT",handleSigint),signalSource.removeListener("SIGTERM",handleSigterm)}}}function waitForChildExit2(child){return child.exitCode!==null||child.signalCode!==null?Promise.resolve():new Promise(resolve19=>{child.once("exit",()=>resolve19())})}import{chmodSync as chmodSync2,existsSync as existsSync23,mkdirSync as mkdirSync11,readFileSync as readFileSync24,rmSync as rmSync6,writeFileSync as writeFileSync12}from"node:fs";import{dirname as dirname14,resolve as resolve16}from"node:path";import{fileURLToPath as fileURLToPath5}from"node:url";import YAML6 from"yaml";var MANAGED_ENV_KEYS=["CONTROL_API_BASE_URL","PUBLIC_API_BASE_URL","RUNTIME_API_BASE_URL","OIDC_ISSUER","OIDC_AUDIENCE","LOGTO_CLI_APP_ID","LOGTO_CLI_REDIRECT_URI","LOGTO_TENANT_APP_ID","LOGTO_TENANT_REDIRECT_URI","TEST_ENV_PROFILE"];function getEnvironmentProfilePath(){return resolveCliStateFilePath("environment.json")}function loadStoredEnvironmentProfile(){let envProfilePath=getEnvironmentProfilePath();return existsSync23(envProfilePath)?JSON.parse(readFileSync24(envProfilePath,"utf8")):null}function persistStoredEnvironmentProfile(input){withCliStateFileWriteFallback({fileName:"environment.json",operation:"\u5199\u5165",write:({filePath,stateDir})=>{mkdirSync11(stateDir,{recursive:!0}),writeFileSync12(filePath,`${JSON.stringify({active_profile:input.active_profile,values:normalizeProfileValues(input.values),updated_at:new Date().toISOString()},null,2)}
|
|
2560
|
+
`,"utf8"),chmodSync2(filePath,384)}})}function clearStoredEnvironmentProfile(){let envProfilePath=getEnvironmentProfilePath();existsSync23(envProfilePath)&&rmSync6(envProfilePath)}function applyStoredEnvironmentProfile(env=process.env){let stored=loadStoredEnvironmentProfile();if(!stored)return null;for(let key of MANAGED_ENV_KEYS){let current=env[key];if(typeof current=="string"&¤t.trim().length>0)continue;let nextValue=stored.values[key];typeof nextValue=="string"&&nextValue.trim().length>0&&(env[key]=nextValue)}return stored}function listKnownEnvironmentProfiles(startDir=getInvocationCwd()){return loadEnvironmentProfileRegistry(startDir).map(profile=>({name:profile.name,values:resolveProfileValues(profile)}))}function resolveKnownEnvironmentProfile(profileName,startDir=getInvocationCwd()){let matched=loadEnvironmentProfileRegistry(startDir).find(profile=>profile.name===profileName);return matched?{name:matched.name,values:resolveProfileValues(matched)}:null}function normalizeProfileValues(values){let normalized={};for(let key of MANAGED_ENV_KEYS){let value=values[key];if(typeof value!="string")continue;let trimmed=value.trim();trimmed.length>0&&(normalized[key]=trimmed)}return normalized}function resolveProfileValues(profile){let values={},scheme=profile.topology?.scheme?.trim(),controlHost=profile.hosts?.control?.trim(),publicHost=profile.hosts?.public?.trim(),runtimeHost=profile.hosts?.runtime?.trim(),authHost=profile.hosts?.auth?.trim(),tenantHost=profile.hosts?.tenant?.trim(),issuer=profile.auth?.issuer?.trim(),audience=profile.auth?.audience?.trim();return scheme&&controlHost&&(values.CONTROL_API_BASE_URL=`${scheme}://${controlHost}`),scheme&&publicHost&&(values.PUBLIC_API_BASE_URL=`${scheme}://${publicHost}`),scheme&&runtimeHost&&(values.RUNTIME_API_BASE_URL=`${scheme}://${runtimeHost}`),issuer&&(values.OIDC_ISSUER=issuer),audience&&(values.OIDC_AUDIENCE=audience),tenantHost&&scheme&&(values.LOGTO_TENANT_REDIRECT_URI=`${scheme}://${tenantHost}/callback`),authHost&&profile.name==="local"?values.LOGTO_CLI_REDIRECT_URI="http://localhost:7300/callback":authHost&&(values.LOGTO_CLI_REDIRECT_URI="http://127.0.0.1:7300/callback"),values.TEST_ENV_PROFILE=profile.name,values}function loadEnvironmentProfileRegistry(startDir){let registryPath=resolveEnvironmentRegistryPath(startDir);if(!existsSync23(registryPath))return[];let parsed=YAML6.parse(readFileSync24(registryPath,"utf8"));return Array.isArray(parsed?.profiles)?parsed.profiles:[]}function resolveEnvironmentRegistryPath(startDir){let invocationWorkspaceRoot=findWorkspaceRoot(startDir),invocationCandidate=resolve16(invocationWorkspaceRoot,"deploy","registry","environment-profiles.yaml");if(existsSync23(invocationCandidate))return invocationCandidate;let cliModuleRoot=resolve16(dirname14(fileURLToPath5(import.meta.url)),".."),cliWorkspaceRoot=findWorkspaceRoot(cliModuleRoot);return resolve16(cliWorkspaceRoot,"deploy","registry","environment-profiles.yaml")}async function runLogsCommand(args){let credentials=await loadStoredCredentialsEnsuringFresh();if(!credentials)throw new Error("\u672A\u627E\u5230\u672C\u5730\u51ED\u636E\uFF0C\u8BF7\u5148\u6267\u884C `platform login`\u3002");let appRoot=findAppRoot(process.cwd()),binding=readBinding(appRoot)?.binding,tenantId=readStringOption8(args,"tenant")??binding?.tenant_id,appId=readStringOption8(args,"app")??binding?.app_id,env=readStringOption8(args,"env")??binding?.env??"preview",releaseId=readStringOption8(args,"release"),limit=readNumberOption3(args,"limit")??100,follow=args.options.follow===!0,from=readStringOption8(args,"from")??new Date(Date.now()-900*1e3).toISOString(),to=readStringOption8(args,"to")??new Date().toISOString();if(!tenantId||!appId)throw new Error("`platform logs` \u9700\u8981\u5DF2\u7ED1\u5B9A\u9879\u76EE\uFF0C\u6216\u663E\u5F0F\u4F20\u5165 `--tenant` \u4E0E `--app`\u3002");let sdk=createControlApiSdk({accessToken:selectApiToken(credentials),tenantId,capability:"m1",requestClass:"control"}),payload={tenant_id:tenantId,app_id:appId,env,...releaseId?{release_id:releaseId}:{},from,to,limit,follow};if(!follow){let result=await sdk.queryLogs(payload);printLogs(result,args.options.json===!0);return}let seen=new Set,currentFrom=from;for(;;){let result=await sdk.queryLogs({...payload,from:currentFrom,to:new Date().toISOString(),follow:!0});if(args.options.json===!0)process.stdout.write(`${JSON.stringify(result,null,2)}
|
|
2558
2561
|
`);else for(let entry of result.entries)seen.has(entry.id)||(seen.add(entry.id),process.stdout.write(`${formatEntry(entry)}
|
|
2559
2562
|
`));result.entries.length>0&&(currentFrom=result.entries[result.entries.length-1]?.timestamp??currentFrom),await sleep4(2e3)}}function printLogs(result,asJson){if(asJson){process.stdout.write(`${JSON.stringify(result,null,2)}
|
|
2560
2563
|
`);return}if(result.entries.length===0){process.stdout.write(`\u672A\u67E5\u8BE2\u5230\u65E5\u5FD7\u3002
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voobase/cli",
|
|
3
|
-
"version": "0.1.1-nonprod.
|
|
3
|
+
"version": "0.1.1-nonprod.2039",
|
|
4
4
|
"private": false,
|
|
5
5
|
"platformDistributionProfile": {
|
|
6
6
|
"name": "nonprod",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"bundleDependencies": [],
|
|
54
54
|
"platformDistributionBuild": {
|
|
55
55
|
"channel": "nonprod",
|
|
56
|
-
"version": "0.1.1-nonprod.
|
|
57
|
-
"sequence":
|
|
58
|
-
"gitSha": "
|
|
59
|
-
"fullGitSha": "
|
|
60
|
-
"buildId": "0.1.1-nonprod.
|
|
56
|
+
"version": "0.1.1-nonprod.2039",
|
|
57
|
+
"sequence": 2039,
|
|
58
|
+
"gitSha": "e5d1c1f",
|
|
59
|
+
"fullGitSha": "e5d1c1f21da6f231f3c7d42fe227ae44b4b16ca1",
|
|
60
|
+
"buildId": "0.1.1-nonprod.2039+e5d1c1f"
|
|
61
61
|
}
|
|
62
62
|
}
|