@voobase/cli 0.1.1-nonprod.2070 → 0.1.1-nonprod.2071
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 +8 -10
- package/package.json +6 -6
package/dist-bundle/index.mjs
CHANGED
|
@@ -2249,14 +2249,12 @@ foreach ($rule in $acl.GetAccessRules($true, $true, [System.Security.Principal.S
|
|
|
2249
2249
|
dacl_present = ($null -ne $rawDescriptor.DiscretionaryAcl)
|
|
2250
2250
|
rules = $rules
|
|
2251
2251
|
} | ConvertTo-Json -Compress -Depth 4
|
|
2252
|
-
`;function inspectCredentialSecurity(options={}){let platform=options.platform??process.platform,stateLocation=options.stateLocation??resolveCliStateLocation(options.stateResolution),credentialPath=options.credentialsPath??join4(stateLocation.dir,"credentials.json"),credentialsExist=options.credentialsExist??existsSync7(credentialPath),backend=options.backend??(credentialsExist?"file":"none");if(!credentialsExist&&backend==="none")return{status:"ok",code:"credential_security_ok",backend,legacy_plaintext:!1,state:serializeStateLocation(stateLocation),credential_path:credentialPath,permissions:{status:"not_applicable",detail:"no_local_credentials"},findings:[]};let findings=[];stateLocation.insideWorkspace&&findings.push({code:"credential_state_in_workspace",level:"warning",message:"CLI \u51ED\u636E\u72B6\u6001\u76EE\u5F55\u4F4D\u4E8E\u5F53\u524D\u5DE5\u4F5C\u533A\u5185\uFF0C\u672C\u6B21\u547D\u4EE4\u5C06\u7EE7\u7EED\u6267\u884C\u3002",action:"\u5C06 PLATFORM_STATE_DIR \u8C03\u6574\u5230\u5F53\u524D\u7528\u6237\u4E13\u5C5E\u76EE\u5F55\u540E\u91CD\u65B0\u767B\u5F55\u3002"}),credentialsExist&&findings.push({code:"credential_store_legacy_plaintext",level:"warning",message:"CLI \u51ED\u636E\u4ECD\u4FDD\u5B58\u5728\u517C\u5BB9\u660E\u6587\u6587\u4EF6\u4E2D\uFF0C\u672C\u6B21\u547D\u4EE4\u5C06\u7EE7\u7EED\u6267\u884C\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u5B89\u5168\u72B6\u6001\u4E0E\u8FC1\u79FB\u5EFA\u8BAE\u3002"});let permissions=credentialsExist?inspectCredentialPermissions(credentialPath,platform,options):{status:"not_applicable",detail:"no_legacy_plaintext"};return permissions.status==="warning"?findings.push({code:"credential_acl_too_broad",level:"warning",message:"\u51ED\u636E\u6587\u4EF6\u6743\u9650\u53EF\u80FD\u5141\u8BB8\u975E\u9884\u671F\u672C\u673A\u4E3B\u4F53\u8BFB\u53D6\uFF0C\u672C\u6B21\u547D\u4EE4\u5C06\u7EE7\u7EED\u6267\u884C\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u8DEF\u5F84\uFF0C\u5E76\u6536\u7D27\u8BE5\u6587\u4EF6\u53CA\u7236\u76EE\u5F55\u6743\u9650\u3002"}):permissions.status==="unknown"&&findings.push({code:"credential_acl_unverified",level:"warning",message:"\u5F53\u524D\u65E0\u6CD5\u53EF\u9760\u5224\u65AD\u51ED\u636E\u6587\u4EF6\u6743\u9650\uFF0C\u672C\u6B21\u547D\u4EE4\u5C06\u7EE7\u7EED\u6267\u884C\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u8BCA\u65AD\u8BE6\u60C5\u3002"}),{status:findings.some(finding=>finding.level==="error")?"error":findings.length>0?"warning":"ok",code:findings[0]?.code??"credential_security_ok",backend,legacy_plaintext:credentialsExist,state:serializeStateLocation(stateLocation),credential_path:credentialPath,permissions,findings}}function formatCredentialSecurityReportText(report){let lines=["credential security diagnostics:",`- status: ${report.status}`,`- code: ${report.code}`,`- backend: ${report.backend}`,`- state_dir: ${report.state.dir}`,`- state_source: ${report.state.source}`,`- credential_path: ${report.credential_path}`,`- legacy_plaintext: ${report.legacy_plaintext}`,`- permissions: ${report.permissions.status} (${report.permissions.detail})`];for(let finding of report.findings)lines.push(`- warning [${finding.code}]: ${finding.message}`),lines.push(`- action: ${finding.action}`);return`${lines.join(`
|
|
2252
|
+
`;function inspectCredentialSecurity(options={}){let platform=options.platform??process.platform,stateLocation=options.stateLocation??resolveCliStateLocation(options.stateResolution),credentialPath=options.credentialsPath??join4(stateLocation.dir,"credentials.json"),credentialsExist=options.credentialsExist??existsSync7(credentialPath),backend=options.backend??(credentialsExist?"file":"none");if(!credentialsExist&&backend==="none")return{status:"ok",code:"credential_security_ok",backend,legacy_plaintext:!1,state:serializeStateLocation(stateLocation),credential_path:credentialPath,permissions:{status:"not_applicable",detail:"no_local_credentials"},findings:[]};let findings=[];stateLocation.insideWorkspace&&findings.push({code:"credential_state_in_workspace",level:"warning",message:"CLI \u51ED\u636E\u72B6\u6001\u76EE\u5F55\u4F4D\u4E8E\u5F53\u524D\u5DE5\u4F5C\u533A\u5185\uFF0C\u672C\u6B21\u547D\u4EE4\u5C06\u7EE7\u7EED\u6267\u884C\u3002",action:"\u5C06 PLATFORM_STATE_DIR \u8C03\u6574\u5230\u5F53\u524D\u7528\u6237\u4E13\u5C5E\u76EE\u5F55\u540E\u91CD\u65B0\u767B\u5F55\u3002"}),credentialsExist&&platform==="win32"&&findings.push({code:"credential_store_legacy_plaintext",level:"warning",message:"CLI \u51ED\u636E\u4ECD\u4FDD\u5B58\u5728\u517C\u5BB9\u660E\u6587\u6587\u4EF6\u4E2D\uFF0C\u672C\u6B21\u547D\u4EE4\u5C06\u7EE7\u7EED\u6267\u884C\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u5B89\u5168\u72B6\u6001\u4E0E\u8FC1\u79FB\u5EFA\u8BAE\u3002"});let permissions=credentialsExist?inspectCredentialPermissions(credentialPath,platform,options):{status:"not_applicable",detail:"no_legacy_plaintext"};return permissions.status==="warning"?findings.push({code:"credential_acl_too_broad",level:"warning",message:"\u51ED\u636E\u6587\u4EF6\u6743\u9650\u53EF\u80FD\u5141\u8BB8\u975E\u9884\u671F\u672C\u673A\u4E3B\u4F53\u8BFB\u53D6\uFF0C\u672C\u6B21\u547D\u4EE4\u5C06\u7EE7\u7EED\u6267\u884C\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u8DEF\u5F84\uFF0C\u5E76\u6536\u7D27\u8BE5\u6587\u4EF6\u53CA\u7236\u76EE\u5F55\u6743\u9650\u3002"}):permissions.status==="unknown"&&findings.push({code:"credential_acl_unverified",level:"warning",message:"\u5F53\u524D\u65E0\u6CD5\u53EF\u9760\u5224\u65AD\u51ED\u636E\u6587\u4EF6\u6743\u9650\uFF0C\u672C\u6B21\u547D\u4EE4\u5C06\u7EE7\u7EED\u6267\u884C\u3002",action:"\u8FD0\u884C `platform diagnostics credentials` \u67E5\u770B\u8BCA\u65AD\u8BE6\u60C5\u3002"}),{status:findings.some(finding=>finding.level==="error")?"error":findings.length>0?"warning":"ok",code:findings[0]?.code??"credential_security_ok",backend,legacy_plaintext:credentialsExist&&platform==="win32",state:serializeStateLocation(stateLocation),credential_path:credentialPath,permissions,findings}}function formatCredentialSecurityReportText(report){let lines=["credential security diagnostics:",`- status: ${report.status}`,`- code: ${report.code}`,`- backend: ${report.backend}`,`- state_dir: ${report.state.dir}`,`- state_source: ${report.state.source}`,`- credential_path: ${report.credential_path}`,`- legacy_plaintext: ${report.legacy_plaintext}`,`- permissions: ${report.permissions.status} (${report.permissions.detail})`];for(let finding of report.findings)lines.push(`- warning [${finding.code}]: ${finding.message}`),lines.push(`- action: ${finding.action}`);return`${lines.join(`
|
|
2253
2253
|
`)}
|
|
2254
2254
|
`}function emitCredentialSecurityWarnings(report,options={}){let warningFindings=report.findings.filter(finding=>finding.level==="warning");if(warningFindings.length===0)return!1;let now=options.now??new Date,fingerprint=createCredentialWarningFingerprint(report),readState=options.readState??(()=>readCredentialWarningState(report.state.dir)),writeState=options.writeState??(state=>writeCredentialWarningState(report.state.dir,state)),previous=readState(),lastNotifiedAt=previous?Date.parse(previous.last_notified_at):Number.NaN;if(previous?.fingerprint===fingerprint&&Number.isFinite(lastNotifiedAt)&&now.getTime()-lastNotifiedAt>=0&&now.getTime()-lastNotifiedAt<(options.intervalMs??DEFAULT_WARNING_INTERVAL_MS))return!1;let message=warningFindings.flatMap(finding=>[`[${finding.code}] ${finding.message}`,`\u5EFA\u8BAE\uFF1A${finding.action}`]).join(`
|
|
2255
2255
|
`);(options.emit??(value=>process.stderr.write(`${value}
|
|
2256
2256
|
`)))(message);try{writeState({fingerprint,last_notified_at:now.toISOString()})}catch{}return!0}function createCredentialWarningFingerprint(report){return createHash3("sha256").update(JSON.stringify({backend:report.backend,state_dir:report.state.dir,state_source:report.state.source,inside_workspace:report.state.inside_workspace,permission_detail:report.permissions.detail,findings:report.findings.map(finding=>finding.code).sort()})).digest("hex")}function readCredentialWarningState(stateDir){try{let payload=JSON.parse(readFileSync7(join4(stateDir,CREDENTIAL_WARNING_STATE_FILE),"utf8"));if(typeof payload.fingerprint=="string"&&typeof payload.last_notified_at=="string")return{fingerprint:payload.fingerprint,last_notified_at:payload.last_notified_at}}catch{}return null}function writeCredentialWarningState(stateDir,state){mkdirSync2(stateDir,{recursive:!0});let targetPath=join4(stateDir,CREDENTIAL_WARNING_STATE_FILE),temporaryPath=`${targetPath}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;writeFileSync3(temporaryPath,`${JSON.stringify(state,null,2)}
|
|
2257
|
-
`,"utf8");try{chmodSync(temporaryPath,384),renameSync(temporaryPath,targetPath)}catch(error){try{existsSync7(temporaryPath)&&unlinkSync(temporaryPath)}catch{}throw error}}function inspectCredentialPermissions(credentialPath,platform,options){if(platform==="win32"){if(options.probeWindowsAcl===!1)return{status:"unknown",detail:"windows_acl_probe_deferred"};try{return(options.windowsAclInspector??inspectWindowsCredentialAcl)(credentialPath)}catch{return{status:"unknown",detail:"windows_acl_probe_failed"}}}try{let stat2=(options.statCredential??(path3=>{let value=lstatSync2(path3);return{mode:value.mode,uid:value.uid,isFile:value.isFile()}}))(credentialPath);if(stat2.isFile===!1)return{status:"unknown",detail:"credential_path_not_regular_file"};let currentUid=options.currentUid??(typeof process.getuid=="function"?process.getuid():void 0),mode=stat2.mode&511;return currentUid===void 0?{status:"unknown",detail:"posix_current_uid_unavailable"}:(mode&63)===0&&stat2.uid===currentUid?{status:"secure",detail:"owner_read_write_only"}:{status:"warning",detail:(mode&63)!==0?"posix_mode_too_broad":"posix_owner_mismatch"}}catch{return{status:"unknown",detail:"posix_permission_probe_failed"}}}function inspectWindowsCredentialAcl(credentialPath){let result=spawnSync(resolveWindowsPowerShellExecutable(),["-NoLogo","-NoProfile","-NonInteractive","-Command",WINDOWS_ACL_SCRIPT],{encoding:"utf8",env:{...process.env,VOOBASE_CREDENTIAL_PATH:credentialPath},shell:!1,timeout:5e3,windowsHide:!0});if(result.error||result.status!==0)return{status:"unknown",detail:result.error?.code==="ETIMEDOUT"?"windows_acl_probe_timeout":"windows_acl_probe_failed"};try{return classifyWindowsAclPayload(JSON.parse(result.stdout.trim()))}catch{}return{status:"unknown",detail:"windows_acl_probe_invalid_output"}}function classifyWindowsAclPayload(value){if(!isWindowsAclPayload(value))return{status:"unknown",detail:"windows_acl_probe_invalid_output"};if(value.owner_sid!==value.current_sid)return{status:"warning",detail:"windows_acl_owner_mismatch"};if(!value.dacl_present)return{status:"warning",detail:"windows_null_dacl"};let allowedReadSids=new Set([value.current_sid,"S-1-5-18","S-1-5-32-544"]);return value.rules.some(rule=>rule.type===0&&(rule.rights&1)!==0&&!allowedReadSids.has(rule.sid))?{status:"warning",detail:"unexpected_read_acl"}:{status:"secure",detail:"current_user_acl"}}function isWindowsAclPayload(value){if(!value||typeof value!="object")return!1;let payload=value;return typeof payload.owner_sid=="string"&&typeof payload.current_sid=="string"&&typeof payload.dacl_present=="boolean"&&Array.isArray(payload.rules)&&payload.rules.every(rule=>!!rule&&typeof rule=="object"&&typeof rule.sid=="string"&&typeof rule.type=="number"&&typeof rule.rights=="number")}function serializeStateLocation(stateLocation){return{dir:stateLocation.dir,source:stateLocation.source,inside_workspace:stateLocation.insideWorkspace}}import{createHash as createHash4,randomBytes as randomBytes2}from"node:crypto";import{spawnSync as
|
|
2258
|
-
${serialized}
|
|
2259
|
-
`);this.assertSucceeded(result)}delete(){let result=this.run(["delete-generic-password","-a",this.options.account,"-s",this.options.service]);result.status!==44&&this.assertSucceeded(result)}run(args,input){return this.spawnSyncImpl("/usr/bin/security",args,{encoding:"utf8",input,shell:!1,timeout:8e3,windowsHide:!0,maxBuffer:2*1024*1024})}assertSucceeded(result){if(!result.error&&result.status===0)return;let code2=result.error?.code,reason=code2==="ENOENT"?"command_missing":code2==="ETIMEDOUT"?"timeout":result.status===36||result.status===51?"access_denied":"operation_failed";throw new CredentialStoreUnavailableError(this.backend,reason)}};import{spawnSync as spawnSync3}from"node:child_process";import{existsSync as existsSync8,mkdirSync as mkdirSync3,unlinkSync as unlinkSync2}from"node:fs";import{dirname as dirname5}from"node:path";var DPAPI_SCRIPT=String.raw`
|
|
2257
|
+
`,"utf8");try{chmodSync(temporaryPath,384),renameSync(temporaryPath,targetPath)}catch(error){try{existsSync7(temporaryPath)&&unlinkSync(temporaryPath)}catch{}throw error}}function inspectCredentialPermissions(credentialPath,platform,options){if(platform==="win32"){if(options.probeWindowsAcl===!1)return{status:"unknown",detail:"windows_acl_probe_deferred"};try{return(options.windowsAclInspector??inspectWindowsCredentialAcl)(credentialPath)}catch{return{status:"unknown",detail:"windows_acl_probe_failed"}}}try{let stat2=(options.statCredential??(path3=>{let value=lstatSync2(path3);return{mode:value.mode,uid:value.uid,isFile:value.isFile()}}))(credentialPath);if(stat2.isFile===!1)return{status:"unknown",detail:"credential_path_not_regular_file"};let currentUid=options.currentUid??(typeof process.getuid=="function"?process.getuid():void 0),mode=stat2.mode&511;return currentUid===void 0?{status:"unknown",detail:"posix_current_uid_unavailable"}:(mode&63)===0&&stat2.uid===currentUid?{status:"secure",detail:"owner_read_write_only"}:{status:"warning",detail:(mode&63)!==0?"posix_mode_too_broad":"posix_owner_mismatch"}}catch{return{status:"unknown",detail:"posix_permission_probe_failed"}}}function inspectWindowsCredentialAcl(credentialPath){let result=spawnSync(resolveWindowsPowerShellExecutable(),["-NoLogo","-NoProfile","-NonInteractive","-Command",WINDOWS_ACL_SCRIPT],{encoding:"utf8",env:{...process.env,VOOBASE_CREDENTIAL_PATH:credentialPath},shell:!1,timeout:5e3,windowsHide:!0});if(result.error||result.status!==0)return{status:"unknown",detail:result.error?.code==="ETIMEDOUT"?"windows_acl_probe_timeout":"windows_acl_probe_failed"};try{return classifyWindowsAclPayload(JSON.parse(result.stdout.trim()))}catch{}return{status:"unknown",detail:"windows_acl_probe_invalid_output"}}function classifyWindowsAclPayload(value){if(!isWindowsAclPayload(value))return{status:"unknown",detail:"windows_acl_probe_invalid_output"};if(value.owner_sid!==value.current_sid)return{status:"warning",detail:"windows_acl_owner_mismatch"};if(!value.dacl_present)return{status:"warning",detail:"windows_null_dacl"};let allowedReadSids=new Set([value.current_sid,"S-1-5-18","S-1-5-32-544"]);return value.rules.some(rule=>rule.type===0&&(rule.rights&1)!==0&&!allowedReadSids.has(rule.sid))?{status:"warning",detail:"unexpected_read_acl"}:{status:"secure",detail:"current_user_acl"}}function isWindowsAclPayload(value){if(!value||typeof value!="object")return!1;let payload=value;return typeof payload.owner_sid=="string"&&typeof payload.current_sid=="string"&&typeof payload.dacl_present=="boolean"&&Array.isArray(payload.rules)&&payload.rules.every(rule=>!!rule&&typeof rule=="object"&&typeof rule.sid=="string"&&typeof rule.type=="number"&&typeof rule.rights=="number")}function serializeStateLocation(stateLocation){return{dir:stateLocation.dir,source:stateLocation.source,inside_workspace:stateLocation.insideWorkspace}}import{createHash as createHash4,randomBytes as randomBytes2}from"node:crypto";import{spawnSync as spawnSync3}from"node:child_process";import{chmodSync as chmodSync2,existsSync as existsSync9,mkdirSync as mkdirSync4,readFileSync as readFileSync8,renameSync as renameSync2,unlinkSync as unlinkSync3,writeFileSync as writeFileSync4}from"node:fs";import{dirname as dirname6,join as join5,resolve as resolve6}from"node:path";import{spawnSync as spawnSync2}from"node:child_process";import{existsSync as existsSync8,mkdirSync as mkdirSync3,unlinkSync as unlinkSync2}from"node:fs";import{dirname as dirname5}from"node:path";var DPAPI_SCRIPT=String.raw`
|
|
2260
2258
|
$ErrorActionPreference = 'Stop'
|
|
2261
2259
|
[void](Add-Type -AssemblyName System.Security -PassThru)
|
|
2262
2260
|
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
|
|
@@ -2294,9 +2292,9 @@ if ($operation -eq 'read') {
|
|
|
2294
2292
|
exit 0
|
|
2295
2293
|
}
|
|
2296
2294
|
throw 'unsupported credential operation'
|
|
2297
|
-
`,WindowsDpapiCredentialStore=class{options;backend="dpapi";spawnSyncImpl;constructor(options){this.options=options,this.spawnSyncImpl=options.spawnSyncImpl??
|
|
2295
|
+
`,WindowsDpapiCredentialStore=class{options;backend="dpapi";spawnSyncImpl;constructor(options){this.options=options,this.spawnSyncImpl=options.spawnSyncImpl??spawnSync2}exists(){return existsSync8(this.options.blobPath)}read(){if(!existsSync8(this.options.blobPath))return null;let result=this.run("read");this.assertSucceeded(result);try{return parseStoredCredentials(result.stdout.trim(),this.backend)}catch(error){throw error instanceof CredentialStoreCorruptedError?error:new CredentialStoreCorruptedError(this.backend)}}write(value){mkdirSync3(dirname5(this.options.blobPath),{recursive:!0});let result=this.run("write",JSON.stringify(value));this.assertSucceeded(result)}delete(){try{unlinkSync2(this.options.blobPath)}catch(error){if(error.code!=="ENOENT")throw new CredentialStoreUnavailableError(this.backend,"operation_failed")}}run(operation,input){return this.spawnSyncImpl(resolveWindowsPowerShellExecutable(),["-NoLogo","-NoProfile","-NonInteractive","-Command",DPAPI_SCRIPT],{encoding:"utf8",input,env:{...process.env,VOOBASE_CREDENTIAL_OPERATION:operation,VOOBASE_CREDENTIAL_PATH:this.options.blobPath,VOOBASE_CREDENTIAL_SERVICE:this.options.service},shell:!1,timeout:8e3,windowsHide:!0,maxBuffer:2*1024*1024})}assertSucceeded(result){if(!result.error&&result.status===0)return;let code2=result.error?.code,reason=code2==="ENOENT"?"command_missing":code2==="ETIMEDOUT"?"timeout":result.status===5?"access_denied":"operation_failed";throw new CredentialStoreUnavailableError(this.backend,reason)}};var CredentialStoreUnavailableError=class extends Error{backend;reason;code="credential_secure_store_unavailable";constructor(backend,reason){super(`Credential store ${backend} is unavailable (${reason}).`),this.backend=backend,this.reason=reason,this.name="CredentialStoreUnavailableError"}},CredentialStoreCorruptedError=class extends Error{backend;code="credential_store_corrupted";constructor(backend){super(`Credential store ${backend} contains invalid data.`),this.backend=backend,this.name="CredentialStoreCorruptedError"}},FileCredentialStore=class{filePath;options;backend="file";constructor(filePath,options={}){this.filePath=filePath,this.options=options}exists(){return existsSync9(this.filePath)}read(){if(!existsSync9(this.filePath))return null;try{return parseStoredCredentials(readFileSync8(this.filePath,"utf8"),this.backend)}catch(error){throw error instanceof CredentialStoreCorruptedError?error:new CredentialStoreUnavailableError(this.backend,"operation_failed")}}write(value){let parentDir=dirname6(this.filePath);mkdirSync4(parentDir,{recursive:!0});let temporaryPath=`${this.filePath}.tmp-${process.pid}-${randomBytes2(4).toString("hex")}`;try{writeFileSync4(temporaryPath,"",{encoding:"utf8",flag:"wx",mode:384}),chmodSync2(temporaryPath,384)}catch{throw tryDeleteFile(temporaryPath),new CredentialStoreUnavailableError(this.backend,"operation_failed")}if((this.options.platform??process.platform)==="win32"){let aclHardened=!1;try{aclHardened=(this.options.windowsAclHardener??hardenWindowsCredentialFileAcl)(temporaryPath)}catch{aclHardened=!1}if(!aclHardened)try{(this.options.onSecurityWarning??defaultFileStoreSecurityWarning)("credential_acl_unverified")}catch{}}try{writeFileSync4(temporaryPath,`${JSON.stringify(value,null,2)}
|
|
2298
2296
|
`,{encoding:"utf8",flag:"r+"}),renameSync2(temporaryPath,this.filePath)}catch{throw tryDeleteFile(temporaryPath),new CredentialStoreUnavailableError(this.backend,"operation_failed")}}delete(){tryDeleteFile(this.filePath)}},FileCredentialBackendPreference=class{filePath;constructor(filePath){this.filePath=filePath}isFilePreferred(){try{return JSON.parse(readFileSync8(this.filePath,"utf8")).preferred_backend==="file"}catch{return!1}}preferFile(){let parentDir=dirname6(this.filePath);mkdirSync4(parentDir,{recursive:!0});let temporaryPath=`${this.filePath}.tmp-${process.pid}-${randomBytes2(4).toString("hex")}`;try{writeFileSync4(temporaryPath,`${JSON.stringify({preferred_backend:"file",reason:"secure_cleanup_failed"},null,2)}
|
|
2299
|
-
`,{encoding:"utf8",flag:"wx",mode:384}),chmodSync2(temporaryPath,384),renameSync2(temporaryPath,this.filePath)}catch{throw tryDeleteFile(temporaryPath),new CredentialStoreUnavailableError("file","operation_failed")}}clear(){tryDeleteFile(this.filePath)}};function readCredentialsWithFallback(options){if(options.backendPreference?.isFilePreferred()){let preferredCredentials=options.legacyStore.read();if(preferredCredentials)return{credentials:preferredCredentials,backend:options.legacyStore.backend,warnings:["credential_secure_store_unavailable"]};try{options.backendPreference.clear()}catch{}}let secureFailure;if(options.secureStore)try{let secureCredentials=options.secureStore.read();if(secureCredentials)return{credentials:secureCredentials,backend:options.secureStore.backend,warnings:[]}}catch(error){secureFailure=error}try{let legacyCredentials=options.legacyStore.read();if(legacyCredentials)return{credentials:legacyCredentials,backend:options.legacyStore.backend,warnings:deduplicateWarnings([secureFailure?classifySecureStoreFailureWithLegacyFallback(secureFailure):"credential_migration_pending"])}}catch(error){throw error instanceof CredentialStoreCorruptedError||error instanceof CredentialStoreUnavailableError?error:new CredentialStoreUnavailableError("file","operation_failed")}if(secureFailure)throw secureFailure instanceof CredentialStoreCorruptedError||secureFailure instanceof CredentialStoreUnavailableError?secureFailure:new CredentialStoreUnavailableError(options.secureStore?.backend??"file","operation_failed");return{credentials:null,backend:"none",warnings:[]}}function writeCredentialsWithFallback(value,options){if(options.secureStore)try{options.secureStore.write(value);let verified=options.secureStore.read();if(!verified||!credentialsEqual(value,verified))throw new CredentialStoreCorruptedError(options.secureStore.backend);try{options.legacyStore.delete();try{options.backendPreference?.clear()}catch{}return{backend:options.secureStore.backend,warnings:[],legacyDeleted:!0}}catch{return{backend:options.secureStore.backend,warnings:["credential_migration_failed"],legacyDeleted:!1}}}catch{options.legacyStore.write(toFileFallbackCredentials(value));let secureDeleted=!1;try{options.secureStore.delete(),secureDeleted=!0}catch{secureDeleted=!1}if(secureDeleted)try{options.backendPreference?.clear()}catch{}else{if(!options.backendPreference)throw new CredentialStoreUnavailableError(options.secureStore.backend,"operation_failed");options.backendPreference.preferFile()}return{backend:options.legacyStore.backend,warnings:["credential_secure_store_unavailable"],legacyDeleted:!1}}return options.legacyStore.write(toFileFallbackCredentials(value)),{backend:options.legacyStore.backend,warnings:[],legacyDeleted:!1}}function migrateLegacyCredentials(options){let legacyCredentials;try{legacyCredentials=options.legacyStore.read()}catch{return{status:"failed",backend:"file",warnings:["credential_migration_failed"],legacyDeleted:!1}}if(!legacyCredentials){if(!options.secureStore)return{status:"not_needed",backend:"none",warnings:[],legacyDeleted:!1};try{return{status:"not_needed",backend:options.secureStore.read()?options.secureStore.backend:"none",warnings:[],legacyDeleted:!1}}catch(error){return{status:"failed",backend:options.secureStore.backend,warnings:[classifySecureStoreFailure(error)],legacyDeleted:!1}}}if(!options.secureStore)return{status:"failed",backend:"file",warnings:["
|
|
2297
|
+
`,{encoding:"utf8",flag:"wx",mode:384}),chmodSync2(temporaryPath,384),renameSync2(temporaryPath,this.filePath)}catch{throw tryDeleteFile(temporaryPath),new CredentialStoreUnavailableError("file","operation_failed")}}clear(){tryDeleteFile(this.filePath)}};function readCredentialsWithFallback(options){if(options.backendPreference?.isFilePreferred()){let preferredCredentials=options.legacyStore.read();if(preferredCredentials)return{credentials:preferredCredentials,backend:options.legacyStore.backend,warnings:["credential_secure_store_unavailable"]};try{options.backendPreference.clear()}catch{}}let secureFailure;if(options.secureStore)try{let secureCredentials=options.secureStore.read();if(secureCredentials)return{credentials:secureCredentials,backend:options.secureStore.backend,warnings:[]}}catch(error){secureFailure=error}try{let legacyCredentials=options.legacyStore.read();if(legacyCredentials)return{credentials:legacyCredentials,backend:options.legacyStore.backend,warnings:options.secureStore?deduplicateWarnings([secureFailure?classifySecureStoreFailureWithLegacyFallback(secureFailure):"credential_migration_pending"]):requiresFileCredentialProjection(legacyCredentials)?["credential_migration_pending"]:[]}}catch(error){throw error instanceof CredentialStoreCorruptedError||error instanceof CredentialStoreUnavailableError?error:new CredentialStoreUnavailableError("file","operation_failed")}if(secureFailure)throw secureFailure instanceof CredentialStoreCorruptedError||secureFailure instanceof CredentialStoreUnavailableError?secureFailure:new CredentialStoreUnavailableError(options.secureStore?.backend??"file","operation_failed");return{credentials:null,backend:"none",warnings:[]}}function writeCredentialsWithFallback(value,options){if(options.secureStore)try{options.secureStore.write(value);let verified=options.secureStore.read();if(!verified||!credentialsEqual(value,verified))throw new CredentialStoreCorruptedError(options.secureStore.backend);try{options.legacyStore.delete();try{options.backendPreference?.clear()}catch{}return{backend:options.secureStore.backend,warnings:[],legacyDeleted:!0}}catch{return{backend:options.secureStore.backend,warnings:["credential_migration_failed"],legacyDeleted:!1}}}catch{options.legacyStore.write(toFileFallbackCredentials(value));let secureDeleted=!1;try{options.secureStore.delete(),secureDeleted=!0}catch{secureDeleted=!1}if(secureDeleted)try{options.backendPreference?.clear()}catch{}else{if(!options.backendPreference)throw new CredentialStoreUnavailableError(options.secureStore.backend,"operation_failed");options.backendPreference.preferFile()}return{backend:options.legacyStore.backend,warnings:["credential_secure_store_unavailable"],legacyDeleted:!1}}return options.legacyStore.write(toFileFallbackCredentials(value)),{backend:options.legacyStore.backend,warnings:[],legacyDeleted:!1}}function migrateLegacyCredentials(options){let legacyCredentials;try{legacyCredentials=options.legacyStore.read()}catch{return{status:"failed",backend:"file",warnings:["credential_migration_failed"],legacyDeleted:!1}}if(!legacyCredentials){if(!options.secureStore)return{status:"not_needed",backend:"none",warnings:[],legacyDeleted:!1};try{return{status:"not_needed",backend:options.secureStore.read()?options.secureStore.backend:"none",warnings:[],legacyDeleted:!1}}catch(error){return{status:"failed",backend:options.secureStore.backend,warnings:[classifySecureStoreFailure(error)],legacyDeleted:!1}}}if(!options.secureStore){if(requiresFileCredentialProjection(legacyCredentials)){let projectedCredentials=toFileFallbackCredentials(legacyCredentials);try{options.legacyStore.write(projectedCredentials);let verified=options.legacyStore.read();if(!verified||!credentialsEqual(projectedCredentials,verified))throw new CredentialStoreCorruptedError("file");return{status:"migrated",backend:"file",warnings:[],legacyDeleted:!1}}catch{try{options.legacyStore.write(legacyCredentials)}catch{}return{status:"failed",backend:"file",warnings:["credential_migration_failed"],legacyDeleted:!1}}}return{status:"not_needed",backend:"file",warnings:[],legacyDeleted:!1}}if(!options.backendPreference?.isFilePreferred())try{if(options.secureStore.read())try{options.legacyStore.delete();try{options.backendPreference?.clear()}catch{}return{status:"not_needed",backend:options.secureStore.backend,warnings:[],legacyDeleted:!0}}catch{return{status:"failed",backend:options.secureStore.backend,warnings:["credential_migration_failed"],legacyDeleted:!1}}}catch(error){if(!(error instanceof CredentialStoreCorruptedError))return{status:"failed",backend:options.secureStore.backend,warnings:["credential_secure_store_unavailable"],legacyDeleted:!1}}try{options.secureStore.write(legacyCredentials);let verified=options.secureStore.read();if(!verified||!credentialsEqual(legacyCredentials,verified))throw new CredentialStoreCorruptedError(options.secureStore.backend);options.legacyStore.delete();try{options.backendPreference?.clear()}catch{}return{status:"migrated",backend:options.secureStore.backend,warnings:[],legacyDeleted:!0}}catch{try{options.secureStore.delete()}catch{}return{status:"failed",backend:options.secureStore.backend,warnings:["credential_migration_failed"],legacyDeleted:!1}}}function toFileFallbackCredentials(value){let{exchange_subject_token:_subjectToken,exchange_subject_token_type:_subjectTokenType,mode_expires_at:_modeExpiresAt,...safeValue}=value;return safeValue.credential_mode==="pat_exchange"&&(safeValue.credential_mode="seeded_token"),safeValue}function requiresFileCredentialProjection(value){return!!(value.exchange_subject_token||value.exchange_subject_token_type||value.mode_expires_at||value.credential_mode==="pat_exchange")}function credentialsEqual(left,right){return JSON.stringify(left)===JSON.stringify(right)}function classifySecureStoreFailure(error){return error instanceof CredentialStoreCorruptedError?"credential_store_corrupted":"credential_secure_store_unavailable"}function classifySecureStoreFailureWithLegacyFallback(error){return error instanceof CredentialStoreCorruptedError?"credential_migration_failed":"credential_secure_store_unavailable"}function deduplicateWarnings(warnings){return[...new Set(warnings)]}var WINDOWS_HARDEN_ACL_SCRIPT=String.raw`
|
|
2300
2298
|
$ErrorActionPreference = 'Stop'
|
|
2301
2299
|
$credentialPath = $env:VOOBASE_CREDENTIAL_PATH
|
|
2302
2300
|
if ([string]::IsNullOrWhiteSpace($credentialPath)) { throw 'credential path missing' }
|
|
@@ -2317,9 +2315,9 @@ foreach ($sidValue in @($currentSid.Value, 'S-1-5-18', 'S-1-5-32-544')) {
|
|
|
2317
2315
|
[void]$acl.AddAccessRule($rule)
|
|
2318
2316
|
}
|
|
2319
2317
|
Set-Acl -LiteralPath $credentialPath -AclObject $acl
|
|
2320
|
-
`;function hardenWindowsCredentialFileAcl(filePath){let result=
|
|
2318
|
+
`;function hardenWindowsCredentialFileAcl(filePath){let result=spawnSync3(resolveWindowsPowerShellExecutable(),["-NoLogo","-NoProfile","-NonInteractive","-Command",WINDOWS_HARDEN_ACL_SCRIPT],{encoding:"utf8",env:{...process.env,VOOBASE_CREDENTIAL_PATH:filePath},shell:!1,timeout:8e3,windowsHide:!0,maxBuffer:2097152});return!result.error&&result.status===0}function defaultFileStoreSecurityWarning(code2){process.stderr.write(`[${code2}] Windows \u51ED\u636E\u6587\u4EF6\u5DF2\u5199\u5165\uFF0C\u4F46\u672A\u80FD\u786E\u8BA4\u5F53\u524D\u7528\u6237\u4E13\u5C5E ACL\uFF1B\u672C\u6B21\u767B\u5F55\u5C06\u7EE7\u7EED\u3002
|
|
2321
2319
|
\u5EFA\u8BAE\uFF1A\u8FD0\u884C \`platform diagnostics credentials\` \u67E5\u770B\u6743\u9650\u72B6\u6001\u3002
|
|
2322
|
-
`)}function createCredentialStore(options){let platform=options.platform??process.platform
|
|
2320
|
+
`)}function createCredentialStore(options){let platform=options.platform??process.platform;return platform==="win32"?new WindowsDpapiCredentialStore({blobPath:join5(options.stateDir,"credentials.dpapi"),service:resolveCredentialStoreService(options.profileName,options.stateDir)}):new FileCredentialStore(join5(options.stateDir,"credentials.json"),{platform})}function resolveCredentialStoreService(profileName,stateDir){let stateIdentity=createHash4("sha256").update(resolve6(stateDir)).digest("hex").slice(0,16);return`cn.voobase.platform-cli.${sanitizeProfileName(profileName)}.${stateIdentity}`}function parseStoredCredentials(serialized,backend){try{let value=JSON.parse(serialized);if(!value||typeof value!="object"||typeof value.access_token!="string"||typeof value.issued_at!="string")throw new Error("invalid credential shape");return value}catch{throw new CredentialStoreCorruptedError(backend)}}function sanitizeProfileName(profileName){return profileName.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu,"-")||"default"}function tryDeleteFile(filePath){try{unlinkSync3(filePath)}catch(error){if(error.code!=="ENOENT")throw new CredentialStoreUnavailableError("file","operation_failed")}}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,credentialOriginBackend=Symbol("credentialOriginBackend"),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(resolve20=>{setTimeout(resolve20,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>
|
|
2323
2321
|
<html lang="zh-CN">
|
|
2324
2322
|
<head>
|
|
2325
2323
|
<meta charset="utf-8" />
|
|
@@ -2468,7 +2466,7 @@ ${routeMarker}`)}return next}function buildAuthDebugPageSource(){return["export
|
|
|
2468
2466
|
`)}function buildDbDebugPageSource(){return["export function renderDbDebugPage() {"," return `<!doctype html>",'<html lang="zh-CN">'," <head>",' <meta charset="utf-8" />',' <meta name="viewport" content="width=device-width, initial-scale=1" />'," <title>DB Debug</title>"," <style>",' :root { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color-scheme: light; }'," body { margin: 0; background: #f8fafc; color: #0f172a; }"," main { width: min(1080px, calc(100vw - 32px)); margin: 40px auto; padding: 32px; border-radius: 24px; background: #fff; border: 1px solid #e2e8f0; box-shadow: 0 24px 80px rgba(15,23,42,.08); }"," h1 { margin: 0 0 12px; font-size: 32px; }"," p { margin: 0 0 12px; color: #475569; line-height: 1.7; }"," .status { margin-top: 16px; padding: 12px 14px; border-radius: 14px; border: 1px solid #e2e8f0; background: #f8fafc; color: #334155; }"," .status-neutral { background: #f8fafc; border-color: #e2e8f0; color: #334155; }"," .status-success { background: #ecfdf5; border-color: #86efac; color: #166534; }"," .status-warning { background: #fffbeb; border-color: #fcd34d; color: #92400e; }"," .status-error { background: #fff1f2; border-color: #fecdd3; color: #be123c; }"," .grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: 20px; }"," .card { border: 1px solid #e2e8f0; border-radius: 16px; padding: 16px; }"," .label { font-size: 12px; color: #64748b; }"," .value { margin-top: 8px; font-weight: 600; word-break: break-word; }"," .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }"," .actions { display: flex; gap: 12px; margin-top: 20px; flex-wrap: wrap; }"," button, a { border: 0; border-radius: 12px; padding: 12px 16px; font: inherit; font-weight: 600; cursor: pointer; background: #0f172a; color: #fff; text-decoration: none; display: inline-flex; align-items: center; }"," button.secondary, a.secondary { background: #fff; color: #0f172a; border: 1px solid #cbd5e1; }"," ul { margin: 0; padding-left: 20px; color: #334155; }"," li { margin: 8px 0; }"," pre { margin: 0; white-space: pre-wrap; word-break: break-word; }"," @media (max-width: 720px) { .grid { grid-template-columns: 1fr; } }"," </style>"," </head>"," <body>"," <main>"," <h1>DB \u6700\u5C0F\u8054\u8C03\u9875</h1>"," <p>\u8FD9\u4E2A\u9875\u9762\u53EA\u7528\u4E8E\u672C\u5730\u6216 preview \u8054\u8C03\u5E73\u53F0 DB \u7ED1\u5B9A\uFF0C\u4E0D\u5C5E\u4E8E\u6B63\u5F0F\u4E1A\u52A1\u9875\u9762\u3002\u5B83\u4F1A\u8BFB\u53D6\u5F53\u524D\u5E94\u7528\u7684 DB \u7ED1\u5B9A\u4E0A\u4E0B\u6587\uFF0C\u5E76\u63D0\u793A\u4F60\u7EE7\u7EED\u4F7F\u7528 `platform db` \u548C `platform dev --remote-bindings` \u9A8C\u8BC1\u771F\u5B9E\u8868\u7ED3\u6784\u4E0E\u67E5\u8BE2\u3002</p>",' <div class="status status-neutral" id="status">\u6B63\u5728\u8BFB\u53D6 DB \u7ED1\u5B9A\u4E0A\u4E0B\u6587...</div>',' <div class="grid">',' <div class="card"><div class="label">\u5F53\u524D\u79DF\u6237 / \u5E94\u7528 / \u73AF\u5883</div><div class="value mono" id="identity">-</div></div>',' <div class="card"><div class="label">DATABASE_URL \u6CE8\u5165\u72B6\u6001</div><div class="value mono" id="db-ready">-</div></div>',' <div class="card"><div class="label">DATABASE_SCHEMA</div><div class="value mono" id="db-schema">-</div></div>',' <div class="card"><div class="label">Capability Version</div><div class="value mono" id="db-capability">-</div></div>'," </div>",' <div class="card" style="margin-top:16px"><div class="label">\u540E\u7AEF\u8FD4\u56DE\u7684 DB \u4E0A\u4E0B\u6587</div><div class="value"><pre id="db-context">-</pre></div></div>',' <div class="card" style="margin-top:16px"><div class="label">\u4E0B\u4E00\u6B65\u5EFA\u8BAE</div><div class="value"><ul><li>\u5148\u8DD1 <code>platform db status</code> \u770B binding / schema / migration\u3002</li><li>\u518D\u8DD1 <code>platform db tables</code> \u6216 <code>platform db query --sql "SELECT ..."</code> \u786E\u8BA4\u771F\u5B9E\u8868\u7ED3\u6784\u3002</li><li>\u5982\u679C\u4F60\u8981\u9A8C\u8BC1\u5E94\u7528\u4EE3\u7801\u76F4\u8FDE DB\uFF0C\u4F7F\u7528 <code>platform dev --remote-bindings</code>\uFF0C\u4E0D\u8981\u53EA\u8DD1\u666E\u901A <code>platform dev</code>\u3002</li></ul></div></div>',' <div class="actions">',' <button id="refresh" type="button">\u5237\u65B0\u72B6\u6001</button>',' <a class="secondary" href="/app">\u8FD4\u56DE\u4E1A\u52A1\u9875</a>'," </div>"," </main>",' <script type="module">'," import { getRuntimeStatusFromError, applyRuntimeStatus } from '/assets/platform-runtime.js';"," const statusEl = document.getElementById('status');"," const identityEl = document.getElementById('identity');"," const dbReadyEl = document.getElementById('db-ready');"," const dbSchemaEl = document.getElementById('db-schema');"," const dbCapabilityEl = document.getElementById('db-capability');"," const dbContextEl = document.getElementById('db-context');"," const refreshEl = document.getElementById('refresh');"," async function refreshDbDebug() {"," applyRuntimeStatus(statusEl, { tone: 'neutral', message: '\u6B63\u5728\u8BFB\u53D6 DB \u8C03\u8BD5\u72B6\u6001...' });"," try {"," const [context, dbContext] = await Promise.all(["," fetch('/api/me').then((item) => item.json()).catch(() => null),"," fetch('/api/debug/db-context').then((item) => item.json()).catch(() => null)"," ]);"," identityEl.textContent = [dbContext?.tenant_id || context?.tenant_id || '-', dbContext?.app_id || context?.app_id || '-', dbContext?.env || context?.env || '-'].join(' / ');"," dbReadyEl.textContent = dbContext?.database_ready ? 'ready' : 'not_injected';"," dbSchemaEl.textContent = dbContext?.database_schema || '-';"," dbCapabilityEl.textContent = dbContext?.database_capability_version || '-';"," dbContextEl.textContent = dbContext ? JSON.stringify(dbContext, null, 2) : '-';"," applyRuntimeStatus(statusEl, dbContext?.database_ready"," ? { tone: 'success', message: '\u5DF2\u68C0\u6D4B\u5230 DATABASE_URL\u3002\u4E0B\u4E00\u6B65\u8BF7\u7528 platform db tables/query \u9A8C\u8BC1\u771F\u5B9E\u8868\u7ED3\u6784\u3002' }"," : { tone: 'warning', message: '\u5F53\u524D\u8FD8\u6CA1\u68C0\u6D4B\u5230 DATABASE_URL\u3002\u82E5\u8981\u8054\u8C03\u5E73\u53F0 DB\uFF0C\u8BF7\u6539\u7528 platform dev --remote-bindings\u3002' });"," } catch (error) {"," applyRuntimeStatus(statusEl, getRuntimeStatusFromError(error, 'DB \u8C03\u8BD5\u9875\u521D\u59CB\u5316\u5931\u8D25\u3002'));"," }"," }"," refreshEl.addEventListener('click', () => { void refreshDbDebug(); });"," void refreshDbDebug();"," </script>"," </body>","</html>`;","}",""].join(`
|
|
2469
2467
|
`)}function resolveWorkspaceDevTarget(target){if(!target)return null;let workspaceRoot=findWorkspaceRoot();return{command:`corepack pnpm --filter ${target.startsWith("@platform/")?target:`@platform/${target}`} dev`,cwd:workspaceRoot}}function buildDevEnvironment(binding,runtimeBindings={}){return{...process.env,PLATFORM_ACTIVE_TENANT_ID:binding?.tenant_id??"",PLATFORM_ACTIVE_APP_ID:binding?.app_id??"",PLATFORM_ACTIVE_ENV:binding?.env??"",PLATFORM_ACTIVE_APP_NAME:binding?.app_name??"",APP_ID:process.env.APP_ID??binding?.app_id??"",APP_ENV:process.env.APP_ENV??binding?.env??"preview",TENANT_ID:process.env.TENANT_ID??runtimeBindings.TENANT_ID??binding?.tenant_id??"",PUBLIC_APP_BASE_URL:process.env.PUBLIC_APP_BASE_URL??runtimeBindings.PUBLIC_APP_BASE_URL??"",CONTROL_API_BASE_URL:process.env.CONTROL_API_BASE_URL??runtimeBindings.CONTROL_API_BASE_URL??DEFAULT_CONTROL_API_BASE_URL,DATABASE_URL:process.env.DATABASE_URL??runtimeBindings.DATABASE_URL??"",DATABASE_SCHEMA:process.env.DATABASE_SCHEMA??runtimeBindings.DATABASE_SCHEMA??"",DATABASE_MIGRATOR_ROLE:process.env.DATABASE_MIGRATOR_ROLE??runtimeBindings.DATABASE_MIGRATOR_ROLE??"",DATABASE_RUNTIME_ROLE:process.env.DATABASE_RUNTIME_ROLE??runtimeBindings.DATABASE_RUNTIME_ROLE??"",DATABASE_CAPABILITY_VERSION:process.env.DATABASE_CAPABILITY_VERSION??runtimeBindings.DATABASE_CAPABILITY_VERSION??""}}function detectLocalDependencyInstallPlan(appDir){let packageJsonPath=join7(appDir,"package.json"),nodeModulesPath=join7(appDir,"node_modules");if(!existsSync11(packageJsonPath))return null;let packageJson=JSON.parse(readFileSync10(packageJsonPath,"utf8")),declaredPackageManager=typeof packageJson.packageManager=="string"?packageJson.packageManager.trim():"",declaredPackageManagerName=declaredPackageManager.includes("@")?declaredPackageManager.slice(0,declaredPackageManager.lastIndexOf("@")):declaredPackageManager,lockfiles=["package-lock.json","pnpm-lock.yaml","yarn.lock"].filter(fileName=>existsSync11(join7(appDir,fileName)));if(lockfiles.length>1)throw new Error(`[conflicting_lockfiles] \u68C0\u6D4B\u5230\u591A\u4E2A\u5305\u7BA1\u7406\u5668 lockfile\uFF1A${lockfiles.join(", ")}\u3002\u8BF7\u53EA\u4FDD\u7559\u9879\u76EE\u58F0\u660E\u7684\u5305\u7BA1\u7406\u5668 lockfile \u540E\u91CD\u8BD5\u3002`);let lockfilePackageManagers={"package-lock.json":"npm","pnpm-lock.yaml":"pnpm","yarn.lock":"yarn"},lockfile=lockfiles[0];if(declaredPackageManagerName&&lockfile&&lockfilePackageManagers[lockfile]!==declaredPackageManagerName)throw new Error(`[package_manager_lock_mismatch] packageManager ${declaredPackageManager} \u4E0E ${lockfile} \u4E0D\u5339\u914D\u3002\u8BF7\u4FDD\u7559\u4E0E packageManager \u4E00\u81F4\u7684 lockfile \u540E\u91CD\u8BD5\u3002`);return existsSync11(nodeModulesPath)?null:lockfile==="package-lock.json"?declaredPackageManagerName==="npm"&&declaredPackageManager?{command:"npx",args:["--yes",declaredPackageManager,"ci","--no-audit","--no-fund"],lockfile:"package-lock.json"}:{command:"npm",args:["ci","--no-audit","--no-fund"],lockfile:"package-lock.json"}:lockfile==="pnpm-lock.yaml"?{command:"corepack",args:["pnpm","install","--frozen-lockfile"],lockfile:"pnpm-lock.yaml"}:lockfile==="yarn.lock"?{command:"yarn",args:["install","--frozen-lockfile"],lockfile:"yarn.lock"}:null}function detectRequestedRemoteBindings(startDir=process.cwd()){let capabilities=new Set;try{let appRoot=findAppRoot(startDir);workspaceHasEffectiveDbMigration(appRoot)&&capabilities.add("db")}catch{return[]}return[...capabilities]}function templatePrefersPlatformCapabilityBindings(templateKey){return templateKey==="frontend-app-vite"||templateKey==="backend-app-node"}function recommendDevCommandForTemplate(templateKey,options={}){return(options.requestedRemoteBindings??[]).includes("db")?"platform dev --remote-bindings=db":templatePrefersPlatformCapabilityBindings(templateKey)?"platform dev --remote-bindings":null}function workspaceHasEffectiveDbMigration(appRoot){let migrationsDir=join7(appRoot,"resources","db","migrations");if(!existsSync11(migrationsDir)||!statSync2(migrationsDir).isDirectory())return!1;for(let entry of readdirSync3(migrationsDir,{withFileTypes:!0})){if(!entry.isFile())continue;if(readFileSync10(join7(migrationsDir,entry.name),"utf8").split(`
|
|
2470
2468
|
`).map(line=>line.replace(/--.*$/,"").trim()).filter(Boolean).join(`
|
|
2471
|
-
`).trim().length>0)return!0}return!1}async function resolveAvailableLocalDevPort(preferredPort,options={}){let host=options.host;return await canBindPort(preferredPort,host)?{port:preferredPort,reusedPreferred:!0}:{port:await allocateEphemeralPort(host),reusedPreferred:!1}}async function canBindPort(port,host){return new Promise(resolve20=>{let server=createNetServer(),finish=available=>{server.removeAllListeners(),resolve20(available)};server.once("error",()=>{finish(!1)});let onListening=()=>{server.close(()=>finish(!0))};if(host){server.listen(port,host,onListening);return}server.listen(port,onListening)})}async function allocateEphemeralPort(host){return new Promise((resolve20,reject)=>{let server=createNetServer();server.once("error",error=>{reject(error instanceof Error?error:new Error(String(error)))});let onListening=()=>{let address=server.address();if(!address||typeof address=="string"){server.close(()=>reject(new Error("\u65E0\u6CD5\u4E3A\u672C\u5730 dev \u5206\u914D\u56DE\u9000\u7AEF\u53E3\u3002")));return}let{port}=address;server.close(error=>{if(error){reject(error);return}resolve20(port)})};if(host){server.listen(0,host,onListening);return}server.listen(0,onListening)})}function collectDevPreflight(startDir=process.cwd(),target,runtimeBindings={}){let{manifest,directory}=readAppManifest(startDir),linked=readBinding(startDir);if(!linked?.binding.tenant_id||!linked.binding.app_id){let sourceContextPath=join7(directory,SOURCE_CONTEXT_FILE);throw new Error(existsSync11(sourceContextPath)?"\u5F53\u524D\u9879\u76EE\u672A\u7ED1\u5B9A tenant/app/env\u3002\u4F18\u5148\u5EFA\u8BAE\u6267\u884C `platform app create ...` \u6216 `platform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>` \u83B7\u53D6\u4E00\u4E2A\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1B\u82E5\u4F60\u8981\u4FEE\u590D\u5F53\u524D\u76EE\u5F55\uFF0C\u518D\u624B\u52A8\u6267\u884C `platform link --tenant <tenant-id> --app <app-id> --env preview`\u3002":"\u5F53\u524D\u76EE\u5F55\u5DF2\u68C0\u6D4B\u5230 `app.yaml`\uFF0C\u4F46\u7F3A\u5C11 `.platform/source-context.json`\uFF0C\u770B\u8D77\u6765\u50CF\u4E00\u4E2A\u5DF2\u8FC1\u79FB\u6216\u672A\u91CD\u65B0\u7ED1\u5B9A\u7684\u5E94\u7528\u5DE5\u7A0B\u3002\u8BF7\u6267\u884C `platform link --tenant <tenant-id> --app <app-id> --env preview` \u91CD\u65B0\u7ED1\u5B9A\u5F53\u524D\u76EE\u5F55\u3002")}let sourceContext=readSourceContext(startDir)?.sourceContext,workspaceTarget=resolveWorkspaceDevTarget(target),command=workspaceTarget?.command??manifest.entry.command,cwd=workspaceTarget?.cwd??directory,env=buildDevEnvironment(linked.binding,runtimeBindings),port=Number(env.PORT||manifest.entry.port||3e3);env.PUBLIC_APP_BASE_URL||(env.PUBLIC_APP_BASE_URL=`http://127.0.0.1:${port}`);let healthPath=manifest.entry.health_check||"/healthz",resolvedTemplateKey=typeof sourceContext?.template_key=="string"&&sourceContext.template_key.trim().length>0?sourceContext.template_key.trim():manifest.template_key,devCommandAnalysis=analyzeDevCommand(command,cwd),previewAddressMayChange=!manifest.dev.auto_restart&&devCommandAnalysis.portMayChange,warnings=["\u5F53\u524D\u9ED8\u8BA4\u8D70\u8F7B\u91CF\u5F00\u53D1\u6A21\u5F0F\uFF1A\u672C\u5730\u5F00\u53D1\u4E0D\u8981\u6C42 registry\u3001kind\u3001ingress-nginx \u6216 build-runner\u3002",`\u5F53\u524D\u542F\u52A8\u547D\u4EE4\u6765\u81EA app.yaml \u7684 entry.command\uFF1A${command}`];return manifest.dev.auto_restart?warnings.push("\u5F53\u524D app.yaml \u5DF2\u914D\u7F6E `dev.auto_restart: true`\uFF1BCLI \u4F1A\u5728\u68C0\u6D4B\u5230\u6E90\u7801\u53D8\u66F4\u540E\u81EA\u52A8\u91CD\u542F dev \u5B50\u8FDB\u7A0B\u3002"):devCommandAnalysis.managedByCommand?warnings.push(devCommandAnalysis.message):warnings.push("\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"),env.DATABASE_URL||warnings.push("\u672A\u68C0\u6D4B\u5230 DATABASE_URL\uFF1B\u672C\u5730\u6A21\u677F\u63A5\u53E3\u548C\u9875\u9762\u5F00\u53D1\u4ECD\u53EF\u7EE7\u7EED\u3002\u82E5\u4F60\u9700\u8981\u8054\u8C03\u5E73\u53F0 DB\uFF0C\u518D\u6267\u884C `platform dev --remote-bindings` \u6216\u624B\u52A8\u8BBE\u7F6E\u672C\u5730\u73AF\u5883\u53D8\u91CF\u3002"),templatePrefersPlatformCapabilityBindings(resolvedTemplateKey)&&warnings.push("\u5F53\u524D\u5B98\u65B9\u6A21\u677F\u9ED8\u8BA4\u5E26 Auth / CMS / Data Form \u793A\u4F8B\u9875\u3002\u82E5\u4F60\u8981\u8054\u8C03\u8FD9\u4E9B\u771F\u5B9E\u5E73\u53F0\u80FD\u529B\uFF0C\u5EFA\u8BAE\u76F4\u63A5\u6267\u884C `platform dev --remote-bindings`\u3002"),!process.env.PUBLIC_APP_BASE_URL&&!runtimeBindings.PUBLIC_APP_BASE_URL&&warnings.push(`\u672A\u663E\u5F0F\u914D\u7F6E PUBLIC_APP_BASE_URL\uFF1B\u672C\u5730 dev \u5DF2\u4E34\u65F6\u56DE\u9000\u4E3A ${env.PUBLIC_APP_BASE_URL}\u3002`),resolvedTemplateKey&&resolvedTemplateKey!=="frontend-app-vite"&&resolvedTemplateKey!=="backend-app-node"&&warnings.push(`\u5F53\u524D\u6A21\u677F\u4E3A ${resolvedTemplateKey}\uFF0C\u8BF7\u786E\u8BA4\u5165\u53E3\u547D\u4EE4\u4E0E\u5065\u5EB7\u68C0\u67E5\u8DEF\u5F84\u5DF2\u7ECF\u548C app.yaml \u5BF9\u9F50\u3002`),{binding:linked.binding,manifest,templateKey:resolvedTemplateKey,directory,command,cwd,env,healthcheckUrl:`http://localhost:${port}${healthPath}`,previewAddressMayChange,warnings}}function analyzeDevCommand(command,cwd){if(/(--watch|\bwatch\b|nodemon|vite|next dev|webpack serve|tsx watch)/iu.test(command))return{managedByCommand:!0,portMayChange:/\bvite\b/iu.test(command),message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u5DF2\u5305\u542B watch / \u70ED\u66F4\u65B0\u80FD\u529B\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u989D\u5916\u63A5\u7BA1\u81EA\u52A8\u91CD\u542F\u3002"};let npmScriptMatch=command.trim().match(/^(?:npm|pnpm|yarn)\s+run\s+([a-zA-Z0-9:_-]+)|^corepack\s+pnpm\s+run\s+([a-zA-Z0-9:_-]+)/u),scriptName=npmScriptMatch?.[1]??npmScriptMatch?.[2];if(!scriptName)return{managedByCommand:!1,portMayChange:!1,message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"};let packageJsonPath=join7(cwd,"package.json");if(!existsSync11(packageJsonPath))return{managedByCommand:!1,portMayChange:!1,message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"};try{let scriptCommand=JSON.parse(readFileSync10(packageJsonPath,"utf8")).scripts?.[scriptName];if(typeof scriptCommand=="string"&&/(--watch|\bwatch\b|nodemon|vite|next dev|webpack serve|tsx watch|scripts\/dev\.mjs|scripts\\dev\.mjs)/iu.test(scriptCommand))return{managedByCommand:!0,portMayChange:/\bvite\b|scripts\/dev\.mjs|scripts\\dev\.mjs/iu.test(scriptCommand),message:scriptCommand.includes("scripts/dev.mjs")?"\u5F53\u524D\u547D\u4EE4\u901A\u8FC7\u6A21\u677F\u81EA\u5E26\u7684\u672C\u5730 dev \u7F16\u6392\u811A\u672C\u542F\u52A8\uFF1B\u524D\u7AEF\u70ED\u66F4\u65B0\u4E0E\u670D\u52A1\u7AEF\u81EA\u52A8\u91CD\u542F\u7531\u6A21\u677F\u81EA\u5DF1\u7BA1\u7406\uFF0CCLI \u4E0D\u4F1A\u989D\u5916\u63A5\u7BA1\u81EA\u52A8\u91CD\u542F\u3002":"\u5F53\u524D\u547D\u4EE4\u901A\u8FC7 package.json script \u81EA\u5E26 watch / \u70ED\u66F4\u65B0\u80FD\u529B\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u989D\u5916\u63A5\u7BA1\u81EA\u52A8\u91CD\u542F\u3002"}}catch{return{managedByCommand:!1,portMayChange:!1,message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"}}return{managedByCommand:!1,portMayChange:!1,message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"}}async function runAppLibraryCommand(args,deps={}){let subcommand=args.rest[0];if(hasHelpFlag2(args)||args.rest.length===0||subcommand==="help"){printAppLibraryHelp();return}let sdk=deps.sdk,tenantId=deps.tenantId;if(!sdk||!tenantId){let credentials=await loadStoredCredentialsEnsuringFresh();if(!credentials)throw new Error("\u672A\u627E\u5230\u672C\u5730\u51ED\u636E\uFF0C\u8BF7\u5148\u6267\u884C `platform login`\u3002");if(tenantId=deps.tenantId??resolveTenantId(args),!tenantId)throw new Error("`platform app-library` \u9700\u8981 tenant \u4E0A\u4E0B\u6587\u3002\u8BF7\u5148\u5728\u5F53\u524D\u9879\u76EE\u7ED1\u5B9A tenant/app\uFF0C\u6216\u663E\u5F0F\u4F20\u5165 `--tenant`\u3002");sdk=createControlApiSdk({accessToken:selectApiToken(credentials),tenantId,capability:"dashboard",requestClass:"control"})}switch(subcommand){case"list":await runList(args,sdk);return;case"search":await runSearch(args,sdk);return;case"inspect":await runInspect(args,sdk);return;case"source":await runSource(args,sdk);return;case"config":await runConfig(args);return;case"open":await runOpen(args,deps);return;case"checkout":await runCheckout(args,sdk);return;case"create":await runCreate(args,sdk);return;case"update":await runUpdate(args,sdk);return;case"submit":await runSubmit(args,sdk,deps);return;case"publish":await runStateAction(args,sdk,"publish");return;case"unpublish":await runStateAction(args,sdk,"unpublish");return;case"archive":await runStateAction(args,sdk,"archive");return;case"delete":await runDelete(args,sdk);return;default:throw new Error("`platform app-library` \u4EC5\u652F\u6301 `list`\u3001`search`\u3001`inspect`\u3001`source`\u3001`config`\u3001`open`\u3001`checkout`\u3001`create`\u3001`update`\u3001`submit`\u3001`publish`\u3001`unpublish`\u3001`archive`\u3001`delete`\u3002")}}function printAppLibraryHelp(){process.stdout.write(["platform app-library <command>","","Commands:"," platform app-library list [--query <keyword>] [--status draft|published|unpublished|archived] [--tag <tag>] [--template-key <key>] [--visibility private|public] [--full] [--json]"," platform app-library search <keyword> [--status draft|published|unpublished|archived] [--full] [--json]"," platform app-library inspect <entry-id> [--json]"," platform app-library source tree <entry-id> [--json]"," platform app-library source read <entry-id> <path> [--json]"," platform app-library source search <entry-id> <query> [--json]"," platform app-library config init [--file app-library.yaml] [--force]"," platform app-library config validate [--file app-library.yaml] [--json]"," platform app-library open <entry-id> [--no-browser]"," platform app-library checkout <entry-id> [--dir <target-dir>] [--write-config] [--no-config] [--json]"," platform app-library create [--file app-library.yaml] [--name <name>] [--summary <text>] [--tags a,b] [--template-key <key>] [--write-config] [--json]"," platform app-library update <entry-id> [--file app-library.yaml] [--name <name>] [--summary <text>] [--tags a,b] [--template-key <key>] [--write-config] [--json]"," platform app-library submit <entry-id> [--file app-library.yaml] [--json]"," platform app-library publish <entry-id> [--json]"," platform app-library unpublish <entry-id> [--json]"," platform app-library archive <entry-id> [--json]"," platform app-library delete <entry-id> [--json]","","Notes:"," - \u521D\u671F\u4EC5\u652F\u6301 `example-app` \u6761\u76EE"," - `list` / `search` \u9ED8\u8BA4\u8FD4\u56DE\u8F7B\u6458\u8981\uFF1B\u5982\u9700\u5B8C\u6574\u5B57\u6BB5\u8BF7\u663E\u5F0F\u4F20 `--full`\uFF0C\u6216\u8FDB\u4E00\u6B65\u6267\u884C `inspect`"," - `list` / `search` \u9ED8\u8BA4\u4F1A\u67E5\u8BE2\u672C\u79DF\u6237 + \u8DE8\u79DF\u6237\u5DF2\u53D1\u5E03\u6761\u76EE\uFF1B\u5982\u663E\u5F0F\u4F20 `--status draft|unpublished|archived`\uFF0C\u5219\u4EC5\u67E5\u8BE2\u672C\u79DF\u6237\u6761\u76EE"," - `submit` \u9700\u8981\u5728\u672C\u5730\u8F7B\u5E94\u7528\u76EE\u5F55\u6267\u884C\uFF0C\u4F1A\u8BFB\u53D6\u5F53\u524D\u6E90\u7801\u5DE5\u4F5C\u533A\u5E76\u4E0A\u4F20\u4E3A\u5F53\u524D\u5FEB\u7167"," - \u5143\u6570\u636E\u9ED8\u8BA4\u8BFB\u53D6\u5F53\u524D\u5E94\u7528\u6839\u76EE\u5F55\u4E0B\u7684 `app-library.yaml`\uFF0CCLI flags \u53EF\u8986\u76D6\u540C\u540D\u5B57\u6BB5"," - `create` / `update` \u5728\u68C0\u6D4B\u5230\u73B0\u6709\u914D\u7F6E\u6587\u4EF6\u6216\u663E\u5F0F\u4F20\u5165 `--write-config` \u65F6\uFF0C\u4F1A\u628A\u6700\u65B0\u5143\u6570\u636E\u56DE\u5199\u5230 `app-library.yaml`"," - `checkout` \u9ED8\u8BA4\u5728\u76EE\u6807\u6E90\u7801\u4E0D\u5305\u542B `app-library.yaml` \u65F6\u81EA\u52A8\u751F\u6210\u4E00\u4EFD\uFF1B\u53EF\u7528 `--write-config` \u5F3A\u5236\u8986\u76D6\uFF0C`--no-config` \u8DF3\u8FC7"," - `open` \u9ED8\u8BA4\u6253\u5F00\u672C\u5730 tenant-workbench \u7684 `#app-library/<entry-id>` \u8DEF\u7531"," - `source tree/read/search` \u7528\u4E8E\u4E0D checkout \u7684\u4E91\u7AEF\u6E90\u7801\u7406\u89E3",""].join(`
|
|
2469
|
+
`).trim().length>0)return!0}return!1}async function resolveAvailableLocalDevPort(preferredPort,options={}){let host=options.host;return await canBindPort(preferredPort,host)?{port:preferredPort,reusedPreferred:!0}:{port:await allocateEphemeralPort(host),reusedPreferred:!1}}async function canBindPort(port,host){return new Promise(resolve20=>{let server=createNetServer(),finish=available=>{server.removeAllListeners(),resolve20(available)};server.once("error",()=>{finish(!1)});let onListening=()=>{server.close(()=>finish(!0))};if(host){server.listen(port,host,onListening);return}server.listen(port,onListening)})}async function allocateEphemeralPort(host){return new Promise((resolve20,reject)=>{let server=createNetServer();server.once("error",error=>{reject(error instanceof Error?error:new Error(String(error)))});let onListening=()=>{let address=server.address();if(!address||typeof address=="string"){server.close(()=>reject(new Error("\u65E0\u6CD5\u4E3A\u672C\u5730 dev \u5206\u914D\u56DE\u9000\u7AEF\u53E3\u3002")));return}let{port}=address;server.close(error=>{if(error){reject(error);return}resolve20(port)})};if(host){server.listen(0,host,onListening);return}server.listen(0,onListening)})}function collectDevPreflight(startDir=process.cwd(),target,runtimeBindings={}){let{manifest,directory}=readAppManifest(startDir),linked=readBinding(startDir);if(!linked?.binding.tenant_id||!linked.binding.app_id){let sourceContextPath=join7(directory,SOURCE_CONTEXT_FILE);throw new Error(existsSync11(sourceContextPath)?"\u5F53\u524D\u9879\u76EE\u672A\u7ED1\u5B9A tenant/app/env\u3002\u4F18\u5148\u5EFA\u8BAE\u6267\u884C `platform app create ...` \u6216 `platform app checkout --tenant <tenant-id> --app <app-id> --dir <project-name>` \u83B7\u53D6\u4E00\u4E2A\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1B\u82E5\u4F60\u8981\u4FEE\u590D\u5F53\u524D\u76EE\u5F55\uFF0C\u518D\u624B\u52A8\u6267\u884C `platform link --tenant <tenant-id> --app <app-id> --env preview`\u3002":"\u5F53\u524D\u76EE\u5F55\u5DF2\u68C0\u6D4B\u5230 `app.yaml`\uFF0C\u4F46\u7F3A\u5C11 `.platform/source-context.json`\uFF0C\u770B\u8D77\u6765\u50CF\u4E00\u4E2A\u5DF2\u8FC1\u79FB\u6216\u672A\u91CD\u65B0\u7ED1\u5B9A\u7684\u5E94\u7528\u5DE5\u7A0B\u3002\u8BF7\u6267\u884C `platform link --tenant <tenant-id> --app <app-id> --env preview` \u91CD\u65B0\u7ED1\u5B9A\u5F53\u524D\u76EE\u5F55\u3002")}let sourceContext=readSourceContext(startDir)?.sourceContext,workspaceTarget=resolveWorkspaceDevTarget(target),command=workspaceTarget?.command??manifest.entry.command,cwd=workspaceTarget?.cwd??directory,env=buildDevEnvironment(linked.binding,runtimeBindings),port=Number(env.PORT||manifest.entry.port||3e3);env.PUBLIC_APP_BASE_URL||(env.PUBLIC_APP_BASE_URL=`http://127.0.0.1:${port}`);let healthPath=manifest.entry.health_check||"/healthz",resolvedTemplateKey=typeof sourceContext?.template_key=="string"&&sourceContext.template_key.trim().length>0?sourceContext.template_key.trim():manifest.template_key,devCommandAnalysis=analyzeDevCommand(command,cwd),previewAddressMayChange=!manifest.dev.auto_restart&&devCommandAnalysis.portMayChange,warnings=["\u5F53\u524D\u9ED8\u8BA4\u8D70\u8F7B\u91CF\u5F00\u53D1\u6A21\u5F0F\uFF1A\u672C\u5730\u5F00\u53D1\u4E0D\u8981\u6C42 registry\u3001kind\u3001ingress-nginx \u6216 build-runner\u3002",`\u5F53\u524D\u542F\u52A8\u547D\u4EE4\u6765\u81EA app.yaml \u7684 entry.command\uFF1A${command}`];return manifest.dev.auto_restart?warnings.push("\u5F53\u524D app.yaml \u5DF2\u914D\u7F6E `dev.auto_restart: true`\uFF1BCLI \u4F1A\u5728\u68C0\u6D4B\u5230\u6E90\u7801\u53D8\u66F4\u540E\u81EA\u52A8\u91CD\u542F dev \u5B50\u8FDB\u7A0B\u3002"):devCommandAnalysis.managedByCommand?warnings.push(devCommandAnalysis.message):warnings.push("\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"),env.DATABASE_URL||warnings.push("\u672A\u68C0\u6D4B\u5230 DATABASE_URL\uFF1B\u672C\u5730\u6A21\u677F\u63A5\u53E3\u548C\u9875\u9762\u5F00\u53D1\u4ECD\u53EF\u7EE7\u7EED\u3002\u82E5\u4F60\u9700\u8981\u8054\u8C03\u5E73\u53F0 DB\uFF0C\u518D\u6267\u884C `platform dev --remote-bindings` \u6216\u624B\u52A8\u8BBE\u7F6E\u672C\u5730\u73AF\u5883\u53D8\u91CF\u3002"),templatePrefersPlatformCapabilityBindings(resolvedTemplateKey)&&warnings.push("\u5F53\u524D\u5B98\u65B9\u6A21\u677F\u9ED8\u8BA4\u5E26 Auth / CMS / Data Form \u793A\u4F8B\u9875\u3002\u82E5\u4F60\u8981\u8054\u8C03\u8FD9\u4E9B\u771F\u5B9E\u5E73\u53F0\u80FD\u529B\uFF0C\u5EFA\u8BAE\u76F4\u63A5\u6267\u884C `platform dev --remote-bindings`\u3002"),!process.env.PUBLIC_APP_BASE_URL&&!runtimeBindings.PUBLIC_APP_BASE_URL&&warnings.push(`\u672A\u663E\u5F0F\u914D\u7F6E PUBLIC_APP_BASE_URL\uFF1B\u672C\u5730 dev \u5DF2\u4E34\u65F6\u56DE\u9000\u4E3A ${env.PUBLIC_APP_BASE_URL}\u3002`),resolvedTemplateKey&&resolvedTemplateKey!=="frontend-app-vite"&&resolvedTemplateKey!=="backend-app-node"&&warnings.push(`\u5F53\u524D\u6A21\u677F\u4E3A ${resolvedTemplateKey}\uFF0C\u8BF7\u786E\u8BA4\u5165\u53E3\u547D\u4EE4\u4E0E\u5065\u5EB7\u68C0\u67E5\u8DEF\u5F84\u5DF2\u7ECF\u548C app.yaml \u5BF9\u9F50\u3002`),{binding:linked.binding,manifest,templateKey:resolvedTemplateKey,directory,command,cwd,env,healthcheckUrl:`http://localhost:${port}${healthPath}`,previewAddressMayChange,warnings}}function analyzeDevCommand(command,cwd){if(/(--watch|\bwatch\b|nodemon|vite|next dev|webpack serve|tsx watch)/iu.test(command))return{managedByCommand:!0,portMayChange:/\bvite\b/iu.test(command),message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u5DF2\u5305\u542B watch / \u70ED\u66F4\u65B0\u80FD\u529B\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u989D\u5916\u63A5\u7BA1\u81EA\u52A8\u91CD\u542F\u3002"};let npmScriptMatch=command.trim().match(/^(?:npm|pnpm|yarn)\s+run\s+([a-zA-Z0-9:_-]+)|^corepack\s+pnpm\s+run\s+([a-zA-Z0-9:_-]+)/u),scriptName=npmScriptMatch?.[1]??npmScriptMatch?.[2];if(!scriptName)return{managedByCommand:!1,portMayChange:!1,message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"};let packageJsonPath=join7(cwd,"package.json");if(!existsSync11(packageJsonPath))return{managedByCommand:!1,portMayChange:!1,message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"};try{let scriptCommand=JSON.parse(readFileSync10(packageJsonPath,"utf8")).scripts?.[scriptName];if(typeof scriptCommand=="string"&&/(--watch|\bwatch\b|nodemon|vite|next dev|webpack serve|tsx watch|scripts\/dev\.mjs|scripts\\dev\.mjs)/iu.test(scriptCommand))return{managedByCommand:!0,portMayChange:/\bvite\b|scripts\/dev\.mjs|scripts\\dev\.mjs/iu.test(scriptCommand),message:scriptCommand.includes("scripts/dev.mjs")?"\u5F53\u524D\u547D\u4EE4\u901A\u8FC7\u6A21\u677F\u81EA\u5E26\u7684\u672C\u5730 dev \u7F16\u6392\u811A\u672C\u542F\u52A8\uFF1B\u524D\u7AEF\u70ED\u66F4\u65B0\u4E0E\u670D\u52A1\u7AEF\u81EA\u52A8\u91CD\u542F\u7531\u6A21\u677F\u81EA\u5DF1\u7BA1\u7406\uFF0CCLI \u4E0D\u4F1A\u989D\u5916\u63A5\u7BA1\u81EA\u52A8\u91CD\u542F\u3002":"\u5F53\u524D\u547D\u4EE4\u901A\u8FC7 package.json script \u81EA\u5E26 watch / \u70ED\u66F4\u65B0\u80FD\u529B\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u989D\u5916\u63A5\u7BA1\u81EA\u52A8\u91CD\u542F\u3002"}}catch{return{managedByCommand:!1,portMayChange:!1,message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"}}return{managedByCommand:!1,portMayChange:!1,message:"\u5F53\u524D\u547D\u4EE4\u81EA\u8EAB\u4E0D\u5E26\u70ED\u66F4\u65B0\uFF1BCLI \u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u3002\u82E5\u4F60\u9700\u8981\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u5728 app.yaml \u4E2D\u663E\u5F0F\u914D\u7F6E `dev.auto_restart: true`\u3002"}}async function runAppLibraryCommand(args,deps={}){let subcommand=args.rest[0];if(hasHelpFlag2(args)||args.rest.length===0||subcommand==="help"){printAppLibraryHelp();return}if(subcommand==="config"){await runConfig(args);return}let sdk=deps.sdk,tenantId=deps.tenantId;if(!sdk||!tenantId){let credentials=await loadStoredCredentialsEnsuringFresh();if(!credentials)throw new Error("\u672A\u627E\u5230\u672C\u5730\u51ED\u636E\uFF0C\u8BF7\u5148\u6267\u884C `platform login`\u3002");if(tenantId=deps.tenantId??resolveTenantId(args),!tenantId)throw new Error("`platform app-library` \u9700\u8981 tenant \u4E0A\u4E0B\u6587\u3002\u8BF7\u5148\u5728\u5F53\u524D\u9879\u76EE\u7ED1\u5B9A tenant/app\uFF0C\u6216\u663E\u5F0F\u4F20\u5165 `--tenant`\u3002");sdk=createControlApiSdk({accessToken:selectApiToken(credentials),tenantId,capability:"dashboard",requestClass:"control"})}switch(subcommand){case"list":await runList(args,sdk);return;case"search":await runSearch(args,sdk);return;case"inspect":await runInspect(args,sdk);return;case"source":await runSource(args,sdk);return;case"open":await runOpen(args,deps);return;case"checkout":await runCheckout(args,sdk);return;case"create":await runCreate(args,sdk);return;case"update":await runUpdate(args,sdk);return;case"submit":await runSubmit(args,sdk,deps);return;case"publish":await runStateAction(args,sdk,"publish");return;case"unpublish":await runStateAction(args,sdk,"unpublish");return;case"archive":await runStateAction(args,sdk,"archive");return;case"delete":await runDelete(args,sdk);return;default:throw new Error("`platform app-library` \u4EC5\u652F\u6301 `list`\u3001`search`\u3001`inspect`\u3001`source`\u3001`config`\u3001`open`\u3001`checkout`\u3001`create`\u3001`update`\u3001`submit`\u3001`publish`\u3001`unpublish`\u3001`archive`\u3001`delete`\u3002")}}function printAppLibraryHelp(){process.stdout.write(["platform app-library <command>","","Commands:"," platform app-library list [--query <keyword>] [--status draft|published|unpublished|archived] [--tag <tag>] [--template-key <key>] [--visibility private|public] [--full] [--json]"," platform app-library search <keyword> [--status draft|published|unpublished|archived] [--full] [--json]"," platform app-library inspect <entry-id> [--json]"," platform app-library source tree <entry-id> [--json]"," platform app-library source read <entry-id> <path> [--json]"," platform app-library source search <entry-id> <query> [--json]"," platform app-library config init [--file app-library.yaml] [--force]"," platform app-library config validate [--file app-library.yaml] [--json]"," platform app-library open <entry-id> [--no-browser]"," platform app-library checkout <entry-id> [--dir <target-dir>] [--write-config] [--no-config] [--json]"," platform app-library create [--file app-library.yaml] [--name <name>] [--summary <text>] [--tags a,b] [--template-key <key>] [--write-config] [--json]"," platform app-library update <entry-id> [--file app-library.yaml] [--name <name>] [--summary <text>] [--tags a,b] [--template-key <key>] [--write-config] [--json]"," platform app-library submit <entry-id> [--file app-library.yaml] [--json]"," platform app-library publish <entry-id> [--json]"," platform app-library unpublish <entry-id> [--json]"," platform app-library archive <entry-id> [--json]"," platform app-library delete <entry-id> [--json]","","Notes:"," - \u521D\u671F\u4EC5\u652F\u6301 `example-app` \u6761\u76EE"," - `list` / `search` \u9ED8\u8BA4\u8FD4\u56DE\u8F7B\u6458\u8981\uFF1B\u5982\u9700\u5B8C\u6574\u5B57\u6BB5\u8BF7\u663E\u5F0F\u4F20 `--full`\uFF0C\u6216\u8FDB\u4E00\u6B65\u6267\u884C `inspect`"," - `list` / `search` \u9ED8\u8BA4\u4F1A\u67E5\u8BE2\u672C\u79DF\u6237 + \u8DE8\u79DF\u6237\u5DF2\u53D1\u5E03\u6761\u76EE\uFF1B\u5982\u663E\u5F0F\u4F20 `--status draft|unpublished|archived`\uFF0C\u5219\u4EC5\u67E5\u8BE2\u672C\u79DF\u6237\u6761\u76EE"," - `submit` \u9700\u8981\u5728\u672C\u5730\u8F7B\u5E94\u7528\u76EE\u5F55\u6267\u884C\uFF0C\u4F1A\u8BFB\u53D6\u5F53\u524D\u6E90\u7801\u5DE5\u4F5C\u533A\u5E76\u4E0A\u4F20\u4E3A\u5F53\u524D\u5FEB\u7167"," - \u5143\u6570\u636E\u9ED8\u8BA4\u8BFB\u53D6\u5F53\u524D\u5E94\u7528\u6839\u76EE\u5F55\u4E0B\u7684 `app-library.yaml`\uFF0CCLI flags \u53EF\u8986\u76D6\u540C\u540D\u5B57\u6BB5"," - `create` / `update` \u5728\u68C0\u6D4B\u5230\u73B0\u6709\u914D\u7F6E\u6587\u4EF6\u6216\u663E\u5F0F\u4F20\u5165 `--write-config` \u65F6\uFF0C\u4F1A\u628A\u6700\u65B0\u5143\u6570\u636E\u56DE\u5199\u5230 `app-library.yaml`"," - `checkout` \u9ED8\u8BA4\u5728\u76EE\u6807\u6E90\u7801\u4E0D\u5305\u542B `app-library.yaml` \u65F6\u81EA\u52A8\u751F\u6210\u4E00\u4EFD\uFF1B\u53EF\u7528 `--write-config` \u5F3A\u5236\u8986\u76D6\uFF0C`--no-config` \u8DF3\u8FC7"," - `open` \u9ED8\u8BA4\u6253\u5F00\u672C\u5730 tenant-workbench \u7684 `#app-library/<entry-id>` \u8DEF\u7531"," - `source tree/read/search` \u7528\u4E8E\u4E0D checkout \u7684\u4E91\u7AEF\u6E90\u7801\u7406\u89E3",""].join(`
|
|
2472
2470
|
`))}async function runList(args,sdk){let status=readStatusOption(args,"status")??"published",includePublic=status==="published",response=await sdk.listLightAppLibraryEntries({query:readStringOption2(args,"query"),status,template_key:readStringOption2(args,"template-key"),tag:readStringOption2(args,"tag"),visibility:readVisibilityOption(args,"visibility"),include_public:includePublic}).catch(error=>{throw formatAppLibraryError(error,"list")}),full=args.options.full===!0;writeJsonOrText(args.options.json===!0,full?response:toEntryListBriefPayload(response),[`items: ${response.items.length}`,...response.items.flatMap((item,index)=>formatEntrySummary(item,index+1,full))])}async function runSearch(args,sdk){let query=args.rest[1]?.trim();if(!query)throw new Error("`platform app-library search` \u9700\u8981 <keyword>\u3002");let status=readStatusOption(args,"status")??"published",includePublic=status==="published",response=await sdk.listLightAppLibraryEntries({query,status,include_public:includePublic}).catch(error=>{throw formatAppLibraryError(error,"search")}),full=args.options.full===!0;writeJsonOrText(args.options.json===!0,full?response:toEntryListBriefPayload(response),[`query: ${query}`,`items: ${response.items.length}`,...response.items.flatMap((item,index)=>formatEntrySummary(item,index+1,full))])}async function runInspect(args,sdk){let config2=loadAppLibraryConfigOptional(),entryId=resolveEntryId(args,config2);if(!entryId)throw new Error("`platform app-library inspect` \u9700\u8981 <entry-id>\uFF0C\u6216\u5728 `app-library.yaml` \u4E2D\u63D0\u4F9B `entry_id`\u3002");let[entry,source]=await Promise.all([sdk.getLightAppLibraryEntry(entryId).catch(error=>{throw formatAppLibraryError(error,"inspect")}),sdk.getLightAppLibraryEntrySource(entryId).catch(error=>{throw formatAppLibraryError(error,"inspect(source)")})]);writeJsonOrText(args.options.json===!0,{entry,source},[`entry_id: ${entry.entry_id}`,`name: ${entry.name}`,`type: ${entry.type==="example_app"?"example-app":entry.type}`,`status: ${entry.status}`,`library: ${entry.library.name} (${entry.library.visibility})`,`summary: ${entry.summary?.trim()||"-"}`,`tags: ${entry.tags.length?entry.tags.join(", "):"-"}`,`template_key: ${entry.template_key??"-"}`,`capabilities: ${entry.capability_dependencies.length?entry.capability_dependencies.map(item=>item.minVersion?`${item.capability}@${item.minVersion}`:item.capability).join(", "):"-"}`,`current_snapshot_id: ${entry.current_snapshot_id??"-"}`,`source_files: ${source.files.length}`,`key_files: ${source.files.filter(file=>file.is_key_file).slice(0,8).map(file=>file.path).join(", ")||"-"}`,`next.inspect: platform app-library inspect ${entry.entry_id} --json`,`next.checkout: platform app-library checkout ${entry.entry_id} --dir ./${sanitizeDirectoryName(entry.name||entry.entry_id)}`])}async function runSource(args,sdk){let action=args.rest[1];if(action==="tree"){await runSourceTree(args,sdk);return}if(action==="read"){await runSourceRead(args,sdk);return}if(action==="search"){await runSourceSearch(args,sdk);return}throw new Error("`platform app-library source` \u4EC5\u652F\u6301 `tree`\u3001`read`\u3001`search`\u3002")}async function runConfig(args){let action=args.rest[1];if(action==="init"){runConfigInit(args);return}if(action==="validate"){runConfigValidate(args);return}throw new Error("`platform app-library config` \u4EC5\u652F\u6301 `init`\u3001`validate`\u3002")}async function runSourceTree(args,sdk){let entryId=resolvePositionalOrConfigEntryId(args,2);if(!entryId)throw new Error("`platform app-library source tree` \u9700\u8981 <entry-id>\uFF0C\u6216\u5728 `app-library.yaml` \u4E2D\u63D0\u4F9B `entry_id`\u3002");let source=await sdk.getLightAppLibraryEntrySource(entryId).catch(error=>{throw formatAppLibraryError(error,"source(tree)")});writeJsonOrText(args.options.json===!0,source,[`entry_id: ${entryId}`,`snapshot_id: ${source.snapshot_id}`,`files: ${source.files.length}`,...source.files.map(file=>{let markers=[file.is_key_file?"key":null,file.is_text?"text":"binary",file.ext||"-"].filter(Boolean).join(", ");return`- ${file.path} [${markers}]`})])}async function runSourceRead(args,sdk){let entryId=resolvePositionalOrConfigEntryId(args,2);if(!entryId)throw new Error("`platform app-library source read` \u9700\u8981 <entry-id>\uFF0C\u6216\u5728 `app-library.yaml` \u4E2D\u63D0\u4F9B `entry_id`\u3002");let path3=args.rest[3]?.trim()||readStringOption2(args,"path");if(!path3)throw new Error("`platform app-library source read` \u9700\u8981 <path>\uFF0C\u6216\u663E\u5F0F\u4F20\u5165 `--path`\u3002");let response=await sdk.readLightAppLibraryEntrySourceFile(entryId,path3).catch(error=>{throw formatAppLibraryError(error,"source(read)")});if(args.options.json===!0){writeJsonOrText(!0,response,[]);return}process.stdout.write(`# ${response.file.path}
|
|
2473
2471
|
|
|
2474
2472
|
`),process.stdout.write(`${response.file.content}${response.file.content.endsWith(`
|
|
@@ -2745,7 +2743,7 @@ ${normalized}`}function countExecutableSqlStatements(sql){return stripSqlComment
|
|
|
2745
2743
|
`))}async function runDiagnostics(args){let subcommand=args.rest[0]??"help";if(hasFlag2(args,"help")||hasFlag2(args,"h")||subcommand==="help"){printDiagnosticsHelp();return}if(subcommand==="credentials"){let diagnostics2=inspectStoredCredentialSecurity();args.options.json===!0?process7.stdout.write(`${JSON.stringify(diagnostics2,null,2)}
|
|
2746
2744
|
`):process7.stdout.write(formatCredentialSecurityReportText(diagnostics2)),hasFlag2(args,"strict")&&diagnostics2.status!=="ok"&&(process7.exitCode=2);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)}
|
|
2747
2745
|
`);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==="-"?readFileSync29(0,"utf8"):readFileSync29(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,startDir=currentInvocationDir()){let linked;try{linked=readBinding(startDir)}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(`
|
|
2748
|
-
`));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")}function printCredentialsHelp(){process7.stdout.write(["platform credentials","","\u7528\u6CD5\uFF1A"," platform credentials migrate [--json]","","\u8BF4\u660E\uFF1A"," \u5C06\u65E7 credentials.json \u8FC1\u79FB\u5230
|
|
2746
|
+
`));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")}function printCredentialsHelp(){process7.stdout.write(["platform credentials","","\u7528\u6CD5\uFF1A"," platform credentials migrate [--json]","","\u8BF4\u660E\uFF1A"," Windows \u5C06\u65E7 credentials.json \u8FC1\u79FB\u5230\u5F53\u524D\u7528\u6237 DPAPI\uFF1BmacOS \u53EF\u51C0\u5316\u65E7\u6587\u4EF6\u4E2D\u7684 PAT \u4EA4\u6362\u5B57\u6BB5\u3002"," \u53EA\u6709\u5B89\u5168\u5B58\u50A8\u5199\u5165\u5E76\u56DE\u8BFB\u6821\u9A8C\u6210\u529F\u540E\u624D\u5220\u9664\u65E7\u660E\u6587\u6587\u4EF6\u3002"," \u8FC1\u79FB\u5931\u8D25\u4F1A\u4FDD\u7559\u539F\u767B\u5F55\u6001\uFF0C\u5E76\u7ED9\u51FA\u660E\u786E\u63D0\u793A\u3002",""].join(`
|
|
2749
2747
|
`))}async function runCredentials(args){let subcommand=args.rest[0]??"help";if(hasFlag2(args,"help")||hasFlag2(args,"h")||subcommand==="help"){printCredentialsHelp();return}if(subcommand!=="migrate")throw printCredentialsHelp(),new Error(`\u672A\u77E5 credentials \u5B50\u547D\u4EE4: ${subcommand}`);let result=migrateStoredCredentials(),output={status:result.status,backend:result.backend,legacy_deleted:result.legacyDeleted,warnings:result.warnings};hasFlag2(args,"json")?process7.stdout.write(`${JSON.stringify(output,null,2)}
|
|
2750
2748
|
`):result.status==="migrated"?process7.stdout.write(`\u51ED\u636E\u8FC1\u79FB\u5B8C\u6210\u3002
|
|
2751
2749
|
\u5B58\u50A8\u540E\u7AEF: ${result.backend}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voobase/cli",
|
|
3
|
-
"version": "0.1.1-nonprod.
|
|
3
|
+
"version": "0.1.1-nonprod.2071",
|
|
4
4
|
"private": false,
|
|
5
5
|
"platformDistributionProfile": {
|
|
6
6
|
"name": "nonprod",
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
"bundleDependencies": [],
|
|
57
57
|
"platformDistributionBuild": {
|
|
58
58
|
"channel": "nonprod",
|
|
59
|
-
"version": "0.1.1-nonprod.
|
|
60
|
-
"sequence":
|
|
61
|
-
"gitSha": "
|
|
62
|
-
"fullGitSha": "
|
|
63
|
-
"buildId": "0.1.1-nonprod.
|
|
59
|
+
"version": "0.1.1-nonprod.2071",
|
|
60
|
+
"sequence": 2071,
|
|
61
|
+
"gitSha": "bb59d25",
|
|
62
|
+
"fullGitSha": "bb59d255b7d15e1ef51163b175f78e60c27910bc",
|
|
63
|
+
"buildId": "0.1.1-nonprod.2071+bb59d25"
|
|
64
64
|
}
|
|
65
65
|
}
|