@fayz-ai/core 0.1.6

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 (172) hide show
  1. package/dist/app/render.d.ts +16 -0
  2. package/dist/app/render.d.ts.map +1 -0
  3. package/dist/blocks/index.d.ts +25 -0
  4. package/dist/blocks/index.d.ts.map +1 -0
  5. package/dist/chunk-2NTHNWEH.cjs +32 -0
  6. package/dist/chunk-2NTHNWEH.cjs.map +1 -0
  7. package/dist/chunk-5EAZOMVP.js +1609 -0
  8. package/dist/chunk-5EAZOMVP.js.map +1 -0
  9. package/dist/chunk-5TKIZVVJ.cjs +16 -0
  10. package/dist/chunk-5TKIZVVJ.cjs.map +1 -0
  11. package/dist/chunk-7RTUHSKY.js +3 -0
  12. package/dist/chunk-7RTUHSKY.js.map +1 -0
  13. package/dist/chunk-AXTWKF5X.cjs +38 -0
  14. package/dist/chunk-AXTWKF5X.cjs.map +1 -0
  15. package/dist/chunk-EGWWQ7AT.cjs +355 -0
  16. package/dist/chunk-EGWWQ7AT.cjs.map +1 -0
  17. package/dist/chunk-KAYQFSR6.js +298 -0
  18. package/dist/chunk-KAYQFSR6.js.map +1 -0
  19. package/dist/chunk-LSVBDYFQ.cjs +1639 -0
  20. package/dist/chunk-LSVBDYFQ.cjs.map +1 -0
  21. package/dist/chunk-SNQW6TRF.cjs +658 -0
  22. package/dist/chunk-SNQW6TRF.cjs.map +1 -0
  23. package/dist/chunk-WKZVSKEU.js +26 -0
  24. package/dist/chunk-WKZVSKEU.js.map +1 -0
  25. package/dist/chunk-Y2C2FBQP.js +35 -0
  26. package/dist/chunk-Y2C2FBQP.js.map +1 -0
  27. package/dist/chunk-YSBXGHAM.js +643 -0
  28. package/dist/chunk-YSBXGHAM.js.map +1 -0
  29. package/dist/data/archetype.d.ts +13 -0
  30. package/dist/data/archetype.d.ts.map +1 -0
  31. package/dist/data/cached.d.ts +19 -0
  32. package/dist/data/cached.d.ts.map +1 -0
  33. package/dist/data/fayz-api.d.ts +19 -0
  34. package/dist/data/fayz-api.d.ts.map +1 -0
  35. package/dist/data/index.cjs +32 -0
  36. package/dist/data/index.cjs.map +1 -0
  37. package/dist/data/index.d.ts +9 -0
  38. package/dist/data/index.d.ts.map +1 -0
  39. package/dist/data/index.js +3 -0
  40. package/dist/data/index.js.map +1 -0
  41. package/dist/data/mock.d.ts +7 -0
  42. package/dist/data/mock.d.ts.map +1 -0
  43. package/dist/data/resolve.d.ts +22 -0
  44. package/dist/data/resolve.d.ts.map +1 -0
  45. package/dist/data/supabase.d.ts +18 -0
  46. package/dist/data/supabase.d.ts.map +1 -0
  47. package/dist/data/types.d.ts +23 -0
  48. package/dist/data/types.d.ts.map +1 -0
  49. package/dist/entity/index.cjs +28 -0
  50. package/dist/entity/index.cjs.map +1 -0
  51. package/dist/entity/index.d.ts +3 -0
  52. package/dist/entity/index.d.ts.map +1 -0
  53. package/dist/entity/index.js +3 -0
  54. package/dist/entity/index.js.map +1 -0
  55. package/dist/entity/registry.d.ts +20 -0
  56. package/dist/entity/registry.d.ts.map +1 -0
  57. package/dist/events/index.d.ts +16 -0
  58. package/dist/events/index.d.ts.map +1 -0
  59. package/dist/i18n/index.cjs +44 -0
  60. package/dist/i18n/index.cjs.map +1 -0
  61. package/dist/i18n/index.d.ts +21 -0
  62. package/dist/i18n/index.d.ts.map +1 -0
  63. package/dist/i18n/index.js +3 -0
  64. package/dist/i18n/index.js.map +1 -0
  65. package/dist/i18n/shell-translations.d.ts +2 -0
  66. package/dist/i18n/shell-translations.d.ts.map +1 -0
  67. package/dist/index.cjs +911 -0
  68. package/dist/index.cjs.map +1 -0
  69. package/dist/index.d.ts +46 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +596 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/lib/cache.d.ts +21 -0
  74. package/dist/lib/cache.d.ts.map +1 -0
  75. package/dist/lib/csv.d.ts +14 -0
  76. package/dist/lib/csv.d.ts.map +1 -0
  77. package/dist/lib/format.d.ts +7 -0
  78. package/dist/lib/format.d.ts.map +1 -0
  79. package/dist/manifest/index.d.ts +80 -0
  80. package/dist/manifest/index.d.ts.map +1 -0
  81. package/dist/plugin/createSafeDataProvider.d.ts +14 -0
  82. package/dist/plugin/createSafeDataProvider.d.ts.map +1 -0
  83. package/dist/plugin/index.cjs +32 -0
  84. package/dist/plugin/index.cjs.map +1 -0
  85. package/dist/plugin/index.d.ts +2 -0
  86. package/dist/plugin/index.d.ts.map +1 -0
  87. package/dist/plugin/index.js +3 -0
  88. package/dist/plugin/index.js.map +1 -0
  89. package/dist/plugin/runtime.d.ts +31 -0
  90. package/dist/plugin/runtime.d.ts.map +1 -0
  91. package/dist/registry/index.d.ts +88 -0
  92. package/dist/registry/index.d.ts.map +1 -0
  93. package/dist/router/index.cjs +16 -0
  94. package/dist/router/index.cjs.map +1 -0
  95. package/dist/router/index.d.ts +8 -0
  96. package/dist/router/index.d.ts.map +1 -0
  97. package/dist/router/index.js +3 -0
  98. package/dist/router/index.js.map +1 -0
  99. package/dist/runtime/index.cjs +16 -0
  100. package/dist/runtime/index.cjs.map +1 -0
  101. package/dist/runtime/index.d.ts +3 -0
  102. package/dist/runtime/index.d.ts.map +1 -0
  103. package/dist/runtime/index.js +3 -0
  104. package/dist/runtime/index.js.map +1 -0
  105. package/dist/runtime/oauth.d.ts +96 -0
  106. package/dist/runtime/oauth.d.ts.map +1 -0
  107. package/dist/tenant/index.d.ts +3 -0
  108. package/dist/tenant/index.d.ts.map +1 -0
  109. package/dist/types/auth.d.ts +27 -0
  110. package/dist/types/auth.d.ts.map +1 -0
  111. package/dist/types/billing.d.ts +17 -0
  112. package/dist/types/billing.d.ts.map +1 -0
  113. package/dist/types/crud.d.ts +107 -0
  114. package/dist/types/crud.d.ts.map +1 -0
  115. package/dist/types/entities.d.ts +134 -0
  116. package/dist/types/entities.d.ts.map +1 -0
  117. package/dist/types/i18n.d.ts +8 -0
  118. package/dist/types/i18n.d.ts.map +1 -0
  119. package/dist/types/index.cjs +4 -0
  120. package/dist/types/index.cjs.map +1 -0
  121. package/dist/types/index.d.ts +10 -0
  122. package/dist/types/index.d.ts.map +1 -0
  123. package/dist/types/index.js +3 -0
  124. package/dist/types/index.js.map +1 -0
  125. package/dist/types/org.d.ts +96 -0
  126. package/dist/types/org.d.ts.map +1 -0
  127. package/dist/types/permissions.d.ts +25 -0
  128. package/dist/types/permissions.d.ts.map +1 -0
  129. package/dist/types/plugins.d.ts +314 -0
  130. package/dist/types/plugins.d.ts.map +1 -0
  131. package/dist/types/theme.d.ts +16 -0
  132. package/dist/types/theme.d.ts.map +1 -0
  133. package/package.json +98 -0
  134. package/src/app/render.tsx +69 -0
  135. package/src/blocks/index.tsx +68 -0
  136. package/src/data/archetype.ts +210 -0
  137. package/src/data/cached.ts +55 -0
  138. package/src/data/fayz-api.ts +200 -0
  139. package/src/data/index.ts +8 -0
  140. package/src/data/mock.ts +84 -0
  141. package/src/data/resolve.ts +108 -0
  142. package/src/data/supabase.ts +169 -0
  143. package/src/data/types.ts +20 -0
  144. package/src/entity/index.ts +2 -0
  145. package/src/entity/registry.ts +42 -0
  146. package/src/events/index.tsx +82 -0
  147. package/src/i18n/index.ts +250 -0
  148. package/src/i18n/shell-translations.ts +1391 -0
  149. package/src/index.ts +132 -0
  150. package/src/lib/cache.ts +118 -0
  151. package/src/lib/csv.ts +54 -0
  152. package/src/lib/format.ts +58 -0
  153. package/src/manifest/app-manifest.schema.json +103 -0
  154. package/src/manifest/index.ts +394 -0
  155. package/src/plugin/createSafeDataProvider.ts +30 -0
  156. package/src/plugin/index.ts +1 -0
  157. package/src/plugin/runtime.ts +313 -0
  158. package/src/registry/index.ts +163 -0
  159. package/src/router/index.ts +29 -0
  160. package/src/runtime/index.ts +15 -0
  161. package/src/runtime/oauth.ts +219 -0
  162. package/src/tenant/index.ts +18 -0
  163. package/src/types/auth.ts +26 -0
  164. package/src/types/billing.ts +17 -0
  165. package/src/types/crud.ts +108 -0
  166. package/src/types/entities.ts +142 -0
  167. package/src/types/i18n.ts +7 -0
  168. package/src/types/index.ts +10 -0
  169. package/src/types/org.ts +94 -0
  170. package/src/types/permissions.ts +32 -0
  171. package/src/types/plugins.ts +363 -0
  172. package/src/types/theme.ts +17 -0
