@fayz-ai/core 0.9.0 → 0.10.0

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.
Files changed (170) hide show
  1. package/README.md +2 -2
  2. package/dist/access/index.js.map +1 -1
  3. package/dist/{chunk-L4TLMYGC.js → chunk-6RBW2Y5K.js} +3 -3
  4. package/dist/chunk-6RBW2Y5K.js.map +1 -0
  5. package/dist/chunk-732GZEUI.js +1592 -0
  6. package/dist/chunk-732GZEUI.js.map +1 -0
  7. package/dist/{chunk-X5THHG6T.js → chunk-CPMHCTX3.js} +3 -3
  8. package/dist/chunk-CPMHCTX3.js.map +1 -0
  9. package/dist/{chunk-V2MSAUHO.js → chunk-JO7Z2AOE.js} +2 -2
  10. package/dist/chunk-JO7Z2AOE.js.map +1 -0
  11. package/dist/{chunk-5RJVUC6J.js → chunk-M27JPX3K.js} +12 -3
  12. package/dist/chunk-M27JPX3K.js.map +1 -0
  13. package/dist/chunk-OXQGRJZT.js +125 -0
  14. package/dist/chunk-OXQGRJZT.js.map +1 -0
  15. package/dist/data/backend-env.d.ts +38 -0
  16. package/dist/data/backend-env.d.ts.map +1 -0
  17. package/dist/data/index.js +1 -1
  18. package/dist/entity/events.d.ts +14 -0
  19. package/dist/entity/events.d.ts.map +1 -0
  20. package/dist/events/envelope.d.ts +31 -0
  21. package/dist/events/envelope.d.ts.map +1 -0
  22. package/dist/events/index.d.ts +4 -0
  23. package/dist/events/index.d.ts.map +1 -1
  24. package/dist/events/log.d.ts +44 -0
  25. package/dist/events/log.d.ts.map +1 -0
  26. package/dist/events/types.d.ts +40 -0
  27. package/dist/events/types.d.ts.map +1 -0
  28. package/dist/i18n/index.d.ts +10 -0
  29. package/dist/i18n/index.d.ts.map +1 -1
  30. package/dist/i18n/index.js +1 -1
  31. package/dist/index.d.ts +27 -17
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +388 -52
  34. package/dist/index.js.map +1 -1
  35. package/dist/integrations/index.js +1 -1
  36. package/dist/{integrations/index.d.ts → integrations.d.ts} +2 -2
  37. package/dist/integrations.d.ts.map +1 -0
  38. package/dist/{address/index.d.ts → lib/address.d.ts} +1 -1
  39. package/dist/{address/index.d.ts.map → lib/address.d.ts.map} +1 -1
  40. package/dist/{phone/index.d.ts → lib/phone.d.ts} +1 -1
  41. package/dist/lib/phone.d.ts.map +1 -0
  42. package/dist/{seo/index.d.ts → lib/seo.d.ts} +18 -1
  43. package/dist/lib/seo.d.ts.map +1 -0
  44. package/dist/{tenant/index.d.ts → lib/tenant.d.ts} +1 -1
  45. package/dist/lib/tenant.d.ts.map +1 -0
  46. package/dist/manifest/index.d.ts +1 -1
  47. package/dist/manifest/index.d.ts.map +1 -1
  48. package/dist/messaging/index.d.ts +3 -0
  49. package/dist/messaging/index.d.ts.map +1 -0
  50. package/dist/messaging/registry.d.ts +35 -0
  51. package/dist/messaging/registry.d.ts.map +1 -0
  52. package/dist/messaging/types.d.ts +67 -0
  53. package/dist/messaging/types.d.ts.map +1 -0
  54. package/dist/plugin/index.js +2 -1
  55. package/dist/plugin/runtime.d.ts +17 -0
  56. package/dist/plugin/runtime.d.ts.map +1 -1
  57. package/dist/registry/block-catalog.d.ts +78 -0
  58. package/dist/registry/block-catalog.d.ts.map +1 -0
  59. package/dist/registry/block-constraints.d.ts +64 -0
  60. package/dist/registry/block-constraints.d.ts.map +1 -0
  61. package/dist/registry/block-schema.d.ts +69 -0
  62. package/dist/registry/block-schema.d.ts.map +1 -0
  63. package/dist/registry/blocks.d.ts +84 -0
  64. package/dist/registry/blocks.d.ts.map +1 -0
  65. package/dist/registry/entities.d.ts +153 -0
  66. package/dist/registry/entities.d.ts.map +1 -0
  67. package/dist/registry/extension-points.d.ts +117 -0
  68. package/dist/registry/extension-points.d.ts.map +1 -0
  69. package/dist/registry/handles.d.ts +41 -0
  70. package/dist/registry/handles.d.ts.map +1 -0
  71. package/dist/registry/index.d.ts +41 -41
  72. package/dist/registry/index.d.ts.map +1 -1
  73. package/dist/registry/loaders.d.ts +55 -0
  74. package/dist/registry/loaders.d.ts.map +1 -0
  75. package/dist/registry/registry-class.d.ts +157 -0
  76. package/dist/registry/registry-class.d.ts.map +1 -0
  77. package/dist/registry/schema-check.d.ts +14 -0
  78. package/dist/registry/schema-check.d.ts.map +1 -0
  79. package/dist/router/index.d.ts +78 -1
  80. package/dist/router/index.d.ts.map +1 -1
  81. package/dist/router/index.js +1 -1
  82. package/dist/testing/index.js +1 -1
  83. package/dist/{testing/index.d.ts → testing.d.ts} +3 -3
  84. package/dist/testing.d.ts.map +1 -0
  85. package/dist/types/analytics.d.ts +196 -0
  86. package/dist/types/analytics.d.ts.map +1 -0
  87. package/dist/types/crud.d.ts +22 -2
  88. package/dist/types/crud.d.ts.map +1 -1
  89. package/dist/types/plugins.d.ts +55 -1
  90. package/dist/types/plugins.d.ts.map +1 -1
  91. package/package.json +6 -18
  92. package/dist/blocks/index.d.ts +0 -25
  93. package/dist/blocks/index.d.ts.map +0 -1
  94. package/dist/chunk-5RJVUC6J.js.map +0 -1
  95. package/dist/chunk-L4TLMYGC.js.map +0 -1
  96. package/dist/chunk-V2MSAUHO.js.map +0 -1
  97. package/dist/chunk-X5THHG6T.js.map +0 -1
  98. package/dist/chunk-Y2C2FBQP.js +0 -35
  99. package/dist/chunk-Y2C2FBQP.js.map +0 -1
  100. package/dist/chunk-YH25Y4FW.js +0 -311
  101. package/dist/chunk-YH25Y4FW.js.map +0 -1
  102. package/dist/integrations/index.d.ts.map +0 -1
  103. package/dist/phone/index.d.ts.map +0 -1
  104. package/dist/seo/index.d.ts.map +0 -1
  105. package/dist/tenant/index.d.ts.map +0 -1
  106. package/dist/testing/index.d.ts.map +0 -1
  107. package/src/access/denial.ts +0 -33
  108. package/src/access/engine.test.ts +0 -48
  109. package/src/access/engine.ts +0 -136
  110. package/src/access/index.ts +0 -14
  111. package/src/access/limits.ts +0 -18
  112. package/src/address/index.ts +0 -188
  113. package/src/app/render.tsx +0 -69
  114. package/src/blocks/index.tsx +0 -68
  115. package/src/data/archetype.ts +0 -255
  116. package/src/data/bulk.ts +0 -35
  117. package/src/data/cached.ts +0 -55
  118. package/src/data/count.test.ts +0 -152
  119. package/src/data/count.ts +0 -131
  120. package/src/data/filters.test.ts +0 -70
  121. package/src/data/filters.ts +0 -90
  122. package/src/data/index.ts +0 -11
  123. package/src/data/mock.ts +0 -90
  124. package/src/data/platform-api.ts +0 -209
  125. package/src/data/refresh.ts +0 -115
  126. package/src/data/resolve.ts +0 -126
  127. package/src/data/supabase.ts +0 -230
  128. package/src/data/types.ts +0 -50
  129. package/src/entity/index.ts +0 -2
  130. package/src/entity/registry.ts +0 -49
  131. package/src/events/index.tsx +0 -82
  132. package/src/i18n/index.ts +0 -476
  133. package/src/i18n/shell-translations.en.ts +0 -875
  134. package/src/i18n/shell-translations.pt-br.ts +0 -873
  135. package/src/index.ts +0 -217
  136. package/src/integrations/index.ts +0 -237
  137. package/src/lib/cache.ts +0 -118
  138. package/src/lib/csv.ts +0 -54
  139. package/src/lib/format.ts +0 -58
  140. package/src/manifest/app-manifest.schema.json +0 -676
  141. package/src/manifest/index.ts +0 -518
  142. package/src/manifest/serialize.ts +0 -52
  143. package/src/phone/index.ts +0 -85
  144. package/src/plugin/createSafeDataProvider.ts +0 -30
  145. package/src/plugin/index.ts +0 -1
  146. package/src/plugin/runtime.ts +0 -331
  147. package/src/registry/index.ts +0 -163
  148. package/src/router/history.ts +0 -86
  149. package/src/router/index.ts +0 -29
  150. package/src/runtime/index.ts +0 -15
  151. package/src/runtime/oauth.ts +0 -219
  152. package/src/search/engine.ts +0 -559
  153. package/src/search/index.ts +0 -25
  154. package/src/search/text.ts +0 -206
  155. package/src/search/types.ts +0 -75
  156. package/src/seo/index.ts +0 -128
  157. package/src/tenant/index.ts +0 -38
  158. package/src/testing/index.ts +0 -116
  159. package/src/types/auth.ts +0 -41
  160. package/src/types/billing.ts +0 -39
  161. package/src/types/crud.ts +0 -184
  162. package/src/types/entities.ts +0 -142
  163. package/src/types/entitlements.ts +0 -45
  164. package/src/types/i18n.ts +0 -7
  165. package/src/types/index.ts +0 -11
  166. package/src/types/org.ts +0 -137
  167. package/src/types/payment.ts +0 -44
  168. package/src/types/permissions.ts +0 -32
  169. package/src/types/plugins.ts +0 -480
  170. package/src/types/theme.ts +0 -8
