@cloudbase/app
Version:
cloudbase javascript sdk core
312 lines (273 loc) • 9.33 kB
text/typescript
import { adapters, constants, utils, helpers } from '@cloudbase/utilities'
import { SDKAdapterInterface, CloudbaseAdapter, IRequestConfig } from '@cloudbase/adapter-interface'
import {
ICloudbaseConfig,
ICloudbaseUpgradedConfig,
ICloudbase,
ICloudbaseExtension,
KV,
ICloudbasePlatformInfo,
EndPointKey,
ICloudbaseApis,
} from '@cloudbase/types'
import { ICloudbaseAuth } from '@cloudbase/types/auth'
import adapterForWxMp from '@cloudbase/adapter-wx_mp'
import { registerComponent, registerHook } from './libs/component'
import { Platform } from './libs/adapter'
import { ICloudbaseComponent, ICloudbaseHook } from '@cloudbase/types/component'
import { ICloudbaseCache } from '@cloudbase/types/cache'
import { initCache, getCacheByEnvId, getLocalCache } from './libs/cache'
import { ICloudbaseRequest } from '@cloudbase/types/request'
import { initRequest, getRequestByEnvId } from './libs/request'
import {
getSdkName,
setSdkVersion,
setRegionLevelEndpoint,
setSdkName,
setGatewayEndPointWithEnv,
type ISetEndPointWithKey,
setEndPointInfo,
getEndPointInfo,
getSdkVersion,
DEFAULT_PROTOCOL,
} from './constants/common'
import { i18nProxy, LANGS } from './libs/lang'
import { generateApis } from './libs/callApis'
export { getBaseEndPoint } from './constants/common'
export { LANGS } from './libs/lang'
const { useAdapters, useDefaultAdapter } = adapters
const { ERRORS, COMMUNITY_SITE_URL } = constants
const { printWarn } = utils
const { catchErrorsDecorator } = helpers
/**
* @constant 默认配置
*/
const DEFAULT_INIT_CONFIG: Partial<ICloudbaseConfig> = {
timeout: 15000,
persistence: 'local', // 持久化存储类型
}
// timeout上限10分钟
const MAX_TIMEOUT = 1000 * 60 * 10
// timeout下限100ms
const MIN_TIMEOUT = 100
const extensionMap: KV<ICloudbaseExtension> = {}
class Cloudbase implements ICloudbase {
public authInstance: ICloudbaseAuth
public oauthInstance: any
public requestClient: any
public oauthClient: any
public version: string
private cloudbaseConfig: ICloudbaseConfig
constructor(config?: ICloudbaseConfig) {
this.cloudbaseConfig = config ? config : this.cloudbaseConfig
this.authInstance = null
this.oauthInstance = null
this.version = getSdkVersion()
}
get config() {
return this.cloudbaseConfig
}
get platform(): ICloudbasePlatformInfo {
return Platform
}
get cache(): ICloudbaseCache {
return getCacheByEnvId(this.cloudbaseConfig.env)
}
get localCache(): ICloudbaseCache {
return getLocalCache(this.cloudbaseConfig.env)
}
get request(): ICloudbaseRequest {
return getRequestByEnvId(this.cloudbaseConfig.env)
}
get apis(): ICloudbaseApis {
return generateApis.call(this)
}
({
mode: 'sync',
title: 'Cloudbase 初始化失败',
messages: [
'请确认以下各项:',
' 1 - 调用 cloudbase.init() 的语法或参数是否正确',
' 2 - 如果是非浏览器环境,是否配置了安全应用来源(https://docs.cloudbase.net/api-reference/webv3/adapter#%E7%AC%AC-2-%E6%AD%A5%E9%85%8D%E7%BD%AE%E5%AE%89%E5%85%A8%E5%BA%94%E7%94%A8%E6%9D%A5%E6%BA%90)',
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
],
})
public init(config: ICloudbaseConfig & { lang?: LANGS }): Cloudbase {
if (!config.env) {
throw new Error(JSON.stringify({
code: ERRORS.INVALID_PARAMS,
msg: 'env must not be specified',
}),)
}
// 初始化时若未兼容平台,则使用默认adapter
if (!Platform.adapter) {
this.useDefaultAdapter()
}
const reqConfig: IRequestConfig = {
timeout: config.timeout || 5000,
timeoutMsg: `[${getSdkName()}][REQUEST TIMEOUT] request had been abort since didn't finished within${
config.timeout / 1000
}s`,
}
this.requestClient = new Platform.adapter.reqClass(reqConfig)
this.cloudbaseConfig = {
...DEFAULT_INIT_CONFIG,
...config,
i18n: i18nProxy(Platform, config),
}
delete (this.cloudbaseConfig as any).lang
// 修正timeout取值
this.cloudbaseConfig.timeout = this.formatTimeout(this.cloudbaseConfig.timeout)
// 初始化cache和request
const { env, persistence, debug, timeout, oauthClient, i18n } = this.cloudbaseConfig
initCache({ env, persistence, debug, platformInfo: this.platform })
setRegionLevelEndpoint(env, config.region || '')
setGatewayEndPointWithEnv(env, DEFAULT_PROTOCOL, config.region || '')
const app = new Cloudbase(this.cloudbaseConfig)
initRequest({
env,
region: config.region || '',
timeout,
oauthClient,
_fromApp: app,
i18n,
endPointMode: config.endPointMode,
})
app.requestClient = this.requestClient
;(this as any)?.fire?.('cloudbase_init', app)
this.try2InitAuth(config, app)
return app
}
public updateConfig(config: ICloudbaseUpgradedConfig) {
const { persistence, debug } = config
this.cloudbaseConfig.persistence = persistence
this.cloudbaseConfig.debug = debug
// persistence改动影响cache
initCache({ env: this.cloudbaseConfig.env, persistence, debug, platformInfo: this.platform })
}
public updateLang(lang: LANGS) {
if (!lang || lang === this.cloudbaseConfig.i18n?.lang) return
this.cloudbaseConfig.i18n.lang = lang
}
public registerExtension(ext: ICloudbaseExtension) {
extensionMap[ext.name] = ext
}
({
title: '调用扩展能力失败',
messages: [
'请确认以下各项:',
' 1 - 调用 invokeExtension() 的语法或参数是否正确',
' 2 - 被调用的扩展能力是否已经安装并通过 registerExtension() 注册',
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
],
})
public async invokeExtension(name: string, opts: any) {
const ext = extensionMap[name]
if (!ext) {
throw new Error(JSON.stringify({
code: ERRORS.INVALID_PARAMS,
msg: `extension:${name} must be registered before invoke`,
}),)
}
return await ext.invoke(opts, this)
}
public useAdapters(adapters: CloudbaseAdapter | CloudbaseAdapter[], options?: any) {
const { adapter, runtime } = useAdapters(adapters, options) || {}
adapter && (Platform.adapter = adapter as SDKAdapterInterface)
runtime && (Platform.runtime = runtime as string)
}
public registerHook(hook: ICloudbaseHook) {
registerHook(Cloudbase, hook)
}
public registerComponent(component: ICloudbaseComponent) {
registerComponent(Cloudbase, component)
}
public registerVersion(version: string) {
setSdkVersion(version)
this.version = version
}
public registerSdkName(name: string) {
setSdkName(name)
}
/** 设置 tcb api 的 endpoint */
public registerEndPoint(url: string, protocol?: 'http' | 'https') {
setEndPointInfo({ baseUrl: url, protocol, env: this.config.env, endPointKey: 'CLOUD_API' })
}
/** 设置网关/tcb api的 endPoint,通过 key 指定 */
public registerEndPointWithKey(props: ISetEndPointWithKey) {
setEndPointInfo({
env: this.config.env,
endPointKey: props.key,
baseUrl: props.url,
protocol: props.protocol,
})
}
/** 拿网关/tcb api的 endPoint,通过 key 指定 */
public getEndPointWithKey(key: EndPointKey) {
const info = getEndPointInfo(this.config.env, key)
return {
BASE_URL: info.baseUrl,
PROTOCOL: info.protocol,
}
}
// 解析URL参数
public parseCaptcha(url) {
let queryObj: any = {}
const matched = url.match(/^(data:.*?)(\?[^#\s]*)?$/)
if (matched) {
url = matched[1]
const search = matched[2]
if (search) {
queryObj = utils.parseQueryString(search)
}
}
const { token, ...restQueryObj } = queryObj
if (/^data:/.test(url) && !token) {
return {
error: 'invalid_argument',
error_description: `invalid captcha data: ${url}`,
}
}
if (!token) {
return {
error: 'unimplemented',
error_description: 'need to impl captcha data',
}
}
// 解析url得到的参数
return {
state: restQueryObj.state,
token, // 验证码token
captchaData: url, // 验证码base64图片
}
}
private useDefaultAdapter() {
const { adapter, runtime } = useDefaultAdapter()
Platform.adapter = adapter as SDKAdapterInterface
Platform.runtime = runtime as string
}
private formatTimeout(timeout: number) {
switch (true) {
case timeout > MAX_TIMEOUT:
printWarn(ERRORS.INVALID_PARAMS, 'timeout is greater than maximum value[10min]')
return MAX_TIMEOUT
case timeout < MIN_TIMEOUT:
printWarn(ERRORS.INVALID_PARAMS, 'timeout is less than maximum value[100ms]')
return MIN_TIMEOUT
default:
return timeout
}
}
private try2InitAuth(config: ICloudbaseConfig, app) {
try {
if (config.accessKey) {
app.auth()
}
} catch (error) {
console.log('try2InitAuth error:', error)
}
}
}
export const cloudbase: ICloudbase = new Cloudbase()
cloudbase.useAdapters(adapterForWxMp)
export default cloudbase