@@ -0,0 +1,219 @@
1
+ export type FayzRuntimeEnvironment = 'preview' | 'production'
2
+
3
+ export interface FayzRuntimeClientOptions {
4
+ baseUrl: string
5
+ projectId: string
6
+ runtimeToken: string | (() => string | Promise<string>)
7
+ fetcher?: typeof fetch
8
+ }
9
+
10
+ export interface PluginOAuthExchangeInput {
11
+ pluginId: string
12
+ environment?: FayzRuntimeEnvironment
13
+ scopes?: string[]
14
+ }
15
+
16
+ export interface RuntimePluginOAuthGrant {
17
+ grantId: string
18
+ provider: string
19
+ scopes: string[]
20
+ }
21
+
22
+ export interface PluginOAuthExchangeResponse {
23
+ token: string
24
+ tokenType: 'Bearer'
25
+ expiresIn: number
26
+ projectId: string
27
+ tenantKey: string
28
+ environment: FayzRuntimeEnvironment
29
+ pluginId: string
30
+ grants: RuntimePluginOAuthGrant[]
31
+ }
32
+
33
+ export interface GoogleCalendarEventTime {
34
+ dateTime: string
35
+ timeZone?: string
36
+ }
37
+
38
+ export interface GoogleCalendarEventInput {
39
+ summary: string
40
+ description?: string
41
+ location?: string
42
+ start: GoogleCalendarEventTime
43
+ end: GoogleCalendarEventTime
44
+ attendees?: Array<{ email: string }>
45
+ }
46
+
47
+ export interface GoogleCalendarEvent {
48
+ id: string
49
+ summary?: string
50
+ description?: string
51
+ location?: string
52
+ start: { dateTime?: string; date?: string; timeZone?: string }
53
+ end: { dateTime?: string; date?: string; timeZone?: string }
54
+ status?: string
55
+ htmlLink?: string
56
+ [key: string]: unknown
57
+ }
58
+
59
+ export interface ListGoogleCalendarEventsInput {
60
+ calendarId: string
61
+ timeMin?: string
62
+ timeMax?: string
63
+ maxResults?: number
64
+ q?: string
65
+ }
66
+
67
+ export class FayzRuntimeError extends Error {
68
+ constructor(
69
+ message: string,
70
+ readonly status: number,
71
+ readonly responseBody?: unknown,
72
+ ) {
73
+ super(message)
74
+ this.name = 'FayzRuntimeError'
75
+ }
76
+ }
77
+
78
+ function normalizeBaseUrl(baseUrl: string): string {
79
+ return baseUrl.replace(/\/+$/, '')
80
+ }
81
+
82
+ function assertRequired(value: string, field: string): string {
83
+ const normalized = value.trim()
84
+ if (!normalized) throw new Error(`[@fayz-ai/core] ${field} is required`)
85
+ return normalized
86
+ }
87
+
88
+ async function resolveRuntimeToken(
89
+ runtimeToken: FayzRuntimeClientOptions['runtimeToken'],
90
+ ): Promise<string> {
91
+ const value = typeof runtimeToken === 'function' ? await runtimeToken() : runtimeToken
92
+ return assertRequired(value, 'runtimeToken')
93
+ }
94
+
95
+ function runtimePath(projectId: string, suffix: string): string {
96
+ return `/api/v1/runtime/projects/${encodeURIComponent(projectId)}${suffix}`
97
+ }
98
+
99
+ function queryString(params: Record<string, string | number | undefined>): string {
100
+ const search = new URLSearchParams()
101
+ for (const [key, value] of Object.entries(params)) {
102
+ if (value !== undefined && value !== '') search.set(key, String(value))
103
+ }
104
+ const value = search.toString()
105
+ return value ? `?${value}` : ''
106
+ }
107
+
108
+ async function parseResponse<T>(response: Response): Promise<T> {
109
+ if (response.status === 204) return undefined as T
110
+
111
+ const text = await response.text()
112
+ let body: unknown
113
+ try {
114
+ body = text ? JSON.parse(text) : undefined
115
+ } catch {
116
+ body = text
117
+ }
118
+
119
+ if (!response.ok) {
120
+ const message = typeof body === 'object' && body && 'message' in body
121
+ ? String((body as { message: unknown }).message)
122
+ : `[@fayz-ai/core] Runtime request failed with status ${response.status}`
123
+ throw new FayzRuntimeError(message, response.status, body)
124
+ }
125
+
126
+ return body as T
127
+ }
128
+
129
+ export function createFayzRuntimeClient(options: FayzRuntimeClientOptions) {
130
+ const baseUrl = normalizeBaseUrl(assertRequired(options.baseUrl, 'baseUrl'))
131
+ const projectId = assertRequired(options.projectId, 'projectId')
132
+ const fetcher = options.fetcher ?? fetch
133
+
134
+ async function request<T>(
135
+ path: string,
136
+ token: string,
137
+ init: Omit<RequestInit, 'headers'> & { headers?: Record<string, string> } = {},
138
+ ): Promise<T> {
139
+ const response = await fetcher(`${baseUrl}${path}`, {
140
+ ...init,
141
+ headers: {
142
+ ...(init.body ? { 'Content-Type': 'application/json' } : {}),
143
+ ...init.headers,
144
+ Authorization: `Bearer ${token}`,
145
+ },
146
+ })
147
+ return parseResponse<T>(response)
148
+ }
149
+
150
+ async function exchangePluginOAuth(
151
+ input: PluginOAuthExchangeInput,
152
+ ): Promise<PluginOAuthExchangeResponse> {
153
+ return request<PluginOAuthExchangeResponse>(
154
+ runtimePath(projectId, '/oauth/exchange'),
155
+ await resolveRuntimeToken(options.runtimeToken),
156
+ {
157
+ method: 'POST',
158
+ body: JSON.stringify({
159
+ pluginId: assertRequired(input.pluginId, 'pluginId'),
160
+ environment: input.environment ?? 'preview',
161
+ ...(input.scopes ? { scopes: input.scopes } : {}),
162
+ }),
163
+ },
164
+ )
165
+ }
166
+
167
+ function googleCalendar(pluginOAuthToken: string) {
168
+ const brokerToken = assertRequired(pluginOAuthToken, 'pluginOAuthToken')
169
+ const eventsPath = runtimePath(projectId, '/oauth/google-calendar/events')
170
+
171
+ return {
172
+ listEvents(input: ListGoogleCalendarEventsInput) {
173
+ const calendarId = assertRequired(input.calendarId, 'calendarId')
174
+ return request<{
175
+ provider: 'google-calendar'
176
+ calendarId: string
177
+ timeMin: string
178
+ timeMax: string
179
+ events: GoogleCalendarEvent[]
180
+ }>(
181
+ `${eventsPath}${queryString({
182
+ calendarId,
183
+ timeMin: input.timeMin,
184
+ timeMax: input.timeMax,
185
+ maxResults: input.maxResults,
186
+ q: input.q,
187
+ })}`,
188
+ brokerToken,
189
+ )
190
+ },
191
+ createEvent(calendarId: string, event: GoogleCalendarEventInput) {
192
+ return request<{ provider: 'google-calendar'; calendarId: string; event: GoogleCalendarEvent }>(
193
+ `${eventsPath}${queryString({ calendarId: assertRequired(calendarId, 'calendarId') })}`,
194
+ brokerToken,
195
+ { method: 'POST', body: JSON.stringify(event) },
196
+ )
197
+ },
198
+ updateEvent(calendarId: string, eventId: string, updates: Partial<GoogleCalendarEventInput>) {
199
+ return request<{ provider: 'google-calendar'; calendarId: string; event: GoogleCalendarEvent }>(
200
+ `${eventsPath}/${encodeURIComponent(assertRequired(eventId, 'eventId'))}${queryString({ calendarId: assertRequired(calendarId, 'calendarId') })}`,
201
+ brokerToken,
202
+ { method: 'PATCH', body: JSON.stringify(updates) },
203
+ )
204
+ },
205
+ deleteEvent(calendarId: string, eventId: string) {
206
+ return request<void>(
207
+ `${eventsPath}/${encodeURIComponent(assertRequired(eventId, 'eventId'))}${queryString({ calendarId: assertRequired(calendarId, 'calendarId') })}`,
208
+ brokerToken,
209
+ { method: 'DELETE' },
210
+ )
211
+ },
212
+ }
213
+ }
214
+
215
+ return {
216
+ exchangePluginOAuth,
217
+ googleCalendar,
218
+ }
219
+ }
@@ -0,0 +1,18 @@
1
+ // Active tenant context — a global accessor the data layer reads for tenant
2
+ // scoping and cache keying. The host (saas shell / app) sets it from its org
3
+ // store via setActiveTenantId; the data providers stay decoupled from any
4
+ // specific org-store implementation (runtime DI).
5
+ import { clearGlobalCache } from '../lib/cache'
6
+
7
+ let _activeTenantId: string | undefined
8
+
9
+ export function setActiveTenantId(id: string | undefined): void {
10
+ if (id !== _activeTenantId) {
11
+ _activeTenantId = id
12
+ clearGlobalCache()
13
+ }
14
+ }
15
+
16
+ export function getActiveTenantId(): string | undefined {
17
+ return _activeTenantId
18
+ }
@@ -0,0 +1,26 @@
1
+ export type AuthProvider = 'google' | 'github' | 'apple' | 'facebook' | (string & {})
2
+
3
+ export interface AuthUser {
4
+ id: string
5
+ email: string
6
+ fullName?: string
7
+ avatarUrl?: string
8
+ role?: string
9
+ }
10
+
11
+ export interface AuthSession {
12
+ user: AuthUser
13
+ accessToken: string
14
+ refreshToken?: string
15
+ expiresAt?: number
16
+ }
17
+
18
+ export interface AuthAdapter {
19
+ getSession(): Promise<{ user: AuthUser; session: AuthSession } | null>
20
+ onAuthStateChange(cb: (user: AuthUser | null) => void): () => void
21
+ signIn(email: string, password: string): Promise<AuthSession>
22
+ signUp(email: string, password: string, fullName: string): Promise<AuthSession>
23
+ signOut(): Promise<void>
24
+ signInWithOAuth(provider: AuthProvider): Promise<void>
25
+ resetPassword(email: string): Promise<void>
26
+ }
@@ -0,0 +1,17 @@
1
+ export interface Plan {
2
+ id: string
3
+ name: string
4
+ description?: string
5
+ price: number
6
+ currency: string
7
+ interval: 'month' | 'year'
8
+ features: string[]
9
+ highlighted?: boolean
10
+ stripePriceId?: string
11
+ }
12
+
13
+ export interface BillingConfig {
14
+ plans: Plan[]
15
+ stripePublishableKey?: string
16
+ portalUrl?: string
17
+ }
@@ -0,0 +1,108 @@
1
+ import type React from 'react'
2
+ import type { EntityArchetype } from './entities'
3
+
4
+ export type FieldType =
5
+ | 'text' | 'email' | 'phone' | 'url' | 'image'
6
+ | 'number' | 'currency'
7
+ | 'select' | 'multiselect' | 'segmented'
8
+ | 'date' | 'datetime' | 'time'
9
+ | 'boolean' | 'textarea'
10
+ | 'color' | 'computed'
11
+
12
+ /** Read-only display produced by a `computed` field's `compute()`. */
13
+ export interface ComputedFieldValue {
14
+ display: string
15
+ /** Drives the value colour (green / red / muted). Default: neutral. */
16
+ tone?: 'positive' | 'negative' | 'neutral'
17
+ }
18
+
19
+ export interface FieldDef {
20
+ key: string
21
+ label: string
22
+ type: FieldType
23
+ required?: boolean
24
+ placeholder?: string
25
+ /** Small helper text shown under the field input. */
26
+ hint?: string
27
+ /** Options for `select` / `multiselect` / `segmented`. The optional
28
+ * `description` is shown under the label on `segmented` radio-cards. */
29
+ options?: string[] | { label: string; value: string; description?: string }[]
30
+ min?: number
31
+ max?: number
32
+ /** ISO currency code for `currency` fields (e.g. 'BRL'). */
33
+ currency?: string
34
+ /** Symbol/locale for the `currency` field's CurrencyInput. Default 'R$' / 'pt-BR'. */
35
+ currencySymbol?: string
36
+ currencyLocale?: string
37
+ showInTable?: boolean
38
+ showInForm?: boolean
39
+ showInDetail?: boolean
40
+ sortable?: boolean
41
+ searchable?: boolean
42
+ /** Custom cell renderer (code escape hatch). For a serializable EntityDef in
43
+ * an AppManifest, reference a registered cell renderer by id instead. */
44
+ renderCell?: (value: unknown, row: unknown) => React.ReactNode
45
+ renderCellId?: string
46
+ /** Derives a read-only value from the other form values (for `computed`
47
+ * fields, e.g. margin). Returns null to render an em-dash. */
48
+ compute?: (values: Record<string, unknown>) => ComputedFieldValue | null
49
+ defaultValue?: unknown
50
+ group?: string
51
+ span?: 1 | 2
52
+ inlineToggle?: boolean
53
+ }
54
+
55
+ export interface FieldGroup {
56
+ id: string
57
+ label: string
58
+ description?: string
59
+ columns?: 1 | 2 | 3
60
+ /** Renders a decorative image slot to the left of the group's fields. */
61
+ imageSlot?: boolean
62
+ }
63
+
64
+ export interface DetailTab {
65
+ id: string
66
+ label: string
67
+ icon?: string
68
+ /** Tab content component, or a registered component id (componentId) for a
69
+ * serializable EntityDef. Exactly one is expected. */
70
+ component?: React.ComponentType<{ item: unknown; entityDef: EntityDef; [key: string]: unknown }>
71
+ componentId?: string
72
+ visibleFor?: string[]
73
+ props?: Record<string, unknown>
74
+ }
75
+
76
+ export type FormLayout = 'person' | 'product' | 'service' | 'location' | 'order' | 'subject' | 'generic'
77
+
78
+ export interface EntityDef<T = Record<string, unknown>> {
79
+ name: string
80
+ namePlural?: string
81
+ icon: string
82
+ layout?: FormLayout
83
+ fields: FieldDef[]
84
+ fieldGroups?: FieldGroup[]
85
+ detailTabs?: DetailTab[]
86
+ data?: {
87
+ table: string
88
+ schema?: string
89
+ tenantScoped?: boolean
90
+ tenantIdColumn?: string
91
+ searchColumns?: string[]
92
+ selectColumns?: string
93
+ columnMap?: Record<string, string>
94
+ archetype?: EntityArchetype
95
+ archetypeKind?: string
96
+ filters?: Record<string, string>
97
+ defaults?: Record<string, unknown>
98
+ cacheTTL?: number
99
+ }
100
+ defaultSort?: string
101
+ defaultSortDir?: 'asc' | 'desc'
102
+ displayField?: string
103
+ subtitleField?: string
104
+ imageField?: string
105
+ /** Faceted filters shown as pills below the list search box. Each references a
106
+ * field whose `options` supply the pills; an "All" pill clears the filter. */
107
+ facets?: { field: string; allLabel?: string }[]
108
+ }
@@ -0,0 +1,142 @@
1
+ export type EntityArchetype = 'person' | 'category' | 'product' | 'service' | 'order' | 'transaction' | 'schedule' | 'location'
2
+
3
+ export interface BaseEntity {
4
+ id: string
5
+ tenantId: string
6
+ createdAt: string
7
+ updatedAt: string
8
+ }
9
+
10
+ export interface PersonEntity extends BaseEntity {
11
+ archetype: 'person'
12
+ kind: string
13
+ name: string
14
+ email?: string
15
+ phone?: string
16
+ documentNumber?: string
17
+ avatarUrl?: string
18
+ dateOfBirth?: string
19
+ address?: string
20
+ city?: string
21
+ state?: string
22
+ country: string
23
+ postalCode?: string
24
+ tags: string[]
25
+ isActive: boolean
26
+ notes?: string
27
+ metadata: Record<string, unknown>
28
+ }
29
+
30
+ export interface CategoryEntity extends BaseEntity {
31
+ archetype: 'category'
32
+ kind: string
33
+ name: string
34
+ slug?: string
35
+ parentId?: string
36
+ icon?: string
37
+ color?: string
38
+ sortOrder: number
39
+ isActive: boolean
40
+ metadata: Record<string, unknown>
41
+ }
42
+
43
+ export interface ProductEntity extends BaseEntity {
44
+ archetype: 'product'
45
+ categoryId?: string
46
+ name: string
47
+ description?: string
48
+ sku?: string
49
+ price?: number
50
+ cost?: number
51
+ currency: string
52
+ unit?: string
53
+ imageUrl?: string
54
+ stock?: number
55
+ minStock?: number
56
+ status: string
57
+ isActive: boolean
58
+ tags: string[]
59
+ metadata: Record<string, unknown>
60
+ }
61
+
62
+ export interface ServiceEntity extends BaseEntity {
63
+ archetype: 'service'
64
+ categoryId?: string
65
+ name: string
66
+ description?: string
67
+ price?: number
68
+ cost?: number
69
+ currency: string
70
+ durationMinutes?: number
71
+ imageUrl?: string
72
+ status: string
73
+ isActive: boolean
74
+ tags: string[]
75
+ metadata: Record<string, unknown>
76
+ }
77
+
78
+ export interface OrderEntity extends BaseEntity {
79
+ archetype: 'order'
80
+ kind: string
81
+ referenceNumber?: string
82
+ status: string
83
+ partyId?: string
84
+ assigneeId?: string
85
+ locationId?: string
86
+ subtotal: number
87
+ discount: number
88
+ tax: number
89
+ total: number
90
+ currency: string
91
+ dueAt?: string
92
+ completedAt?: string
93
+ notes?: string
94
+ tags: string[]
95
+ metadata: Record<string, unknown>
96
+ }
97
+
98
+ export interface TransactionEntity extends BaseEntity {
99
+ archetype: 'transaction'
100
+ kind: string
101
+ orderId?: string
102
+ partyId?: string
103
+ amount: number
104
+ currency: string
105
+ paymentMethod?: string
106
+ reference?: string
107
+ status: string
108
+ transactedAt: string
109
+ notes?: string
110
+ metadata: Record<string, unknown>
111
+ }
112
+
113
+ export interface LocationEntity extends BaseEntity {
114
+ archetype: 'location'
115
+ kind: string
116
+ name: string
117
+ email?: string
118
+ phone?: string
119
+ address?: string
120
+ city?: string
121
+ state?: string
122
+ country: string
123
+ postalCode?: string
124
+ isHeadquarters: boolean
125
+ isActive: boolean
126
+ tags: string[]
127
+ notes?: string
128
+ metadata: Record<string, unknown>
129
+ }
130
+
131
+ export interface ScheduleEntity extends BaseEntity {
132
+ archetype: 'schedule'
133
+ kind: string
134
+ assigneeId?: string
135
+ locationId?: string
136
+ dayOfWeek?: number
137
+ specificDate?: string
138
+ startsAt: string
139
+ endsAt: string
140
+ isActive: boolean
141
+ metadata: Record<string, unknown>
142
+ }
@@ -0,0 +1,7 @@
1
+ export interface LocaleConfig {
2
+ default: string
3
+ supported: string[]
4
+ translations?: Record<string, Record<string, string>>
5
+ /** ISO 4217 currency code for money formatting (e.g. 'BRL', 'USD'). */
6
+ currency?: string
7
+ }
@@ -0,0 +1,10 @@
1
+ // Re-export all core types
2
+ export type { EntityArchetype, BaseEntity, PersonEntity, ProductEntity, ServiceEntity, OrderEntity, TransactionEntity, LocationEntity, ScheduleEntity, CategoryEntity } from './entities'
3
+ export type { EntityDef, FieldDef, FieldType, FieldGroup, DetailTab, FormLayout, ComputedFieldValue } from './crud'
4
+ export type { PluginManifest, PluginScope, PluginStatus, ResolvedPluginManifest, PluginRuntime, PluginRuntimeContext, PluginWidgetZone, PluginWidgetDefinition, PluginNavigationEntry, PluginSettingsTab, PluginRouteDefinition, PluginAITool, PluginRegistryDef, PluginMigration, VerticalId, ScaffoldType } from './plugins'
5
+ export type { AuthAdapter, AuthUser, AuthSession } from './auth'
6
+ export type { OrgAdapter, Organization, OrgMember } from './org'
7
+ export type { PermissionsConfig, FeatureDeclaration, PermissionAction } from './permissions'
8
+ export type { Plan, BillingConfig } from './billing'
9
+ export type { SaasTheme, ThemeConfig } from './theme'
10
+ export type { LocaleConfig } from './i18n'
@@ -0,0 +1,94 @@
1
+ import type { PermissionProfile } from './permissions'
2
+
3
+ export interface Organization {
4
+ id: string
5
+ name: string
6
+ slug: string
7
+ logoUrl?: string
8
+ verticalId?: string
9
+ plan?: string
10
+ settings?: Record<string, unknown>
11
+ createdAt: string
12
+ updatedAt: string
13
+ }
14
+
15
+ export interface OrgMember {
16
+ id: string
17
+ userId: string
18
+ orgId: string
19
+ profileId: string
20
+ profileName: string
21
+ user: {
22
+ id: string
23
+ email: string
24
+ fullName: string
25
+ avatarUrl?: string
26
+ }
27
+ joinedAt: string
28
+ }
29
+
30
+ export interface OrgMembership {
31
+ orgId: string
32
+ orgName: string
33
+ orgSlug: string
34
+ orgLogoUrl?: string
35
+ profileId: string
36
+ profileName: string
37
+ }
38
+
39
+ export interface Location {
40
+ id: string
41
+ tenantId: string
42
+ name: string
43
+ address?: string
44
+ city?: string
45
+ state?: string
46
+ country?: string
47
+ phone?: string
48
+ isHeadquarters: boolean
49
+ isActive: boolean
50
+ createdAt: string
51
+ updatedAt: string
52
+ }
53
+
54
+ export interface Invite {
55
+ id: string
56
+ orgId: string
57
+ email: string
58
+ profileId: string
59
+ profileName: string
60
+ invitedBy: string
61
+ token: string
62
+ status: 'pending' | 'accepted' | 'expired'
63
+ createdAt: string
64
+ expiresAt: string
65
+ }
66
+
67
+ export interface CreateOrgOptions {
68
+ verticalId?: string
69
+ timezone?: string
70
+ currency?: string
71
+ locale?: string
72
+ teamSize?: string
73
+ }
74
+
75
+ export interface OrgAdapter {
76
+ listUserOrgs(userId: string): Promise<OrgMembership[]>
77
+ getOrg(orgId: string): Promise<Organization>
78
+ createOrg(name: string, userId: string, options?: CreateOrgOptions): Promise<Organization>
79
+ updateOrg(orgId: string, data: Partial<Organization>): Promise<Organization>
80
+ listMembers(orgId: string): Promise<OrgMember[]>
81
+ updateMemberProfile(orgId: string, memberId: string, profileId: string): Promise<void>
82
+ removeMember(orgId: string, memberId: string): Promise<void>
83
+ listProfiles(orgId: string): Promise<PermissionProfile[]>
84
+ createProfile(orgId: string, profile: Omit<PermissionProfile, 'id' | 'isSystem'>): Promise<PermissionProfile>
85
+ updateProfile(orgId: string, profileId: string, data: Partial<PermissionProfile>): Promise<PermissionProfile>
86
+ deleteProfile(orgId: string, profileId: string): Promise<void>
87
+ listInvites(orgId: string): Promise<Invite[]>
88
+ createInvite(orgId: string, email: string, profileId: string, invitedBy: string): Promise<Invite>
89
+ bulkInvite(orgId: string, emails: string[], profileId: string, invitedBy: string): Promise<Invite[]>
90
+ revokeInvite(orgId: string, inviteId: string): Promise<void>
91
+ resendInvite(orgId: string, inviteId: string): Promise<Invite>
92
+ listLocations(orgId: string): Promise<Location[]>
93
+ createLocation(orgId: string, data: { name: string; address?: string; city?: string; state?: string; country?: string; phone?: string; isHeadquarters?: boolean }): Promise<Location>
94
+ }
@@ -0,0 +1,32 @@
1
+ export type PermissionAction = 'read' | 'create' | 'edit' | 'write' | 'delete' | 'manage' | (string & {})
2
+
3
+ export type SystemPermission =
4
+ | 'manage_team'
5
+ | 'manage_billing'
6
+ | 'manage_settings'
7
+ | 'manage_permissions'
8
+
9
+ export interface FeatureDeclaration {
10
+ id: string
11
+ label: string
12
+ description?: string
13
+ /** Settings group this feature appears under (matches saas-core runtime) */
14
+ group?: string
15
+ actions?: PermissionAction[]
16
+ pluginId?: string
17
+ }
18
+
19
+ export interface PermissionProfile {
20
+ id: string
21
+ name: string
22
+ description?: string
23
+ isSystem?: boolean
24
+ systemPermissions?: SystemPermission[]
25
+ /** feature key → allowed actions. The canonical permission map (saas-core shell name). */
26
+ grants: Record<string, PermissionAction[]>
27
+ }
28
+
29
+ export interface PermissionsConfig {
30
+ features: FeatureDeclaration[]
31
+ defaultProfiles?: PermissionProfile[]
32
+ }