@fayz-ai/core 0.8.1 → 0.8.3
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/access/denial.d.ts +21 -0
- package/dist/access/denial.d.ts.map +1 -0
- package/dist/access/engine.d.ts +63 -0
- package/dist/access/engine.d.ts.map +1 -0
- package/dist/access/index.cjs +60 -0
- package/dist/access/index.cjs.map +1 -0
- package/dist/access/index.d.ts +6 -0
- package/dist/access/index.d.ts.map +1 -0
- package/dist/access/index.js +51 -0
- package/dist/access/index.js.map +1 -0
- package/dist/access/limits.d.ts +10 -0
- package/dist/access/limits.d.ts.map +1 -0
- package/dist/address/index.d.ts +52 -0
- package/dist/address/index.d.ts.map +1 -0
- package/dist/{chunk-QR7U2URY.cjs → chunk-CATASHPK.cjs} +345 -4
- package/dist/chunk-CATASHPK.cjs.map +1 -0
- package/dist/{chunk-WKZVSKEU.js → chunk-CU64QI4A.js} +2 -2
- package/dist/chunk-CU64QI4A.js.map +1 -0
- package/dist/{chunk-KNIVT6XZ.js → chunk-DZALZ6Q6.js} +345 -4
- package/dist/chunk-DZALZ6Q6.js.map +1 -0
- package/dist/{chunk-54SRL7AJ.cjs → chunk-KSI2L3E4.cjs} +145 -86
- package/dist/chunk-KSI2L3E4.cjs.map +1 -0
- package/dist/{chunk-ZBIWYDAR.js → chunk-TYPVSWLG.js} +144 -87
- package/dist/chunk-TYPVSWLG.js.map +1 -0
- package/dist/{chunk-2NTHNWEH.cjs → chunk-UKU4RIWM.cjs} +2 -2
- package/dist/chunk-UKU4RIWM.cjs.map +1 -0
- package/dist/{chunk-CHGX6UYR.js → chunk-YH25Y4FW.js} +6 -3
- package/dist/chunk-YH25Y4FW.js.map +1 -0
- package/dist/{chunk-5X2VX3RQ.cjs → chunk-ZOPJB5FN.cjs} +6 -3
- package/dist/chunk-ZOPJB5FN.cjs.map +1 -0
- package/dist/data/archetype.d.ts.map +1 -1
- package/dist/data/count.d.ts +34 -0
- package/dist/data/count.d.ts.map +1 -0
- package/dist/data/index.cjs +18 -10
- package/dist/data/index.d.ts +2 -0
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +1 -1
- package/dist/data/refresh.d.ts +36 -0
- package/dist/data/refresh.d.ts.map +1 -0
- package/dist/data/resolve.d.ts.map +1 -1
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/data/types.d.ts +6 -0
- package/dist/data/types.d.ts.map +1 -1
- package/dist/entity/index.cjs +6 -6
- package/dist/entity/index.js +1 -1
- package/dist/entity/registry.d.ts +9 -0
- package/dist/entity/registry.d.ts.map +1 -1
- package/dist/i18n/index.cjs +10 -10
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/shell-translations.d.ts.map +1 -1
- package/dist/index.cjs +1517 -180
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1412 -110
- package/dist/index.js.map +1 -1
- package/dist/manifest/index.d.ts +109 -3
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/serialize.d.ts +14 -0
- package/dist/manifest/serialize.d.ts.map +1 -0
- package/dist/plugin/index.cjs +7 -7
- package/dist/plugin/index.js +1 -1
- package/dist/plugin/runtime.d.ts.map +1 -1
- package/dist/search/engine.d.ts +12 -0
- package/dist/search/engine.d.ts.map +1 -0
- package/dist/search/index.d.ts +5 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/text.d.ts +37 -0
- package/dist/search/text.d.ts.map +1 -0
- package/dist/search/types.d.ts +72 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/types/billing.d.ts +20 -0
- package/dist/types/billing.d.ts.map +1 -1
- package/dist/types/crud.d.ts +47 -1
- package/dist/types/crud.d.ts.map +1 -1
- package/dist/types/entitlements.d.ts +45 -0
- package/dist/types/entitlements.d.ts.map +1 -0
- package/dist/types/index.d.ts +4 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/org.d.ts +28 -0
- package/dist/types/org.d.ts.map +1 -1
- package/dist/types/plugins.d.ts +88 -0
- package/dist/types/plugins.d.ts.map +1 -1
- package/package.json +14 -4
- package/src/access/denial.ts +33 -0
- package/src/access/engine.test.ts +48 -0
- package/src/access/engine.ts +121 -0
- package/src/access/index.ts +13 -0
- package/src/access/limits.ts +18 -0
- package/src/address/index.ts +188 -0
- package/src/data/archetype.ts +4 -2
- package/src/data/count.test.ts +152 -0
- package/src/data/count.ts +131 -0
- package/src/data/index.ts +2 -0
- package/src/data/refresh.ts +105 -0
- package/src/data/resolve.ts +7 -1
- package/src/data/supabase.ts +3 -1
- package/src/data/types.ts +6 -0
- package/src/entity/registry.ts +7 -0
- package/src/i18n/shell-translations.ts +345 -2
- package/src/index.ts +37 -4
- package/src/manifest/app-manifest.schema.json +618 -45
- package/src/manifest/index.ts +127 -3
- package/src/manifest/serialize.ts +52 -0
- package/src/plugin/runtime.ts +5 -1
- package/src/search/engine.ts +551 -0
- package/src/search/index.ts +25 -0
- package/src/search/text.ts +206 -0
- package/src/search/types.ts +75 -0
- package/src/types/billing.ts +22 -0
- package/src/types/crud.ts +48 -1
- package/src/types/entitlements.ts +45 -0
- package/src/types/index.ts +4 -3
- package/src/types/org.ts +29 -0
- package/src/types/plugins.ts +83 -0
- package/dist/chunk-2NTHNWEH.cjs.map +0 -1
- package/dist/chunk-54SRL7AJ.cjs.map +0 -1
- package/dist/chunk-5X2VX3RQ.cjs.map +0 -1
- package/dist/chunk-CHGX6UYR.js.map +0 -1
- package/dist/chunk-KNIVT6XZ.js.map +0 -1
- package/dist/chunk-QR7U2URY.cjs.map +0 -1
- package/dist/chunk-WKZVSKEU.js.map +0 -1
- package/dist/chunk-ZBIWYDAR.js.map +0 -1
package/src/manifest/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { EntityDef } from '../types/crud'
|
|
2
2
|
import type { LocaleConfig } from '../types/i18n'
|
|
3
|
-
import type { PermissionsConfig } from '../types/permissions'
|
|
3
|
+
import type { PermissionsConfig, FeatureDeclaration } from '../types/permissions'
|
|
4
4
|
import type { BillingConfig } from '../types/billing'
|
|
5
|
+
import type { LimitDeclaration } from '../types/entitlements'
|
|
6
|
+
import type { AIToolParameters, AIToolExecution, AgentRpcDeclaration } from '../types/plugins'
|
|
5
7
|
import type { BlockNode } from '../blocks'
|
|
6
8
|
|
|
7
9
|
// ---------------------------------------------------------------------------
|
|
@@ -18,7 +20,7 @@ import type { BlockNode } from '../blocks'
|
|
|
18
20
|
// right is why W1 is the "point of no return".
|
|
19
21
|
// ---------------------------------------------------------------------------
|
|
20
22
|
|
|
21
|
-
export const CURRENT_MANIFEST_VERSION =
|
|
23
|
+
export const CURRENT_MANIFEST_VERSION = 3
|
|
22
24
|
|
|
23
25
|
export type BackendProvider = 'supabase' | 'fayz-api' | 'fayz-shop' | 'mock' | 'custom'
|
|
24
26
|
|
|
@@ -68,6 +70,97 @@ export interface SurfaceManifest {
|
|
|
68
70
|
options?: Record<string, unknown>
|
|
69
71
|
}
|
|
70
72
|
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Agent Contract (manifest v3) — everything a SERVER-SIDE agent runtime needs
|
|
75
|
+
// to operate the app without a browser: the full entity surface, the tool
|
|
76
|
+
// catalog with its authorization requirements, the pool RPCs writes go
|
|
77
|
+
// through, and the structured domain knowledge the app wants in the prompt.
|
|
78
|
+
// Derived from app code at publish (never hand-written) and synced to the
|
|
79
|
+
// Fayz platform, where it becomes the versioned AgentContract the broker
|
|
80
|
+
// validates every turn against.
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
/** JSON-safe projection of an EntityDef — schema only, no components/closures.
|
|
84
|
+
* `data` mirrors EntityDef.data: everything the server-plane read executor
|
|
85
|
+
* needs (tenant scoping, search/select column allowlists, fixed filters). */
|
|
86
|
+
export interface EntityContract {
|
|
87
|
+
key: string
|
|
88
|
+
label: string
|
|
89
|
+
labelPlural?: string
|
|
90
|
+
/** Plan-limit key rows of this entity consume (EntityDef.limitKey). */
|
|
91
|
+
limitKey?: string
|
|
92
|
+
/** Permission to READ via the generic data primitives (EntityDef.permission). */
|
|
93
|
+
permission?: { feature: string; action: string }
|
|
94
|
+
data: {
|
|
95
|
+
table: string
|
|
96
|
+
schema?: string
|
|
97
|
+
tenantScoped?: boolean
|
|
98
|
+
tenantIdColumn?: string
|
|
99
|
+
searchColumns?: string[]
|
|
100
|
+
selectColumns?: string
|
|
101
|
+
columnMap?: Record<string, string>
|
|
102
|
+
archetype?: string
|
|
103
|
+
archetypeKind?: string
|
|
104
|
+
filters?: Record<string, string>
|
|
105
|
+
}
|
|
106
|
+
fields: Array<{
|
|
107
|
+
key: string
|
|
108
|
+
label: string
|
|
109
|
+
type: string
|
|
110
|
+
required?: boolean
|
|
111
|
+
searchable?: boolean
|
|
112
|
+
/** FieldDef.hint — the field's helper text. Carried into the contract
|
|
113
|
+
* because it is what tells the agent what a non-obvious column expects:
|
|
114
|
+
* an id to look up, a default it should not restate, a format. */
|
|
115
|
+
hint?: string
|
|
116
|
+
/** Allowed values for select-like fields. */
|
|
117
|
+
options?: string[]
|
|
118
|
+
/** Table the relation field points at (FieldRelation.table). */
|
|
119
|
+
relationTable?: string
|
|
120
|
+
}>
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** JSON-safe projection of a PluginAITool + its owning plugin. */
|
|
124
|
+
export interface AIToolContract {
|
|
125
|
+
id: string
|
|
126
|
+
name: string
|
|
127
|
+
description: string
|
|
128
|
+
mode: 'read' | 'persist'
|
|
129
|
+
parameters?: AIToolParameters
|
|
130
|
+
permission?: { feature: string; action: string }
|
|
131
|
+
limitKey?: string
|
|
132
|
+
execution?: AIToolExecution
|
|
133
|
+
requiresConfirmation?: boolean
|
|
134
|
+
pluginId?: string
|
|
135
|
+
category?: string
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** A tenant-scoped pool RPC the server-plane executor may call. Canonical
|
|
139
|
+
* definition lives with the plugin types (plugins declare these). */
|
|
140
|
+
export type { AgentRpcDeclaration as RpcContract } from '../types/plugins'
|
|
141
|
+
|
|
142
|
+
/** Structured domain knowledge rendered into the agent's prompt as labelled
|
|
143
|
+
* sections — statuses with transitions, scheduling defaults, free-form rules. */
|
|
144
|
+
export interface AgentDomainKnowledge {
|
|
145
|
+
statuses?: Record<string, Array<{ id: string; label: string; availableWhen?: unknown }>>
|
|
146
|
+
scheduleDefaults?: Record<string, unknown>
|
|
147
|
+
businessRules?: Array<{ id: string; description: string }>
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface AgentContract {
|
|
151
|
+
persona?: { name?: string; systemPrompt?: string; icon?: string }
|
|
152
|
+
/** When 'server', surfaces stop shipping data-tool executors: the broker
|
|
153
|
+
* executes reads/writes server-plane and the surface only handles
|
|
154
|
+
* client-plane tools. Flipped per app — no lockstep release. */
|
|
155
|
+
executionPlane?: 'client' | 'server'
|
|
156
|
+
entities?: EntityContract[]
|
|
157
|
+
tools?: AIToolContract[]
|
|
158
|
+
registries?: Array<{ pluginId: string; id: string; entityKey?: string; readOnly?: boolean }>
|
|
159
|
+
declaredFeatures?: FeatureDeclaration[]
|
|
160
|
+
rpcs?: AgentRpcDeclaration[]
|
|
161
|
+
domainKnowledge?: AgentDomainKnowledge
|
|
162
|
+
}
|
|
163
|
+
|
|
71
164
|
export interface AppManifest {
|
|
72
165
|
manifestVersion: number
|
|
73
166
|
id: string
|
|
@@ -83,6 +176,13 @@ export interface AppManifest {
|
|
|
83
176
|
entities?: EntityDef[]
|
|
84
177
|
permissions?: PermissionsConfig
|
|
85
178
|
billing?: BillingConfig
|
|
179
|
+
/** The RESOLVED limit declarations (4-layer merge: core < entity-derived <
|
|
180
|
+
* plugin < app), so a server runtime counts exactly what the client counts. */
|
|
181
|
+
limitDeclarations?: LimitDeclaration[]
|
|
182
|
+
/** v3: the agent contract — see the section comment above. */
|
|
183
|
+
agent?: AgentContract
|
|
184
|
+
/** sha256 of the canonical serialization (excluding this field). */
|
|
185
|
+
contractHash?: string
|
|
86
186
|
}
|
|
87
187
|
|
|
88
188
|
// ---------------------------------------------------------------------------
|
|
@@ -108,6 +208,9 @@ const allowedManifestKeys = new Set([
|
|
|
108
208
|
'billing',
|
|
109
209
|
'entities',
|
|
110
210
|
'surfaces',
|
|
211
|
+
'limitDeclarations',
|
|
212
|
+
'agent',
|
|
213
|
+
'contractHash',
|
|
111
214
|
])
|
|
112
215
|
const allowedBackendKeys = new Set(['provider', 'projectRef', 'url', 'adapterId', 'options'])
|
|
113
216
|
const allowedSurfaceKeys = new Set(['scaffold', 'options', 'plugins', 'pages'])
|
|
@@ -122,6 +225,12 @@ export function registerManifestMigration(fromVersion: number, fn: ManifestMigra
|
|
|
122
225
|
migrations.set(fromVersion, fn)
|
|
123
226
|
}
|
|
124
227
|
|
|
228
|
+
// v2 → v3 is purely additive (limitDeclarations/agent/contractHash are optional):
|
|
229
|
+
// a v2 manifest is a valid v3 manifest with those sections absent. Registered
|
|
230
|
+
// here so every consumer migrates for free; `fayz manifest emit` fills the new
|
|
231
|
+
// sections on the next regeneration.
|
|
232
|
+
registerManifestMigration(2, (m) => m)
|
|
233
|
+
|
|
125
234
|
/** Bring any manifest up to CURRENT_MANIFEST_VERSION, or throw if it was built
|
|
126
235
|
* for a newer SDK than this runtime understands. */
|
|
127
236
|
export function migrateManifest(input: AnyManifest): AppManifest {
|
|
@@ -167,6 +276,21 @@ export function validateManifest(m: AppManifest): string[] {
|
|
|
167
276
|
validateLooseObject(manifest.theme, 'manifest.theme', problems)
|
|
168
277
|
validateLooseObject(manifest.permissions, 'manifest.permissions', problems)
|
|
169
278
|
validateLooseObject(manifest.billing, 'manifest.billing', problems)
|
|
279
|
+
validateLooseObject(manifest.agent, 'manifest.agent', problems)
|
|
280
|
+
if (manifest.contractHash !== undefined && !isNonEmptyString(manifest.contractHash)) {
|
|
281
|
+
problems.push('manifest.contractHash must be a non-empty string')
|
|
282
|
+
}
|
|
283
|
+
if (manifest.limitDeclarations !== undefined) {
|
|
284
|
+
if (!Array.isArray(manifest.limitDeclarations)) {
|
|
285
|
+
problems.push('manifest.limitDeclarations must be an array')
|
|
286
|
+
} else {
|
|
287
|
+
manifest.limitDeclarations.forEach((decl, index) => {
|
|
288
|
+
if (!isRecord(decl) || !isNonEmptyString(decl.key) || !isNonEmptyString(decl.table)) {
|
|
289
|
+
problems.push(`manifest.limitDeclarations[${index}] must declare key and table`)
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
}
|
|
170
294
|
if (manifest.entities !== undefined) {
|
|
171
295
|
if (!Array.isArray(manifest.entities)) {
|
|
172
296
|
problems.push('manifest.entities must be an array')
|
|
@@ -368,7 +492,7 @@ function addUnsupportedKeys(
|
|
|
368
492
|
): void {
|
|
369
493
|
for (const key of Object.keys(value)) {
|
|
370
494
|
if (!allowedKeys.has(key)) {
|
|
371
|
-
problems.push(`${path}.${key} is not part of AppManifest
|
|
495
|
+
problems.push(`${path}.${key} is not part of AppManifest v${CURRENT_MANIFEST_VERSION}`)
|
|
372
496
|
}
|
|
373
497
|
}
|
|
374
498
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { AppManifest } from './index'
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Deterministic serialization — the SAME manifest object must always produce
|
|
5
|
+
// the SAME bytes, because the sha256 of those bytes (`contractHash`) is what
|
|
6
|
+
// makes `fayz manifest sync` idempotent and lets `fayz doctor` prove the
|
|
7
|
+
// committed app.manifest.json is not stale. Rules: object keys sorted, arrays
|
|
8
|
+
// kept in declared order (order is meaning: nav position, migration order),
|
|
9
|
+
// 2-space indent, trailing newline, `contractHash` itself excluded.
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
function sortValue(value: unknown): unknown {
|
|
13
|
+
if (Array.isArray(value)) return value.map(sortValue)
|
|
14
|
+
if (value !== null && typeof value === 'object') {
|
|
15
|
+
const record = value as Record<string, unknown>
|
|
16
|
+
const out: Record<string, unknown> = {}
|
|
17
|
+
for (const key of Object.keys(record).sort()) {
|
|
18
|
+
const v = record[key]
|
|
19
|
+
if (v !== undefined) out[key] = sortValue(v)
|
|
20
|
+
}
|
|
21
|
+
return out
|
|
22
|
+
}
|
|
23
|
+
return value
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Canonical JSON of a manifest (contractHash excluded, keys sorted). */
|
|
27
|
+
export function serializeManifest(manifest: AppManifest): string {
|
|
28
|
+
const { contractHash: _omit, ...rest } = manifest
|
|
29
|
+
return `${JSON.stringify(sortValue(rest), null, 2)}\n`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* sha256 (hex) of the canonical serialization. Async because it runs on
|
|
34
|
+
* WebCrypto (`globalThis.crypto.subtle`), which exists in every runtime we
|
|
35
|
+
* target (browsers, Node ≥ 18, edge) — no node:crypto import, keeping this
|
|
36
|
+
* module bundleable everywhere.
|
|
37
|
+
*/
|
|
38
|
+
export async function computeContractHash(manifest: AppManifest): Promise<string> {
|
|
39
|
+
const bytes = new TextEncoder().encode(serializeManifest(manifest))
|
|
40
|
+
const digest = await globalThis.crypto.subtle.digest('SHA-256', bytes)
|
|
41
|
+
return Array.from(new Uint8Array(digest))
|
|
42
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
43
|
+
.join('')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Serialize WITH the freshly computed contractHash embedded — what
|
|
47
|
+
* `fayz manifest emit` writes to app.manifest.json. */
|
|
48
|
+
export async function serializeManifestWithHash(manifest: AppManifest): Promise<string> {
|
|
49
|
+
const contractHash = await computeContractHash(manifest)
|
|
50
|
+
const { contractHash: _omit, ...rest } = manifest
|
|
51
|
+
return `${JSON.stringify(sortValue({ ...rest, contractHash }), null, 2)}\n`
|
|
52
|
+
}
|
package/src/plugin/runtime.ts
CHANGED
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
DashboardSurface,
|
|
21
21
|
} from '../types/plugins'
|
|
22
22
|
import type { FeatureDeclaration } from '../types/permissions'
|
|
23
|
+
import type { LimitDeclaration } from '../types/entitlements'
|
|
23
24
|
import type { ConnectorDefinition } from '../integrations'
|
|
24
25
|
import { getComponent } from '../registry'
|
|
25
26
|
|
|
@@ -110,6 +111,7 @@ function createEmptyRuntime(context: PluginRuntimeContext = EMPTY_CONTEXT): Plug
|
|
|
110
111
|
registries: new Map(),
|
|
111
112
|
connectorsByHost: new Map(),
|
|
112
113
|
pluginFeatures: [],
|
|
114
|
+
pluginLimits: [],
|
|
113
115
|
issues: [],
|
|
114
116
|
}
|
|
115
117
|
}
|
|
@@ -242,6 +244,7 @@ export function resolvePluginRuntime({
|
|
|
242
244
|
const registries = new Map<string, PluginRegistryDef[]>()
|
|
243
245
|
const connectorsByHost = new Map<string, ConnectorDefinition[]>()
|
|
244
246
|
const pluginFeatures: FeatureDeclaration[] = []
|
|
247
|
+
const pluginLimits: LimitDeclaration[] = []
|
|
245
248
|
|
|
246
249
|
for (const plugin of activePlugins) {
|
|
247
250
|
routes.push(...plugin.routes.map((r) => ({ ...r, plugin })))
|
|
@@ -261,6 +264,7 @@ export function resolvePluginRuntime({
|
|
|
261
264
|
connectorsByHost.set(connector.hostPluginId, list)
|
|
262
265
|
}
|
|
263
266
|
if (plugin.declaredFeatures) pluginFeatures.push(...plugin.declaredFeatures)
|
|
267
|
+
if (plugin.declaredLimits) pluginLimits.push(...plugin.declaredLimits)
|
|
264
268
|
widgets.push(...plugin.widgets.map((w, i) => ({
|
|
265
269
|
...w,
|
|
266
270
|
order: w.order ?? i,
|
|
@@ -283,7 +287,7 @@ export function resolvePluginRuntime({
|
|
|
283
287
|
widgets.sort((a, b) => a.zone !== b.zone ? a.zone.localeCompare(b.zone) : a.order - b.order)
|
|
284
288
|
dashboardWidgets.sort((a, b) => a.order - b.order)
|
|
285
289
|
|
|
286
|
-
return { context, plugins: resolvedPlugins, activePlugins, routes, navigation, settingsTabs, widgets, dashboardWidgets, capabilities, aiTools, issues, registries, connectorsByHost, pluginFeatures }
|
|
290
|
+
return { context, plugins: resolvedPlugins, activePlugins, routes, navigation, settingsTabs, widgets, dashboardWidgets, capabilities, aiTools, issues, registries, connectorsByHost, pluginFeatures, pluginLimits }
|
|
287
291
|
}
|
|
288
292
|
|
|
289
293
|
export function getWidgetsForZone(
|