@artisan-cloud/plugin-framework-admin 0.0.1-alpha → 0.0.2-alpha
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/index.ts
CHANGED
|
@@ -4,13 +4,27 @@ export interface PowerXAdminConfigOptions {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
export function definePowerXAdminConfig(options: PowerXAdminConfigOptions) {
|
|
7
|
+
const pluginId = options.pluginId
|
|
8
|
+
const inferredApiBase =
|
|
9
|
+
process.env.NUXT_PUBLIC_POWERX_API_BASE?.trim() || `/_p/${pluginId}/api/v1`
|
|
10
|
+
const inferredCapabilityEndpoint =
|
|
11
|
+
process.env.NUXT_PUBLIC_POWERX_CAPABILITY_ENDPOINT?.trim() || '/integration/capabilities/invoke'
|
|
12
|
+
|
|
7
13
|
return {
|
|
8
14
|
extends: ['@artisan-cloud/plugin-framework-admin/layer'],
|
|
9
15
|
appConfig: {
|
|
10
16
|
powerx: {
|
|
11
|
-
pluginId
|
|
17
|
+
pluginId,
|
|
12
18
|
starterPages: options.starterPages ?? true
|
|
13
19
|
}
|
|
20
|
+
},
|
|
21
|
+
runtimeConfig: {
|
|
22
|
+
public: {
|
|
23
|
+
powerx: {
|
|
24
|
+
apiBase: inferredApiBase,
|
|
25
|
+
capabilityEndpoint: inferredCapabilityEndpoint
|
|
26
|
+
}
|
|
27
|
+
}
|
|
14
28
|
}
|
|
15
29
|
}
|
|
16
30
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useNuxtApp } from '#app'
|
|
2
|
+
import type {
|
|
3
|
+
PowerXCapabilityBridge,
|
|
4
|
+
PowerXCapabilityRequest,
|
|
5
|
+
PowerXCapabilityResponse
|
|
6
|
+
} from '../plugins/powerx-capability.client'
|
|
7
|
+
|
|
8
|
+
export interface UsePowerXCapabilityOptions extends Partial<Omit<PowerXCapabilityRequest, 'capabilityId' | 'action' | 'payload'>> {
|
|
9
|
+
payload?: Record<string, any> | null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type UsePowerXCapabilityInvoker = (
|
|
13
|
+
capabilityId: string,
|
|
14
|
+
action: string,
|
|
15
|
+
payload?: Record<string, any> | null,
|
|
16
|
+
options?: UsePowerXCapabilityOptions
|
|
17
|
+
) => Promise<PowerXCapabilityResponse>
|
|
18
|
+
|
|
19
|
+
export const usePowerXCapability = (bridge?: PowerXCapabilityBridge): UsePowerXCapabilityInvoker => {
|
|
20
|
+
const nuxtApp = useNuxtApp()
|
|
21
|
+
const client = bridge ?? nuxtApp.$powerxCapability
|
|
22
|
+
if (!client) {
|
|
23
|
+
throw new Error('PowerX capability bridge is not initialized. Ensure the powerx-capability plugin is registered.')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return async (capabilityId, action, payload, options) => {
|
|
27
|
+
const mergedPayload = options?.payload ?? payload ?? {}
|
|
28
|
+
|
|
29
|
+
return client.invoke({
|
|
30
|
+
capabilityId,
|
|
31
|
+
action,
|
|
32
|
+
payload: mergedPayload,
|
|
33
|
+
headers: options?.headers,
|
|
34
|
+
requestId: options?.requestId,
|
|
35
|
+
signal: options?.signal,
|
|
36
|
+
apiBase: options?.apiBase,
|
|
37
|
+
endpoint: options?.endpoint
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { useRuntimeConfig } from '#imports'
|
|
2
|
+
import { ofetch, type OFetch, type FetchResponse } from 'ofetch'
|
|
3
|
+
|
|
4
|
+
const DEFAULT_ENDPOINT = '/integration/capabilities/invoke'
|
|
5
|
+
|
|
6
|
+
export interface PowerXCapabilityRequest {
|
|
7
|
+
capabilityId: string
|
|
8
|
+
action: string
|
|
9
|
+
payload?: Record<string, any> | null
|
|
10
|
+
headers?: Record<string, string>
|
|
11
|
+
requestId?: string
|
|
12
|
+
signal?: AbortSignal
|
|
13
|
+
apiBase?: string
|
|
14
|
+
endpoint?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface PowerXCapabilityResponse {
|
|
18
|
+
traceId?: string
|
|
19
|
+
status?: string
|
|
20
|
+
data?: Record<string, any> | null
|
|
21
|
+
errors?: Record<string, any> | Record<string, any>[] | null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class PowerXCapabilityBridgeError extends Error {
|
|
25
|
+
status?: number
|
|
26
|
+
traceId?: string
|
|
27
|
+
details?: any
|
|
28
|
+
|
|
29
|
+
constructor(message: string, opts: { status?: number; traceId?: string; details?: any } = {}) {
|
|
30
|
+
super(message)
|
|
31
|
+
this.name = 'PowerXCapabilityBridgeError'
|
|
32
|
+
this.status = opts.status
|
|
33
|
+
this.traceId = opts.traceId
|
|
34
|
+
this.details = opts.details
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PowerXCapabilityBridge {
|
|
39
|
+
invoke(request: PowerXCapabilityRequest): Promise<PowerXCapabilityResponse>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface BridgeOptions {
|
|
43
|
+
apiBase?: string
|
|
44
|
+
endpoint?: string
|
|
45
|
+
fetcher?: OFetch
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const combineURL = (base?: string, endpoint?: string) => {
|
|
49
|
+
const normalizedBase = (base || '').replace(/\/+$/, '')
|
|
50
|
+
const normalizedEndpoint = ('/' + (endpoint || '').replace(/^\/+/, '')).replace(/\/{2,}/g, '/')
|
|
51
|
+
if (!normalizedBase) {
|
|
52
|
+
return normalizedEndpoint
|
|
53
|
+
}
|
|
54
|
+
return `${normalizedBase}${normalizedEndpoint}`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const createBridge = (options: BridgeOptions): PowerXCapabilityBridge => {
|
|
58
|
+
const fetcher = options.fetcher ?? ofetch
|
|
59
|
+
const endpoint = options.endpoint || DEFAULT_ENDPOINT
|
|
60
|
+
return {
|
|
61
|
+
async invoke(request) {
|
|
62
|
+
const capabilityId = request.capabilityId?.trim()
|
|
63
|
+
if (!capabilityId) {
|
|
64
|
+
throw new PowerXCapabilityBridgeError('capabilityId is required')
|
|
65
|
+
}
|
|
66
|
+
const action = request.action?.trim()
|
|
67
|
+
if (!action) {
|
|
68
|
+
throw new PowerXCapabilityBridgeError('action is required')
|
|
69
|
+
}
|
|
70
|
+
const url = combineURL(request.apiBase ?? options.apiBase, request.endpoint ?? endpoint)
|
|
71
|
+
const headers: Record<string, string> = {
|
|
72
|
+
'Content-Type': 'application/json',
|
|
73
|
+
...request.headers
|
|
74
|
+
}
|
|
75
|
+
if (request.requestId && !headers['X-Request-ID']) {
|
|
76
|
+
headers['X-Request-ID'] = request.requestId
|
|
77
|
+
}
|
|
78
|
+
let response: FetchResponse<Record<string, any>>
|
|
79
|
+
try {
|
|
80
|
+
response = await fetcher.raw(url, {
|
|
81
|
+
method: 'POST',
|
|
82
|
+
headers,
|
|
83
|
+
body: {
|
|
84
|
+
capabilityId,
|
|
85
|
+
action,
|
|
86
|
+
payload: request.payload ?? {}
|
|
87
|
+
},
|
|
88
|
+
signal: request.signal
|
|
89
|
+
})
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new PowerXCapabilityBridgeError(error instanceof Error ? error.message : 'capability invoke failed')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const payload = response._data ?? {}
|
|
95
|
+
const traceId = payload.traceId || response.headers.get('x-trace-id') || undefined
|
|
96
|
+
if (response.status >= 400 || payload.error) {
|
|
97
|
+
throw new PowerXCapabilityBridgeError(payload.error?.message || 'capability invoke failed', {
|
|
98
|
+
status: response.status,
|
|
99
|
+
traceId,
|
|
100
|
+
details: payload.error || payload.errors
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
traceId,
|
|
106
|
+
status: payload.status,
|
|
107
|
+
data: payload.data ?? null,
|
|
108
|
+
errors: payload.errors ?? null
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
115
|
+
const runtimeConfig = useRuntimeConfig()
|
|
116
|
+
const publicConfig = runtimeConfig?.public as Record<string, any> | undefined
|
|
117
|
+
const powerxConfig = (publicConfig?.powerx ?? {}) as Record<string, any>
|
|
118
|
+
|
|
119
|
+
const bridge = createBridge({
|
|
120
|
+
apiBase: (powerxConfig.apiBase as string | undefined) ?? '',
|
|
121
|
+
endpoint: (powerxConfig.capabilityEndpoint as string | undefined) ?? DEFAULT_ENDPOINT,
|
|
122
|
+
fetcher: nuxtApp.$fetch
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
provide: {
|
|
127
|
+
powerxCapability: bridge
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
declare module '#app' {
|
|
133
|
+
interface NuxtApp {
|
|
134
|
+
$powerxCapability: PowerXCapabilityBridge
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
declare module 'vue' {
|
|
139
|
+
interface ComponentCustomProperties {
|
|
140
|
+
$powerxCapability: PowerXCapabilityBridge
|
|
141
|
+
}
|
|
142
|
+
}
|
package/layer/nuxt.config.ts
CHANGED
|
@@ -6,6 +6,14 @@ const layerDir = dirname(fileURLToPath(import.meta.url))
|
|
|
6
6
|
const appDir = resolve(layerDir, 'app')
|
|
7
7
|
|
|
8
8
|
const config: NuxtConfig = {
|
|
9
|
+
runtimeConfig: {
|
|
10
|
+
public: {
|
|
11
|
+
powerx: {
|
|
12
|
+
apiBase: process.env.NUXT_PUBLIC_POWERX_API_BASE ?? '',
|
|
13
|
+
capabilityEndpoint: process.env.NUXT_PUBLIC_POWERX_CAPABILITY_ENDPOINT ?? '/integration/capabilities/invoke'
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
9
17
|
imports: {
|
|
10
18
|
dirs: [
|
|
11
19
|
resolve(appDir, 'composables'),
|
|
@@ -35,3 +43,12 @@ const config: NuxtConfig = {
|
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
export default config
|
|
46
|
+
|
|
47
|
+
declare module 'nuxt/schema' {
|
|
48
|
+
interface PublicRuntimeConfig {
|
|
49
|
+
powerx: {
|
|
50
|
+
apiBase: string
|
|
51
|
+
capabilityEndpoint: string
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|