feat(private): add private deployment SDK module
Adds @xuqm/vue3-sdk/private entry point with JSON-based initialization, feature gating, and error codes for private deployment scenarios. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
7ef2d011a3
当前提交
cd28487dad
@ -14,6 +14,11 @@
|
|||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"import": "./dist/index.es.js",
|
"import": "./dist/index.es.js",
|
||||||
"require": "./dist/index.cjs.js"
|
"require": "./dist/index.cjs.js"
|
||||||
|
},
|
||||||
|
"./private": {
|
||||||
|
"types": "./dist/private/index.d.ts",
|
||||||
|
"import": "./dist/private/index.es.js",
|
||||||
|
"require": "./dist/private/index.cjs.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
25
package.private.json
普通文件
25
package.private.json
普通文件
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "@xuqm-private/vue3-sdk",
|
||||||
|
"version": "0.2.3",
|
||||||
|
"description": "XuqmGroup Vue3 Private SDK — for private deployment environments",
|
||||||
|
"private": false,
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://nexus.xuqinmin.com/repository/npm-hosted/"
|
||||||
|
},
|
||||||
|
"main": "dist/private/index.cjs.js",
|
||||||
|
"module": "dist/private/index.es.js",
|
||||||
|
"types": "dist/private/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/private/index.d.ts",
|
||||||
|
"import": "./dist/private/index.es.js",
|
||||||
|
"require": "./dist/private/index.cjs.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/private"
|
||||||
|
],
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.5.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/private/index.ts
普通文件
15
src/private/index.ts
普通文件
@ -0,0 +1,15 @@
|
|||||||
|
export {
|
||||||
|
initFromConfig,
|
||||||
|
initFromFile,
|
||||||
|
reloadConfig,
|
||||||
|
requireFeature,
|
||||||
|
getPrivateConfig,
|
||||||
|
isFeatureEnabled,
|
||||||
|
setToken,
|
||||||
|
setUserId,
|
||||||
|
getToken,
|
||||||
|
getUserId,
|
||||||
|
} from './sdk'
|
||||||
|
|
||||||
|
export type { PrivateSdkConfig, PrivateSdkFeatures, PrivateSdkState, PrivateErrorCode } from './types'
|
||||||
|
export { PrivateSdkError } from './types'
|
||||||
138
src/private/sdk.ts
普通文件
138
src/private/sdk.ts
普通文件
@ -0,0 +1,138 @@
|
|||||||
|
import type { PrivateSdkConfig, PrivateSdkState } from './types'
|
||||||
|
import { PrivateSdkError } from './types'
|
||||||
|
import { configureHttp } from '../core/http'
|
||||||
|
|
||||||
|
const SUPPORTED_SCHEMA_VERSIONS = [1]
|
||||||
|
|
||||||
|
const state: PrivateSdkState = {
|
||||||
|
config: null,
|
||||||
|
token: null,
|
||||||
|
userId: null,
|
||||||
|
initialized: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateConfig(cfg: PrivateSdkConfig): void {
|
||||||
|
if (!SUPPORTED_SCHEMA_VERSIONS.includes(cfg.schemaVersion)) {
|
||||||
|
throw new PrivateSdkError(
|
||||||
|
'XUQM_PRIVATE_1003',
|
||||||
|
`Unsupported schemaVersion: ${cfg.schemaVersion}. Supported: ${SUPPORTED_SCHEMA_VERSIONS.join(', ')}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (cfg.deployment !== 'PRIVATE') {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1002', 'deployment must be "PRIVATE"')
|
||||||
|
}
|
||||||
|
if (!cfg.appKey) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1002', 'appKey is required')
|
||||||
|
}
|
||||||
|
if (!cfg.controlBaseUrl) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1002', 'controlBaseUrl is required')
|
||||||
|
}
|
||||||
|
validateUrl('controlBaseUrl', cfg.controlBaseUrl, false)
|
||||||
|
if (cfg.features.im) {
|
||||||
|
if (!cfg.imApiBaseUrl) throw new PrivateSdkError('XUQM_PRIVATE_1002', 'imApiBaseUrl is required when im is enabled')
|
||||||
|
if (!cfg.imWsUrl) throw new PrivateSdkError('XUQM_PRIVATE_1002', 'imWsUrl is required when im is enabled')
|
||||||
|
validateUrl('imApiBaseUrl', cfg.imApiBaseUrl, false)
|
||||||
|
validateWsUrl('imWsUrl', cfg.imWsUrl)
|
||||||
|
}
|
||||||
|
if (cfg.features.push && !cfg.pushBaseUrl) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1002', 'pushBaseUrl is required when push is enabled')
|
||||||
|
}
|
||||||
|
if (cfg.features.update && !cfg.updateBaseUrl) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1002', 'updateBaseUrl is required when update is enabled')
|
||||||
|
}
|
||||||
|
if (cfg.features.license && !cfg.licenseBaseUrl) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1002', 'licenseBaseUrl is required when license is enabled')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateUrl(field: string, url: string, optional: boolean): void {
|
||||||
|
if (!url) {
|
||||||
|
if (!optional) throw new PrivateSdkError('XUQM_PRIVATE_1004', `${field} is required`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1004', `${field} must start with http:// or https://`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateWsUrl(field: string, url: string): void {
|
||||||
|
if (!url.startsWith('ws://') && !url.startsWith('wss://')) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1004', `${field} must start with ws:// or wss://`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveActiveConfig(cfg: PrivateSdkConfig): PrivateSdkConfig {
|
||||||
|
if (!cfg.activeProfile || !cfg.profiles) return cfg
|
||||||
|
const profile = cfg.profiles[cfg.activeProfile]
|
||||||
|
if (!profile) return cfg
|
||||||
|
return { ...cfg, ...profile, activeProfile: cfg.activeProfile, profiles: cfg.profiles }
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyConfig(cfg: PrivateSdkConfig): void {
|
||||||
|
const resolved = resolveActiveConfig(cfg)
|
||||||
|
validateConfig(resolved)
|
||||||
|
state.config = resolved
|
||||||
|
state.initialized = true
|
||||||
|
// wire up the shared http client with the control base URL (no default fallback)
|
||||||
|
configureHttp(normalizeUrl(resolved.controlBaseUrl), () => state.token)
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeUrl(url: string): string {
|
||||||
|
return url.endsWith('/') ? url.slice(0, -1) : url
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initFromConfig(cfg: PrivateSdkConfig): void {
|
||||||
|
applyConfig(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initFromFile(url: string): Promise<void> {
|
||||||
|
const res = await fetch(url)
|
||||||
|
if (!res.ok) throw new PrivateSdkError('XUQM_PRIVATE_1002', `Failed to load config from ${url}: ${res.status}`)
|
||||||
|
const cfg = (await res.json()) as PrivateSdkConfig
|
||||||
|
applyConfig(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function reloadConfig(url: string): Promise<void> {
|
||||||
|
await initFromFile(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function requireFeature(
|
||||||
|
feature: keyof PrivateSdkConfig['features'],
|
||||||
|
): void {
|
||||||
|
if (!state.config) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1001', 'Private SDK not initialized. Call initFromConfig() or initFromFile() first.')
|
||||||
|
}
|
||||||
|
if (!state.config.features[feature]) {
|
||||||
|
throw new PrivateSdkError(
|
||||||
|
'XUQM_PRIVATE_2001',
|
||||||
|
`Feature "${feature}" is not enabled in this deployment. Contact your administrator to enable it.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPrivateConfig(): PrivateSdkConfig {
|
||||||
|
if (!state.config) {
|
||||||
|
throw new PrivateSdkError('XUQM_PRIVATE_1001', 'Private SDK not initialized.')
|
||||||
|
}
|
||||||
|
return state.config
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFeatureEnabled(feature: keyof PrivateSdkConfig['features']): boolean {
|
||||||
|
return !!state.config?.features[feature]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setToken(token: string | null): void {
|
||||||
|
state.token = token
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUserId(userId: string | null): void {
|
||||||
|
state.userId = userId
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getToken(): string | null {
|
||||||
|
return state.token
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserId(): string | null {
|
||||||
|
return state.userId
|
||||||
|
}
|
||||||
53
src/private/types.ts
普通文件
53
src/private/types.ts
普通文件
@ -0,0 +1,53 @@
|
|||||||
|
export interface PrivateSdkFeatures {
|
||||||
|
file?: boolean
|
||||||
|
im?: boolean
|
||||||
|
push?: boolean
|
||||||
|
update?: boolean
|
||||||
|
license?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PrivateSdkConfig {
|
||||||
|
schemaVersion: number
|
||||||
|
configVersion?: string
|
||||||
|
deployment: 'PRIVATE'
|
||||||
|
appKey: string
|
||||||
|
controlBaseUrl: string
|
||||||
|
imApiBaseUrl?: string
|
||||||
|
imWsUrl?: string
|
||||||
|
pushBaseUrl?: string
|
||||||
|
updateBaseUrl?: string
|
||||||
|
fileBaseUrl?: string
|
||||||
|
licenseBaseUrl?: string
|
||||||
|
docsBaseUrl?: string
|
||||||
|
features: PrivateSdkFeatures
|
||||||
|
connectTimeoutMs?: number
|
||||||
|
readTimeoutMs?: number
|
||||||
|
logLevel?: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR'
|
||||||
|
activeProfile?: string
|
||||||
|
profiles?: Record<string, Partial<PrivateSdkConfig>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PrivateSdkState {
|
||||||
|
config: PrivateSdkConfig | null
|
||||||
|
token: string | null
|
||||||
|
userId: string | null
|
||||||
|
initialized: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PrivateErrorCode =
|
||||||
|
| 'XUQM_PRIVATE_1001' // config not initialized / JSON not found
|
||||||
|
| 'XUQM_PRIVATE_1002' // invalid config: missing required field or parse error
|
||||||
|
| 'XUQM_PRIVATE_1003' // schema version incompatible
|
||||||
|
| 'XUQM_PRIVATE_1004' // invalid URL format
|
||||||
|
| 'XUQM_PRIVATE_2001' // feature not enabled in deployment
|
||||||
|
| 'XUQM_PRIVATE_2004' // module not initialized
|
||||||
|
|
||||||
|
export class PrivateSdkError extends Error {
|
||||||
|
constructor(
|
||||||
|
public readonly code: PrivateErrorCode,
|
||||||
|
message: string,
|
||||||
|
) {
|
||||||
|
super(`[${code}] ${message}`)
|
||||||
|
this.name = 'PrivateSdkError'
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,10 +10,13 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'src/index.ts'),
|
entry: {
|
||||||
|
index: resolve(__dirname, 'src/index.ts'),
|
||||||
|
'private/index': resolve(__dirname, 'src/private/index.ts'),
|
||||||
|
},
|
||||||
name: 'XuqmVue3SDK',
|
name: 'XuqmVue3SDK',
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es', 'cjs'],
|
||||||
fileName: (format) => `index.${format}.js`,
|
fileName: (format, entryName) => `${entryName}.${format}.js`,
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: ['vue'],
|
external: ['vue'],
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户