@@ -1,331 +0,0 @@
1
- import * as React from 'react'
2
- import type {
3
- PluginManifest,
4
- PluginRuntime,
5
- PluginRuntimeContext,
6
- PluginRuntimeIssue,
7
- PluginRuntimeRoute,
8
- PluginSettingsTab,
9
- PluginWidgetDefinition,
10
- PluginWidgetZone,
11
- ResolvedPluginManifest,
12
- ResolvedPluginWidget,
13
- TenantPluginBinding,
14
- PluginRegistryDef,
15
- PluginAITool,
16
- PluginNavigationEntry,
17
- PluginCapability,
18
- PluginWidgetVisibility,
19
- ResolvedDashboardWidget,
20
- DashboardSurface,
21
- } from '../types/plugins'
22
- import type { FeatureDeclaration } from '../types/permissions'
23
- import type { LimitDeclaration } from '../types/entitlements'
24
- import type { ConnectorDefinition } from '../integrations'
25
- import { getComponent } from '../registry'
26
-
27
- /** The plugin contract version this runtime understands. A plugin declaring a
28
- * higher apiVersion is rejected rather than mis-rendered. */
29
- export const PLUGIN_API_VERSION = 1
30
-
31
- /** Resolve a plugin route/widget/settings/onboarding target to a component,
32
- * whether it provided the component directly or a registered component id. */
33
- export function resolvePluginComponent(
34
- def: { component?: React.ComponentType<unknown>; componentId?: string },
35
- ): React.ComponentType<unknown> | undefined {
36
- if (def.component) return def.component
37
- if (def.componentId) return getComponent(def.componentId) as React.ComponentType<unknown> | undefined
38
- return undefined
39
- }
40
-
41
- interface ResolvePluginRuntimeOptions {
42
- plugins?: PluginManifest[]
43
- tenantPlugins?: TenantPluginBinding[]
44
- hasTenantBindings?: boolean
45
- context: PluginRuntimeContext
46
- }
47
-
48
- const EMPTY_CONTEXT: PluginRuntimeContext = {
49
- tenant: null,
50
- user: null,
51
- currentPath: '/',
52
- matchedPath: '/',
53
- layout: 'sidebar',
54
- }
55
-
56
- function slugify(input: string): string {
57
- return input.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')
58
- }
59
-
60
- function matchesRoutePattern(pattern: string, currentPath: string): boolean {
61
- if (pattern === currentPath) return true
62
- if (pattern.endsWith('/*')) {
63
- const base = pattern.slice(0, -2)
64
- return currentPath === base || currentPath.startsWith(`${base}/`)
65
- }
66
- if (pattern.endsWith('*')) return currentPath.startsWith(pattern.slice(0, -1))
67
- return false
68
- }
69
-
70
- function isWidgetVisible(widget: ResolvedPluginWidget, context: PluginRuntimeContext): boolean {
71
- if (widget.permission && context.hasPermission && !context.hasPermission(widget.permission)) return false
72
- const visibility: PluginWidgetVisibility | undefined = widget.visibility
73
- if (!visibility) return true
74
-
75
- if (visibility.layouts && !visibility.layouts.includes(context.layout)) return false
76
- if (visibility.roles && context.user?.role && !visibility.roles.includes(context.user.role)) return false
77
- if (visibility.roles && !context.user?.role) return false
78
- if (visibility.plans && context.tenant?.plan && !visibility.plans.includes(context.tenant.plan)) return false
79
- if (visibility.plans && !context.tenant?.plan) return false
80
- if (visibility.routes && !visibility.routes.some((p) => matchesRoutePattern(p, context.currentPath))) return false
81
- if (visibility.excludeRoutes?.some((p) => matchesRoutePattern(p, context.currentPath))) return false
82
- if (visibility.permissions?.length) {
83
- if (!context.hasPermission) return false
84
- if (!visibility.permissions.every((req) => context.hasPermission?.(req))) return false
85
- }
86
- if (visibility.when && !visibility.when(context)) return false
87
- return true
88
- }
89
-
90
- function normalizeSettingsTabs(plugin: PluginManifest): PluginSettingsTab[] {
91
- return (plugin.settings ?? []).map((entry, index) => ({
92
- ...entry,
93
- pluginId: entry.pluginId ?? plugin.id,
94
- order: entry.order ?? index,
95
- id: entry.id ?? `${plugin.id}-${slugify(entry.label)}`,
96
- }))
97
- }
98
-
99
- function createEmptyRuntime(context: PluginRuntimeContext = EMPTY_CONTEXT): PluginRuntime {
100
- return {
101
- context,
102
- plugins: [],
103
- activePlugins: [],
104
- routes: [],
105
- navigation: [],
106
- settingsTabs: [],
107
- widgets: [],
108
- dashboardWidgets: [],
109
- capabilities: [],
110
- aiTools: [],
111
- registries: new Map(),
112
- connectorsByHost: new Map(),
113
- pluginFeatures: [],
114
- pluginLimits: [],
115
- issues: [],
116
- }
117
- }
118
-
119
- export function definePlugin<T extends PluginManifest>(plugin: T): T {
120
- return plugin
121
- }
122
-
123
- export function resolvePluginRuntime({
124
- plugins = [],
125
- tenantPlugins = [],
126
- hasTenantBindings,
127
- context,
128
- }: ResolvePluginRuntimeOptions): PluginRuntime {
129
- if (plugins.length === 0) return createEmptyRuntime(context)
130
-
131
- const issues: PluginRuntimeIssue[] = []
132
- const normalizedPlugins = new Map<string, PluginManifest>()
133
-
134
- for (const plugin of plugins) {
135
- if (normalizedPlugins.has(plugin.id)) {
136
- issues.push({ type: 'duplicate_plugin', pluginId: plugin.id, message: `Plugin "${plugin.id}" registered more than once.` })
137
- continue
138
- }
139
- if (plugin.apiVersion != null && plugin.apiVersion > PLUGIN_API_VERSION) {
140
- issues.push({
141
- type: 'incompatible_api_version',
142
- pluginId: plugin.id,
143
- message: `Plugin "${plugin.id}" requires plugin API v${plugin.apiVersion}, but this runtime supports v${PLUGIN_API_VERSION}. Upgrade @fayz-ai/core.`,
144
- })
145
- continue
146
- }
147
- normalizedPlugins.set(plugin.id, plugin)
148
- }
149
-
150
- const bindings = new Map<string, TenantPluginBinding>()
151
- for (const b of tenantPlugins) bindings.set(b.pluginId, b)
152
- const bindingsAreManaged = hasTenantBindings ?? tenantPlugins.length > 0
153
-
154
- const requested = new Set<string>()
155
- const activationReason = new Map<string, ResolvedPluginManifest['activationReason']>()
156
-
157
- for (const plugin of normalizedPlugins.values()) {
158
- const binding = bindings.get(plugin.id)
159
- if (binding?.status === 'active') {
160
- requested.add(plugin.id)
161
- activationReason.set(plugin.id, 'tenant')
162
- continue
163
- }
164
- if (plugin.defaultEnabled === true || (!bindingsAreManaged && plugin.defaultEnabled !== false)) {
165
- requested.add(plugin.id)
166
- activationReason.set(plugin.id, 'default')
167
- }
168
- }
169
-
170
- const orderedIds: string[] = []
171
- const visiting = new Set<string>()
172
- const visited = new Set<string>()
173
-
174
- function visit(pluginId: string, ancestry: string[] = []): void {
175
- if (visited.has(pluginId)) return
176
- const plugin = normalizedPlugins.get(pluginId)
177
- if (!plugin) return
178
- if (visiting.has(pluginId)) {
179
- issues.push({ type: 'circular_dependency', pluginId, message: `Circular dependency: ${[...ancestry, pluginId].join(' -> ')}.` })
180
- return
181
- }
182
- visiting.add(pluginId)
183
- for (const depId of plugin.dependencies ?? []) {
184
- if (!normalizedPlugins.has(depId)) {
185
- issues.push({ type: 'missing_dependency', pluginId, dependencyId: depId, message: `Plugin "${plugin.id}" depends on missing plugin "${depId}".` })
186
- continue
187
- }
188
- if (requested.has(pluginId) && !requested.has(depId)) {
189
- requested.add(depId)
190
- activationReason.set(depId, 'dependency')
191
- }
192
- visit(depId, [...ancestry, pluginId])
193
- }
194
- visiting.delete(pluginId)
195
- visited.add(pluginId)
196
- orderedIds.push(pluginId)
197
- }
198
-
199
- for (const id of normalizedPlugins.keys()) visit(id)
200
-
201
- const resolvedById = new Map<string, ResolvedPluginManifest>()
202
-
203
- for (const pluginId of orderedIds) {
204
- const plugin = normalizedPlugins.get(pluginId)
205
- if (!plugin) continue
206
- const binding = bindings.get(plugin.id)
207
- const missing = (plugin.dependencies ?? []).filter((id) => !normalizedPlugins.has(id))
208
- const compatible = !plugin.verticalId || plugin.verticalId === context.tenant?.verticalId
209
- if (!compatible) {
210
- issues.push({ type: 'vertical_mismatch', pluginId: plugin.id, message: `Plugin "${plugin.id}" requires vertical "${plugin.verticalId}".` })
211
- }
212
- const reason = activationReason.get(plugin.id) ?? 'inactive'
213
- const depsReady = (plugin.dependencies ?? []).every((id) => resolvedById.get(id)?.isActive)
214
- const explicitlyDisabled = binding?.status === 'disabled' || binding?.status === 'removed'
215
- const shouldActivate = reason === 'dependency' ? true : requested.has(plugin.id) && !explicitlyDisabled
216
- const isActive = shouldActivate && compatible && missing.length === 0 && depsReady
217
-
218
- resolvedById.set(plugin.id, {
219
- ...plugin,
220
- status: isActive ? 'active' : (binding?.status ?? 'disabled'),
221
- isActive,
222
- activationReason: isActive ? reason : 'inactive',
223
- config: binding?.config ?? {},
224
- missingDependencies: missing,
225
- settingsTabs: normalizeSettingsTabs(plugin),
226
- widgets: plugin.widgets ?? [],
227
- resolvedRegistries: plugin.registries ?? [],
228
- resolvedAITools: plugin.aiTools ?? [],
229
- })
230
- }
231
-
232
- const resolvedPlugins = orderedIds
233
- .map((id) => resolvedById.get(id))
234
- .filter((p): p is ResolvedPluginManifest => Boolean(p))
235
-
236
- const activePlugins = resolvedPlugins.filter((p) => p.isActive)
237
- const routes: PluginRuntimeRoute[] = []
238
- const navigation: PluginNavigationEntry[] = []
239
- const settingsTabs: PluginSettingsTab[] = []
240
- const widgets: ResolvedPluginWidget[] = []
241
- const dashboardWidgets: ResolvedDashboardWidget[] = []
242
- const capabilities: PluginCapability[] = []
243
- const aiTools: PluginAITool[] = []
244
- const registries = new Map<string, PluginRegistryDef[]>()
245
- const connectorsByHost = new Map<string, ConnectorDefinition[]>()
246
- const pluginFeatures: FeatureDeclaration[] = []
247
- const pluginLimits: LimitDeclaration[] = []
248
-
249
- for (const plugin of activePlugins) {
250
- routes.push(...plugin.routes.map((r) => ({ ...r, plugin })))
251
- navigation.push(...plugin.navigation.map((entry, i) => ({
252
- ...entry,
253
- id: entry.id ?? `${plugin.id}:${entry.route}:${i}`,
254
- icon: entry.icon ?? plugin.icon,
255
- })))
256
- settingsTabs.push(...plugin.settingsTabs)
257
- capabilities.push(...(plugin.capabilities ?? []))
258
- aiTools.push(...plugin.resolvedAITools)
259
- if (plugin.resolvedRegistries.length > 0) registries.set(plugin.id, plugin.resolvedRegistries)
260
- // Group each addon's connectors under the host plugin they extend.
261
- for (const connector of plugin.connectors ?? []) {
262
- const list = connectorsByHost.get(connector.hostPluginId) ?? []
263
- list.push(connector)
264
- connectorsByHost.set(connector.hostPluginId, list)
265
- }
266
- if (plugin.declaredFeatures) pluginFeatures.push(...plugin.declaredFeatures)
267
- if (plugin.declaredLimits) pluginLimits.push(...plugin.declaredLimits)
268
- widgets.push(...plugin.widgets.map((w, i) => ({
269
- ...w,
270
- order: w.order ?? i,
271
- config: { ...plugin.config, ...(w.props ?? {}) },
272
- plugin,
273
- })))
274
- dashboardWidgets.push(...(plugin.dashboardWidgets ?? []).map((w, i) => ({
275
- ...w,
276
- domain: w.domain ?? plugin.id,
277
- order: w.defaultOrder ?? i,
278
- plugin,
279
- })))
280
- }
281
-
282
- navigation.sort((a, b) => {
283
- const order = { main: 0, secondary: 1, settings: 2 }
284
- return (order[a.section] ?? 99) - (order[b.section] ?? 99) || a.position - b.position
285
- })
286
- settingsTabs.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
287
- widgets.sort((a, b) => a.zone !== b.zone ? a.zone.localeCompare(b.zone) : a.order - b.order)
288
- dashboardWidgets.sort((a, b) => a.order - b.order)
289
-
290
- return { context, plugins: resolvedPlugins, activePlugins, routes, navigation, settingsTabs, widgets, dashboardWidgets, capabilities, aiTools, issues, registries, connectorsByHost, pluginFeatures, pluginLimits }
291
- }
292
-
293
- export function getWidgetsForZone(
294
- runtime: PluginRuntime,
295
- zone: PluginWidgetZone,
296
- contextOverrides?: Partial<PluginRuntimeContext>,
297
- ): ResolvedPluginWidget[] {
298
- const ctx = { ...runtime.context, ...contextOverrides }
299
- return runtime.widgets.filter((w) => w.zone === zone && isWidgetVisible(w, ctx))
300
- }
301
-
302
- export function getDashboardWidgets(
303
- runtime: PluginRuntime,
304
- options: { surface: DashboardSurface; domain?: string; contextOverrides?: Partial<PluginRuntimeContext> },
305
- ): ResolvedDashboardWidget[] {
306
- const ctx = { ...runtime.context, ...options.contextOverrides }
307
- return runtime.dashboardWidgets.filter((w) => {
308
- const surfaces = w.surfaces ?? ['home', 'plugin-home']
309
- if (!surfaces.includes(options.surface)) return false
310
- if (options.domain && w.domain !== options.domain) return false
311
- if (w.verticalId && ctx.tenant?.verticalId && w.verticalId !== ctx.tenant.verticalId) return false
312
- if (w.permission && ctx.hasPermission && !ctx.hasPermission(w.permission)) return false
313
- return true
314
- })
315
- }
316
-
317
- const PluginRuntimeContext = React.createContext<PluginRuntime | null>(null)
318
- export const PluginRuntimeProvider = PluginRuntimeContext.Provider
319
-
320
- export function usePluginRuntime(): PluginRuntime {
321
- return React.useContext(PluginRuntimeContext) ?? createEmptyRuntime()
322
- }
323
-
324
- export function usePluginRuntimeOptional(): PluginRuntime | null {
325
- return React.useContext(PluginRuntimeContext)
326
- }
327
-
328
- /** Connectors contributed by addon plugins that extend the given host plugin. */
329
- export function useConnectorsForPlugin(hostPluginId: string): ConnectorDefinition[] {
330
- return usePluginRuntime().connectorsByHost.get(hostPluginId) ?? []
331
- }
@@ -1,163 +0,0 @@
1
- import type { ComponentType } from 'react'
2
-
3
- // ---------------------------------------------------------------------------
4
- // Uniform registry — the indirection layer that lets a pure-data AppManifest
5
- // reference code by string id. Generalizes the entity registry pattern to
6
- // components, blocks, pages, metrics, scaffolds and plugins.
7
- //
8
- // Naming convention: SDK/plugin artifacts use a namespaced id
9
- // (`agenda.week-view`, `crud.detail-header`); app-local custom code uses the
10
- // reserved `custom:` prefix (`custom:tannat.HarvestBoard`). The platform never
11
- // generates `custom:` ids — they only come from an app's registry.tsx.
12
- // ---------------------------------------------------------------------------
13
-
14
- /** A JSON Schema object (loosely typed; validated by tooling, not at runtime). */
15
- export type JsonSchema = Record<string, unknown>
16
-
17
- export type RegistrySource = 'sdk' | 'plugin' | 'app'
18
-
19
- export interface RegistryMeta {
20
- /** Human label for the platform editor. */
21
- label?: string
22
- description?: string
23
- /** Where this artifact came from (for introspection / conflict reporting). */
24
- source?: RegistrySource
25
- /** Owning plugin id, when source is 'plugin'. */
26
- pluginId?: string
27
- /** JSON Schema for this artifact's props/config — drives the visual editor
28
- * and constrains AI generation. Optional but strongly encouraged. */
29
- propsSchema?: JsonSchema
30
- }
31
-
32
- export interface RegistryEntry<T> {
33
- id: string
34
- value: T
35
- meta: RegistryMeta
36
- }
37
-
38
- /** A typed, introspectable id→value map. Last registration wins (so an app's
39
- * registry.tsx can override an SDK artifact by re-registering its id). */
40
- export class Registry<T> {
41
- private readonly entries = new Map<string, RegistryEntry<T>>()
42
-
43
- constructor(readonly kind: string) {}
44
-
45
- register(id: string, value: T, meta: RegistryMeta = {}): void {
46
- this.entries.set(id, { id, value, meta })
47
- }
48
-
49
- get(id: string): T | undefined {
50
- return this.entries.get(id)?.value
51
- }
52
-
53
- getEntry(id: string): RegistryEntry<T> | undefined {
54
- return this.entries.get(id)
55
- }
56
-
57
- has(id: string): boolean {
58
- return this.entries.has(id)
59
- }
60
-
61
- list(): RegistryEntry<T>[] {
62
- return Array.from(this.entries.values())
63
- }
64
-
65
- ids(): string[] {
66
- return Array.from(this.entries.keys())
67
- }
68
-
69
- clear(): void {
70
- this.entries.clear()
71
- }
72
- }
73
-
74
- /** True for app-local custom artifacts (`custom:*`). */
75
- export function isCustomId(id: string): boolean {
76
- return id.startsWith('custom:')
77
- }
78
-
79
- // ---------------------------------------------------------------------------
80
- // Metric definitions (consumed by dashboard / reports / KPI panels).
81
- // ---------------------------------------------------------------------------
82
-
83
- export type MetricFormat = 'number' | 'currency' | 'percent' | 'duration' | 'rating'
84
-
85
- export interface MetricContext {
86
- tenantId?: string
87
- /** ISO date range the metric should compute over, when applicable. */
88
- range?: { from: string; to: string }
89
- [key: string]: unknown
90
- }
91
-
92
- export interface MetricValue {
93
- value: number
94
- previousValue?: number
95
- trend?: 'up' | 'down' | 'flat'
96
- }
97
-
98
- export interface MetricDefinition {
99
- id: string
100
- label?: string
101
- category?: string
102
- format?: MetricFormat
103
- compute: (ctx: MetricContext) => Promise<MetricValue> | MetricValue
104
- }
105
-
106
- // ---------------------------------------------------------------------------
107
- // Concrete registries. Components/blocks/pages/scaffolds hold React component
108
- // types; metrics hold definitions; plugins hold opaque manifests (typed at the
109
- // plugin layer to avoid a circular import).
110
- // ---------------------------------------------------------------------------
111
-
112
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
113
- type AnyComponent = ComponentType<any>
114
-
115
- export const componentRegistry = new Registry<AnyComponent>('component')
116
- export const blockRegistry = new Registry<AnyComponent>('block')
117
- export const pageRegistry = new Registry<AnyComponent>('page')
118
- export const scaffoldRegistry = new Registry<AnyComponent>('scaffold')
119
- export const metricRegistry = new Registry<MetricDefinition>('metric')
120
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
- export const pluginRegistry = new Registry<any>('plugin')
122
-
123
- // Thin functional facade (the public API surface) -----------------------------
124
-
125
- export const registerComponent = (id: string, c: AnyComponent, meta?: RegistryMeta) =>
126
- componentRegistry.register(id, c, meta)
127
- export const getComponent = (id: string) => componentRegistry.get(id)
128
-
129
- export const registerBlock = (id: string, c: AnyComponent, meta?: RegistryMeta) =>
130
- blockRegistry.register(id, c, meta)
131
- export const getBlock = (id: string) => blockRegistry.get(id)
132
- export const listBlocks = () => blockRegistry.list()
133
-
134
- export const registerPage = (id: string, c: AnyComponent, meta?: RegistryMeta) =>
135
- pageRegistry.register(id, c, meta)
136
- export const getPage = (id: string) => pageRegistry.get(id)
137
-
138
- export const registerScaffold = (id: string, c: AnyComponent, meta?: RegistryMeta) =>
139
- scaffoldRegistry.register(id, c, meta)
140
- export const getScaffold = (id: string) => scaffoldRegistry.get(id)
141
-
142
- export const registerMetric = (def: MetricDefinition, meta?: RegistryMeta) =>
143
- metricRegistry.register(def.id, def, meta)
144
- export const getMetric = (id: string) => metricRegistry.get(id)
145
- export const listMetrics = () => metricRegistry.list()
146
-
147
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
148
- export const registerPlugin = (id: string, manifest: any, meta?: RegistryMeta) =>
149
- pluginRegistry.register(id, manifest, meta)
150
- export const getPlugin = (id: string) => pluginRegistry.get(id)
151
- export const listPlugins = () => pluginRegistry.list()
152
-
153
- // Plugin factories — a generated app registers each installed @fayz-ai/plugin-*
154
- // factory by id (src/plugins.generated.ts), so a scaffold can resolve a
155
- // manifest's PluginRef (id + JSON config) to a live PluginManifest:
156
- // getPluginFactory(ref.id)?.(ref.config)
157
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
- export type PluginFactory = (config?: Record<string, unknown>) => any
159
- export const pluginFactoryRegistry = new Registry<PluginFactory>('plugin-factory')
160
- export const registerPluginFactory = (id: string, factory: PluginFactory, meta?: RegistryMeta) =>
161
- pluginFactoryRegistry.register(id, factory, meta)
162
- export const getPluginFactory = (id: string) => pluginFactoryRegistry.get(id)
163
- export const listPluginFactories = () => pluginFactoryRegistry.list()
@@ -1,86 +0,0 @@
1
- import { create } from 'zustand'
2
-
3
- /**
4
- * Global, cross-module navigation history.
5
- *
6
- * Per-module nav hooks (useModuleNavigation) only remember views *within* one
7
- * module, so they can't tell you where you came from after crossing a module
8
- * boundary (e.g. Financial statements → a client/person page). This store sits
9
- * above all modules: the app shell records every route change here with a
10
- * human label, and the shared SubpageHeader reads it to render a context-aware
11
- * "back to {where you came from}" link that returns to the actual previous page.
12
- */
13
-
14
- export interface NavHistoryEntry {
15
- /** Route path without the leading '#', e.g. '/financial/statements'. */
16
- path: string
17
- /** Human, module-level label for the page, e.g. 'Financeiro'. */
18
- label: string
19
- }
20
-
21
- interface NavHistoryState {
22
- stack: NavHistoryEntry[]
23
- /** Record a visit. Consecutive visits to the same path collapse (label refreshes). */
24
- record: (entry: NavHistoryEntry) => void
25
- }
26
-
27
- const MAX_ENTRIES = 20
28
-
29
- export const useNavHistoryStore = create<NavHistoryState>((set) => ({
30
- stack: [],
31
- record: (entry) =>
32
- set((s) => {
33
- const top = s.stack[s.stack.length - 1]
34
- if (top && top.path === entry.path) {
35
- if (top.label === entry.label) return s
36
- const next = s.stack.slice()
37
- next[next.length - 1] = entry
38
- return { stack: next }
39
- }
40
- const next = [...s.stack, entry]
41
- return { stack: next.length > MAX_ENTRIES ? next.slice(-MAX_ENTRIES) : next }
42
- }),
43
- }))
44
-
45
- /** Record a route visit. Call from the app shell whenever the route changes. */
46
- export function recordNavigation(path: string, label: string): void {
47
- useNavHistoryStore.getState().record({ path, label })
48
- }
49
-
50
- // Dev-only debug handle: inspect history in the console via `__navHistory.getState().stack`.
51
- if (typeof window !== 'undefined') {
52
- ;(window as unknown as { __navHistory?: typeof useNavHistoryStore }).__navHistory = useNavHistoryStore
53
- }
54
-
55
- /**
56
- * The page the user most recently came from, relative to `currentPath`.
57
- *
58
- * Returns the latest recorded entry whose path differs from `currentPath`. This
59
- * is intentionally robust to ordering: it gives the right referrer whether or
60
- * not the current page has been recorded yet, avoiding a stale first paint.
61
- */
62
- export function useNavReferrer(currentPath: string): NavHistoryEntry | null {
63
- return useNavHistoryStore((s) => {
64
- for (let i = s.stack.length - 1; i >= 0; i--) {
65
- if (s.stack[i].path !== currentPath) return s.stack[i]
66
- }
67
- return null
68
- })
69
- }
70
-
71
- /**
72
- * Return to the actual previous page via the browser history. Falls back to the
73
- * provided callback when there's no in-app history to pop (e.g. a deep link).
74
- */
75
- export function navHistoryBack(fallback?: () => void): void {
76
- if (useNavHistoryStore.getState().stack.length >= 2) {
77
- window.history.back()
78
- } else {
79
- fallback?.()
80
- }
81
- }
82
-
83
- /** Top-level module segment of a route path ('/financial/statements' → 'financial'). */
84
- export function routeModule(path: string): string {
85
- return path.replace(/^\/+/, '').split('/')[0] ?? ''
86
- }
@@ -1,29 +0,0 @@
1
- export interface RouterAdapter {
2
- navigate(to: string): void
3
- getCurrentPath(): string
4
- onPathChange(cb: (path: string) => void): () => void
5
- }
6
-
7
- export function hashRouterAdapter(): RouterAdapter {
8
- return {
9
- navigate(to) { window.location.hash = to },
10
- getCurrentPath() { return window.location.hash.slice(1) || '/' },
11
- onPathChange(cb) {
12
- const handler = () => cb(window.location.hash.slice(1) || '/')
13
- window.addEventListener('hashchange', handler)
14
- return () => window.removeEventListener('hashchange', handler)
15
- },
16
- }
17
- }
18
-
19
- export function windowRouterAdapter(): RouterAdapter {
20
- return {
21
- navigate(to) { window.history.pushState(null, '', to) },
22
- getCurrentPath() { return window.location.pathname },
23
- onPathChange(cb) {
24
- const handler = () => cb(window.location.pathname)
25
- window.addEventListener('popstate', handler)
26
- return () => window.removeEventListener('popstate', handler)
27
- },
28
- }
29
- }
@@ -1,15 +0,0 @@
1
- export {
2
- createFayzRuntimeClient,
3
- FayzRuntimeError,
4
- } from '@fayz-ai/sdk/runtime'
5
- export type {
6
- FayzRuntimeClientOptions,
7
- FayzRuntimeEnvironment,
8
- GoogleCalendarEvent,
9
- GoogleCalendarEventInput,
10
- GoogleCalendarEventTime,
11
- ListGoogleCalendarEventsInput,
12
- PluginOAuthExchangeInput,
13
- PluginOAuthExchangeResponse,
14
- RuntimePluginOAuthGrant,
15
- } from '@fayz-ai/sdk/runtime'