@voobase/cli 0.1.0-nonprod.1819 → 0.1.0-nonprod.1820
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 +10 -10
- package/package.json +8 -9
package/dist-bundle/index.mjs
CHANGED
|
@@ -2223,7 +2223,7 @@ function inferUpstreamPath(pathname: string, routeBasePath: string): string {
|
|
|
2223
2223
|
`);return}process.stdout.write([action==="add"?"\u7D20\u6750\u6807\u7B7E\u5DF2\u6DFB\u52A0\u3002":"\u7D20\u6750\u6807\u7B7E\u5DF2\u79FB\u9664\u3002",`asset: ${response.asset.asset_id}`,`tags: ${response.tags.length>0?response.tags.map(item=>item.label).join(", "):"-"}`,""].join(`
|
|
2224
2224
|
`));return}throw new Error("`platform asset tag` \u4EC5\u652F\u6301 `list`\u3001`add <asset-id> <label>`\u3001`remove <asset-id> <label>`\u3002")}function readStringOption(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}function hasOption(args,key){return Object.prototype.hasOwnProperty.call(args.options,key)}function readCsvOption(args,key){return(readStringOption(args,key)??"").split(",").map(item=>item.trim()).filter(Boolean)}function readBooleanOption(args,key){let value=readStringOption(args,key);if(value!==void 0){if(value==="true")return!0;if(value==="false")return!1;throw new Error(`\`--${key}\` \u4EC5\u652F\u6301 true \u6216 false\u3002`)}}function readNumberOption(args,key){let value=readStringOption(args,key);if(value===void 0)return;let parsed=Number(value);if(!Number.isFinite(parsed))throw new Error(`\`--${key}\` \u9700\u8981\u6570\u5B57\u3002`);return Math.trunc(parsed)}function readMediaTypeOption(args){let value=readStringOption(args,"media-type");if(value){if(value==="image"||value==="video")return value;throw new Error("`--media-type` \u4EC5\u652F\u6301 image \u6216 video\u3002")}}function readOrientationOption(args){let value=readStringOption(args,"orientation");if(value){if(value==="landscape"||value==="portrait"||value==="square")return value;throw new Error("`--orientation` \u4EC5\u652F\u6301 landscape\u3001portrait\u3001square\u3002")}}function readVariantKindOption(args){let value=readStringOption(args,"variant");if(value){if(value==="thumbnail"||value==="sm"||value==="md"||value==="lg"||value==="cover")return value;throw new Error("`--variant` \u4EC5\u652F\u6301 thumbnail\u3001sm\u3001md\u3001lg\u3001cover\u3002")}}function pickRecommendedAnalysisSource(detail){let mdUrl=detail.variant_urls.md;if(mdUrl)return{kind:"md",url:mdUrl};let smUrl=detail.variant_urls.sm;if(smUrl)return{kind:"sm",url:smUrl};let thumbnailUrl=detail.variant_urls.thumbnail;return thumbnailUrl?{kind:"thumbnail",url:thumbnailUrl}:{kind:"original",url:detail.original_url}}function hasHelpFlag(args){return args.options.help===!0||args.options.h===!0}function inferMimeType(fileName){switch(extname(fileName).toLowerCase()){case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".webp":return"image/webp";case".gif":return"image/gif";case".svg":return"image/svg+xml";case".mp4":return"video/mp4";case".mov":return"video/quicktime";case".webm":return"video/webm";default:throw new Error(`\u5F53\u524D\u4EC5\u652F\u6301\u5E38\u89C1\u56FE\u7247\u4E0E\u89C6\u9891\u6269\u5C55\u540D\uFF0C\u65E0\u6CD5\u8BC6\u522B\u6587\u4EF6\u7C7B\u578B: ${fileName}`)}}function formatVariantLines(variantUrls){let lines=Object.entries(variantUrls).filter(entry=>typeof entry[1]=="string"&&entry[1].length>0).map(([kind,url])=>`variant.${kind}: ${url}`);return lines.length>0?lines:["variant: -"]}function normalizeNullableCliText(value){let normalized=value?.trim()??"";return normalized||null}function buildAnalyzeUpdateTemplate(assetId){return[`platform asset update ${assetId} \\`,' --summary "..." \\',' --caption "..." \\',' --scene "..." \\',' --objects "..." \\',' --tags "..."'].join(`
|
|
2225
2225
|
`)}function flattenShellContinuation(template){return template.replace(/\s*\\\s*\n\s*/g," ").replace(/\s{2,}/g," ").trim()}function buildVariantFileName(originalFileName,variants,variantKind){let variant=variants.find(item=>item.variant_kind===variantKind),extension=variant?inferExtensionFromMimeType(variant.mime_type):extname(originalFileName)||".bin";return`${basename(originalFileName,extname(originalFileName))}.${variantKind}${extension}`}function inferExtensionFromMimeType(mimeType){switch(mimeType){case"image/jpeg":return".jpg";case"image/png":return".png";case"image/webp":return".webp";case"image/gif":return".gif";case"image/svg+xml":return".svg";case"video/mp4":return".mp4";case"video/webm":return".webm";default:return".bin"}}function resolveOutputPath(explicitOutputPath,fileName){if(explicitOutputPath)return resolve2(explicitOutputPath);let directory=mkdtempSync(join(tmpdir(),"platform-asset-"));return join(directory,fileName)}function tryOpenLocalFile(path){try{return process.platform==="darwin"?(spawn("open",[path],{stdio:"ignore",detached:!0}).unref(),!0):process.platform==="win32"?(spawn("cmd",["/c","start","",path],{stdio:"ignore",detached:!0}).unref(),!0):(spawn("xdg-open",[path],{stdio:"ignore",detached:!0}).unref(),!0)}catch{return!1}}function formatAssetError(error,action){return error instanceof PlatformApiError?new Error([`\u7D20\u6750 ${action} \u5931\u8D25\u3002`,`\u72B6\u6001\u7801: ${error.status}`,`\u9519\u8BEF\u7801: ${error.code??"-"}`,error.message].join(`
|
|
2226
|
-
`)):error instanceof Error?error:new Error(`\u7D20\u6750 ${action} \u5931\u8D25\u3002`)}import{existsSync as existsSync9,mkdirSync as mkdirSync4,readdirSync as readdirSync3,readFileSync as readFileSync9,writeFileSync as writeFileSync5}from"node:fs";import{dirname as dirname6,join as join5,resolve as resolve6}from"node:path";import{spawn as spawn2}from"node:child_process";import YAML2 from"yaml";import{createServer}from"node:http";import{createHash as createHash3,randomBytes}from"node:crypto";import{chmodSync,existsSync as existsSync7,mkdirSync as mkdirSync2,readFileSync as readFileSync7,writeFileSync as writeFileSync3}from"node:fs";import{existsSync as existsSync6,mkdirSync,writeFileSync as writeFileSync2}from"node:fs";import{homedir}from"node:os";import{dirname as dirname4,join as join3,resolve as resolve4}from"node:path";import{fileURLToPath as fileURLToPath4}from"node:url";import{existsSync as existsSync4,readFileSync as readFileSync5}from"node:fs";import{dirname as dirname2,join as join2}from"node:path";import{fileURLToPath as fileURLToPath2}from"node:url";var defaultDeveloperProfile={name:"developer",defaults:{CONTROL_API_BASE_URL:"http://localhost:7001",PUBLIC_API_BASE_URL:"http://localhost:7007",RUNTIME_API_BASE_URL:"http://127.0.0.1.nip.io",OIDC_ISSUER:"http://localhost:3001/oidc",OIDC_AUDIENCE:"platform",LOGTO_CLI_REDIRECT_URI:"http://localhost:7300/callback",LOGTO_TENANT_REDIRECT_URI:"http://localhost:7102/callback"
|
|
2226
|
+
`)):error instanceof Error?error:new Error(`\u7D20\u6750 ${action} \u5931\u8D25\u3002`)}import{existsSync as existsSync9,mkdirSync as mkdirSync4,readdirSync as readdirSync3,readFileSync as readFileSync9,writeFileSync as writeFileSync5}from"node:fs";import{dirname as dirname6,join as join5,resolve as resolve6}from"node:path";import{spawn as spawn2}from"node:child_process";import YAML2 from"yaml";import{createServer}from"node:http";import{createHash as createHash3,randomBytes}from"node:crypto";import{chmodSync,existsSync as existsSync7,mkdirSync as mkdirSync2,readFileSync as readFileSync7,writeFileSync as writeFileSync3}from"node:fs";import{existsSync as existsSync6,mkdirSync,writeFileSync as writeFileSync2}from"node:fs";import{homedir}from"node:os";import{dirname as dirname4,join as join3,resolve as resolve4}from"node:path";import{fileURLToPath as fileURLToPath4}from"node:url";import{existsSync as existsSync4,readFileSync as readFileSync5}from"node:fs";import{dirname as dirname2,join as join2}from"node:path";import{fileURLToPath as fileURLToPath2}from"node:url";var AUTH_CLI_CLIENT_ID_KEYS=["AUTH_CLI_CLIENT_ID","LOGTO_CLI_APP_ID"],AUTH_CLI_REDIRECT_URI_KEYS=["AUTH_CLI_REDIRECT_URI","LOGTO_CLI_REDIRECT_URI"],AUTH_TENANT_CLIENT_ID_KEYS=["AUTH_TENANT_CLIENT_ID","LOGTO_TENANT_APP_ID","LOGTO_APP_ID"],AUTH_TENANT_REDIRECT_URI_KEYS=["AUTH_TENANT_REDIRECT_URI","LOGTO_TENANT_REDIRECT_URI"];function readTrimmedConfigValue(source,key){let value=source?.[key]?.trim();if(!(!value||/^<.+>$/.test(value)))return value}function readAuthConfigValue(keys,env=process.env){for(let key of keys){let fromEnv=readTrimmedConfigValue(env,key);if(fromEnv)return fromEnv}let defaults=getDistributionProfile().defaults??{};for(let key of keys){let fromDefaults=readTrimmedConfigValue(defaults,key);if(fromDefaults)return fromDefaults}}var defaultDeveloperProfile={name:"developer",defaults:{CONTROL_API_BASE_URL:"http://localhost:7001",PUBLIC_API_BASE_URL:"http://localhost:7007",RUNTIME_API_BASE_URL:"http://127.0.0.1.nip.io",OIDC_ISSUER:"http://localhost:3001/oidc",OIDC_AUDIENCE:"platform",LOGTO_CLI_REDIRECT_URI:"http://localhost:7300/callback",LOGTO_TENANT_REDIRECT_URI:"http://localhost:7102/callback"}},cachedProfile=null;function getDistributionProfile(){if(cachedProfile)return cachedProfile;let packageJsonPath=resolvePackageJsonPath();if(!packageJsonPath)return cachedProfile=defaultDeveloperProfile,cachedProfile;try{let packageJson=JSON.parse(readFileSync5(packageJsonPath,"utf8"));return cachedProfile=normalizeDistributionProfile(packageJson.platformDistributionProfile),cachedProfile}catch{return cachedProfile=defaultDeveloperProfile,cachedProfile}}function applyDistributionProfileDefaults(env=process.env){let profile=getDistributionProfile();for(let[key,value]of Object.entries(profile.defaults??{}))typeof value!="string"||value.trim().length===0||typeof env[key]=="string"&&env[key].trim().length>0||(env[key]=value);return profile}function getCliPackageVersion(){let packageJsonPath=resolvePackageJsonPath();if(!packageJsonPath)return"0.0.0";try{let packageJson=JSON.parse(readFileSync5(packageJsonPath,"utf8"));return typeof packageJson.version=="string"&&packageJson.version.trim().length>0?packageJson.version.trim():"0.0.0"}catch{return"0.0.0"}}function normalizeDistributionProfile(input){if(!input||input.name!=="developer"&&input.name!=="test-only"&&input.name!=="sandbox"&&input.name!=="nonprod")return defaultDeveloperProfile;let defaults=input.name==="developer"?{...defaultDeveloperProfile.defaults}:{};for(let[key,value]of Object.entries(input.defaults??{}))typeof value=="string"&&value.trim().length>0&&(defaults[key]=value.trim());return{name:input.name,defaults}}function resolvePackageJsonPath(){let distDir=dirname2(fileURLToPath2(import.meta.url)),candidates=[join2(distDir,"..","package.json"),join2(distDir,"..","..","package.json")];for(let candidate of candidates)if(existsSync4(candidate))return candidate;return null}import{existsSync as existsSync5,readFileSync as readFileSync6,statSync as statSync2}from"node:fs";import{dirname as dirname3,resolve as resolve3}from"node:path";import{fileURLToPath as fileURLToPath3}from"node:url";function stripQuotes(value){return value.startsWith('"')&&value.endsWith('"')||value.startsWith("'")&&value.endsWith("'")?value.slice(1,-1):value}function hasWorkspaceMarker(directory){return existsSync5(resolve3(directory,"pnpm-workspace.yaml"))}function getInvocationCwd(){let candidates=[process.env.PLATFORM_INVOCATION_CWD,process.env.INIT_CWD,process.env.PWD,process.cwd()];for(let candidate of candidates){if(!candidate||candidate.trim().length===0)continue;let resolved=resolve3(candidate);if(existsSync5(resolved))try{if(statSync2(resolved).isDirectory())return resolved}catch{continue}}return resolve3(process.cwd())}function tryFindWorkspaceRoot(startDir=getInvocationCwd()){let current=resolve3(startDir);for(;;){if(hasWorkspaceMarker(current))return current;let parent=dirname3(current);if(parent===current)return null;current=parent}}function findWorkspaceRoot(startDir=getInvocationCwd()){return tryFindWorkspaceRoot(startDir)??resolve3(startDir)}function loadDotenvFiles(startDir=getInvocationCwd()){let workspaceRoot=findWorkspaceRoot(startDir),appRoot=resolve3(startDir),cliModuleRoot=resolve3(dirname3(fileURLToPath3(import.meta.url)),".."),cliWorkspaceRoot=findWorkspaceRoot(cliModuleRoot),developerLocalEnvFile=getDistributionProfile().name==="developer"?resolve3(process.env.PLATFORM_LOCAL_CLI_ENV_FILE?.trim()||resolve3(workspaceRoot,"TMP","local-cli.env")):null,candidates=[resolve3(workspaceRoot,".env"),resolve3(workspaceRoot,".env.local"),...developerLocalEnvFile?[developerLocalEnvFile]:[],resolve3(appRoot,".env"),resolve3(appRoot,".env.local"),resolve3(cliWorkspaceRoot,".env"),resolve3(cliWorkspaceRoot,".env.local"),resolve3(cliModuleRoot,".env"),resolve3(cliModuleRoot,".env.local")],visited=new Set;for(let filePath of candidates){if(visited.has(filePath)||(visited.add(filePath),!existsSync5(filePath)))continue;let lines=readFileSync6(filePath,"utf8").split(/\r?\n/u);for(let line of lines){let trimmed=line.trim();if(trimmed.length===0||trimmed.startsWith("#"))continue;let separatorIndex=trimmed.indexOf("=");if(separatorIndex<=0)continue;let key=trimmed.slice(0,separatorIndex).trim(),value=stripQuotes(trimmed.slice(separatorIndex+1).trim());process.env[key]||(process.env[key]=value)}}}var DEFAULT_STATE_DIR_NAME=".platform",LOCAL_DEVELOPER_STATE_DIR=join3("TMP","local-cli-state"),WORKSPACE_FALLBACK_STATE_DIR=join3("TMP","local-cli-state-fallback"),WORKSPACE_FALLBACK_MARKER=".state-fallback-active",activeFallbackStateDir=null,emittedFallbackWarnings=new Set,CliStateAccessError=class extends Error{operation;path;cause;constructor(operation,path,cause){super([`\u65E0\u6CD5${operation} CLI \u672C\u5730\u72B6\u6001\u6587\u4EF6\uFF1A${path}`,"\u8FD9\u901A\u5E38\u662F\u56E0\u4E3A\u5F53\u524D HOME / PLATFORM_STATE_DIR \u5BF9\u5E94\u76EE\u5F55\u4E0D\u53EF\u5199\uFF0C\u6216\u8FD0\u884C\u5728\u53D7\u9650\u6C99\u7BB1\u73AF\u5883\u4E2D\u3002","\u53EF\u5C1D\u8BD5\uFF1A","1. \u91CD\u65B0\u6267\u884C\u5E76\u786E\u8BA4\u5F53\u524D\u8D26\u53F7\u5BF9\u8BE5\u76EE\u5F55\u6709\u5199\u6743\u9650","2. \u663E\u5F0F\u8BBE\u7F6E `PLATFORM_STATE_DIR` \u6307\u5411\u4E00\u4E2A\u53EF\u5199\u76EE\u5F55","3. \u82E5\u5728\u9694\u79BB\u73AF\u5883\u4E2D\u8FD0\u884C\uFF0C\u53EF\u4E3A\u8BE5\u73AF\u5883\u5355\u72EC\u914D\u7F6E `HOME` \u6216 `PLATFORM_STATE_DIR`"].join(`
|
|
2227
2227
|
`)),this.operation=operation,this.path=path,this.cause=cause,this.name="CliStateAccessError"}};function resolveDeveloperStateDir(){let cliModuleRoot=resolve4(dirname4(fileURLToPath4(import.meta.url)),".."),workspaceRoot=findWorkspaceRoot(cliModuleRoot);return resolve4(workspaceRoot,LOCAL_DEVELOPER_STATE_DIR)}function resolveWorkspaceFallbackStateDir(startDir=getInvocationCwd()){let workspaceRoot=tryFindWorkspaceRoot(startDir);return workspaceRoot?resolve4(workspaceRoot,WORKSPACE_FALLBACK_STATE_DIR):null}function resolveCliStateLocation(options={}){let configured=options.configuredStateDir??process.env.PLATFORM_STATE_DIR?.trim()??"";if(configured)return{dir:resolve4(configured),source:"configured"};if(activeFallbackStateDir)return{dir:activeFallbackStateDir,source:"workspace-fallback"};if((options.distributionProfileName??getDistributionProfile().name)==="developer")return{dir:resolveDeveloperStateDir(),source:"developer"};let fallbackDir=resolveWorkspaceFallbackStateDir(options.startDir);return fallbackDir&&existsSync6(resolve4(fallbackDir,WORKSPACE_FALLBACK_MARKER))?{dir:fallbackDir,source:"workspace-fallback"}:{dir:join3(options.homeDir??homedir(),DEFAULT_STATE_DIR_NAME),source:"home"}}function isCliStateAccessFailure(error){return error instanceof Error&&"code"in error&&typeof error.code=="string"&&["EACCES","EPERM","EROFS"].includes(error.code??"")}function activateWorkspaceFallback(startDir=getInvocationCwd()){let fallbackDir=resolveWorkspaceFallbackStateDir(startDir);return fallbackDir?(mkdirSync(fallbackDir,{recursive:!0}),writeFileSync2(resolve4(fallbackDir,WORKSPACE_FALLBACK_MARKER),`active
|
|
2228
2228
|
`,"utf8"),activeFallbackStateDir=fallbackDir,fallbackDir):null}function emitFallbackWarning(originalPath,fallbackDir){emittedFallbackWarnings.has(fallbackDir)||(emittedFallbackWarnings.add(fallbackDir),console.warn([`\u68C0\u6D4B\u5230 CLI state \u9ED8\u8BA4\u76EE\u5F55\u4E0D\u53EF\u5199\uFF1A${originalPath}`,`\u5DF2\u81EA\u52A8\u5207\u6362\u5230\u4ED3\u5E93\u5185\u672C\u5730\u72B6\u6001\u76EE\u5F55\uFF1A${fallbackDir}`,"\u5982\u9700\u56FA\u5B9A\u8BE5\u884C\u4E3A\uFF0C\u53EF\u663E\u5F0F\u8BBE\u7F6E `PLATFORM_STATE_DIR`\u3002"].join(`
|
|
2229
2229
|
`)))}function withCliStateFileWriteFallback(args){let primary=resolveCliStateLocation(args.resolution),primaryPath=join3(primary.dir,args.fileName);try{return args.write({filePath:primaryPath,stateDir:primary.dir})}catch(error){if(!isCliStateAccessFailure(error))throw error;let configuredStateDir=args.resolution?.configuredStateDir??process.env.PLATFORM_STATE_DIR?.trim();if(primary.source!=="home"||configuredStateDir?.trim())throw new CliStateAccessError(args.operation,primaryPath,error);try{let fallbackDir=activateWorkspaceFallback(args.resolution?.startDir);if(!fallbackDir)throw new CliStateAccessError(args.operation,primaryPath,error);emitFallbackWarning(primaryPath,fallbackDir);let fallbackPath=join3(fallbackDir,args.fileName);try{return args.write({filePath:fallbackPath,stateDir:fallbackDir})}catch(fallbackError){throw isCliStateAccessFailure(fallbackError)?new CliStateAccessError(args.operation,fallbackPath,fallbackError):fallbackError}}catch(fallbackError){throw fallbackError instanceof CliStateAccessError?fallbackError:isCliStateAccessFailure(fallbackError)?new CliStateAccessError(args.operation,primaryPath,fallbackError):fallbackError}}}function resolveCliStateDir(options={}){return resolveCliStateLocation(options).dir}function resolveCliStateFilePath(fileName){return join3(resolveCliStateDir(),fileName)}var DEFAULT_CONTROL_API_BASE_URL="http://localhost:7001",DEFAULT_RUNTIME_ENDPOINT_CAPABILITIES="end_user_auth,cms",runtimeEndpointCapabilities=["end_user_auth","workflow","end_user_notification"],publicEndpointCapabilities=["cms","asset_library"];function getControlApiBaseUrl(env=process.env){let configured=env.CONTROL_API_BASE_URL?.trim();if(configured&&configured.length>0)return configured;let profileDefault=getDistributionProfile().defaults?.CONTROL_API_BASE_URL?.trim();return profileDefault&&profileDefault.length>0?profileDefault:DEFAULT_CONTROL_API_BASE_URL}function resolveControlApiEndpoint(args={}){let env=args.env??process.env,controlApiBaseUrl=getControlApiBaseUrl(env),allowlist=readRuntimeEndpointCapabilityAllowlist(env);return(args.requestClass==="runtime"&&isRuntimeEndpointCapabilityEnabled(args.capability,allowlist)?readOptionalBaseUrl(env.RUNTIME_API_BASE_URL)??readOptionalBaseUrl(env.PUBLIC_API_BASE_URL)??controlApiBaseUrl:args.requestClass==="public"&&isRuntimeEndpointCapabilityEnabled(args.capability,allowlist)?readOptionalBaseUrl(env.PUBLIC_API_BASE_URL)??readOptionalBaseUrl(env.RUNTIME_API_BASE_URL)??controlApiBaseUrl:void 0)??controlApiBaseUrl}function listResolvedControlApiEndpoints(env=process.env){let controlApiBaseUrl=getControlApiBaseUrl(env),runtimeBaseUrl=readOptionalBaseUrl(env.RUNTIME_API_BASE_URL)??readOptionalBaseUrl(env.PUBLIC_API_BASE_URL)??controlApiBaseUrl,publicBaseUrl=readOptionalBaseUrl(env.PUBLIC_API_BASE_URL)??readOptionalBaseUrl(env.RUNTIME_API_BASE_URL)??controlApiBaseUrl,allowlist=parseRuntimeEndpointCapabilityAllowlist(readRuntimeEndpointCapabilityAllowlist(env)),runtimeCapabilities=filterAllowedEndpointCapabilities(runtimeEndpointCapabilities,allowlist),publicCapabilities=filterAllowedEndpointCapabilities(publicEndpointCapabilities,allowlist);return[{role:"control",baseUrl:controlApiBaseUrl,enabled:!0,capabilities:[],requestClass:"control"},{role:"runtime",baseUrl:runtimeBaseUrl,enabled:runtimeBaseUrl!=null&&runtimeCapabilities.length>0,capabilities:runtimeCapabilities,requestClass:"runtime",...runtimeBaseUrl==null?{reason:"not_configured"}:runtimeCapabilities.length===0?{reason:"disabled_by_allowlist"}:{}},{role:"public",baseUrl:publicBaseUrl,enabled:publicBaseUrl!=null&&publicCapabilities.length>0,capabilities:publicCapabilities,requestClass:"public",...publicBaseUrl==null?{reason:"not_configured"}:publicCapabilities.length===0?{reason:"disabled_by_allowlist"}:{}}]}function createControlApiSdk(args){return createPlatformSdk({baseUrl:args.baseUrl??resolveControlApiEndpoint({capability:args.capability,requestClass:args.requestClass}),getHeaders:()=>({Authorization:`Bearer ${args.accessToken}`,...args.tenantId?{"X-Tenant-Id":args.tenantId}:{},...Object.fromEntries(Object.entries(args.extraHeaders??{}).filter(([,value])=>value!=null))})})}function readOptionalBaseUrl(value){let trimmed=value?.trim();return trimmed&&trimmed.length>0?trimmed:void 0}function isRuntimeEndpointCapabilityEnabled(capability,rawAllowlist){if(!capability)return!1;let allowlist=parseRuntimeEndpointCapabilityAllowlist(rawAllowlist);return allowlist.has("*")||allowlist.has(capability)}function readRuntimeEndpointCapabilityAllowlist(env){return Object.prototype.hasOwnProperty.call(env,"CONTROL_API_RUNTIME_ENDPOINT_CAPABILITIES")?env.CONTROL_API_RUNTIME_ENDPOINT_CAPABILITIES:DEFAULT_RUNTIME_ENDPOINT_CAPABILITIES}function parseRuntimeEndpointCapabilityAllowlist(value){return new Set((value??"").split(/[,\s]+/u).map(item=>item.trim()).filter(item=>item.length>0))}function filterAllowedEndpointCapabilities(capabilities,allowlist){return allowlist.has("*")?[...capabilities]:capabilities.filter(capability=>allowlist.has(capability))}var TOKEN_REFRESH_SKEW_MS=6e4,PAT_LOGIN_VALIDITY_MS=10080*60*1e3,CliSessionExpiredError=class extends Error{detail;constructor(detail){super(detail&&detail.trim().length>0?`CLI \u4F1A\u8BDD\u5DF2\u5931\u6548\uFF08${detail.trim()}\uFF09\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C \`platform login\`\u3002`:"CLI \u4F1A\u8BDD\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`\u3002"),this.detail=detail,this.name="CliSessionExpiredError"}};function sleep(ms){return new Promise(resolve16=>{setTimeout(resolve16,ms)})}function normalizeOidcGrantFailure(detail){let normalized=detail?.trim();return normalized&&(/(^|[\s:_-])(invalid_grant)([\s:_-]|$)/iu.test(normalized)||/grant request is invalid/iu.test(normalized))?normalized:null}function mapTokenFailureToAuthError(args){let detail=normalizeOidcGrantFailure(args.errorDescription)??normalizeOidcGrantFailure(args.error);return detail?new CliSessionExpiredError(detail):new Error(args.errorDescription??args.error??args.fallback)}function maybeWrapCredentialRefreshError(error){if(error instanceof CliSessionExpiredError)throw error;if(error instanceof Error){let detail=normalizeOidcGrantFailure(error.message);if(detail)throw new CliSessionExpiredError(detail)}throw error}function applyResource(params,audience){if(audience){if(/^[a-z][a-z0-9+.-]*:/iu.test(audience)){params.set("resource",audience);return}params.set("audience",audience)}}function normalizeAuthorizationPrompt(scopes,prompt){let normalized=(prompt??"").split(/\s+/u).map(item=>item.trim()).filter(Boolean);return scopes.includes("offline_access")&&!normalized.includes("consent")&&normalized.push("consent"),normalized.length>0?normalized.join(" "):void 0}function getLoginSuccessHtml(){return`<!DOCTYPE html>
|
|
@@ -2361,7 +2361,7 @@ function inferUpstreamPath(pathname: string, routeBasePath: string): string {
|
|
|
2361
2361
|
</div>
|
|
2362
2362
|
</body>
|
|
2363
2363
|
</html>`}function escapeHtml(s){return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}async function discoverOidcEndpoints(issuer){let discoveryUrl=`${issuer.endsWith("/")?issuer.slice(0,-1):issuer}/.well-known/openid-configuration`,response=await fetch(discoveryUrl);if(!response.ok)throw new Error(`\u83B7\u53D6 OIDC discovery \u5931\u8D25: ${response.status}`);let document=await response.json();if(!document.authorization_endpoint||!document.token_endpoint)throw new Error("OIDC discovery \u7F3A\u5C11\u6388\u6743\u6216 token \u7AEF\u70B9");return{authorization_endpoint:document.authorization_endpoint,device_authorization_endpoint:document.device_authorization_endpoint,token_endpoint:document.token_endpoint}}function getCredentialPath(){return resolveCliStateFilePath("credentials.json")}function getCliContextPath(){return resolveCliStateFilePath("context.json")}function loadStoredCredentials(){let credentialsPath=getCredentialPath();return existsSync7(credentialsPath)?JSON.parse(readFileSync7(credentialsPath,"utf8")):null}function selectApiToken(credentials){return looksLikeJwt(credentials.access_token)?credentials.access_token:looksLikeJwt(credentials.id_token)?credentials.id_token:credentials.access_token}function loadStoredCliContext(){let cliContextPath=getCliContextPath();return existsSync7(cliContextPath)?JSON.parse(readFileSync7(cliContextPath,"utf8")):null}function persistCredentials(credentials){withCliStateFileWriteFallback({fileName:"credentials.json",operation:"\u5199\u5165",write:({filePath,stateDir})=>{mkdirSync2(stateDir,{recursive:!0}),writeFileSync3(filePath,`${JSON.stringify(credentials,null,2)}
|
|
2364
|
-
`,"utf8"),chmodSync(filePath,384)}})}function resolveStoredClientId(credentials){return credentials.client_id?.trim()||
|
|
2364
|
+
`,"utf8"),chmodSync(filePath,384)}})}function resolveStoredClientId(credentials){return credentials.client_id?.trim()||readAuthConfigValue(AUTH_CLI_CLIENT_ID_KEYS)||readAuthConfigValue(AUTH_TENANT_CLIENT_ID_KEYS)}function readJwtExpiryMs(token){if(!looksLikeJwt(token))return null;try{let[,payload]=token.split("."),decoded=JSON.parse(Buffer.from(payload,"base64url").toString("utf8"));return typeof decoded.exp=="number"&&Number.isFinite(decoded.exp)?decoded.exp*1e3:null}catch{return null}}function isCredentialExpired(credentials,now=Date.now()){if(typeof credentials.expires_in=="number"&&Number.isFinite(credentials.expires_in)){let issuedAt=Date.parse(credentials.issued_at);if(Number.isFinite(issuedAt))return issuedAt+credentials.expires_in*1e3-TOKEN_REFRESH_SKEW_MS<=now}let jwtExpiry=readJwtExpiryMs(credentials.access_token)??readJwtExpiryMs(credentials.id_token);return typeof jwtExpiry=="number"?jwtExpiry-TOKEN_REFRESH_SKEW_MS<=now:!1}function canUsePatExchange(credentials,now=Date.now()){if(credentials.credential_mode!=="pat_exchange"||!credentials.exchange_subject_token||!credentials.exchange_subject_token_type||!resolveStoredClientId(credentials)||!credentials.mode_expires_at)return!1;let expiresAt=Date.parse(credentials.mode_expires_at);return Number.isFinite(expiresAt)&&expiresAt>now}async function refreshCredentials(credentials){let issuer=process.env.OIDC_ISSUER?.trim()||getDistributionProfile().defaults?.OIDC_ISSUER?.trim();if(!issuer)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11 OIDC_ISSUER\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 CLI \u51ED\u636E\u3002");let clientId=resolveStoredClientId(credentials);if(!clientId)throw new Error("\u5F53\u524D\u51ED\u636E\u7F3A\u5C11 client_id\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 CLI \u51ED\u636E\u3002");if(!credentials.refresh_token)throw new Error("\u5F53\u524D\u51ED\u636E\u7F3A\u5C11 refresh_token\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`\u3002");let endpoints=await discoverOidcEndpoints(issuer),body=new URLSearchParams;body.set("grant_type","refresh_token"),body.set("client_id",clientId),body.set("refresh_token",credentials.refresh_token),applyResource(body,process.env.OIDC_AUDIENCE?.trim()||getDistributionProfile().defaults?.OIDC_AUDIENCE?.trim());let response=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body}),payload=await response.json();if(!response.ok)throw mapTokenFailureToAuthError({error:payload.error,errorDescription:payload.error_description,fallback:"\u5237\u65B0 CLI token \u5931\u8D25"});if(typeof payload.access_token!="string"||payload.access_token.length===0)throw new Error("\u5237\u65B0\u540E\u7684 token \u54CD\u5E94\u7F3A\u5C11 access_token");let nextCredentials={access_token:payload.access_token,id_token:typeof payload.id_token=="string"?payload.id_token:credentials.id_token,refresh_token:typeof payload.refresh_token=="string"?payload.refresh_token:credentials.refresh_token,client_id:clientId,token_type:payload.token_type??credentials.token_type,expires_in:typeof payload.expires_in=="number"?payload.expires_in:credentials.expires_in,scope:payload.scope??credentials.scope,issued_at:new Date().toISOString(),credential_mode:credentials.credential_mode??"interactive",exchange_subject_token:credentials.exchange_subject_token,exchange_subject_token_type:credentials.exchange_subject_token_type,mode_expires_at:credentials.mode_expires_at};return persistCredentials(nextCredentials),nextCredentials}async function exchangePatCredentials(credentials){let issuer=process.env.OIDC_ISSUER?.trim()||getDistributionProfile().defaults?.OIDC_ISSUER?.trim();if(!issuer)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11 OIDC_ISSUER\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0 PAT \u51ED\u636E\u3002");let clientId=resolveStoredClientId(credentials);if(!clientId)throw new Error("\u5F53\u524D PAT \u51ED\u636E\u7F3A\u5C11 client_id\uFF0C\u65E0\u6CD5\u81EA\u52A8\u5237\u65B0\u3002");if(!credentials.exchange_subject_token||!credentials.exchange_subject_token_type)throw new Error("\u5F53\u524D PAT \u51ED\u636E\u7F3A\u5C11 subject_token\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login --pat <token>`\u3002");if(credentials.mode_expires_at){let hardExpiry=Date.parse(credentials.mode_expires_at);if(Number.isFinite(hardExpiry)&&hardExpiry<=Date.now())throw new Error("\u5F53\u524D PAT \u767B\u5F55\u5DF2\u8D85\u8FC7 7 \u5929\u6709\u6548\u671F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login --pat <token>`\u3002")}let endpoints=await discoverOidcEndpoints(issuer),body=new URLSearchParams;body.set("grant_type","urn:ietf:params:oauth:grant-type:token-exchange"),body.set("client_id",clientId),body.set("subject_token",credentials.exchange_subject_token),body.set("subject_token_type",credentials.exchange_subject_token_type),body.set("requested_token_type","urn:ietf:params:oauth:token-type:access_token"),credentials.scope?.trim()&&body.set("scope",credentials.scope.trim()),applyResource(body,process.env.OIDC_AUDIENCE?.trim()||getDistributionProfile().defaults?.OIDC_AUDIENCE?.trim());let response=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body}),payload=await response.json();if(!response.ok)throw mapTokenFailureToAuthError({error:payload.error,errorDescription:payload.error_description,fallback:"PAT \u4EA4\u6362 access token \u5931\u8D25"});if(typeof payload.access_token!="string"||payload.access_token.length===0)throw new Error("PAT \u4EA4\u6362\u540E\u7684 token \u54CD\u5E94\u7F3A\u5C11 access_token");let nextCredentials={access_token:payload.access_token,id_token:typeof payload.id_token=="string"?payload.id_token:credentials.id_token,client_id:clientId,token_type:payload.token_type??credentials.token_type,expires_in:typeof payload.expires_in=="number"?payload.expires_in:credentials.expires_in,scope:payload.scope??credentials.scope,issued_at:new Date().toISOString(),credential_mode:"pat_exchange",exchange_subject_token:credentials.exchange_subject_token,exchange_subject_token_type:credentials.exchange_subject_token_type,mode_expires_at:credentials.mode_expires_at};return persistCredentials(nextCredentials),nextCredentials}async function loadStoredCredentialsEnsuringFresh(options={}){let credentials=loadStoredCredentials();if(!credentials)return null;let expired=isCredentialExpired(credentials);if(!options.forceRefresh&&!expired)return credentials;if(credentials.refresh_token)try{return refreshCredentials(credentials)}catch(error){maybeWrapCredentialRefreshError(error)}if(canUsePatExchange(credentials))try{return exchangePatCredentials(credentials)}catch(error){maybeWrapCredentialRefreshError(error)}if(expired)throw new Error("\u5F53\u524D\u51ED\u636E\u5DF2\u8FC7\u671F\u4E14\u4E0D\u652F\u6301\u81EA\u52A8\u5237\u65B0\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login` \u6216 `platform login --pat <token>`\u3002");return credentials}function persistCliContext(context){withCliStateFileWriteFallback({fileName:"context.json",operation:"\u5199\u5165",write:({filePath,stateDir})=>{mkdirSync2(stateDir,{recursive:!0}),writeFileSync3(filePath,`${JSON.stringify({...context,updated_at:new Date().toISOString()},null,2)}
|
|
2365
2365
|
`,"utf8"),chmodSync(filePath,384)}})}async function performDeviceCodeLogin(config2){let endpoints=await discoverOidcEndpoints(config2.issuer);if(!endpoints.device_authorization_endpoint)throw new Error("OIDC discovery \u7F3A\u5C11 Device Flow \u7AEF\u70B9");let authBody=new URLSearchParams;authBody.set("client_id",config2.clientId),authBody.set("scope",config2.scopes.join(" ")),applyResource(authBody,config2.audience);let deviceResponse=await fetch(endpoints.device_authorization_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:authBody}),devicePayload=await deviceResponse.json();if(!deviceResponse.ok)throw new Error(devicePayload.error_description??devicePayload.error??"\u7533\u8BF7 device_code \u5931\u8D25");config2.onPrompt?.({verificationUri:devicePayload.verification_uri_complete??devicePayload.verification_uri??config2.issuer,userCode:devicePayload.user_code,expiresIn:devicePayload.expires_in});let intervalSeconds=Math.max(devicePayload.interval??5,1),deadline=Date.now()+devicePayload.expires_in*1e3;for(;Date.now()<deadline;){await sleep(intervalSeconds*1e3);let tokenBody=new URLSearchParams;tokenBody.set("grant_type","urn:ietf:params:oauth:grant-type:device_code"),tokenBody.set("device_code",devicePayload.device_code),tokenBody.set("client_id",config2.clientId);let tokenResponse=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:tokenBody}),tokenPayload=await tokenResponse.json();if(tokenResponse.ok)return{access_token:tokenPayload.access_token,id_token:tokenPayload.id_token,refresh_token:tokenPayload.refresh_token,client_id:config2.clientId,token_type:tokenPayload.token_type,expires_in:tokenPayload.expires_in,scope:tokenPayload.scope,issued_at:new Date().toISOString(),verificationUri:devicePayload.verification_uri_complete??devicePayload.verification_uri??config2.issuer,userCode:devicePayload.user_code};if(tokenPayload.error!=="authorization_pending"){if(tokenPayload.error==="slow_down"){await sleep(intervalSeconds*1e3);continue}throw new Error(tokenPayload.error_description??tokenPayload.error??"\u8F6E\u8BE2 token \u5931\u8D25")}}throw new Error("Device Code \u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`")}async function performAuthorizationCodeLogin(config2){let endpoints=await discoverOidcEndpoints(config2.issuer),redirectUrl=new URL(config2.redirectUri);if(redirectUrl.protocol!=="http:")throw new Error("CLI \u6D4F\u89C8\u5668\u6388\u6743\u4EC5\u652F\u6301 http \u56DE\u8C03\u5730\u5740");let state=randomBytes(16).toString("base64url"),nonce=randomBytes(16).toString("base64url"),codeVerifier=randomBytes(32).toString("base64url"),codeChallenge=createHash3("sha256").update(codeVerifier).digest("base64url"),authorizationUrl=new URL(endpoints.authorization_endpoint);authorizationUrl.searchParams.set("client_id",config2.clientId),authorizationUrl.searchParams.set("redirect_uri",config2.redirectUri),authorizationUrl.searchParams.set("response_type","code"),authorizationUrl.searchParams.set("scope",config2.scopes.join(" ")),authorizationUrl.searchParams.set("state",state),authorizationUrl.searchParams.set("nonce",nonce),authorizationUrl.searchParams.set("code_challenge",codeChallenge),authorizationUrl.searchParams.set("code_challenge_method","S256");let normalizedPrompt=normalizeAuthorizationPrompt(config2.scopes,config2.prompt);normalizedPrompt&&authorizationUrl.searchParams.set("prompt",normalizedPrompt),applyResource(authorizationUrl.searchParams,config2.audience);let callbackResult=await new Promise((resolve16,reject)=>{let timeout=setTimeout(()=>{server.close(()=>{}),reject(new Error("\u6D4F\u89C8\u5668\u6388\u6743\u8D85\u65F6\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C `platform login`"))},3e5),server=createServer((req,res)=>{let url=new URL(req.url??"/",config2.redirectUri);if(url.pathname!==redirectUrl.pathname){res.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),res.end("Not Found");return}let returnedState=url.searchParams.get("state"),error=url.searchParams.get("error"),code2=url.searchParams.get("code");if(error){clearTimeout(timeout);let errMsg=url.searchParams.get("error_description")??error;res.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),res.end(getLoginFailureHtml(errMsg)),server.close(()=>{}),reject(new Error(errMsg));return}if(!code2||returnedState!==state){clearTimeout(timeout),res.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),res.end(getLoginFailureHtml("\u6D4F\u89C8\u5668\u56DE\u8C03\u7F3A\u5C11\u6388\u6743\u7801\u6216 state \u4E0D\u5339\u914D\u3002")),server.close(()=>{}),reject(new Error("\u6D4F\u89C8\u5668\u56DE\u8C03\u7F3A\u5C11 code \u6216 state \u4E0D\u5339\u914D"));return}clearTimeout(timeout),res.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),res.end(getLoginSuccessHtml()),server.close(()=>{}),resolve16({code:code2})});server.on("error",error=>{clearTimeout(timeout),reject(error)}),server.listen(Number(redirectUrl.port||80),redirectUrl.hostname,()=>{config2.onPrompt?.({authorizationUrl:authorizationUrl.toString(),redirectUri:config2.redirectUri})})}),tokenBody=new URLSearchParams;tokenBody.set("grant_type","authorization_code"),tokenBody.set("client_id",config2.clientId),tokenBody.set("code",callbackResult.code),tokenBody.set("redirect_uri",config2.redirectUri),tokenBody.set("code_verifier",codeVerifier),applyResource(tokenBody,config2.audience);let tokenResponse=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:tokenBody}),tokenPayload=await tokenResponse.json();if(!tokenResponse.ok)throw new Error(tokenPayload.error_description??tokenPayload.error??"\u6388\u6743\u7801\u6362\u53D6 token \u5931\u8D25");return{access_token:tokenPayload.access_token,id_token:tokenPayload.id_token,refresh_token:tokenPayload.refresh_token,client_id:config2.clientId,token_type:tokenPayload.token_type,expires_in:tokenPayload.expires_in,scope:tokenPayload.scope,issued_at:new Date().toISOString(),authorizationUrl:authorizationUrl.toString(),redirectUri:config2.redirectUri}}async function performPatTokenExchangeLogin(config2){let endpoints=await discoverOidcEndpoints(config2.issuer),body=new URLSearchParams;body.set("grant_type","urn:ietf:params:oauth:grant-type:token-exchange"),body.set("client_id",config2.clientId),body.set("subject_token",config2.subjectToken),body.set("subject_token_type",config2.subjectTokenType??"urn:logto:token-type:personal_access_token"),body.set("requested_token_type","urn:ietf:params:oauth:token-type:access_token"),config2.scopes.length>0&&body.set("scope",config2.scopes.join(" ")),applyResource(body,config2.audience);let tokenResponse=await fetch(endpoints.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body}),tokenPayload=await tokenResponse.json();if(!tokenResponse.ok)throw new Error(tokenPayload.error_description??tokenPayload.error??"PAT \u4EA4\u6362 token \u5931\u8D25");return{access_token:tokenPayload.access_token,id_token:typeof tokenPayload.id_token=="string"?tokenPayload.id_token:void 0,client_id:config2.clientId,token_type:tokenPayload.token_type,expires_in:tokenPayload.expires_in,scope:tokenPayload.scope??config2.scopes.join(" "),issued_at:new Date().toISOString(),credential_mode:"pat_exchange",exchange_subject_token:config2.subjectToken,exchange_subject_token_type:config2.subjectTokenType??"urn:logto:token-type:personal_access_token",mode_expires_at:new Date(Date.now()+PAT_LOGIN_VALIDITY_MS).toISOString()}}async function fetchWhoAmI(args){return createControlApiSdk({baseUrl:args.baseUrl,accessToken:args.accessToken,tenantId:args.tenantId,capability:"auth",requestClass:"control"}).getWhoAmI()}async function fetchTenantOverview(args){return createControlApiSdk({baseUrl:args.baseUrl,accessToken:args.accessToken,tenantId:args.tenantId,capability:"dashboard",requestClass:"control"}).getTenantOverview()}async function listTenantWorkspaces(args){return createControlApiSdk({baseUrl:args.baseUrl,accessToken:args.accessToken,capability:"auth",requestClass:"control"}).listTenantWorkspaces()}function looksLikeJwt(token){if(!token)return!1;let parts=token.split(".");return parts.length>=2&&parts.every(part=>part.length>0)}import{existsSync as existsSync8,mkdirSync as mkdirSync3,readdirSync as readdirSync2,readFileSync as readFileSync8,statSync as statSync3,writeFileSync as writeFileSync4}from"node:fs";import{createServer as createNetServer}from"node:net";import{dirname as dirname5,join as join4,relative,resolve as resolve5}from"node:path";import YAML from"yaml";var DEFAULT_APP_TEMPLATE_KEY="frontend-app-vite";function normalizeAppTemplateKey(value){if(typeof value>"u"||value.trim().length===0)return;let normalized=value.trim();if(normalized==="frontend-app-vite")return"frontend-app-vite";if(normalized==="backend-app-node")return"backend-app-node";throw new Error(`\u4E0D\u652F\u6301\u7684\u5E94\u7528\u6A21\u677F: ${normalized}\u3002\u5F53\u524D\u4EC5\u652F\u6301 \`frontend-app-vite\`\u3001\`backend-app-node\`\u3002\u65E7\u6A21\u677F\u5DF2\u4E0B\u7EBF\u3002`)}var PLATFORM_DIRECTORY=".platform",APP_MANIFEST_FILE="app.yaml",LEGACY_BINDING_FILE=join4(PLATFORM_DIRECTORY,"config.json"),SOURCE_CONTEXT_FILE=join4(PLATFORM_DIRECTORY,"source-context.json"),PLATFORM_BLOCKS_LOCKFILE=join4(PLATFORM_DIRECTORY,"platform-blocks.lock.json").replace(/\\/g,"/"),SOURCE_WORKSPACE_BYTES_LIMIT=50*1024*1024,SOURCE_WORKSPACE_ASSET_EXTENSIONS=new Set([".png",".jpg",".jpeg",".gif",".webp",".svg",".ico",".bmp",".avif",".mp4",".mp3",".wav",".ogg",".pdf",".woff",".woff2",".ttf",".otf",".eot",".zip",".gz"]);function ensureDirectory(directory){mkdirSync3(directory,{recursive:!0})}function writeFileIfMissing(path,content){if(existsSync8(path))throw new Error(`\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u62D2\u7EDD\u8986\u76D6: ${path}`);ensureDirectory(dirname5(path)),writeFileSync4(path,content,"utf8")}function listFilesRecursively(root,current=root){if(!existsSync8(current)||!statSync3(current).isDirectory())return[];let files=[];for(let entry of readdirSync2(current,{withFileTypes:!0})){let absolutePath=join4(current,entry.name);if(entry.isDirectory()){files.push(...listFilesRecursively(root,absolutePath));continue}entry.isFile()&&files.push(relative(root,absolutePath))}return files.sort((left,right)=>left.localeCompare(right))}function seedRuntimeSdkVendor(targetDir){let workspaceRoot=findWorkspaceRoot(),runtimeSdkDistDir=join4(workspaceRoot,"packages","runtime-sdk","dist");if(!existsSync8(runtimeSdkDistDir)||!statSync3(runtimeSdkDistDir).isDirectory())throw new Error(`\u7F3A\u5C11\u6D4F\u89C8\u5668\u4FA7 runtime-sdk \u6784\u5EFA\u4EA7\u7269\uFF1A${runtimeSdkDistDir}\u3002\u8BF7\u5148\u6267\u884C \`pnpm --filter @platform/runtime-sdk build\`\uFF0C\u518D\u91CD\u65B0\u521D\u59CB\u5316\u8F7B\u5E94\u7528\u6A21\u677F\u3002`);let created=[];for(let relativePath of listFilesRecursively(runtimeSdkDistDir)){let sourcePath=join4(runtimeSdkDistDir,relativePath),outputPath=join4(targetDir,"vendor","runtime-sdk",relativePath);writeFileIfMissing(outputPath,readFileSync8(sourcePath,"utf8")),created.push(relative(process.cwd(),outputPath))}return created}function normalizeAppManifest(input){let name=typeof input?.name=="string"&&input.name.trim().length>0?input.name.trim():"light-app",moduleName=typeof input?.module=="string"&&input.module.trim().length>0?input.module.trim():"light-app",templateKey=typeof input?.template_key=="string"&&input.template_key.trim().length>0?input.template_key.trim():DEFAULT_APP_TEMPLATE_KEY,normalizedEnvironments=Array.isArray(input?.environments)&&input.environments.length>0?input.environments.map(environment=>typeof environment?.name=="string"&&environment.name.trim().length>0?{name:environment.name.trim()}:null).filter(environment=>environment!==null):[];return{name,version:typeof input?.version=="string"&&input.version.trim().length>0?input.version.trim():"0.1.0",module:moduleName,template_key:templateKey,dev:{auto_restart:input?.dev?.auto_restart===!0},entry:{command:typeof input?.entry?.command=="string"&&input.entry.command.trim().length>0?input.entry.command.trim():"npm run dev",port:typeof input?.entry?.port=="number"&&Number.isFinite(input.entry.port)&&input.entry.port>0?input.entry.port:3e3,health_check:typeof input?.entry?.health_check=="string"&&input.entry.health_check.trim().length>0?input.entry.health_check.trim():"/healthz"},required_skills:Array.isArray(input?.required_skills)?input.required_skills.filter(Boolean):["db","auth"],permissions:Array.isArray(input?.permissions)?input.permissions.filter(Boolean):["app:read","app:write","app:publish"],env_vars:Array.isArray(input?.env_vars)?input.env_vars.filter(Boolean):["PORT","NODE_ENV","APP_ID","APP_ENV","TENANT_ID","DATABASE_URL","DATABASE_SCHEMA","CONTROL_API_BASE_URL"],runtime:{cpu:typeof input?.runtime?.cpu=="string"&&input.runtime.cpu.trim().length>0?input.runtime.cpu.trim():"250m",memory_mb:typeof input?.runtime?.memory_mb=="number"&&Number.isFinite(input.runtime.memory_mb)&&input.runtime.memory_mb>0?input.runtime.memory_mb:256},environments:normalizedEnvironments.length>0?normalizedEnvironments:[{name:"preview"},{name:"prod"}]}}function initProject(targetDir,_appName,templateKey=DEFAULT_APP_TEMPLATE_KEY){let absoluteTargetDir=resolve5(getInvocationCwd(),targetDir);ensureDirectory(absoluteTargetDir);let createdFiles=[],normalizedTemplateKey=normalizeAppTemplateKey(templateKey)??DEFAULT_APP_TEMPLATE_KEY,scaffoldFiles=normalizedTemplateKey==="frontend-app-vite"?assembleFrontendAppViteTemplate():normalizedTemplateKey==="backend-app-node"?assembleBackendAppNodeTemplate():assembleFrontendAppViteTemplate();for(let file of scaffoldFiles){let outputPath=join4(absoluteTargetDir,file.path);writeFileIfMissing(outputPath,file.content),createdFiles.push(relative(getInvocationCwd(),outputPath))}let vendorCreated=scaffoldFiles.some(file=>file.path.startsWith("vendor/runtime-sdk/")||file.path.startsWith("src/vendor/runtime-sdk/"))?[]:seedRuntimeSdkVendor(absoluteTargetDir);return[...createdFiles,...vendorCreated]}function scaffoldAppDebugSurface(startDir,scaffold){let appRoot=findAppRoot(startDir),appJsPath=join4(appRoot,"src","app.js");if(!existsSync8(appJsPath))throw new Error(`\u672A\u627E\u5230\u5E94\u7528\u5165\u53E3\u6587\u4EF6: ${appJsPath}`);let spec=getAppDebugScaffoldSpec(scaffold),createdFiles=[],updatedFiles=[],targetFilePath=join4(appRoot,spec.filePath);existsSync8(targetFilePath)||(ensureDirectory(dirname5(targetFilePath)),writeFileSync4(targetFilePath,spec.source,"utf8"),createdFiles.push(relative(appRoot,targetFilePath).replace(/\\/g,"/")));let appSource=readFileSync8(appJsPath,"utf8"),nextSource=injectDebugRouteIntoAppSource(appSource,spec);return nextSource!==appSource&&(writeFileSync4(appJsPath,nextSource,"utf8"),updatedFiles.push(relative(appRoot,appJsPath).replace(/\\/g,"/"))),{appRoot,createdFiles,updatedFiles,routePath:spec.routePath}}function readAppManifest(startDir=getInvocationCwd()){let appRoot=findAppRoot(startDir),manifestPath=join4(appRoot,APP_MANIFEST_FILE),raw=readFileSync8(manifestPath,"utf8"),manifest=normalizeAppManifest(YAML.parse(raw));if(!manifest||typeof manifest!="object")throw new Error(`\u65E0\u6548\u7684 app.yaml: ${manifestPath}`);return{directory:appRoot,path:manifestPath,manifest}}function readLegacyBinding(startDir=getInvocationCwd()){let appRoot=findAppRoot(startDir),bindingPath=join4(appRoot,LEGACY_BINDING_FILE);if(!existsSync8(bindingPath))return null;let raw=JSON.parse(readFileSync8(bindingPath,"utf8")),binding={schema_version:typeof raw.schema_version=="number"?raw.schema_version:1,tenant_id:raw.tenant_id??"",app_id:raw.app_id??"",env:raw.env??"preview",linked_at:raw.linked_at??new Date(0).toISOString(),workspace_name:raw.workspace_name,app_name:raw.app_name,app_display_name:raw.app_display_name,validated_at:raw.validated_at};return{path:bindingPath,binding}}function readBinding(startDir=getInvocationCwd()){let sourceContext=readSourceContext(startDir);if(sourceContext?.sourceContext.tenant_id&&sourceContext.sourceContext.app_id){let context=sourceContext.sourceContext;return{path:sourceContext.path,binding:{schema_version:1,tenant_id:context.tenant_id,app_id:context.app_id,env:context.env||"preview",linked_at:context.linked_at??context.checked_out_at??context.updated_at,workspace_name:context.workspace_name,app_name:context.app_name,app_display_name:context.app_display_name,validated_at:context.validated_at}}}return readLegacyBinding(startDir)}function writeBinding(startDir,binding){let result=updateSourceContext(startDir,{tenant_id:binding.tenant_id,app_id:binding.app_id,env:binding.env,workspace_name:binding.workspace_name,app_name:binding.app_name,app_display_name:binding.app_display_name,validated_at:binding.validated_at,linked_at:new Date().toISOString()});return{appRoot:result.appRoot,path:result.path}}function readSourceContext(startDir=getInvocationCwd()){let appRoot=findAppRoot(startDir),sourceContextPath=join4(appRoot,SOURCE_CONTEXT_FILE);if(!existsSync8(sourceContextPath))return null;let raw=JSON.parse(readFileSync8(sourceContextPath,"utf8")),sourceContext={schema_version:typeof raw.schema_version=="number"?raw.schema_version:1,tenant_id:raw.tenant_id??"",app_id:raw.app_id??"",env:raw.env??"preview",linked_at:raw.linked_at,validated_at:raw.validated_at,workspace_name:raw.workspace_name,app_name:raw.app_name,app_display_name:raw.app_display_name,template_key:raw.template_key,default_directory:raw.default_directory,generated_from_template:typeof raw.generated_from_template=="boolean"?raw.generated_from_template:void 0,base_source_version_id:raw.base_source_version_id,checked_out_at:raw.checked_out_at,last_submitted_source_version_id:raw.last_submitted_source_version_id,last_submitted_at:raw.last_submitted_at,last_preview_source_version_id:raw.last_preview_source_version_id,last_preview_build_id:raw.last_preview_build_id,last_preview_generated_at:raw.last_preview_generated_at,control_plane:raw.control_plane&&typeof raw.control_plane=="object"?raw.control_plane:void 0,updated_at:raw.updated_at??new Date(0).toISOString()};return{path:sourceContextPath,sourceContext}}function writeSourceContext(startDir,sourceContext){let appRoot=findAppRoot(startDir),path=join4(appRoot,SOURCE_CONTEXT_FILE);return ensureDirectory(dirname5(path)),writeFileSync4(path,`${JSON.stringify({schema_version:1,...sourceContext,updated_at:new Date().toISOString()},null,2)}
|
|
2366
2366
|
`,"utf8"),{appRoot,path}}function updateSourceContext(startDir,patch){let appRoot=findAppRoot(startDir),existing=readSourceContext(appRoot)?.sourceContext,legacyBinding=readLegacyBinding(appRoot)?.binding;return writeSourceContext(appRoot,{tenant_id:patch.tenant_id??existing?.tenant_id??legacyBinding?.tenant_id??"",app_id:patch.app_id??existing?.app_id??legacyBinding?.app_id??"",env:patch.env??existing?.env??legacyBinding?.env??"preview",linked_at:patch.linked_at??existing?.linked_at??legacyBinding?.linked_at,validated_at:patch.validated_at??existing?.validated_at??legacyBinding?.validated_at,workspace_name:patch.workspace_name??existing?.workspace_name??legacyBinding?.workspace_name,app_name:patch.app_name??existing?.app_name??legacyBinding?.app_name,app_display_name:patch.app_display_name??existing?.app_display_name??legacyBinding?.app_display_name,template_key:patch.template_key??existing?.template_key,default_directory:patch.default_directory??existing?.default_directory,generated_from_template:typeof patch.generated_from_template=="boolean"?patch.generated_from_template:existing?.generated_from_template,base_source_version_id:patch.base_source_version_id??existing?.base_source_version_id,checked_out_at:patch.checked_out_at??existing?.checked_out_at,last_submitted_source_version_id:patch.last_submitted_source_version_id??existing?.last_submitted_source_version_id,last_submitted_at:patch.last_submitted_at??existing?.last_submitted_at,last_preview_source_version_id:patch.last_preview_source_version_id??existing?.last_preview_source_version_id,last_preview_build_id:patch.last_preview_build_id??existing?.last_preview_build_id,last_preview_generated_at:patch.last_preview_generated_at??existing?.last_preview_generated_at,control_plane:patch.control_plane??existing?.control_plane})}function checkoutSourceWorkspace(targetDir,files,binding){let absoluteTargetDir=resolve5(getInvocationCwd(),targetDir);if(existsSync8(absoluteTargetDir)){if(readdirSync2(absoluteTargetDir).length>0)throw new Error(`\u76EE\u6807\u76EE\u5F55\u975E\u7A7A\uFF0C\u62D2\u7EDD\u8986\u76D6: ${absoluteTargetDir}`)}else ensureDirectory(absoluteTargetDir);let writtenFiles=[];for(let file of files){let normalizedPath=file.path.replace(/^\/+/g,"");if(normalizedPath.length===0||normalizedPath.startsWith("..")||normalizedPath.includes("../")||normalizedPath.includes("..\\"))throw new Error(`\u4E91\u7AEF\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\u975E\u6CD5: ${file.path}`);let outputPath=join4(absoluteTargetDir,normalizedPath);writeFileIfMissing(outputPath,file.content),writtenFiles.push(relative(getInvocationCwd(),outputPath))}return writeBinding(absoluteTargetDir,binding),writtenFiles}function collectSourceWorkspaceFiles(startDir=getInvocationCwd()){let appRoot=findAppRoot(startDir),files=walkSourceWorkspace(appRoot,appRoot);return{appRoot,files}}function assertSourceWorkspaceCloudUploadPolicy(appRoot,commandLabel){let stats=scanSourceWorkspaceUploadPolicy(appRoot,appRoot);if(stats.sourceBytes>SOURCE_WORKSPACE_BYTES_LIMIT)throw new Error(`\u5F53\u524D\u6E90\u7801\u5305\u4F53\u79EF ${stats.sourceBytes} bytes\uFF0C\u8D85\u8FC7\u4E91\u7AEF\u6E90\u7801\u4E0A\u4F20\u4E0A\u9650 ${SOURCE_WORKSPACE_BYTES_LIMIT} bytes\u3002`);if(stats.assetHits.length>0)throw new Error([`\u68C0\u6D4B\u5230\u672C\u5730\u7D20\u6750\u8D44\u6E90\uFF0C\u5F53\u524D \`${commandLabel}\` \u4E0D\u8D1F\u8D23\u7D20\u6750\u4E0A\u4F20\u56DE\u5199\u3002`,"Agent \u8BF7\u5148\u53C2\u8003 Skill \u6587\u6863 `design-import.md` \u6267\u884C\u8BBE\u8BA1\u6E90\u7801\u9884\u5904\u7406\uFF0C\u5C06\u672C\u5730\u7D20\u6750\u4E0A\u4F20\u7D20\u6750\u5E93\u5E76\u628A\u6E90\u7801\u6539\u5199\u4E3A\u7D20\u6750\u5E93\u5F15\u7528\u540E\u518D\u8BD5\u3002",`\u793A\u4F8B\u547D\u4E2D: ${stats.assetHits.slice(0,10).join(", ")}`].join(`
|
|
2367
2367
|
`));return stats}function detectPathBaseRuntimeViolations(files){let violations=[],textFilePattern=/\.(?:[cm]?[jt]sx?|html?|css)$/i,patterns=[{kind:"root_relative_fetch",regex:/\bfetch\(\s*['"`]\/(?!\/)/g},{kind:"root_relative_http_client",regex:/\baxios(?:\.(?:get|post|put|patch|delete|head|options))?\(\s*['"`]\/(?!\/)/g},{kind:"root_relative_href",regex:/\bhref\s*=\s*['"]\/(?!\/)/g},{kind:"root_relative_src",regex:/\bsrc\s*=\s*['"]\/(?!\/)/g}];for(let file of files){if(!textFilePattern.test(file.path)||/^README\.md$/i.test(file.path)||isPlatformDevSupportFile(file.path))continue;let lines=file.content.split(/\r?\n/);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({path:file.path,line:index+1,kind:pattern.kind,snippet:line.trim().slice(0,180)})}}return violations}function isPlatformDevSupportFile(path){return path.startsWith("src/platform/dev/")||path.startsWith("src/web/platform/dev/")||path.startsWith("src/server/platform/dev/")}function scanSourceWorkspaceUploadPolicy(appRoot,currentDir){let entries=readdirSync2(currentDir,{withFileTypes:!0}),sourceBytes=0,assetHits=[];for(let entry of entries){let absolutePath=join4(currentDir,entry.name),relativePath=relative(appRoot,absolutePath).replace(/\\/g,"/");if(!shouldIgnoreSourceWorkspaceUploadPolicyPath(relativePath,entry.isDirectory())){if(entry.isDirectory()){let nested=scanSourceWorkspaceUploadPolicy(appRoot,absolutePath);sourceBytes+=nested.sourceBytes,assetHits.push(...nested.assetHits);continue}entry.isFile()&&(sourceBytes+=statSync3(absolutePath).size,isSourceWorkspaceAssetPath(relativePath)&&assetHits.push(relativePath))}}return{sourceBytes,assetHits}}function shouldIgnoreSourceWorkspaceUploadPolicyPath(relativePath,isDirectory){let normalized=relativePath.replace(/^\.\/+/g,"");if(!normalized)return!1;let topLevel=normalized.split("/")[0];return isDirectory&&topLevel.startsWith(".")?!0:new Set([".git",".platform","node_modules","dist","coverage","evidence","Log","TMP"]).has(topLevel)}function isSourceWorkspaceAssetPath(relativePath){let lower=relativePath.toLowerCase(),dotIndex=lower.lastIndexOf(".");return dotIndex<0?!1:SOURCE_WORKSPACE_ASSET_EXTENSIONS.has(lower.slice(dotIndex))}function walkSourceWorkspace(appRoot,currentDir){let entries=readdirSync2(currentDir,{withFileTypes:!0}),files=[];for(let entry of entries){let absolutePath=join4(currentDir,entry.name),relativePath=relative(appRoot,absolutePath).replace(/\\/g,"/");if(!shouldIgnoreSourceWorkspacePath(relativePath,entry.isDirectory())){if(entry.isDirectory()){files.push(...walkSourceWorkspace(appRoot,absolutePath));continue}entry.isFile()&&files.push({path:relativePath,content:readFileSync8(absolutePath,"utf8")})}}return files.sort((left,right)=>left.path.localeCompare(right.path))}function shouldIgnoreSourceWorkspacePath(relativePath,isDirectory){let normalized=relativePath.replace(/^\.\/+/g,"");if(normalized.length===0)return!1;let topLevel=normalized.split("/")[0];return isDirectory&&topLevel.startsWith(".")&&topLevel!==".platform"||new Set([".git","node_modules","dist","coverage","evidence","Log","TMP"]).has(topLevel)?!0:topLevel===".platform"?isDirectory?normalized===".platform/platform-blocks.history":normalized!==PLATFORM_BLOCKS_LOCKFILE:!!(!isDirectory&&new Set([".DS_Store",".env",".env.local",".env.dev",".env.ci"]).has(normalized))}function findAppRoot(startDir=getInvocationCwd()){let current=resolve5(getInvocationCwd(),startDir);for(;;){let manifestPath=join4(current,APP_MANIFEST_FILE);if(existsSync8(manifestPath)&&statSync3(manifestPath).isFile())return current;let parent=dirname5(current);if(parent===current)throw new Error("\u672A\u627E\u5230 app.yaml\u3002\u4F18\u5148\u5EFA\u8BAE\u5148\u6267\u884C `platform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>` \u83B7\u5F97\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1B\u82E5\u4F60\u660E\u786E\u8981\u5728\u5F53\u524D\u7A7A\u76EE\u5F55\u521D\u59CB\u5316\uFF0C\u518D\u6267\u884C `platform init <project-name>`\u3002");current=parent}}function getAppDebugScaffoldSpec(scaffold){return scaffold==="auth-debug"?{kind:scaffold,routePath:"/debug/auth",filePath:"src/lib/debug-auth-page.js",importLine:'import { renderAuthDebugPage } from "./lib/debug-auth-page.js";',renderCall:"renderAuthDebugPage()",source:buildAuthDebugPageSource()}:scaffold==="cms-debug"?{kind:scaffold,routePath:"/debug/cms",filePath:"src/lib/debug-cms-page.js",importLine:'import { renderCmsDebugPage } from "./lib/debug-cms-page.js";',renderCall:"renderCmsDebugPage()",source:buildCmsDebugPageSource()}:scaffold==="db-debug"?{kind:scaffold,routePath:"/debug/db",filePath:"src/lib/debug-db-page.js",importLine:'import { renderDbDebugPage } from "./lib/debug-db-page.js";',renderCall:"renderDbDebugPage()",source:buildDbDebugPageSource(),extraRouteBlocks:[[' if (pathname === "/api/debug/db-context" && req.method === "GET") {'," sendJson(res, 200, {"," app_id: config.appId,"," tenant_id: config.tenantId || null,"," env: config.appEnv,"," request_id: requestId,"," database_ready: Boolean(config.databaseUrl),"," database_schema: config.databaseSchema || null,"," database_capability_version: process.env.DATABASE_CAPABILITY_VERSION || null,"," database_runtime_role: process.env.DATABASE_RUNTIME_ROLE || null,"," database_migrator_role: process.env.DATABASE_MIGRATOR_ROLE || null"," });"," return;"," }",""].join(`
|
|
@@ -2515,7 +2515,7 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2515
2515
|
`);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(`
|
|
2516
2516
|
`))}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(`
|
|
2517
2517
|
`).map(line=>line.replace(/--.*$/,"").trim()).filter(Boolean).join(`
|
|
2518
|
-
`).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.LOGTO_TENANT_REDIRECT_URI
|
|
2518
|
+
`).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 readdirSync9,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)}
|
|
2519
2519
|
`);return}process.stdout.write(`${result.map(item=>`OK ${item.resource_key} ${item.manifest_path} fields=${item.field_count}`).join(`
|
|
2520
2520
|
`)}
|
|
2521
2521
|
`);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)}
|
|
@@ -2547,8 +2547,8 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2547
2547
|
`)+`
|
|
2548
2548
|
`);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(`
|
|
2549
2549
|
`)+`
|
|
2550
|
-
`)}import{spawn as spawn4}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=spawn4("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((resolve16,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}resolve16(port)})})})}async function listenLocalServer(server,port){await new Promise((resolve16,reject)=>{server.once("error",reject),server.listen(port,"127.0.0.1",()=>{server.off("error",reject),resolve16()})})}async function closeServer(server){await new Promise(resolve16=>{server.close(()=>resolve16())})}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(resolve16=>{let socket=net.createConnection({host,port}),done=value=>{socket.removeAllListeners(),socket.destroyed||socket.destroy(),resolve16(value)};socket.once("connect",()=>done(!0)),socket.once("error",()=>done(!1)),socket.setTimeout(500,()=>done(!1))})}async function waitForChildExit(child){await new Promise(resolve16=>{if(child.exitCode!==null){resolve16();return}child.once("exit",()=>resolve16()),setTimeout(()=>resolve16(),1e3)})}function sleep3(ms){return new Promise(resolve16=>{setTimeout(resolve16,ms)})}import{spawn as spawn5}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 state={child:null,watcher:null,restartTimer:null,stopping:!1,restartPending:!1},stopChild=()=>{!state.child||state.child.killed||state.child.kill("SIGTERM")},cleanup=()=>{state.stopping=!0,state.restartTimer&&(clearTimeout(state.restartTimer),state.restartTimer=null),state.watcher?.close(),state.watcher=null,stopChild()},handleSignal=signal=>{cleanup(),process4.kill(process4.pid,signal)};process4.once("SIGINT",handleSignal),process4.once("SIGTERM",handleSignal);let startChild=()=>{state.child=spawn5(options.command,{cwd:options.cwd,env:options.env,stdio:"inherit",shell:!0}),state.child.on("exit",(code2,signal)=>{let exitedChild=state.child;if(state.child=null,state.stopping){state.resolveRun?.();return}if(state.restartPending){state.restartPending=!1,startChild();return}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}exitedChild&&state.resolveRun?.()}),state.child.on("error",error=>{state.rejectRun?.(error instanceof Error?error:new Error(String(error)))})},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(()=>{if(state.restartTimer=null,!state.child){startChild();return}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...`),stopChild()},RESTART_DEBOUNCE_MS))};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 new Promise((resolve16,reject)=>{state.resolveRun=resolve16,state.rejectRun=reject})}finally{cleanup(),process4.removeListener("SIGINT",handleSignal),process4.removeListener("SIGTERM",handleSignal)}}import{chmodSync as chmodSync2,existsSync as existsSync23,mkdirSync as mkdirSync11,readFileSync as readFileSync24,rmSync as rmSync5,writeFileSync as writeFileSync12}from"node:fs";import{dirname as dirname13,resolve as resolve14}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","LOGTO_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)}
|
|
2551
|
-
`,"utf8"),chmodSync2(filePath,384)}})}function clearStoredEnvironmentProfile(){let envProfilePath=getEnvironmentProfilePath();existsSync23(envProfilePath)&&rmSync5(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(),
|
|
2550
|
+
`)}import{spawn as spawn4}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=spawn4("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((resolve16,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}resolve16(port)})})})}async function listenLocalServer(server,port){await new Promise((resolve16,reject)=>{server.once("error",reject),server.listen(port,"127.0.0.1",()=>{server.off("error",reject),resolve16()})})}async function closeServer(server){await new Promise(resolve16=>{server.close(()=>resolve16())})}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(resolve16=>{let socket=net.createConnection({host,port}),done=value=>{socket.removeAllListeners(),socket.destroyed||socket.destroy(),resolve16(value)};socket.once("connect",()=>done(!0)),socket.once("error",()=>done(!1)),socket.setTimeout(500,()=>done(!1))})}async function waitForChildExit(child){await new Promise(resolve16=>{if(child.exitCode!==null){resolve16();return}child.once("exit",()=>resolve16()),setTimeout(()=>resolve16(),1e3)})}function sleep3(ms){return new Promise(resolve16=>{setTimeout(resolve16,ms)})}import{spawn as spawn5}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 state={child:null,watcher:null,restartTimer:null,stopping:!1,restartPending:!1},stopChild=()=>{!state.child||state.child.killed||state.child.kill("SIGTERM")},cleanup=()=>{state.stopping=!0,state.restartTimer&&(clearTimeout(state.restartTimer),state.restartTimer=null),state.watcher?.close(),state.watcher=null,stopChild()},handleSignal=signal=>{cleanup(),process4.kill(process4.pid,signal)};process4.once("SIGINT",handleSignal),process4.once("SIGTERM",handleSignal);let startChild=()=>{state.child=spawn5(options.command,{cwd:options.cwd,env:options.env,stdio:"inherit",shell:!0}),state.child.on("exit",(code2,signal)=>{let exitedChild=state.child;if(state.child=null,state.stopping){state.resolveRun?.();return}if(state.restartPending){state.restartPending=!1,startChild();return}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}exitedChild&&state.resolveRun?.()}),state.child.on("error",error=>{state.rejectRun?.(error instanceof Error?error:new Error(String(error)))})},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(()=>{if(state.restartTimer=null,!state.child){startChild();return}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...`),stopChild()},RESTART_DEBOUNCE_MS))};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 new Promise((resolve16,reject)=>{state.resolveRun=resolve16,state.rejectRun=reject})}finally{cleanup(),process4.removeListener("SIGINT",handleSignal),process4.removeListener("SIGTERM",handleSignal)}}import{chmodSync as chmodSync2,existsSync as existsSync23,mkdirSync as mkdirSync11,readFileSync as readFileSync24,rmSync as rmSync5,writeFileSync as writeFileSync12}from"node:fs";import{dirname as dirname13,resolve as resolve14}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)}
|
|
2551
|
+
`,"utf8"),chmodSync2(filePath,384)}})}function clearStoredEnvironmentProfile(){let envProfilePath=getEnvironmentProfilePath();existsSync23(envProfilePath)&&rmSync5(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=resolve14(invocationWorkspaceRoot,"deploy","registry","environment-profiles.yaml");if(existsSync23(invocationCandidate))return invocationCandidate;let cliModuleRoot=resolve14(dirname13(fileURLToPath5(import.meta.url)),".."),cliWorkspaceRoot=findWorkspaceRoot(cliModuleRoot);return resolve14(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)}
|
|
2552
2552
|
`);else for(let entry of result.entries)seen.has(entry.id)||(seen.add(entry.id),process.stdout.write(`${formatEntry(entry)}
|
|
2553
2553
|
`));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)}
|
|
2554
2554
|
`);return}if(result.entries.length===0){process.stdout.write(`\u672A\u67E5\u8BE2\u5230\u65E5\u5FD7\u3002
|
|
@@ -2636,14 +2636,14 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2636
2636
|
`),process.exitCode=1;return}await spawnControlApiWorker([worker,...serializeOptions(args.options)])}function printWorkerHelp(){process.stdout.write(["platform worker","","\u7528\u6CD5\uFF1A"," platform worker preview-retention [--once] [--dry-run] [--tenant <tenant-id>] [--app <app-id>] [--ttl-hours <n>] [--limit <n>] [--json]","","\u8BF4\u660E\uFF1A"," worker \u547D\u4EE4\u662F\u672C\u5730\u5F00\u53D1/\u8FD0\u7EF4\u5165\u53E3\uFF0C\u4F1A\u8F6C\u4EA4\u7ED9 @platform/control-api \u7684 worker \u5B9E\u73B0\u3002"," preview-retention \u9ED8\u8BA4\u4EE5\u524D\u53F0\u5E38\u9A7B worker \u8FD0\u884C\uFF1B\u52A0 --once \u65F6\u53EA\u6267\u884C\u4E00\u6B21\u3002",""].join(`
|
|
2637
2637
|
`))}function serializeOptions(options){let result=[];for(let[key,value]of Object.entries(options))key==="help"||key==="h"||(result.push(`--${key}`),typeof value=="string"&&result.push(value));return result}async function spawnControlApiWorker(args){await new Promise((resolve16,reject)=>{let child=spawn7("corepack",["pnpm","--silent","--filter","@platform/control-api","worker",...args],{stdio:"inherit"});child.on("error",reject),child.on("exit",(code2,signal)=>{if(signal){reject(new Error(`control-api worker exited by signal ${signal}`));return}code2&&code2!==0&&(process.exitCode=code2),resolve16()})})}applyStoredEnvironmentProfile();applyDistributionProfileDefaults();loadDotenvFiles();var distributionProfile=getDistributionProfile(),cliPackageVersion=getCliPackageVersion();function persistActiveTenantSelection(tenant){let currentContext=loadStoredCliContext();persistCliContext({active_tenant_id:tenant.tenant_id,active_tenant_name:tenant.name,selected_app_tenant_id:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_tenant_id,selected_app_id:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_id,selected_app_env:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_env,selected_app_name:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_name,selected_app_display_name:contextBelongsToDifferentTenant(currentContext,tenant.tenant_id)?void 0:currentContext?.selected_app_display_name})}function currentInvocationDir(){return getInvocationCwd()}function parseArgs5(argv){let[command="help",...rest]=argv,options={},positionals=[];for(let index=0;index<rest.length;index+=1){let current=rest[index];if(current==="--help"){options.help=!0;continue}if(current==="-h"){options.h=!0;continue}if(!current.startsWith("--")){positionals.push(current);continue}let[key,inlineValue]=current.slice(2).split("=",2);if(inlineValue!==void 0){options[key]=inlineValue;continue}let next=rest[index+1];if(next&&!next.startsWith("--")){options[key]=next,index+=1;continue}options[key]=!0}return{command,rest:positionals,options}}function printHelp(){let envCommandLines=distributionProfile.name!=="developer"?[]:[" env use <profile> \u5207\u6362 CLI \u73AF\u5883 profile\uFF08\u5982 local / test\uFF09"," env current \u67E5\u770B\u5F53\u524D CLI \u73AF\u5883 profile"," env list \u67E5\u770B\u53EF\u7528 CLI \u73AF\u5883 profile"];process7.stdout.write(["platform <command>","","Commands:"," login \u5168\u5C40\u767B\u5F55\u5E76\u4FDD\u5B58\u51ED\u636E"," version \u8F93\u51FA\u5F53\u524D CLI \u7248\u672C\u53F7"," app create \u5728\u4E91\u7AEF\u521B\u5EFA\u5E94\u7528\uFF0C\u5E76 checkout \u5230\u672C\u5730\u65B0\u76EE\u5F55"," app checkout \u4ECE\u4E91\u7AEF checkout \u5E94\u7528\u6E90\u7801\u526F\u672C\u5230\u672C\u5730\u65B0\u76EE\u5F55"," app submit \u5C06\u5F53\u524D\u672C\u5730\u6E90\u7801\u63D0\u4EA4\u4E3A\u65B0\u7684\u4E91\u7AEF\u6E90\u7801\u7248\u672C"," app version create \u5728\u5F53\u524D app \u4E0B\u57FA\u4E8E\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u65B0\u7684\u6E90\u7801\u7248\u672C\u9AA8\u67B6"," app version list \u67E5\u770B\u5E94\u7528\u7684\u6E90\u7801\u7248\u672C\u5217\u8868"," app versions \u67E5\u770B\u5E94\u7528\u7684\u6E90\u7801\u7248\u672C\u5217\u8868"," app status \u67E5\u770B\u5E94\u7528\u63A7\u5236\u9762\u603B\u89C8\uFF08\u542B Auth / DB / \u7248\u672C\u6982\u51B5\uFF09"," app diagnose \u67E5\u770B\u5E94\u7528\u662F\u5426\u5DF2 ready for runtime validation"," app preflight \u4E00\u6B21\u6027\u6267\u884C whoami / app current / app diagnose \u98CE\u683C\u68C0\u67E5"," app sync-platform-blocks \u540C\u6B65\u53CC\u6A21\u677F\u5E73\u53F0\u7EF4\u62A4\u533A\uFF08dry-run / adopt / apply / rollback --last\uFF09"," app import preprocess \u9884\u5904\u7406\u7B2C\u4E09\u65B9\u8BBE\u8BA1\u6E90\u7801\u5305\uFF0C\u751F\u6210 clean-source \u4E0E\u62A5\u544A"," app import stage \u628A clean-source \u4E0E\u62A5\u544A stage \u5230\u6A21\u677F\u5DE5\u4F5C\u533A"," app import merge \u628A\u4E0A\u6E38 src \u5B89\u5168\u5E76\u5165 src/imported-upstream/"," app scaffold \u6309\u9700\u6CE8\u5165\u672C\u5730 debug scaffold\uFF08auth/workflow/cms/db\uFF09"," app-library \u7BA1\u7406\u8F7B\u5E94\u7528\u8D44\u6E90\u5E93 example-app \u6761\u76EE"," app use \u517C\u5BB9\u8DEF\u5F84\uFF1A\u4E3A init/link/dev \u9009\u62E9\u76EE\u6807\u5E94\u7528"," app current \u67E5\u770B\u5F53\u524D\u5DF2\u9009\u5E94\u7528\u4E0A\u4E0B\u6587"," tenant use <id> \u8BBE\u7F6E\u9ED8\u8BA4\u79DF\u6237\u4E0A\u4E0B\u6587"," tenant current \u67E5\u770B\u5F53\u524D\u9ED8\u8BA4\u79DF\u6237\u4E0A\u4E0B\u6587",...envCommandLines," whoami \u8C03\u7528 Control API \u8F93\u51FA\u5F53\u524D\u4E3B\u4F53"," preview \u9ED8\u8BA4\u6253\u5F00\u5F53\u524D\u53EF\u7528 Preview\uFF1B\u751F\u6210\u8BF7\u7528 `platform preview generate`"," init [name] \u751F\u6210\u9879\u76EE\u9AA8\u67B6\uFF0C\u5E76\u81EA\u52A8\u5199\u5165\u5DF2\u9009\u5E94\u7528\u7ED1\u5B9A"," link \u7ED1\u5B9A tenant/app/env \u5230\u5F53\u524D\u5E94\u7528\u76EE\u5F55"," dev \u9ED8\u8BA4\u8F7B\u91CF\u5F00\u53D1\u5165\u53E3\uFF1A\u6CE8\u5165\u7ED1\u5B9A\u540E\u542F\u52A8\u672C\u5730\u5F00\u53D1\u6001"," dev push \u5C06\u5F53\u524D\u672C\u5730\u6E90\u7801\u8986\u76D6\u63A8\u9001\u5230\u4E91\u7AEF Dev Workspace"," dev preview generate \u57FA\u4E8E\u4E91\u7AEF Dev Workspace \u751F\u6210\u5DE5\u4F5C\u533A Preview"," auth \u7BA1\u7406 Auth \u57FA\u5EA7\u80FD\u529B\uFF08discover / configure / bind / inspect\uFF09"," cms \u7BA1\u7406 CMS \u57FA\u5EA7\u80FD\u529B\uFF08discover / configure / apply / inspect\uFF09"," asset \u7BA1\u7406\u79DF\u6237\u5171\u4EAB\u7D20\u6750\uFF08upload / list / folder / get / update / analyze / move / open / tag\uFF09"," blob \u7BA1\u7406 Object Storage Blob\uFF08upload / list / get / url\uFF09"," db \u67E5\u770B DB \u72B6\u6001\u3001\u8868\u7ED3\u6784\u4E0E\u53EA\u8BFB\u67E5\u8BE2"," data-form \u6821\u9A8C/\u7F16\u8BD1/apply/query Data Form schema \u4E0E\u8BB0\u5F55"," workflow \u7BA1\u7406 Workflow \u57FA\u5EA7\u80FD\u529B\uFF08template / definition / binding / runtime\uFF09"," notification \u7BA1\u7406 Notification \u57FA\u5EA7\u80FD\u529B\uFF08inbox / announce / delivery\uFF09"," publish \u7BA1\u7406\u5E94\u7528\u6B63\u5F0F\u53D1\u5E03\u72B6\u6001\u4E0E\u5F53\u524D\u90E8\u7F72\u7248\u672C"," resources \u6267\u884C\u8D44\u6E90 diff/apply/rollback"," logs \u67E5\u8BE2\u8FD0\u884C\u65F6\u65E5\u5FD7\uFF0C\u652F\u6301 --follow"," diagnostics \u5E73\u53F0\u672C\u5730\u8BCA\u65AD\uFF08control-api endpoint / readiness\uFF09"," worker \u542F\u52A8\u5E73\u53F0\u540E\u53F0 worker\uFF08preview-retention\uFF09","","Advanced commands:"," build \u9AD8\u7EA7\u8BCA\u65AD\u5165\u53E3\uFF1A\u53D1\u8D77\u548C\u67E5\u8BE2 build"," deploy \u8FC7\u6E21\u5165\u53E3\uFF1A\u9AD8\u7EA7\u53D1\u5E03\uFF08artifact / promote\uFF09"," rollback \u8FC7\u6E21\u5165\u53E3\uFF1A\u56DE\u6EDA\u5230\u76EE\u6807 release \u6216\u7248\u672C","","App commands:"," platform app create --tenant <tenant-id> --name <display-name> --dir <project-name> [--template frontend-app-vite|backend-app-node]"," platform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>"," platform app checkout --tenant <tenant-id> --app <app-id> --source-version <srcver>",' platform app submit --message "local iteration"',' platform app version create --message "switch template" --template backend-app-node'," platform app versions --tenant <tenant-id> --app <app-id>"," platform app status [--tenant <tenant-id>] [--app <app-id>] [--env preview|prod]"," platform app sync-platform-blocks [--dry-run|--adopt|--apply|--rollback --last]"," platform app diagnose [--tenant <tenant-id>] [--app <app-id>] [--env preview|prod]"," platform app import preprocess [--dir <third-party-source-dir>] [--dry-run]"," platform app import stage --preprocess <source-dir|.design-preprocess|reports|import-manifest.json>"," platform app import merge [--workspace-dir <template-workspace-dir>]"," platform app scaffold <auth-debug|workflow-debug|cms-debug|db-debug>"," platform app-library list"," platform app-library config init"," platform app-library inspect entry-demo"," platform app-library checkout entry-demo --dir ./example-app-demo",' platform app-library create --name "Data Form Verify" --summary "\u672C\u5730\u9A8C\u8BC1\u540E\u7684\u793A\u4F8B\u5E94\u7528"'," platform app-library submit entry-demo"," platform app use --tenant <tenant-id> --app <app-id> --env preview"," platform app current","","DB commands:"," platform db status"," platform db history --limit 10"," platform db migrate [--dry-run]"," platform db tables",' platform db query --sql "SELECT ... LIMIT 5"'," platform db open","","Auth commands:"," platform auth discover [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth configure [--tenant <tenant-id>] [--app <app-id>] --enable [--template <template>] [--user-store-id <id>] [--enable-admin-password|--disable-admin-password] [--enable-phone-sms-otp|--disable-phone-sms-otp] [--json]"," platform auth bind [--tenant <tenant-id>] [--app <app-id>] [--action bind|rebind|disable] [--user-store-id <id>] [--json]"," platform auth inspect [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth role list [--tenant <tenant-id>] [--app <app-id>] [--json]"," platform auth role create [--tenant <tenant-id>] [--app <app-id>] --key <role-key> --name <display-name> [--description <text>] [--status active|disabled] [--json]"," platform auth role inspect [--tenant <tenant-id>] [--app <app-id>] --role <role-key> [--json]"," platform auth role update [--tenant <tenant-id>] [--app <app-id>] --role <role-key> [--name <display-name>] [--description <text> | --clear-description] [--status active|disabled] [--json]"," platform auth user-role list [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> [--json]"," platform auth user-role assign [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --roles role-a,role-b [--json]"," platform auth user-role replace [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --roles role-a,role-b [--json]"," platform auth user-role remove [--tenant <tenant-id>] [--app <app-id>] --user <app-user-id> --role <role-key> [--json]","","CMS commands:"," platform cms discover [--collection <name>] [--json]"," platform cms configure collection --file <spec.json> [--json]"," platform cms configure item --file <item.json> [--item-id <item-id>] [--json]"," platform cms configure category --collection <name> --name <name> --slug <slug> [--parent-id <id>] [--order <n>] [--json]"," platform cms import markdown <file> [--collection <name>] [--item-id <item-id> | --item-id-prefix <prefix>] [--tags <label,label>] [--category-path <segment/segment>] [--cover-asset-id <asset-id>] [--publish | --publish-status draft|published|archived] [--skip-existing] [--dry-run] [--json]"," platform cms import url <url> [--collection <name>] [--item-id <item-id>] [--tags <label,label>] [--category-path <segment/segment>] [--publish | --publish-status draft|published|archived] [--skip-existing] [--no-assetize-images] [--dry-run] [--json]"," platform cms attach asset --collection <name> --item-id <id> --field <field-name> --asset-id <id[,id]> [--replace] [--json]"," platform cms ensure category --collection <name> --path <segment/segment> [--json]"," platform cms list items --collection <name> [--page <n>] [--page-size <n>] [--status draft|published|archived] [--category-id <id>] [--q <keyword>] [--json]"," platform cms batch update --collection <name> --item-id <id[,id]> [--category-id <id> | --clear-category] [--add-tags <label,label>] [--status draft|published|archived] [--json]"," platform cms apply schema --collection <name> --version <n> [--json]"," platform cms apply publish --collection <name> --item-id <id> --status draft|published|archived [--json]"," platform cms inspect schema --collection <name> [--json]"," platform cms inspect item --collection <name> --id <id> [--json]"," platform cms inspect delivery list --collection <name> [--page <n>] [--page-size <n>] [--tag <tag>] [--category-id <id>] [--json]"," platform cms inspect delivery get --collection <name> (--slug <slug> | --id <id>) [--json]"," platform cms inspect delivery categories --collection <name> [--json]","","Asset commands:"," platform asset upload <file-path> [--title <title>] [--folder-id <folder-id>]"," platform asset list [--q <keyword>] [--media-type image|video] [--folder-id <folder-id>] [--page <n>] [--limit <n>]"," platform asset folder list"," platform asset folder create <name> [--parent-folder-id <folder-id>]"," platform asset folder rename <folder-id> --name <name> [--parent-folder-id <folder-id> | --root]"," platform asset get <asset-id>"," platform asset move <asset-id> [--folder-id <folder-id> | --root]"," platform asset update <asset-id> [--title <title>] [--folder-id <folder-id> | --root] [--tags <label,label>]"," platform asset analyze <asset-id> [--json]"," platform asset open <asset-id> [--output <path>]"," platform asset download <asset-id> --variant thumbnail|sm|md|lg|cover [--output <path>]"," platform asset tag list [--asset <asset-id>]"," platform asset tag add <asset-id> <label>"," platform asset tag remove <asset-id> <label>","","Preview commands:"," platform preview"," platform preview open [--source-version <srcver>]"," platform preview generate [--source-version <srcver>]"," platform preview generate --from-build <build-id>","","Publish commands:"," platform publish"," platform publish status"," platform publish set [--source-version <srcver>] [--status published|unpublished]"," platform publish rollback <srcver>","","Workflow commands:"," platform workflow template list"," platform workflow template inspect --template <key>"," platform workflow definition list [--status draft|active|inactive]"," platform workflow definition inspect --definition <key>"," platform workflow definition create --definition <key> --app <app-id> [--template <template-key> | --object-type <type> --schema <json>]"," platform workflow binding list [--app <app-id>] [--definition <key>]"," platform workflow binding inspect --definition <key> [--target-id <id>]"," platform workflow binding update --definition <key> [--target-id <id>] --file <override.json>"," platform workflow role bind --definition <key> --app <app-id> --file <bindings.json> # \u4F4E\u5C42\u9AD8\u7EA7\u5165\u53E3"," platform workflow diagnose [--app <app-id>]"," platform workflow start --definition <key> --object-type <type> --object-id <id>"," platform workflow action --instance <instance-id> --action <action-key>"," platform workflow tasks [--status pending]"," platform workflow instance <instance-id>","","Notification commands:"," platform notification inbox list [--app <app-id>] [--type task_projection|announcement|notification|alert] [--status unread|read|dismissed|archived] [--limit <n>]"," platform notification inbox update <item-id> --status unread|read|dismissed|archived"," platform notification announce platform --tenant <tenant-id> --title <text> [--body <text>] [--level info|success|warning|error]"," platform notification announce app --tenant <tenant-id> --app <app-id> --title <text> [--body <text>] [--level info|success|warning|error]"," platform notification delivery [--app <app-id>] [--status pending|running|succeeded|failed|dead]"," platform notification end-user users --app <app-id>"," platform notification end-user inbox --app <app-id> --end-user <app-user-id> [--type task_projection|announcement|notification|alert] [--status unread|read|dismissed|archived] [--limit <n>]"," platform notification end-user unread --app <app-id> --end-user <app-user-id>"," platform notification end-user publish --app <app-id> --end-user <app-user-id> --title <text> [--body <text>] [--kind notification|alert|announcement]"," platform notification end-user announcement --app <app-id> --end-user <app-user-id> --title <text> --body <text>"," platform notification end-user reminder --app <app-id> --end-user <app-user-id> --title <text> --remind-at <ISO datetime> [--body <text>]","","Advanced release commands:"," platform deploy [--source-version <srcver>] [--prod]"," platform rollback <release-id|version>","","Advanced build commands:"," platform build run --source-version <srcver>"," platform build get <build-id>"," platform build events <build-id>"," platform build validate --app <app-id> --source-version <srcver>"," platform logs --follow"," platform diagnostics control-api [--json]"," platform worker preview-retention [--once] [--dry-run] [--json]","","Resource commands:"," platform resources diff --base-snapshot <rsnap-id>"," platform resources apply --base-snapshot <rsnap-id>"," platform resources rollback <rsnap-id> --approve-id <approve-id>","","Examples:"," platform login"," platform login --pat <personal-access-token>"," platform env use local"," platform env use test"," platform env current",' platform app create --tenant t-default --name "\u6D3B\u52A8\u9080\u8BF7\u51FD" --dir invite-frontend',' platform app create --tenant t-default --name "\u62A5\u540D\u52A9\u624B" --dir signup-runtime --template backend-app-node',' platform app create --tenant t-default --name "\u8425\u9500\u9875" --dir landing-page --template frontend-app-vite',' platform app create --tenant t-default --name "\u4E1A\u52A1\u540E\u53F0" --dir ops-console --template backend-app-node'," platform app checkout --tenant t-default --app app-demo --dir app-demo"," platform app checkout --tenant t-default --app app-demo --source-version srcver-123",' platform app submit --message "local iteration"'," platform dev push"," platform dev preview generate"," platform dev preview open",' platform asset upload ./logo.png --title "\u54C1\u724C Logo"'," platform asset folder create \u54C1\u724C\u7D20\u6750"," platform asset folder rename asset-folder-123 --name \u54C1\u724C\u89C6\u89C9 --root"," platform asset folder list"," platform asset list --q logo --tag-ids tag-1,tag-2 --page 2"," platform asset get asset-123"," platform asset move asset-123 --folder-id asset-folder-123",' platform asset update asset-123 --title "\u9996\u9875 Hero \u56FE" --scene outdoor --tags hero,homepage'," platform asset analyze asset-123"," platform asset open asset-123"," platform asset download asset-123 --variant md"," platform asset tag list --asset asset-123"," platform asset tag add asset-123 logo"," platform asset tag remove asset-123 logo"," platform app versions --tenant t-default --app app-demo"," platform whoami --tenant t-default"," platform build get build-123"," platform build events build-123"," platform build run --source-version srcver-123"," platform build validate --app app-demo --source-version srcver-123"," platform preview"," platform preview open --source-version srcver-123"," platform preview generate"," platform preview generate --source-version srcver-123"," platform publish"," platform publish status"," platform publish set --status unpublished"," platform publish set --source-version srcver-123 --status published"," platform publish rollback srcver-122"," cd signup-lite && platform dev"," cd signup-lite && platform dev push"," cd signup-lite && platform dev preview generate"," cd signup-lite && platform dev preview open"," platform deploy --source-version srcver-123"," platform deploy --prod"," platform rollback v0.2.0","","Other examples:"," platform app current"," platform tenant use t-default"," platform tenant current"," platform db status"," platform db history --limit 10"," platform db tables",' platform db query --sql "SELECT * FROM example_items LIMIT 5"'," platform auth discover --app app-demo"," platform auth configure --app app-demo --enable --template email_magic_link_only"," platform auth configure --app app-demo --enable --template phone_sms_otp_only"," platform auth configure --app app-demo --enable --template email_magic_link_and_phone_sms_otp"," platform auth configure --app app-demo --enable --enable-phone-sms-otp"," platform auth bind --app app-checkin --action bind --user-store-id us_xxx"," platform auth inspect --app app-demo --json"," platform cms discover"," platform cms discover --collection article"," platform cms configure collection --file ./cms/article.collection.json"," platform cms configure item --file ./cms/article.item.json"," platform cms import markdown ./docs/post.md --collection article --tags cms,agent --category-path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03 --cover-asset-id asset-123 --publish"," platform cms import url https://zhuanlan.zhihu.com/p/488185988 --collection article --tags cms,url --dry-run"," platform cms import url https://example.com/post --collection article --no-assetize-images"," platform cms import markdown ./docs/articles --collection article --recursive --item-id-prefix article-doc --skip-existing"," platform cms import markdown ./docs/post.md --collection article --category-path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03 --dry-run --json"," platform cms import markdown ./docs/post.md --collection article --skip-existing --publish"," platform cms attach asset --collection article --item-id cms-item-123 --field cover --asset-id asset-123"," platform cms ensure category --collection article --path \u4EA7\u54C1\u66F4\u65B0/\u7248\u672C\u53D1\u5E03"," platform cms list items --collection article --status draft"," platform cms batch update --collection article --item-id item-a,item-b --category-id cms-category-123 --add-tags cms,cli --status published"," platform cms apply schema --collection article --version 1"," platform cms inspect schema --collection article --json"," platform cms inspect item --collection article --id cms-item-123"," platform cms inspect delivery list --collection article --tag cms"," platform cms inspect delivery get --collection article --slug introducing-cms-base"," platform resources diff --base-snapshot rsnap-123"," platform resources apply --base-snapshot rsnap-123"," platform resources rollback rsnap-122 --approve-id approve-123"," platform logs --follow","","Compatible path examples:"," platform app use --tenant t-default --app app-demo --env preview"," platform init demo-app"," platform link --tenant t-default --app app-demo --env preview"," platform dev --target tenant-workbench"," platform dev --remote-bindings"," platform dev --remote-bindings=db",""].join(`
|
|
2638
2638
|
`))}function printVersion(){process7.stdout.write(`v${cliPackageVersion}
|
|
2639
|
-
`)}function normalizeAppTemplateOption(value){return normalizeAppTemplateKey(value)}function readRequiredEnv(key){let value=process7.env[key];if(!value||value.trim().length===0)throw new Error(`\u7F3A\u5C11\u73AF\u5883\u53D8\u91CF: ${key}`);return value.trim()}function
|
|
2639
|
+
`)}function normalizeAppTemplateOption(value){return normalizeAppTemplateKey(value)}function readRequiredEnv(key){let value=process7.env[key];if(!value||value.trim().length===0)throw new Error(`\u7F3A\u5C11\u73AF\u5883\u53D8\u91CF: ${key}`);return value.trim()}function resolveBrowserLoginConfig(){let cliClientId=readAuthConfigValue(AUTH_CLI_CLIENT_ID_KEYS),cliRedirectUri=readAuthConfigValue(AUTH_CLI_REDIRECT_URI_KEYS);if(cliClientId&&cliRedirectUri)return{clientId:cliClientId,redirectUri:cliRedirectUri,source:"cli-app"};let fallbackClientId=readAuthConfigValue(AUTH_TENANT_CLIENT_ID_KEYS),fallbackRedirectUri=readAuthConfigValue(AUTH_TENANT_REDIRECT_URI_KEYS);return!fallbackClientId||!fallbackRedirectUri?null:{clientId:fallbackClientId,redirectUri:fallbackRedirectUri,source:"workbench-fallback"}}function shouldFallbackToBrowserLogin(error){if(!(error instanceof Error))return!1;let message=error.message;return message.includes("OIDC discovery \u7F3A\u5C11 Device Flow \u7AEF\u70B9")||message.includes("device_code is not allowed for this client")||message.includes("grant-type:device_code is not allowed for this client")}function tryOpenBrowser2(url){let normalizedUrl=url.trim();if(!normalizedUrl)return!1;try{return process7.platform==="darwin"?(spawn8("open",[normalizedUrl],{stdio:"ignore",detached:!0}).unref(),!0):process7.platform==="win32"?(spawn8("cmd",["/c","start","",normalizedUrl],{stdio:"ignore",detached:!0}).unref(),!0):(spawn8("xdg-open",[normalizedUrl],{stdio:"ignore",detached:!0}).unref(),!0)}catch{return!1}}function readOption2(args,key){let value=args.options[key];return typeof value=="string"?value:void 0}function hasFlag2(args,key){return args.options[key]===!0}function printDiagnosticsHelp(){process7.stdout.write(["platform diagnostics","","\u7528\u6CD5\uFF1A"," platform diagnostics control-api [--json]","","\u8BF4\u660E\uFF1A"," \u8F93\u51FA control/runtime/public endpoint \u5206\u533A\u8BCA\u65AD\uFF0C\u4E0D\u6539\u53D8\u9ED8\u8BA4 URL\u3002"," runtime/public endpoint \u4EC5\u5728\u914D\u7F6E\u5B58\u5728\u4E14 capability allowlist \u547D\u4E2D\u65F6\u63A2\u6D4B\u3002","","\u73AF\u5883\u53D8\u91CF\uFF1A"," CONTROL_API_BASE_URL"," RUNTIME_API_BASE_URL"," PUBLIC_API_BASE_URL"," CONTROL_API_RUNTIME_ENDPOINT_CAPABILITIES",""].join(`
|
|
2640
2640
|
`))}async function runDiagnostics(args){let subcommand=args.rest[0]??"help";if(hasFlag2(args,"help")||hasFlag2(args,"h")||subcommand==="help"){printDiagnosticsHelp();return}if(subcommand!=="control-api")throw printDiagnosticsHelp(),new Error(`\u672A\u77E5 diagnostics \u5B50\u547D\u4EE4: ${subcommand}`);let diagnostics=await collectControlApiFailureDiagnostics();if(args.options.json===!0){process7.stdout.write(`${JSON.stringify(diagnostics,null,2)}
|
|
2641
2641
|
`);return}process7.stdout.write(formatControlApiDiagnosticsText(diagnostics))}function readIntegerOption(args,key){let raw=readOption2(args,key);if(raw===void 0)return;let value=Number(raw);if(!Number.isInteger(value))throw new Error(`\u65E0\u6548\u7684 \`--${key}\`\uFF0C\u5FC5\u987B\u662F\u6574\u6570\u3002`);return value}function readCsvOption3(args,key){let raw=readOption2(args,key);return raw?raw.split(",").map(item=>item.trim()).filter(Boolean):[]}function readJsonInput(args,key="file"){let filePath=readOption2(args,key);if(!filePath)throw new Error(`\u7F3A\u5C11 \`--${key} <path>\`\u3002`);let content=filePath==="-"?readFileSync26(0,"utf8"):readFileSync26(filePath,"utf8");try{return JSON.parse(content)}catch(error){throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON \u8F93\u5165: ${filePath==="-"?"stdin":filePath}\u3002${error instanceof Error?` ${error.message}`:""}`)}}async function findExistingTenantCmsItemForImport(args){let lookup=args.lookup;if(!lookup)return null;if(lookup.kind==="item_id")try{return{item:await args.sdk.getTenantCmsItem({collection:args.collection,id:lookup.value}),matchedBy:"item_id"}}catch(error){if(error instanceof PlatformApiError&&error.status===404)return null;throw error}let matched=(await args.sdk.listTenantCmsItems({collection:args.collection,page:1,pageSize:20,query:lookup.value})).items.find(item=>item.system.slug===lookup.value);return matched?{item:matched,matchedBy:"slug"}:null}function resolveTenantContext(args){let linked;try{linked=readBinding(currentInvocationDir())}catch{linked=null}let storedContext=loadStoredCliContext();return readOption2(args,"tenant")??linked?.binding.tenant_id??storedContext?.selected_app_tenant_id??storedContext?.active_tenant_id}function tryReadCurrentBinding2(){try{return readBinding(currentInvocationDir())}catch{return null}}function syncSelectedAppContextFromBinding(binding){let existing=loadStoredCliContext();persistCliContext({active_tenant_id:binding.tenant_id,active_tenant_name:existing?.active_tenant_id===binding.tenant_id?existing.active_tenant_name:void 0,selected_app_tenant_id:binding.tenant_id,selected_app_id:binding.app_id,selected_app_env:binding.env,selected_app_name:binding.app_name??binding.app_id,selected_app_display_name:binding.app_display_name})}function tryReadCurrentSourceContext(){try{return readSourceContext(currentInvocationDir())}catch{return null}}function readStoredCredentialModeSafely(){try{return loadStoredCredentials()?.credential_mode}catch{return}}function readCredentialPathSafely(){try{return getCredentialPath()}catch{return}}function formatRuntimeTargetLabel(env){return env==="preview"?"\u4E91\u7AEF Preview":"\u4E91\u7AEF Prod"}function summarizePreflightAppContext(args){let binding=tryReadCurrentBinding2()?.binding??null,sourceContextResult=tryReadCurrentSourceContext(),sourceContext=sourceContextResult?.sourceContext??null,context=loadStoredCliContext(),tenantId=readOption2(args,"tenant")??sourceContext?.tenant_id??binding?.tenant_id??context?.selected_app_tenant_id??context?.active_tenant_id,appId=readOption2(args,"app")??sourceContext?.app_id??binding?.app_id??context?.selected_app_id??args.rest[1],env=readOption2(args,"env")??sourceContext?.env??binding?.env??context?.selected_app_env??"preview";return sourceContext?.tenant_id&&sourceContext.app_id&&binding?.tenant_id&&binding.app_id?{status:"ready",detail:`\u5F53\u524D\u76EE\u5F55\u5DF2\u7ED1\u5B9A ${sourceContext.tenant_id}/${sourceContext.app_id}/${sourceContext.env??env}`,tenantId,appId,env,bindingPath:`${currentInvocationDir()}/.platform/config.json`,sourceContextPath:sourceContextResult?.path??null}:sourceContext?.tenant_id&&sourceContext.app_id?{status:"warning",detail:`\u5F53\u524D\u76EE\u5F55\u4EC5\u68C0\u6D4B\u5230 source-context\uFF1A${sourceContext.tenant_id}/${sourceContext.app_id}/${sourceContext.env??env}`,tenantId,appId,env,bindingPath:binding?`${currentInvocationDir()}/.platform/config.json`:null,sourceContextPath:sourceContextResult?.path??null}:binding?.tenant_id&&binding.app_id?{status:"warning",detail:`\u5F53\u524D\u76EE\u5F55\u4EC5\u68C0\u6D4B\u5230\u76EE\u5F55\u7ED1\u5B9A\uFF1A${binding.tenant_id}/${binding.app_id}/${binding.env??env}`,tenantId,appId,env,bindingPath:`${currentInvocationDir()}/.platform/config.json`,sourceContextPath:sourceContextResult?.path??null}:context?.selected_app_tenant_id&&context.selected_app_id?{status:"warning",detail:`\u5F53\u524D\u4EC5\u547D\u4E2D\u5168\u5C40 CLI \u5E94\u7528\u4E0A\u4E0B\u6587\uFF1A${context.selected_app_tenant_id}/${context.selected_app_id}/${context.selected_app_env??env}`,tenantId,appId,env,bindingPath:null,sourceContextPath:sourceContextResult?.path??null}:{status:"blocked",detail:"\u5F53\u524D\u672A\u89E3\u6790\u51FA\u53EF\u7528\u7684 tenant/app \u4E0A\u4E0B\u6587",tenantId,appId,env,bindingPath:null,sourceContextPath:sourceContextResult?.path??null}}function mergePreflightRecommendations(items){let seen=new Set,merged=[];for(let item of items){let normalized=item.trim();!normalized||seen.has(normalized)||(seen.add(normalized),merged.push(normalized))}return merged}function summarizeCheckStatuses(checks){return checks.some(item=>item.status==="blocked")?"blocked":checks.some(item=>item.status!=="ready")?"warning":"ready"}function resolveAppIdFromContext(args,positionalIndex=1){let binding=tryReadCurrentBinding2()?.binding,context=loadStoredCliContext();return readOption2(args,"app")??binding?.app_id??context?.selected_app_id??args.rest[positionalIndex]}async function collectAppControlPlaneSnapshot(args){let[overview,sourceVersions,publishSettings,authConfig,authInspect,appUsers,dbInstance,deploymentTimeline,workflowDefinitions,workflowBindings]=await Promise.all([fetchTenantOverview({baseUrl:getControlApiBaseUrl(),accessToken:selectApiToken(args.credentials),tenantId:args.tenantId}),args.sdk.listTenantAppSourceVersions(args.appId).catch(()=>({items:[]})),args.sdk.getTenantAppPublishSettings(args.appId).catch(()=>null),args.sdk.getTenantAppEndUserAuthDiscovery(args.appId).catch(()=>null),args.sdk.getTenantAppEndUserAuthInspect(args.appId).catch(()=>null),args.sdk.listTenantAppEndUsers(args.appId).catch(()=>({items:[]})),args.sdk.getTenantAppDbInstance(args.appId,args.env).catch(()=>null),args.sdk.listTenantAppDeploymentTimeline(args.appId,{limit:10}).catch(()=>({items:[]})),args.sdk.listWorkflowDefinitions({target_id:args.appId,status:"active"}).catch(()=>[]),args.sdk.listWorkflowBindings({target_id:args.appId}).catch(()=>[])]),app=overview.apps.find(item=>item.id===args.appId);if(!app)throw new Error(`\u5728\u79DF\u6237 ${args.tenantId} \u4E0B\u672A\u627E\u5230\u5E94\u7528 ${args.appId}\u3002`);return{overview,app,sourceVersions,publishSettings,authConfig,authInspect,appUsers,dbInstance,deploymentTimeline,workflowDefinitions,workflowBindings}}function buildAppStatusPayload(args){let{tenantId,appId,env,snapshot}=args,authEnabled=snapshot.authConfig?.auth_enabled===!0,appUserItems=snapshot.appUsers?.items??[],blockedCount=appUserItems.filter(item=>item.status==="blocked").length,envOverview=snapshot.overview.environments.filter(item=>item.app_id===appId),previewEnv=envOverview.find(item=>item.env==="preview"),prodEnv=envOverview.find(item=>item.env==="prod"),previewDeployment=snapshot.deploymentTimeline.items.find(item=>item.env==="preview"&&item.is_current_release),prodDeployment=snapshot.deploymentTimeline.items.find(item=>item.env==="prod"&&item.is_current_release),latestSourceVersion=snapshot.sourceVersions.items[0]??null;return{tenant_id:tenantId,app_id:appId,env,app:{display_name:snapshot.app.name,slug:snapshot.app.slug??null,template_key:snapshot.app.template_key??null,publish_status:snapshot.publishSettings?.publish_status??snapshot.app.publish_status,source_versions_count:snapshot.sourceVersions.items.length,latest_source_version_id:latestSourceVersion?.source_version_id??null,latest_source_version_message:latestSourceVersion?.message??null,latest_deployment_class_suggested:latestSourceVersion?.deployment_class_suggested??null,latest_deployment_class_post_build:latestSourceVersion?.deployment_class_post_build??null},publish:{deployment_class_confirmed:snapshot.publishSettings?.deployment_class_confirmed??null,current_deployment_class_used:snapshot.publishSettings?.current_deployment_class_used??null,current_artifact_kind:snapshot.publishSettings?.current_artifact_kind??null,current_execution_mode:snapshot.publishSettings?.current_execution_mode??null,current_object_prefix:snapshot.publishSettings?.current_object_prefix??null,public_prod_url:snapshot.publishSettings?.public_prod_url??null},auth:{enabled:authEnabled,capability_name:snapshot.authConfig?.capability_name??"auth",capability_version:snapshot.authConfig?.capability_version??null,contract_version:snapshot.authConfig?.contract_version??null,user_store_id:snapshot.authConfig?.user_store_id??null,binding_id:snapshot.authConfig?.binding_id??null,binding_mode:snapshot.authConfig?.binding_mode??null,binding_status:snapshot.authConfig?.binding_status??null,auth_template:snapshot.authConfig?.auth_template??null,ui_driver:snapshot.authConfig?.ui_driver??null,enabled_recipes:snapshot.authConfig?.enabled_recipes??[],sign_in_methods:snapshot.authConfig?.sign_in_methods?.map(item=>item.method)??[],registration_mode:snapshot.authConfig?.registration_mode??null,auto_provision_app_user:typeof snapshot.authConfig?.auto_provision_app_user=="boolean"?snapshot.authConfig.auto_provision_app_user:null,owner_service:snapshot.authConfig?.owner_service??null,last_runtime_status:snapshot.authConfig?.last_runtime_status??null,inspect_status:snapshot.authInspect?.inspect_status??null,inspect_issues:snapshot.authInspect?.issues??[],runtime_environments:snapshot.authInspect?.environments.map(item=>({env:item.env,status:item.status,missing_binding_keys:item.missing_binding_keys,issues:item.issues,updated_at:item.updated_at??null}))??[],app_user_count:appUserItems.length,blocked_app_user_count:blockedCount},runtime:{preview:{version:previewEnv?.version??null,health:previewEnv?.health??previewDeployment?.health??null,source_version_id:previewEnv?.source_version_id??previewDeployment?.source_version_id??null,preview_url:previewDeployment?.preview_url??null},prod:{version:prodEnv?.version??null,health:prodEnv?.health??prodDeployment?.health??null,source_version_id:prodEnv?.source_version_id??prodDeployment?.source_version_id??null}},db:{bound:snapshot.dbInstance?.bound??!1,status:snapshot.dbInstance?.status??null,schema_name:snapshot.dbInstance?.schema_name??null,database_name:snapshot.dbInstance?.database_name??null,tables_count:typeof snapshot.dbInstance?.tables_count=="number"?snapshot.dbInstance.tables_count:null,latest_migration:snapshot.dbInstance?.latest_migration?.migration_path??null},workflow:{active_definition_count:snapshot.workflowDefinitions.length,binding_count:snapshot.workflowBindings.length,definitions:snapshot.workflowDefinitions.map(item=>({definition_key:item.definition_key,status:item.status,object_type:item.object_type})),bindings:snapshot.workflowBindings.map(item=>({definition_key:item.definition_key,target_id:item.target_id,target_scope:item.target_scope,status:item.status}))}}}function buildAppDiagnosePayload(args){let authEnv=args.statusPayload.auth.runtime_environments.find(item=>item.env===args.env)??null,dbTablesCount=args.statusPayload.db.tables_count,databaseStatus=args.statusPayload.db.bound?typeof dbTablesCount=="number"&&dbTablesCount===0?"warning":"ready":"warning",databaseDetail=args.statusPayload.db.bound?typeof dbTablesCount=="number"&&dbTablesCount===0?`${args.statusPayload.db.database_name??"-"} / ${args.statusPayload.db.schema_name??"-"} (0 tables)`:`${args.statusPayload.db.database_name??"-"} / ${args.statusPayload.db.schema_name??"-"}`:"\u5F53\u524D\u73AF\u5883\u672A\u5B8C\u6210 DB \u7ED1\u5B9A",checks={app_context:{status:args.bindingPath?"ready":"warning",detail:args.bindingPath?`\u5DF2\u7ED1\u5B9A\u9879\u76EE\u76EE\u5F55 (${args.bindingPath})`:"\u5F53\u524D\u76EE\u5F55\u672A\u68C0\u6D4B\u5230 `.platform/config.json`"},auth_runtime:{status:args.statusPayload.auth.enabled&&authEnv?.status==="ready"?"ready":args.statusPayload.auth.enabled?"warning":"not_configured",detail:args.statusPayload.auth.enabled?authEnv?`${args.env}=${authEnv.status}`:`\u7F3A\u5C11 ${args.env} \u8FD0\u884C\u65F6\u68C0\u67E5\u7ED3\u679C`:"\u5F53\u524D app \u672A\u542F\u7528 Auth\uFF1B\u5982\u679C\u5F53\u524D\u6A21\u677F\u4E0D\u4F9D\u8D56\u767B\u5F55\uFF0C\u53EF\u5FFD\u7565"},database:{status:databaseStatus,detail:databaseDetail},workflow:{status:args.statusPayload.workflow.active_definition_count>0&&args.statusPayload.workflow.binding_count>0?"ready":args.statusPayload.workflow.active_definition_count>0?"warning":"not_configured",detail:args.statusPayload.workflow.active_definition_count>0?`definitions=${args.statusPayload.workflow.active_definition_count}, bindings=${args.statusPayload.workflow.binding_count}`:"\u5F53\u524D app \u672A\u914D\u7F6E Workflow\uFF1B\u5982\u679C\u5F53\u524D\u6A21\u677F\u4E0D\u4F9D\u8D56\u5BA1\u6279\u6D41\uFF0C\u53EF\u5FFD\u7565"},preview_runtime:{status:args.env==="preview"?args.statusPayload.runtime.preview.preview_url?"ready":"warning":args.statusPayload.runtime.prod.source_version_id?"ready":"warning",detail:args.env==="preview"?args.statusPayload.runtime.preview.preview_url??"\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u4E91\u7AEF Preview \u5730\u5740":args.statusPayload.runtime.prod.source_version_id??"\u5F53\u524D\u6CA1\u6709\u4E91\u7AEF Prod \u90E8\u7F72\u7248\u672C"},source_version:{status:args.statusPayload.app.latest_source_version_id?"ready":"warning",detail:args.statusPayload.app.latest_source_version_id??"\u5F53\u524D\u5E94\u7528\u8FD8\u6CA1\u6709\u63D0\u4EA4\u8FC7\u6E90\u7801\u7248\u672C"},source_context:{status:args.sourceContextPath?"ready":"warning",detail:args.sourceContextPath?`\u5DF2\u8BB0\u5F55\u6E90\u7801\u4E0A\u4E0B\u6587 (${args.sourceContextPath})`:"\u5F53\u524D\u76EE\u5F55\u672A\u68C0\u6D4B\u5230 `.platform/source-context.json`"}},recommendations=[];return args.bindingPath||recommendations.push("\u5148\u6267\u884C `platform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>`\uFF0C\u6216\u5728\u73B0\u6709\u76EE\u5F55\u6267\u884C `platform link --tenant <tenant-id> --app <app-id> --env preview`\u3002"),args.statusPayload.app.latest_source_version_id||recommendations.push('\u6267\u884C `platform app submit --message "initial iteration"` \u751F\u6210\u9996\u4E2A\u6E90\u7801\u7248\u672C\u3002'),args.statusPayload.auth.enabled&&authEnv?.status!=="ready"&&recommendations.push(`\u6267\u884C \`platform auth inspect\` \u786E\u8BA4 ${args.env} \u73AF\u5883\u7F3A\u5931\u7684\u8FD0\u884C\u65F6\u7ED1\u5B9A\uFF0C\u518D\u6839\u636E\u7ED3\u679C\u6267\u884C \`platform resources apply --env `+args.env+"`\u3002"),args.statusPayload.db.bound?typeof dbTablesCount=="number"&&dbTablesCount===0&&recommendations.push("\u5F53\u524D DB \u5DF2\u7ED1\u5B9A\uFF0C\u4F46 schema \u4ECD\u4E3A 0 \u8868\u3002\u82E5\u4F60\u8BA1\u5212\u63A5\u5165\u4E1A\u52A1 DB\uFF0C\u8BF7\u5148\u628A `resources/db/migrations/` \u91CC\u7684\u7A7A scaffold \u6539\u6210\u771F\u5B9E migration\uFF0C\u518D\u6267\u884C `platform db migrate`\u3001`platform db tables`\u3002"):recommendations.push("\u5982\u679C\u5F53\u524D app \u9700\u8981 DB\uFF0C\u518D\u6267\u884C `platform resources apply --env "+args.env+"`\uFF0C\u8BA9 DB \u7ED1\u5B9A\u548C\u8FC1\u79FB\u843D\u5230\u76EE\u6807\u73AF\u5883\u3002"),args.statusPayload.workflow.active_definition_count===0?recommendations.push("\u5982\u679C\u5F53\u524D app \u4F9D\u8D56\u5BA1\u6279\u6D41\uFF0C\u518D\u6267\u884C `platform workflow definition create ...` \u4E0E `platform workflow binding update ...`\u3002"):args.statusPayload.workflow.binding_count===0&&recommendations.push("Workflow definition \u5DF2\u5B58\u5728\uFF0C\u4F46\u7F3A\u5C11 app \u7EA7 binding\uFF1B\u8865\u6267\u884C `platform workflow binding update ...`\u3002"),args.env==="preview"&&!args.statusPayload.runtime.preview.preview_url&&recommendations.push("\u6267\u884C `platform preview generate` \u751F\u6210\u4E91\u7AEF Preview\uFF1B\u8FD9\u4E00\u6B65\u4E0D\u540C\u4E8E\u672C\u5730 `platform dev` \u9884\u89C8\u3002"),args.env==="prod"&&!args.statusPayload.runtime.prod.source_version_id&&recommendations.push("\u4E91\u7AEF Prod \u4E0D\u4F1A\u968F\u7740 Preview \u81EA\u52A8\u66F4\u65B0\uFF1B\u5982\u9700\u4E0A\u7EBF\u6B63\u5F0F\u73AF\u5883\uFF0C\u8BF7\u6267\u884C `platform publish set --source-version <srcver> --status published`\u3002"),recommendations.length===0&&recommendations.push(args.env==="prod"?"\u63A7\u5236\u9762\u89C6\u89D2\u4E0B\u5F53\u524D prod \u5DF2\u57FA\u672C ready\uFF1B\u540E\u7EED\u82E5\u8981\u5207\u6362\u6B63\u5F0F\u7248\u672C\uFF0C\u8BF7\u7EE7\u7EED\u4F7F\u7528 `platform publish`\u3002":"\u63A7\u5236\u9762\u89C6\u89D2\u4E0B\u5F53\u524D\u5E94\u7528\u5DF2\u57FA\u672C ready\uFF1B\u4E0B\u4E00\u6B65\u53EF\u76F4\u63A5\u505A\u9875\u9762\u8054\u8C03\u6216\u8FD0\u884C\u65F6\u9A8C\u8BC1\u3002"),{tenant_id:args.tenantId,app_id:args.appId,env:args.env,checks,recommendations}}function findDevPreviewTimelineItem(items,target){return items.find(item=>item.env==="preview"&&target.deploymentId&&item.deployment_id===target.deploymentId)??items.find(item=>item.env==="preview"&&target.releaseId&&item.release_id===target.releaseId)??items.find(item=>item.env==="preview"&&item.is_current_release)??null}function formatDevPreviewLines(args){let lines=[args.title,`tenant/app: ${args.tenantId}/${args.appId}`,`source version: ${args.sourceVersionId??"-"}`,`build: ${args.buildId??"-"}`,`release: ${args.releaseId??"-"}`,`deployment: ${args.deploymentId??"-"}`];return args.previewUrl&&lines.push(`preview url: ${args.previewUrl}`),args.health&&lines.push(`health: ${args.health}`),args.healthCheckUrl&&lines.push(`health_check_url: ${args.healthCheckUrl}`),args.message&&lines.push(`message: ${args.message}`),args.failureReason&&lines.push(`failure_reason: ${args.failureReason}`),args.diagnosticUrl&&lines.push(`diagnostic_url: ${args.diagnosticUrl}`),lines}function createTenantScopedSdk(credentials,tenantId,options={}){if(!credentials)throw new Error("\u672A\u627E\u5230\u672C\u5730\u51ED\u636E\uFF0C\u8BF7\u5148\u6267\u884C `platform login`\u3002");return createControlApiSdk({accessToken:selectApiToken(credentials),tenantId,capability:options.capability,requestClass:options.requestClass??"control"})}async function loadRemoteDbRuntimeBindings(binding,requestedBindings){let credentials=await loadStoredCredentialsEnsuringFresh();if(!credentials)return{values:{},cleanup:null};let env=binding.env==="prod"?"prod":"preview",sdk=createControlApiSdk({accessToken:selectApiToken(credentials),tenantId:binding.tenant_id,capability:"db",requestClass:"control"}),result=await sdk.resolveDevRuntimeBindings({app_id:binding.app_id,env,requested_bindings:requestedBindings});if(result.mode==="unavailable")throw new Error([result.message??"\u5F53\u524D\u73AF\u5883\u5C1A\u672A\u63D0\u4F9B\u5F00\u53D1\u673A\u53EF\u8FBE\u7684 DB binding\u3002",result.remediation,result.request_id?`request_id: ${result.request_id}`:void 0].filter(item=>!!(item&&item.trim().length>0)).join(`
|
|
2642
|
-
`));return{values:result.values,cleanup:result.session_id?async()=>{try{await sdk.revokeDevRuntimeBindings({app_id:binding.app_id,env,session_id:result.session_id})}catch{}}:null}}function resolveRequestedRemoteBindings(args,startDir=process7.cwd()){let explicitValue=readOption2(args,"remote-bindings")?.trim().toLowerCase();if(!explicitValue||explicitValue==="auto")return{capabilities:detectRequestedRemoteBindings(startDir),mode:"auto"};if(explicitValue==="db")return{capabilities:["db"],mode:"db"};throw new Error("`platform dev --remote-bindings` \u76EE\u524D\u4EC5\u652F\u6301 `auto` \u6216 `db`\u3002")}async function runLogin(args){let issuer=readRequiredEnv("OIDC_ISSUER"),audience=process7.env.OIDC_AUDIENCE?.trim(),scopes=(process7.env.LOGTO_CLI_SCOPES??"openid profile offline_access").split(/\s+/u).filter(Boolean),cliClientId=
|
|
2642
|
+
`));return{values:result.values,cleanup:result.session_id?async()=>{try{await sdk.revokeDevRuntimeBindings({app_id:binding.app_id,env,session_id:result.session_id})}catch{}}:null}}function resolveRequestedRemoteBindings(args,startDir=process7.cwd()){let explicitValue=readOption2(args,"remote-bindings")?.trim().toLowerCase();if(!explicitValue||explicitValue==="auto")return{capabilities:detectRequestedRemoteBindings(startDir),mode:"auto"};if(explicitValue==="db")return{capabilities:["db"],mode:"db"};throw new Error("`platform dev --remote-bindings` \u76EE\u524D\u4EC5\u652F\u6301 `auto` \u6216 `db`\u3002")}async function runLogin(args){let issuer=readRequiredEnv("OIDC_ISSUER"),audience=process7.env.OIDC_AUDIENCE?.trim(),scopes=(process7.env.LOGTO_CLI_SCOPES??"openid profile offline_access").split(/\s+/u).filter(Boolean),cliClientId=readAuthConfigValue(AUTH_CLI_CLIENT_ID_KEYS),browserLoginConfig=resolveBrowserLoginConfig(),pat=readOption2(args,"pat")?.trim(),credentials;if(pat){if(!cliClientId)throw new Error("`platform login --pat` \u9700\u8981\u5DF2\u914D\u7F6E `AUTH_CLI_CLIENT_ID`\uFF08\u6216\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_APP_ID`\uFF09\u3002");credentials=await performPatTokenExchangeLogin({issuer,clientId:cliClientId,audience,scopes,subjectToken:pat}),persistCredentials(credentials),process7.stdout.write(["PAT \u767B\u5F55\u5DF2\u5B8C\u6210\u3002",`\u51ED\u636E\u5DF2\u5199\u5165: ${getCredentialPath()}`,"\u8BF4\u660E: \u5F53\u524D\u4E3A\u673A\u5668\u51ED\u636E\u6A21\u5F0F\uFF0CCLI \u4F1A\u5728 7 \u5929\u7A97\u53E3\u5185\u81EA\u52A8\u91CD\u65B0\u4EA4\u6362 access token\u3002","\u4E0B\u4E00\u6B65\u5EFA\u8BAE\uFF1A"," 1. platform whoami"," 2. \u5982\u9700\u957F\u671F\u4EBA\u5DE5\u5F00\u53D1\uFF0C\u4F18\u5148\u6539\u7528 `platform login` \u6D4F\u89C8\u5668\u767B\u5F55",""].join(`
|
|
2643
2643
|
`));return}if(cliClientId)try{credentials=await performDeviceCodeLogin({issuer,clientId:cliClientId,audience,scopes,onPrompt:({verificationUri,userCode,expiresIn})=>{let opened=tryOpenBrowser2(verificationUri);process7.stdout.write((opened?["\u5DF2\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u5B8C\u6210\u767B\u5F55\u6388\u6743\u3002",""]:["\u8BF7\u5728\u6D4F\u89C8\u5668\u5B8C\u6210\u767B\u5F55\u6388\u6743\u3002",`\u9A8C\u8BC1\u5730\u5740: ${verificationUri}`,`User Code: ${userCode}`,`\u6709\u6548\u671F: ${expiresIn} \u79D2`,""]).join(`
|
|
2644
2644
|
`))}})}catch(error){if(!shouldFallbackToBrowserLogin(error))throw error;if(process7.stdout.write(`\u5F53\u524D\u73AF\u5883\u4E0D\u53EF\u7528 Device Flow\uFF0C\u81EA\u52A8\u5207\u6362\u5230\u6D4F\u89C8\u5668\u6388\u6743\u7801\u767B\u5F55\u3002
|
|
2645
|
-
`),!browserLoginConfig)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11\u53EF\u7528\u4E8E\u6D4F\u89C8\u5668\u767B\u5F55\u7684\u914D\u7F6E\uFF0C\u8BF7\u8865\u9F50 `LOGTO_CLI_REDIRECT_URI`\uFF0C\u6216\u63D0\u4F9B `
|
|
2646
|
-
`))}})}else{if(!browserLoginConfig)throw new Error("\u7F3A\u5C11\u6D4F\u89C8\u5668\u767B\u5F55\u914D\u7F6E\uFF1A\u8BF7\u4F18\u5148\u8865\u9F50 `
|
|
2645
|
+
`),!browserLoginConfig)throw new Error("\u5F53\u524D\u73AF\u5883\u7F3A\u5C11\u53EF\u7528\u4E8E\u6D4F\u89C8\u5668\u767B\u5F55\u7684\u914D\u7F6E\uFF0C\u8BF7\u8865\u9F50 `AUTH_CLI_REDIRECT_URI`\uFF08\u6216\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_REDIRECT_URI`\uFF09\uFF0C\u6216\u63D0\u4F9B `AUTH_TENANT_CLIENT_ID / AUTH_TENANT_REDIRECT_URI`\uFF08\u65E7\u540D `LOGTO_TENANT_*`\uFF09\u4F5C\u4E3A\u56DE\u9000\u3002");credentials=await performAuthorizationCodeLogin({issuer,clientId:browserLoginConfig.clientId,redirectUri:browserLoginConfig.redirectUri,audience,scopes,prompt:"login",onPrompt:({authorizationUrl,redirectUri})=>{let opened=tryOpenBrowser2(authorizationUrl);process7.stdout.write((opened?["\u5DF2\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u5B8C\u6210\u6388\u6743\u7801\u767B\u5F55\u3002",""]:[browserLoginConfig.source==="cli-app"?"\u4F7F\u7528\u4E13\u7528 CLI App \u6267\u884C\u6D4F\u89C8\u5668\u6388\u6743\u7801\u767B\u5F55\uFF0C\u5E76\u81EA\u52A8\u9644\u5E26 consent \u4EE5\u6362\u53D6 refresh token\u3002":"\u4F7F\u7528 workbench \u914D\u7F6E\u56DE\u9000\u6267\u884C\u6D4F\u89C8\u5668\u6388\u6743\u7801\u767B\u5F55\uFF0C\u5E76\u5F3A\u5236 prompt=login consent \u4EE5\u907F\u514D\u590D\u7528\u9519\u8BEF SSO \u4F1A\u8BDD\u5E76\u6362\u53D6 refresh token\u3002","\u8BF7\u5728\u6D4F\u89C8\u5668\u5B8C\u6210\u6388\u6743\u7801\u767B\u5F55\u3002",`\u6388\u6743\u5730\u5740: ${authorizationUrl}`,`\u56DE\u8C03\u5730\u5740: ${redirectUri}`,browserLoginConfig.source==="workbench-fallback"?"\u82E5\u56DE\u8C03\u7AEF\u53E3\u88AB\u672C\u5730 workbench \u5360\u7528\uFF0C\u8BF7\u5148\u6682\u65F6\u505C\u6B62\u5BF9\u5E94\u670D\u52A1\u540E\u91CD\u8BD5\u3002":"\u8BF7\u786E\u8BA4\u8BE5\u56DE\u8C03\u5730\u5740\u5DF2\u5728\u4E13\u7528 CLI App \u4E2D\u6CE8\u518C\u3002",""]).join(`
|
|
2646
|
+
`))}})}else{if(!browserLoginConfig)throw new Error("\u7F3A\u5C11\u6D4F\u89C8\u5668\u767B\u5F55\u914D\u7F6E\uFF1A\u8BF7\u4F18\u5148\u8865\u9F50 `AUTH_CLI_CLIENT_ID / AUTH_CLI_REDIRECT_URI`\uFF08\u517C\u5BB9\u65E7\u540D `LOGTO_CLI_*`\uFF09\uFF1B\u82E5\u6682\u65F6\u65E0\u6CD5\u63D0\u4F9B\uFF0C\u518D\u8865\u9F50 `AUTH_TENANT_CLIENT_ID / AUTH_TENANT_REDIRECT_URI`\uFF08\u517C\u5BB9\u65E7\u540D `LOGTO_TENANT_*`\uFF09\u4F5C\u4E3A\u56DE\u9000\u3002");process7.stdout.write(browserLoginConfig.source==="cli-app"?`\u5F53\u524D\u4F7F\u7528\u4E13\u7528 CLI App \u6267\u884C\u6D4F\u89C8\u5668\u6388\u6743\u7801\u767B\u5F55\uFF0C\u5E76\u81EA\u52A8\u9644\u5E26 consent \u4EE5\u6362\u53D6 refresh token\u3002
|
|
2647
2647
|
`:`\u672A\u914D\u7F6E\u5B8C\u6574\u4E13\u7528 CLI \u6D4F\u89C8\u5668\u767B\u5F55\u53C2\u6570\uFF0C\u81EA\u52A8\u56DE\u9000\u590D\u7528 workbench \u767B\u5F55\u914D\u7F6E\uFF0C\u5E76\u5F3A\u5236 prompt=login consent\u3002
|
|
2648
2648
|
`),credentials=await performAuthorizationCodeLogin({issuer,clientId:browserLoginConfig.clientId,redirectUri:browserLoginConfig.redirectUri,audience,scopes,prompt:"login",onPrompt:({authorizationUrl,redirectUri})=>{let opened=tryOpenBrowser2(authorizationUrl);process7.stdout.write((opened?["\u5DF2\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u5B8C\u6210\u6388\u6743\u7801\u767B\u5F55\u3002",""]:["\u8BF7\u5728\u6D4F\u89C8\u5668\u5B8C\u6210\u6388\u6743\u7801\u767B\u5F55\u3002",`\u6388\u6743\u5730\u5740: ${authorizationUrl}`,`\u56DE\u8C03\u5730\u5740: ${redirectUri}`,browserLoginConfig.source==="workbench-fallback"?"\u5F53\u524D\u4E3A workbench \u56DE\u9000\u767B\u5F55\uFF0C\u5DF2\u5F3A\u5236 prompt=login consent\uFF1B\u82E5\u56DE\u8C03\u7AEF\u53E3\u88AB\u5360\u7528\uFF0C\u8BF7\u5148\u6682\u65F6\u505C\u6B62\u5BF9\u5E94\u670D\u52A1\u540E\u91CD\u8BD5\u3002":"\u8BF7\u786E\u8BA4\u8BE5\u56DE\u8C03\u5730\u5740\u5DF2\u5728\u4E13\u7528 CLI App \u4E2D\u6CE8\u518C\u3002",""]).join(`
|
|
2649
2649
|
`))}})}persistCredentials({...credentials,credential_mode:"interactive"});let autoSelectedTenant=null,autoSelectionNote=null;try{let workspaces=await listTenantWorkspaces({baseUrl:getControlApiBaseUrl(),accessToken:selectApiToken(credentials)});autoSelectedTenant=chooseDefaultTenantWorkspace(workspaces.items),autoSelectedTenant?persistActiveTenantSelection(autoSelectedTenant):workspaces.items.length>1&&(autoSelectionNote="\u68C0\u6D4B\u5230\u591A\u4E2A\u53EF\u7528\u79DF\u6237\uFF0C\u672A\u81EA\u52A8\u5207\u6362\u9ED8\u8BA4\u79DF\u6237\uFF1B\u8BF7\u6267\u884C `platform tenant use <tenant-id>`\u3002")}catch(error){autoSelectionNote=`\u9ED8\u8BA4\u79DF\u6237\u81EA\u52A8\u9009\u62E9\u5931\u8D25\uFF1A${error.message}`}process7.stdout.write(["\u767B\u5F55\u5DF2\u5B8C\u6210\u3002",`\u51ED\u636E\u5DF2\u5199\u5165: ${getCredentialPath()}`,...autoSelectedTenant?[`\u9ED8\u8BA4\u79DF\u6237\u5DF2\u81EA\u52A8\u8BBE\u7F6E: ${autoSelectedTenant.tenant_id} (${autoSelectedTenant.name})`,`\u4E0A\u4E0B\u6587\u5DF2\u5199\u5165: ${getCliContextPath()}`]:autoSelectionNote?[autoSelectionNote]:[],"\u4E0B\u4E00\u6B65\u5EFA\u8BAE\uFF1A"," 1. platform whoami",' 2. \u65B0\u5EFA\u5E94\u7528\uFF1Aplatform app create --tenant <tenant-id> --name "<app-name>" --dir <project-name>'," 3. \u7F16\u8F91\u5DF2\u6709\u5E94\u7528\uFF1Aplatform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>"," 4. cd <project-name> && platform dev"," 5. \u9ED8\u8BA4\u5148\u8D70\u8F7B\u91CF\u5F00\u53D1\u6A21\u5F0F\uFF1B\u771F\u5B9E build / preview \u8054\u8C03\u5C5E\u4E8E\u9AD8\u7EA7\u8DEF\u5F84",""].join(`
|
|
@@ -2651,7 +2651,7 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2651
2651
|
`)}async function runTenant(args){let subcommand=args.rest[0]??"current";if(subcommand==="current"){let context=loadStoredCliContext();if(!context?.active_tenant_id){process7.stdout.write(`\u5F53\u524D\u672A\u8BBE\u7F6E\u9ED8\u8BA4\u79DF\u6237\u4E0A\u4E0B\u6587\u3002
|
|
2652
2652
|
`);return}process7.stdout.write([`\u5F53\u524D\u9ED8\u8BA4\u79DF\u6237: ${context.active_tenant_id}`,`\u79DF\u6237\u540D\u79F0: ${context.active_tenant_name??"-"}`,`\u66F4\u65B0\u65F6\u95F4: ${context.updated_at}`,`\u4E0A\u4E0B\u6587\u6587\u4EF6: ${getCliContextPath()}`,""].join(`
|
|
2653
2653
|
`));return}if(subcommand!=="use")throw new Error(`\u672A\u77E5 tenant \u5B50\u547D\u4EE4: ${subcommand}`);let tenantId=args.rest[1]??readOption2(args,"tenant");if(!tenantId)throw new Error("`platform tenant use` \u9700\u8981\u4E00\u4E2A tenant id\uFF0C\u4F8B\u5982 `platform tenant use t-default`\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 workspaces=await listTenantWorkspaces({baseUrl:getControlApiBaseUrl(),accessToken:selectApiToken(credentials)}),matched=workspaces.items.find(item=>item.tenant_id===tenantId);if(!matched){let available=workspaces.items.map(item=>`${item.tenant_id} (${item.name})`).join(", ");throw new Error(available.length>0?`\u5F53\u524D\u8D26\u53F7\u6CA1\u6709\u79DF\u6237 ${tenantId} \u7684\u8BBF\u95EE\u6743\u9650\u3002\u53EF\u7528\u79DF\u6237: ${available}`:"\u5F53\u524D\u8D26\u53F7\u4E0B\u6CA1\u6709\u53EF\u7528\u79DF\u6237\uFF0C\u8BF7\u5148\u5728 workbench \u4E2D\u786E\u8BA4\u6210\u5458\u5173\u7CFB\u3002")}persistActiveTenantSelection(matched),process7.stdout.write([`\u9ED8\u8BA4\u79DF\u6237\u5DF2\u5207\u6362\u4E3A: ${matched.tenant_id}`,`\u79DF\u6237\u540D\u79F0: ${matched.name}`,`\u4E0A\u4E0B\u6587\u5DF2\u5199\u5165: ${getCliContextPath()}`,"\u4E0B\u4E00\u6B65\u5EFA\u8BAE\uFF1A\u6267\u884C `platform whoami`\uFF0C\u7136\u540E\u8D70\u4E3B\u8DEF\u5F84 `platform app create ...` \u65B0\u5EFA\u5E94\u7528\uFF0C\u6216 `platform app checkout --app <app-id> ...` \u56DE\u62C9\u5DF2\u6709\u5E94\u7528\uFF1B\u82E5\u5F53\u524D\u76EE\u5F55\u5DF2\u7ED1\u5B9A\u9879\u76EE\uFF0C\u518D\u6267\u884C `platform dev`\u3002",""].join(`
|
|
2654
|
-
`))}var ENV_PROFILE_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","
|
|
2654
|
+
`))}var ENV_PROFILE_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 readManagedEnvironmentOverrides(args){let optionMap=[{option:"control-api-base-url",key:"CONTROL_API_BASE_URL"},{option:"public-api-base-url",key:"PUBLIC_API_BASE_URL"},{option:"runtime-api-base-url",key:"RUNTIME_API_BASE_URL"},{option:"oidc-issuer",key:"OIDC_ISSUER"},{option:"oidc-audience",key:"OIDC_AUDIENCE"},{option:"logto-cli-app-id",key:"LOGTO_CLI_APP_ID"},{option:"logto-cli-redirect-uri",key:"LOGTO_CLI_REDIRECT_URI"},{option:"logto-tenant-app-id",key:"LOGTO_TENANT_APP_ID"},{option:"logto-tenant-redirect-uri",key:"LOGTO_TENANT_REDIRECT_URI"}],overrides={};for(let mapping of optionMap){let value=readOption2(args,mapping.option)?.trim();value&&(overrides[mapping.key]=value)}return overrides}function printEnvironmentProfileDetail(args){let lines=[`\u5F53\u524D\u73AF\u5883 profile: ${args.profileName}`];for(let key of ENV_PROFILE_KEYS)lines.push(`${key}: ${args.values[key]??"-"}`);args.updatedAt&&lines.push(`\u66F4\u65B0\u65F6\u95F4: ${args.updatedAt}`),args.path&&lines.push(`\u914D\u7F6E\u6587\u4EF6: ${args.path}`),lines.push(""),process7.stdout.write(lines.join(`
|
|
2655
2655
|
`))}async function runEnvironment(args){if(distributionProfile.name!=="developer")throw new Error(`\u5F53\u524D ${distributionProfile.name} \u5206\u53D1 CLI \u5DF2\u56FA\u5B9A\u9ED8\u8BA4\u73AF\u5883\uFF0C\u4E0D\u652F\u6301 \`platform env\`\u3002`);let subcommand=args.rest[0]??"current";if(subcommand==="current"){let stored=loadStoredEnvironmentProfile();if(!stored){process7.stdout.write(`\u5F53\u524D\u672A\u8BBE\u7F6E CLI \u73AF\u5883 profile\u3002
|
|
2656
2656
|
`);return}printEnvironmentProfileDetail({profileName:stored.active_profile,values:stored.values,updatedAt:stored.updated_at,path:getEnvironmentProfilePath()});return}if(subcommand==="list"){let stored=loadStoredEnvironmentProfile(),knownProfiles=listKnownEnvironmentProfiles();if(knownProfiles.length===0){process7.stdout.write(`\u5F53\u524D\u672A\u53D1\u73B0\u53EF\u7528\u73AF\u5883 profile\u3002
|
|
2657
2657
|
`);return}let lines=["\u53EF\u7528\u73AF\u5883 profile\uFF1A"];for(let profile of knownProfiles){let marker=stored?.active_profile===profile.name?"*":"-";lines.push(`${marker} ${profile.name} control=${profile.values.CONTROL_API_BASE_URL??"-"} runtime=${profile.values.RUNTIME_API_BASE_URL??"-"}`)}lines.push(""),process7.stdout.write(lines.join(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voobase/cli",
|
|
3
|
-
"version": "0.1.0-nonprod.
|
|
3
|
+
"version": "0.1.0-nonprod.1820",
|
|
4
4
|
"private": false,
|
|
5
5
|
"platformDistributionProfile": {
|
|
6
6
|
"name": "nonprod",
|
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
"RUNTIME_API_BASE_URL": "https://runtime.voobase.21epub.com",
|
|
11
11
|
"OIDC_ISSUER": "https://auth.voobase.21epub.com/oidc",
|
|
12
12
|
"OIDC_AUDIENCE": "platform",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"LOGTO_REDIRECT_URI": "https://admin.voobase.21epub.com/callback"
|
|
13
|
+
"AUTH_CLI_CLIENT_ID": "6bhf054sho0etid9nob9h",
|
|
14
|
+
"AUTH_CLI_REDIRECT_URI": "http://127.0.0.1:7300/callback",
|
|
15
|
+
"AUTH_TENANT_CLIENT_ID": "77oz11v81kji9vs1wqred",
|
|
16
|
+
"AUTH_TENANT_REDIRECT_URI": "https://tenant.voobase.21epub.com/callback"
|
|
18
17
|
}
|
|
19
18
|
},
|
|
20
19
|
"type": "module",
|
|
@@ -51,10 +50,10 @@
|
|
|
51
50
|
"bundleDependencies": [],
|
|
52
51
|
"platformDistributionBuild": {
|
|
53
52
|
"channel": "nonprod",
|
|
54
|
-
"version": "0.1.0-nonprod.
|
|
55
|
-
"sequence":
|
|
53
|
+
"version": "0.1.0-nonprod.1820",
|
|
54
|
+
"sequence": 1820,
|
|
56
55
|
"gitSha": "4468924",
|
|
57
56
|
"fullGitSha": "44689243f3e68d3a0a552f63e0a6ac1a1ffdc8b9",
|
|
58
|
-
"buildId": "0.1.0-nonprod.
|
|
57
|
+
"buildId": "0.1.0-nonprod.1820+4468924"
|
|
59
58
|
}
|
|
60
59
|
}
|