@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.
- package/README.md +2 -2
- package/dist/access/index.js.map +1 -1
- package/dist/{chunk-L4TLMYGC.js → chunk-6RBW2Y5K.js} +3 -3
- package/dist/chunk-6RBW2Y5K.js.map +1 -0
- package/dist/chunk-732GZEUI.js +1592 -0
- package/dist/chunk-732GZEUI.js.map +1 -0
- package/dist/{chunk-X5THHG6T.js → chunk-CPMHCTX3.js} +3 -3
- package/dist/chunk-CPMHCTX3.js.map +1 -0
- package/dist/{chunk-V2MSAUHO.js → chunk-JO7Z2AOE.js} +2 -2
- package/dist/chunk-JO7Z2AOE.js.map +1 -0
- package/dist/{chunk-5RJVUC6J.js → chunk-M27JPX3K.js} +12 -3
- package/dist/chunk-M27JPX3K.js.map +1 -0
- package/dist/chunk-OXQGRJZT.js +125 -0
- package/dist/chunk-OXQGRJZT.js.map +1 -0
- package/dist/data/backend-env.d.ts +38 -0
- package/dist/data/backend-env.d.ts.map +1 -0
- package/dist/data/index.js +1 -1
- package/dist/entity/events.d.ts +14 -0
- package/dist/entity/events.d.ts.map +1 -0
- package/dist/events/envelope.d.ts +31 -0
- package/dist/events/envelope.d.ts.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/log.d.ts +44 -0
- package/dist/events/log.d.ts.map +1 -0
- package/dist/events/types.d.ts +40 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/i18n/index.d.ts +10 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/index.d.ts +27 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +388 -52
- package/dist/index.js.map +1 -1
- package/dist/integrations/index.js +1 -1
- package/dist/{integrations/index.d.ts → integrations.d.ts} +2 -2
- package/dist/integrations.d.ts.map +1 -0
- package/dist/{address/index.d.ts → lib/address.d.ts} +1 -1
- package/dist/{address/index.d.ts.map → lib/address.d.ts.map} +1 -1
- package/dist/{phone/index.d.ts → lib/phone.d.ts} +1 -1
- package/dist/lib/phone.d.ts.map +1 -0
- package/dist/{seo/index.d.ts → lib/seo.d.ts} +18 -1
- package/dist/lib/seo.d.ts.map +1 -0
- package/dist/{tenant/index.d.ts → lib/tenant.d.ts} +1 -1
- package/dist/lib/tenant.d.ts.map +1 -0
- package/dist/manifest/index.d.ts +1 -1
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/messaging/index.d.ts +3 -0
- package/dist/messaging/index.d.ts.map +1 -0
- package/dist/messaging/registry.d.ts +35 -0
- package/dist/messaging/registry.d.ts.map +1 -0
- package/dist/messaging/types.d.ts +67 -0
- package/dist/messaging/types.d.ts.map +1 -0
- package/dist/plugin/index.js +2 -1
- package/dist/plugin/runtime.d.ts +17 -0
- package/dist/plugin/runtime.d.ts.map +1 -1
- package/dist/registry/block-catalog.d.ts +78 -0
- package/dist/registry/block-catalog.d.ts.map +1 -0
- package/dist/registry/block-constraints.d.ts +64 -0
- package/dist/registry/block-constraints.d.ts.map +1 -0
- package/dist/registry/block-schema.d.ts +69 -0
- package/dist/registry/block-schema.d.ts.map +1 -0
- package/dist/registry/blocks.d.ts +84 -0
- package/dist/registry/blocks.d.ts.map +1 -0
- package/dist/registry/entities.d.ts +153 -0
- package/dist/registry/entities.d.ts.map +1 -0
- package/dist/registry/extension-points.d.ts +117 -0
- package/dist/registry/extension-points.d.ts.map +1 -0
- package/dist/registry/handles.d.ts +41 -0
- package/dist/registry/handles.d.ts.map +1 -0
- package/dist/registry/index.d.ts +41 -41
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/loaders.d.ts +55 -0
- package/dist/registry/loaders.d.ts.map +1 -0
- package/dist/registry/registry-class.d.ts +157 -0
- package/dist/registry/registry-class.d.ts.map +1 -0
- package/dist/registry/schema-check.d.ts +14 -0
- package/dist/registry/schema-check.d.ts.map +1 -0
- package/dist/router/index.d.ts +78 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/{testing/index.d.ts → testing.d.ts} +3 -3
- package/dist/testing.d.ts.map +1 -0
- package/dist/types/analytics.d.ts +196 -0
- package/dist/types/analytics.d.ts.map +1 -0
- package/dist/types/crud.d.ts +22 -2
- package/dist/types/crud.d.ts.map +1 -1
- package/dist/types/plugins.d.ts +55 -1
- package/dist/types/plugins.d.ts.map +1 -1
- package/package.json +6 -18
- package/dist/blocks/index.d.ts +0 -25
- package/dist/blocks/index.d.ts.map +0 -1
- package/dist/chunk-5RJVUC6J.js.map +0 -1
- package/dist/chunk-L4TLMYGC.js.map +0 -1
- package/dist/chunk-V2MSAUHO.js.map +0 -1
- package/dist/chunk-X5THHG6T.js.map +0 -1
- package/dist/chunk-Y2C2FBQP.js +0 -35
- package/dist/chunk-Y2C2FBQP.js.map +0 -1
- package/dist/chunk-YH25Y4FW.js +0 -311
- package/dist/chunk-YH25Y4FW.js.map +0 -1
- package/dist/integrations/index.d.ts.map +0 -1
- package/dist/phone/index.d.ts.map +0 -1
- package/dist/seo/index.d.ts.map +0 -1
- package/dist/tenant/index.d.ts.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/src/access/denial.ts +0 -33
- package/src/access/engine.test.ts +0 -48
- package/src/access/engine.ts +0 -136
- package/src/access/index.ts +0 -14
- package/src/access/limits.ts +0 -18
- package/src/address/index.ts +0 -188
- package/src/app/render.tsx +0 -69
- package/src/blocks/index.tsx +0 -68
- package/src/data/archetype.ts +0 -255
- package/src/data/bulk.ts +0 -35
- package/src/data/cached.ts +0 -55
- package/src/data/count.test.ts +0 -152
- package/src/data/count.ts +0 -131
- package/src/data/filters.test.ts +0 -70
- package/src/data/filters.ts +0 -90
- package/src/data/index.ts +0 -11
- package/src/data/mock.ts +0 -90
- package/src/data/platform-api.ts +0 -209
- package/src/data/refresh.ts +0 -115
- package/src/data/resolve.ts +0 -126
- package/src/data/supabase.ts +0 -230
- package/src/data/types.ts +0 -50
- package/src/entity/index.ts +0 -2
- package/src/entity/registry.ts +0 -49
- package/src/events/index.tsx +0 -82
- package/src/i18n/index.ts +0 -476
- package/src/i18n/shell-translations.en.ts +0 -875
- package/src/i18n/shell-translations.pt-br.ts +0 -873
- package/src/index.ts +0 -217
- package/src/integrations/index.ts +0 -237
- package/src/lib/cache.ts +0 -118
- package/src/lib/csv.ts +0 -54
- package/src/lib/format.ts +0 -58
- package/src/manifest/app-manifest.schema.json +0 -676
- package/src/manifest/index.ts +0 -518
- package/src/manifest/serialize.ts +0 -52
- package/src/phone/index.ts +0 -85
- package/src/plugin/createSafeDataProvider.ts +0 -30
- package/src/plugin/index.ts +0 -1
- package/src/plugin/runtime.ts +0 -331
- package/src/registry/index.ts +0 -163
- package/src/router/history.ts +0 -86
- package/src/router/index.ts +0 -29
- package/src/runtime/index.ts +0 -15
- package/src/runtime/oauth.ts +0 -219
- package/src/search/engine.ts +0 -559
- package/src/search/index.ts +0 -25
- package/src/search/text.ts +0 -206
- package/src/search/types.ts +0 -75
- package/src/seo/index.ts +0 -128
- package/src/tenant/index.ts +0 -38
- package/src/testing/index.ts +0 -116
- package/src/types/auth.ts +0 -41
- package/src/types/billing.ts +0 -39
- package/src/types/crud.ts +0 -184
- package/src/types/entities.ts +0 -142
- package/src/types/entitlements.ts +0 -45
- package/src/types/i18n.ts +0 -7
- package/src/types/index.ts +0 -11
- package/src/types/org.ts +0 -137
- package/src/types/payment.ts +0 -44
- package/src/types/permissions.ts +0 -32
- package/src/types/plugins.ts +0 -480
- package/src/types/theme.ts +0 -8
package/src/index.ts
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
// Types
|
|
2
|
-
export type { EntityArchetype, BaseEntity, PersonEntity, ProductEntity, ServiceEntity, OrderEntity, TransactionEntity, LocationEntity, ScheduleEntity, CategoryEntity } from './types/entities'
|
|
3
|
-
export type { EntityDef, EntityImageConfig, FieldDef, FieldType, FieldRelation, FieldGroup, DetailTab, FormLayout, ComputedFieldValue } from './types/crud'
|
|
4
|
-
export type { PluginManifest, PluginScope, PluginStatus, ResolvedPluginManifest, PluginRuntime, PluginRuntimeContext, PluginWidgetZone, PluginWidgetDefinition, PluginNavigationEntry, PluginSettingsTab, PluginRouteDefinition, PluginAITool, AIToolMode, AIToolExecution, AgentRpcDeclaration, AIToolParameterProperty, AIToolParameters, AIToolSuggestion, PluginRegistryDef, PluginMigration, PluginDiagnostic, VerticalId, ScaffoldType, TenantPluginBinding, DashboardWidgetDef, DashboardWidgetKind, DashboardSurface, DashboardLayoutConfig, ResolvedDashboardWidget } from './types/plugins'
|
|
5
|
-
export { WidgetZone } from './types/plugins'
|
|
6
|
-
export type { AuthAdapter, AuthUser, AuthSession, AuthProvider } from './types/auth'
|
|
7
|
-
export type { OrgAdapter, Organization, OrgMember, OrgMembership, TeamPerson, Location, Invite, CreateOrgOptions } from './types/org'
|
|
8
|
-
export type { PermissionsConfig, FeatureDeclaration, PermissionAction, PermissionProfile, SystemPermission } from './types/permissions'
|
|
9
|
-
export type { Plan, BillingConfig, BillingCheckoutFn } from './types/billing'
|
|
10
|
-
export type { PlanEntitlements, LimitDeclaration } from './types/entitlements'
|
|
11
|
-
export type { ThemeBrand, ThemeRadius, ThemeMode } from './types/theme'
|
|
12
|
-
export type { LocaleConfig } from './types/i18n'
|
|
13
|
-
|
|
14
|
-
// Data providers
|
|
15
|
-
export { createSupabaseProvider, setGlobalSupabaseClient, getSupabaseClientOptional } from './data/supabase'
|
|
16
|
-
export { countByTenant, invalidateCount } from './data/count'
|
|
17
|
-
export type { CountByTenantOptions } from './data/count'
|
|
18
|
-
export { createFayzApiProvider } from './data/platform-api'
|
|
19
|
-
export { createMockProvider } from './data/mock'
|
|
20
|
-
export { createArchetypeProvider } from './data/archetype'
|
|
21
|
-
export { withCache } from './data/cached'
|
|
22
|
-
export { resolveDataProvider } from './data/resolve'
|
|
23
|
-
export { bulkCreate } from './data/bulk'
|
|
24
|
-
export type { BulkWriteOptions, BulkWriteResult } from './data/types'
|
|
25
|
-
export {
|
|
26
|
-
parseRangeFilter,
|
|
27
|
-
isFilterObject,
|
|
28
|
-
matchesRange,
|
|
29
|
-
applyRangeToQuery,
|
|
30
|
-
} from './data/filters'
|
|
31
|
-
export type { RangeFilter } from './data/filters'
|
|
32
|
-
export {
|
|
33
|
-
DATA_CHANGED_EVENT,
|
|
34
|
-
emitDataChanged,
|
|
35
|
-
matchesDataChange,
|
|
36
|
-
useDataChanged,
|
|
37
|
-
} from './data/refresh'
|
|
38
|
-
export type { DataChangedPayload, DataChangedMatch } from './data/refresh'
|
|
39
|
-
export { createSafeDataProvider } from './plugin/createSafeDataProvider'
|
|
40
|
-
export {
|
|
41
|
-
COUNTRIES, DEFAULT_COUNTRY, getCountry, unmaskPhone, maskPhone, maskDigitCount,
|
|
42
|
-
} from './phone'
|
|
43
|
-
export type { CountryDef } from './phone'
|
|
44
|
-
export {
|
|
45
|
-
normalizePostalCode, formatPostalCode, isValidPostalCode,
|
|
46
|
-
createViaCepProvider, setPostalLookupProvider, getPostalLookupProvider,
|
|
47
|
-
lookupPostalCode, clearPostalCache,
|
|
48
|
-
} from './address'
|
|
49
|
-
export type { PostalAddress, PostalLookupProvider } from './address'
|
|
50
|
-
export type {
|
|
51
|
-
PaymentProvider, PaymentMethod, ChargeStatus, CreateChargeInput, PixCharge,
|
|
52
|
-
} from './types/payment'
|
|
53
|
-
export {
|
|
54
|
-
useSeo, applySeo, absoluteUrl, seoOrigin, breadcrumbJsonLd, organizationJsonLd,
|
|
55
|
-
} from './seo'
|
|
56
|
-
export type { SeoConfig, BreadcrumbItem } from './seo'
|
|
57
|
-
export type { DataProvider, CrudQuery, CrudResult, SupabaseProviderConfig, FayzApiProviderConfig } from './data/index'
|
|
58
|
-
|
|
59
|
-
// Tenant context (runtime DI for the data layer)
|
|
60
|
-
export { setActiveTenantId, getActiveTenantId, subscribeActiveTenant, useActiveTenantId } from './tenant'
|
|
61
|
-
|
|
62
|
-
// Runtime broker helpers
|
|
63
|
-
export { createFayzRuntimeClient, FayzRuntimeError } from './runtime'
|
|
64
|
-
export type {
|
|
65
|
-
FayzRuntimeClientOptions,
|
|
66
|
-
FayzRuntimeEnvironment,
|
|
67
|
-
GoogleCalendarEvent,
|
|
68
|
-
GoogleCalendarEventInput,
|
|
69
|
-
GoogleCalendarEventTime,
|
|
70
|
-
ListGoogleCalendarEventsInput,
|
|
71
|
-
PluginOAuthExchangeInput,
|
|
72
|
-
PluginOAuthExchangeResponse,
|
|
73
|
-
RuntimePluginOAuthGrant,
|
|
74
|
-
} from './runtime'
|
|
75
|
-
|
|
76
|
-
// Plugin contract assertions (integrity half of the deploy gate)
|
|
77
|
-
export { assertPluginManifestContract, assertConnectorContract, PluginContractError } from './testing'
|
|
78
|
-
|
|
79
|
-
// Integration connector spine (shared contract for external-provider sync)
|
|
80
|
-
export { withAfterHooks, connectorPlanes, preferredPlane, connectorDirection } from './integrations'
|
|
81
|
-
export type {
|
|
82
|
-
Connector,
|
|
83
|
-
ConnectorCapability,
|
|
84
|
-
ConnectionConfig,
|
|
85
|
-
SyncRun,
|
|
86
|
-
SyncDirection,
|
|
87
|
-
SyncTrigger,
|
|
88
|
-
IntegrationAuthKind,
|
|
89
|
-
TestConnectionResult,
|
|
90
|
-
ConnectorDefinition,
|
|
91
|
-
ConnectorField,
|
|
92
|
-
ConnectorStatus,
|
|
93
|
-
ConnectorPlane,
|
|
94
|
-
ConnectorDirection,
|
|
95
|
-
ConnectorAgentTool,
|
|
96
|
-
} from './integrations'
|
|
97
|
-
|
|
98
|
-
// Shared utilities
|
|
99
|
-
export { formatCurrency, formatDate, formatDateTime, getActiveLocale, getDefaultCurrency, setDefaultCurrency } from './lib/format'
|
|
100
|
-
export { exportCSV, buildCSV, downloadCSV } from './lib/csv'
|
|
101
|
-
export type { CSVColumn } from './lib/csv'
|
|
102
|
-
export { globalCache, createCacheStore, stableKey, clearGlobalCache } from './lib/cache'
|
|
103
|
-
export type { CacheStore } from './lib/cache'
|
|
104
|
-
|
|
105
|
-
// Plugin system
|
|
106
|
-
export { definePlugin, resolvePluginRuntime, getWidgetsForZone, getDashboardWidgets, PluginRuntimeProvider, usePluginRuntime, usePluginRuntimeOptional, useConnectorsForPlugin, PLUGIN_API_VERSION, resolvePluginComponent } from './plugin/runtime'
|
|
107
|
-
export type { PluginEventDefinition, PluginQuickAction } from './types/plugins'
|
|
108
|
-
|
|
109
|
-
// Event bus
|
|
110
|
-
export { createEventBus, eventBus, useOnEvent } from './events'
|
|
111
|
-
export type { EventBus, EventHandler } from './events'
|
|
112
|
-
|
|
113
|
-
// Entity registry
|
|
114
|
-
export { registerEntity, getEntityByKey, getAllEntities, clearEntityRegistry, deriveEntityKey } from './entity/registry'
|
|
115
|
-
export type { RegisteredEntity } from './entity/registry'
|
|
116
|
-
|
|
117
|
-
// Global search (command palette + agent lookups share one engine)
|
|
118
|
-
export {
|
|
119
|
-
searchEverything, clearSearchCache, setSearchIndexAvailable, isSearchIndexAvailable,
|
|
120
|
-
MIN_QUERY_LENGTH, foldText, foldWithMap, digitsOf, normalizeQuery, similarity,
|
|
121
|
-
scoreCandidate, highlightRanges,
|
|
122
|
-
} from './search'
|
|
123
|
-
export type {
|
|
124
|
-
SearchTarget, SearchHit, SearchGroup, SearchPath, SearchOptions, GlobalSearchResult,
|
|
125
|
-
NormalizedQuery, RankCandidate,
|
|
126
|
-
} from './search'
|
|
127
|
-
|
|
128
|
-
// Uniform registry (component / block / page / metric / scaffold / plugin)
|
|
129
|
-
export {
|
|
130
|
-
Registry,
|
|
131
|
-
isCustomId,
|
|
132
|
-
componentRegistry,
|
|
133
|
-
blockRegistry,
|
|
134
|
-
pageRegistry,
|
|
135
|
-
scaffoldRegistry,
|
|
136
|
-
metricRegistry,
|
|
137
|
-
pluginRegistry,
|
|
138
|
-
registerComponent,
|
|
139
|
-
getComponent,
|
|
140
|
-
registerBlock,
|
|
141
|
-
getBlock,
|
|
142
|
-
listBlocks,
|
|
143
|
-
registerPage,
|
|
144
|
-
getPage,
|
|
145
|
-
registerScaffold,
|
|
146
|
-
getScaffold,
|
|
147
|
-
registerMetric,
|
|
148
|
-
getMetric,
|
|
149
|
-
listMetrics,
|
|
150
|
-
registerPlugin,
|
|
151
|
-
getPlugin,
|
|
152
|
-
listPlugins,
|
|
153
|
-
pluginFactoryRegistry,
|
|
154
|
-
registerPluginFactory,
|
|
155
|
-
getPluginFactory,
|
|
156
|
-
listPluginFactories,
|
|
157
|
-
} from './registry'
|
|
158
|
-
export type { PluginFactory } from './registry'
|
|
159
|
-
export type {
|
|
160
|
-
JsonSchema,
|
|
161
|
-
RegistrySource,
|
|
162
|
-
RegistryMeta,
|
|
163
|
-
RegistryEntry,
|
|
164
|
-
MetricFormat,
|
|
165
|
-
MetricContext,
|
|
166
|
-
MetricValue,
|
|
167
|
-
MetricDefinition,
|
|
168
|
-
} from './registry'
|
|
169
|
-
|
|
170
|
-
// Block system (universal page primitive)
|
|
171
|
-
export { BlockRenderer, renderBlocks, BlockChildren } from './blocks'
|
|
172
|
-
export type { BlockNode, BlockComponentProps } from './blocks'
|
|
173
|
-
|
|
174
|
-
// App manifest (the app, as data) + migration runner
|
|
175
|
-
export {
|
|
176
|
-
CURRENT_MANIFEST_VERSION,
|
|
177
|
-
registerManifestMigration,
|
|
178
|
-
migrateManifest,
|
|
179
|
-
validateManifest,
|
|
180
|
-
} from './manifest'
|
|
181
|
-
export type {
|
|
182
|
-
AppManifest,
|
|
183
|
-
BackendProvider,
|
|
184
|
-
BackendRef,
|
|
185
|
-
SurfaceManifest,
|
|
186
|
-
PageManifest,
|
|
187
|
-
PluginRef,
|
|
188
|
-
ManifestMigration,
|
|
189
|
-
AgentContract,
|
|
190
|
-
AgentDomainKnowledge,
|
|
191
|
-
EntityContract,
|
|
192
|
-
AIToolContract,
|
|
193
|
-
RpcContract,
|
|
194
|
-
} from './manifest'
|
|
195
|
-
export { serializeManifest, computeContractHash, serializeManifestWithHash } from './manifest/serialize'
|
|
196
|
-
export { default as appManifestSchema } from './manifest/app-manifest.schema.json'
|
|
197
|
-
|
|
198
|
-
// App entry points (manifest → running app)
|
|
199
|
-
export { defineApp, renderApp, useManifest } from './app/render'
|
|
200
|
-
export type { RenderAppOptions } from './app/render'
|
|
201
|
-
|
|
202
|
-
// i18n
|
|
203
|
-
export { I18nProvider, useI18nConfig, useTranslation, coreTranslations, mergeTranslations, registerTranslations, getCurrentLocale, setCurrentLocale, preloadLocale, setLocaleStore } from './i18n/index'
|
|
204
|
-
|
|
205
|
-
// Router
|
|
206
|
-
export { hashRouterAdapter, windowRouterAdapter } from './router/index'
|
|
207
|
-
export type { RouterAdapter } from './router/index'
|
|
208
|
-
|
|
209
|
-
// Global cross-module navigation history (context-aware back buttons)
|
|
210
|
-
export {
|
|
211
|
-
useNavHistoryStore,
|
|
212
|
-
recordNavigation,
|
|
213
|
-
useNavReferrer,
|
|
214
|
-
navHistoryBack,
|
|
215
|
-
routeModule,
|
|
216
|
-
} from './router/history'
|
|
217
|
-
export type { NavHistoryEntry } from './router/history'
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Integration Connector spine
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// An integration is a connector that keeps canonical Fayz data in agreement
|
|
5
|
-
// with an external provider (Google Calendar, open banking, Shopify, …). This
|
|
6
|
-
// module is the thin shared contract both native (SDK) and client-built
|
|
7
|
-
// connectors implement. The heavy lifting (auth, fetch/push, idempotent
|
|
8
|
-
// upserts) runs in the data plane — typically a Supabase Edge Function — while
|
|
9
|
-
// the control plane (a settings tab + this contract) lives in the app/plugin.
|
|
10
|
-
//
|
|
11
|
-
// Design notes live in docs/design/bling-integration-brief.md. Proven precedents:
|
|
12
|
-
// the Fayz runtime OAuth broker (packages/core/src/runtime/oauth.ts) and the
|
|
13
|
-
// bank-statement edge functions in the predecessor app.
|
|
14
|
-
import type * as React from 'react'
|
|
15
|
-
|
|
16
|
-
/** How a connector authenticates to its provider. */
|
|
17
|
-
export type IntegrationAuthKind = 'oauth' | 'api-key' | 'mtls'
|
|
18
|
-
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
// Planes — the two ways a connector gets honoured
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
// "Integração" and "conector" are the same noun. What differs is the plane it
|
|
23
|
-
// runs on:
|
|
24
|
-
//
|
|
25
|
-
// - 'agentic' — the provider's tools are handed to the assistant. Nothing is
|
|
26
|
-
// copied: the agent calls the provider at the moment it needs the answer,
|
|
27
|
-
// so there is no mirror to drift and no de-para to maintain. Preferred
|
|
28
|
-
// whenever the provider offers it.
|
|
29
|
-
// - 'sync' — the old-school pipeline: authorize, map, run, keep an audit
|
|
30
|
-
// trail. Required when the data must exist *inside* Fayz — to be listed,
|
|
31
|
-
// filtered, reported on, or read while the provider is unreachable.
|
|
32
|
-
//
|
|
33
|
-
// A connector may support both; `preferredPlane` encodes the house rule.
|
|
34
|
-
export type ConnectorPlane = 'agentic' | 'sync'
|
|
35
|
-
|
|
36
|
-
/** Which side reaches for the other, from this app's point of view. */
|
|
37
|
-
export type ConnectorDirection = 'inbound' | 'outbound'
|
|
38
|
-
|
|
39
|
-
/** A tool the assistant gains once a connector is resolved on the agentic plane. */
|
|
40
|
-
export interface ConnectorAgentTool {
|
|
41
|
-
name: string
|
|
42
|
-
description?: string
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Which way data flows for a given capability. */
|
|
46
|
-
export type SyncDirection = 'inbound' | 'outbound' | 'bidirectional'
|
|
47
|
-
|
|
48
|
-
/** What causes a sync to run. */
|
|
49
|
-
export type SyncTrigger = 'on-write' | 'scheduled' | 'manual' | 'webhook'
|
|
50
|
-
|
|
51
|
-
/** One thing a connector can sync (an entity + its direction + triggers). */
|
|
52
|
-
export interface ConnectorCapability {
|
|
53
|
-
/** Canonical entity synced, e.g. 'booking', 'movement'. */
|
|
54
|
-
entity: string
|
|
55
|
-
direction: SyncDirection
|
|
56
|
-
triggers: SyncTrigger[]
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** The state of a tenant's connection to a provider (one row in a *_integrations table). */
|
|
60
|
-
export interface ConnectionConfig {
|
|
61
|
-
/** Provider key, e.g. 'google', 'plugbank'. */
|
|
62
|
-
provider: string
|
|
63
|
-
/** Whether the connection is active and should sync. */
|
|
64
|
-
active: boolean
|
|
65
|
-
/** Opaque, provider-specific config (calendar id, account id, cursor, …). Never secrets. */
|
|
66
|
-
settings?: Record<string, unknown>
|
|
67
|
-
/** Last successful sync, ISO timestamp. */
|
|
68
|
-
lastSyncAt?: string
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Audit record of one sync execution (generalizes *_sync_log / *_sync_runs). */
|
|
72
|
-
export interface SyncRun {
|
|
73
|
-
id?: string
|
|
74
|
-
provider: string
|
|
75
|
-
direction: SyncDirection
|
|
76
|
-
trigger: SyncTrigger
|
|
77
|
-
status: 'success' | 'partial' | 'error'
|
|
78
|
-
/** Items pulled/pushed and how many were written. */
|
|
79
|
-
fetched?: number
|
|
80
|
-
written?: number
|
|
81
|
-
/** Pagination/incremental cursor advanced by this run. */
|
|
82
|
-
cursor?: string
|
|
83
|
-
error?: string
|
|
84
|
-
startedAt?: string
|
|
85
|
-
finishedAt?: string
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface TestConnectionResult {
|
|
89
|
-
ok: boolean
|
|
90
|
-
message?: string
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* A connector's control-plane descriptor. The data-plane verbs (testConnection,
|
|
95
|
-
* sync) are usually thin clients that invoke a Supabase Edge Function — the
|
|
96
|
-
* function holds credentials and does the real work.
|
|
97
|
-
*/
|
|
98
|
-
export interface Connector {
|
|
99
|
-
/** Stable connector id, e.g. 'google-calendar', 'plugbank'. */
|
|
100
|
-
id: string
|
|
101
|
-
/** Provider key matching ConnectionConfig.provider. */
|
|
102
|
-
provider: string
|
|
103
|
-
/** Plugin this connector extends, e.g. 'agenda', 'financial'. */
|
|
104
|
-
pluginId: string
|
|
105
|
-
authKind: IntegrationAuthKind
|
|
106
|
-
capabilities: ConnectorCapability[]
|
|
107
|
-
/** Validate the stored credentials/config without syncing. */
|
|
108
|
-
testConnection?(config: ConnectionConfig): Promise<TestConnectionResult>
|
|
109
|
-
/** Run a sync for the given direction; returns the audit record. */
|
|
110
|
-
sync?(input: { config: ConnectionConfig; direction: SyncDirection; trigger: SyncTrigger }): Promise<SyncRun>
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// ---------------------------------------------------------------------------
|
|
114
|
-
// Connector UI contract — how an addon plugin EXTENDS a host plugin's settings
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
// An addon plugin declares one or more ConnectorDefinitions on its manifest
|
|
117
|
-
// (`connectors: [...]`). The runtime groups them by `hostPluginId`, and the host
|
|
118
|
-
// plugin's settings panel renders them in a unified "Integrations" tab — the
|
|
119
|
-
// same connect/credentials experience for every connector. The connector-
|
|
120
|
-
// specific bits (import a statement, sync now, history) live in `ExtraPanel`.
|
|
121
|
-
|
|
122
|
-
/** A credential input the unified setup form renders for an api-key/mtls connector. */
|
|
123
|
-
export interface ConnectorField {
|
|
124
|
-
key: string
|
|
125
|
-
label: string
|
|
126
|
-
type: 'text' | 'password'
|
|
127
|
-
placeholder?: string
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export interface ConnectorStatus {
|
|
131
|
-
connected: boolean
|
|
132
|
-
detail?: string
|
|
133
|
-
/** Which plane the live connection is running on (when connected). */
|
|
134
|
-
plane?: ConnectorPlane
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* UI-facing connector descriptor. Built on the data-plane `Connector` concept
|
|
139
|
-
* (`pluginId` → `hostPluginId`), plus the control-plane hooks the unified
|
|
140
|
-
* Integrations hub calls. Lives in core so `PluginManifest.connectors` can type
|
|
141
|
-
* it; the rendering hub lives in `@fayz-ai/saas`.
|
|
142
|
-
*/
|
|
143
|
-
export interface ConnectorDefinition {
|
|
144
|
-
/** Stable connector id, e.g. 'google-calendar', 'plugbank'. */
|
|
145
|
-
id: string
|
|
146
|
-
/** The plugin this connector extends, e.g. 'financial', 'agenda'. */
|
|
147
|
-
hostPluginId: string
|
|
148
|
-
name: string
|
|
149
|
-
description?: string
|
|
150
|
-
/** Lucide icon name. */
|
|
151
|
-
icon?: string
|
|
152
|
-
/**
|
|
153
|
-
* The connector's own brand mark — a URL or an inline data URI. Preferred
|
|
154
|
-
* over the catalogue's icon and over `icon`, so a connector the Fayz
|
|
155
|
-
* directory doesn't carry still shows up as itself.
|
|
156
|
-
*/
|
|
157
|
-
logoUrl?: string
|
|
158
|
-
authKind: IntegrationAuthKind
|
|
159
|
-
/** Planes this connector can be honoured on. Default: `['sync']`. */
|
|
160
|
-
planes?: ConnectorPlane[]
|
|
161
|
-
/** Default `'outbound'` — this app reaching a provider. */
|
|
162
|
-
direction?: ConnectorDirection
|
|
163
|
-
/** What the assistant gains on the agentic plane — shown before connecting. */
|
|
164
|
-
agentTools?: ConnectorAgentTool[]
|
|
165
|
-
/** Canonical entities this connector touches ('booking', 'movement'). */
|
|
166
|
-
entities?: string[]
|
|
167
|
-
/** Catalog category ('scheduling', 'payments', …) — matches the Fayz catalog. */
|
|
168
|
-
category?: string
|
|
169
|
-
/** Provider documentation, linked from the connector's detail. */
|
|
170
|
-
docsUrl?: string
|
|
171
|
-
/** Declarative credentials — the unified form renders these (api-key / mtls). */
|
|
172
|
-
fields?: ConnectorField[]
|
|
173
|
-
/** Current connection state for the status badge. */
|
|
174
|
-
getStatus(): Promise<ConnectorStatus>
|
|
175
|
-
/** Validate credentials without persisting (api-key / mtls). */
|
|
176
|
-
testConnection?(values: Record<string, string>): Promise<TestConnectionResult>
|
|
177
|
-
/** Persist the connection (api-key / mtls). */
|
|
178
|
-
saveConnection?(values: Record<string, string>): Promise<void>
|
|
179
|
-
/** Begin an OAuth connect flow — returns the consent URL to redirect to. */
|
|
180
|
-
startOAuth?(redirectTo?: string): Promise<string>
|
|
181
|
-
/** Tear down the connection. */
|
|
182
|
-
disconnect?(): Promise<void>
|
|
183
|
-
/** Move an existing connection between planes (only when `planes` has both). */
|
|
184
|
-
setPlane?(plane: ConnectorPlane): Promise<void>
|
|
185
|
-
/** Optional connector-specific UI below the connect panel (import / sync / history). */
|
|
186
|
-
ExtraPanel?: React.ComponentType
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** Planes a connector supports — the contract's default is the sync pipeline. */
|
|
190
|
-
export function connectorPlanes(def: Pick<ConnectorDefinition, 'planes'>): ConnectorPlane[] {
|
|
191
|
-
return def.planes?.length ? def.planes : ['sync']
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* The plane to offer first. Agentic wins whenever the connector supports it:
|
|
196
|
-
* handing the assistant a tool costs nothing to keep in agreement, while a sync
|
|
197
|
-
* pipeline is a copy that has to be maintained for as long as it exists.
|
|
198
|
-
*/
|
|
199
|
-
export function preferredPlane(def: Pick<ConnectorDefinition, 'planes'>): ConnectorPlane {
|
|
200
|
-
return connectorPlanes(def).includes('agentic') ? 'agentic' : 'sync'
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/** Direction a connector moves data in — outbound unless it says otherwise. */
|
|
204
|
-
export function connectorDirection(def: Pick<ConnectorDefinition, 'direction'>): ConnectorDirection {
|
|
205
|
-
return def.direction ?? 'outbound'
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Wrap an object's async methods so a handler fires AFTER selected methods
|
|
210
|
-
* resolve — the non-invasive hook for outbound, event-driven sync when there's
|
|
211
|
-
* no app-level event bus. Example: wrap an AgendaDataProvider so that after
|
|
212
|
-
* createBooking/updateBooking/deleteBooking succeed, an external calendar is
|
|
213
|
-
* updated. The handler runs fire-and-forget; its failures never break the call.
|
|
214
|
-
*/
|
|
215
|
-
export function withAfterHooks<T extends object>(
|
|
216
|
-
target: T,
|
|
217
|
-
methods: Partial<Record<keyof T, (args: unknown[], result: unknown) => void | Promise<void>>>,
|
|
218
|
-
): T {
|
|
219
|
-
return new Proxy(target, {
|
|
220
|
-
get(obj, prop, receiver) {
|
|
221
|
-
const orig = Reflect.get(obj, prop, receiver)
|
|
222
|
-
const hook = (methods as Record<string | symbol, ((args: unknown[], result: unknown) => void | Promise<void>) | undefined>)[prop]
|
|
223
|
-
if (typeof orig !== 'function' || !hook) return orig
|
|
224
|
-
return (...args: unknown[]) => {
|
|
225
|
-
const result = (orig as (...a: unknown[]) => unknown).apply(obj, args)
|
|
226
|
-
if (result instanceof Promise) {
|
|
227
|
-
return result.then((value) => {
|
|
228
|
-
try { void Promise.resolve(hook(args, value)).catch(() => {}) } catch { /* never break the call */ }
|
|
229
|
-
return value
|
|
230
|
-
})
|
|
231
|
-
}
|
|
232
|
-
try { void Promise.resolve(hook(args, result)).catch(() => {}) } catch { /* noop */ }
|
|
233
|
-
return result
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
})
|
|
237
|
-
}
|
package/src/lib/cache.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Types
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
interface CacheEntry<T = unknown> {
|
|
6
|
-
data: T
|
|
7
|
-
expiresAt: number
|
|
8
|
-
lastAccess: number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface CacheStore {
|
|
12
|
-
get<T>(key: string): T | undefined
|
|
13
|
-
set<T>(key: string, data: T, ttl?: number): void
|
|
14
|
-
/** Clear all entries whose key starts with `prefix` */
|
|
15
|
-
invalidate(prefix: string): void
|
|
16
|
-
clear(): void
|
|
17
|
-
size(): number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface CacheConfig {
|
|
21
|
-
/** Default time-to-live in ms (default: 60 000 — 1 minute) */
|
|
22
|
-
defaultTTL?: number
|
|
23
|
-
/** Maximum cached entries before LRU eviction (default: 500) */
|
|
24
|
-
maxEntries?: number
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
// Stable key helper — deterministic JSON for cache keys
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
|
|
31
|
-
function sortDeep(value: unknown): unknown {
|
|
32
|
-
if (value === null || value === undefined || typeof value !== 'object') return value
|
|
33
|
-
if (Array.isArray(value)) return value.map(sortDeep)
|
|
34
|
-
const sorted: Record<string, unknown> = {}
|
|
35
|
-
for (const k of Object.keys(value as Record<string, unknown>).sort()) {
|
|
36
|
-
sorted[k] = sortDeep((value as Record<string, unknown>)[k])
|
|
37
|
-
}
|
|
38
|
-
return sorted
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function stableKey(...parts: unknown[]): string {
|
|
42
|
-
return parts.map((p) => (typeof p === 'string' ? p : JSON.stringify(sortDeep(p)))).join(':')
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
// CacheStore implementation
|
|
47
|
-
// ---------------------------------------------------------------------------
|
|
48
|
-
|
|
49
|
-
export function createCacheStore(config?: CacheConfig): CacheStore {
|
|
50
|
-
const defaultTTL = config?.defaultTTL ?? 60_000
|
|
51
|
-
const maxEntries = config?.maxEntries ?? 500
|
|
52
|
-
const entries = new Map<string, CacheEntry>()
|
|
53
|
-
|
|
54
|
-
function evictLRU() {
|
|
55
|
-
if (entries.size <= maxEntries) return
|
|
56
|
-
// Find the entry with the oldest lastAccess
|
|
57
|
-
let oldestKey: string | null = null
|
|
58
|
-
let oldestAccess = Infinity
|
|
59
|
-
for (const [key, entry] of entries) {
|
|
60
|
-
if (entry.lastAccess < oldestAccess) {
|
|
61
|
-
oldestAccess = entry.lastAccess
|
|
62
|
-
oldestKey = key
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (oldestKey) entries.delete(oldestKey)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
get<T>(key: string): T | undefined {
|
|
70
|
-
const entry = entries.get(key)
|
|
71
|
-
if (!entry) return undefined
|
|
72
|
-
if (Date.now() > entry.expiresAt) {
|
|
73
|
-
entries.delete(key)
|
|
74
|
-
return undefined
|
|
75
|
-
}
|
|
76
|
-
entry.lastAccess = Date.now()
|
|
77
|
-
return entry.data as T
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
set<T>(key: string, data: T, ttl?: number): void {
|
|
81
|
-
const now = Date.now()
|
|
82
|
-
entries.set(key, {
|
|
83
|
-
data,
|
|
84
|
-
expiresAt: now + (ttl ?? defaultTTL),
|
|
85
|
-
lastAccess: now,
|
|
86
|
-
})
|
|
87
|
-
evictLRU()
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
invalidate(prefix: string): void {
|
|
91
|
-
for (const key of entries.keys()) {
|
|
92
|
-
if (key.startsWith(prefix)) {
|
|
93
|
-
entries.delete(key)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
clear(): void {
|
|
99
|
-
entries.clear()
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
size(): number {
|
|
103
|
-
return entries.size
|
|
104
|
-
},
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ---------------------------------------------------------------------------
|
|
109
|
-
// Global singleton — auto-flushes on tenant/org switch
|
|
110
|
-
// ---------------------------------------------------------------------------
|
|
111
|
-
|
|
112
|
-
export const globalCache = createCacheStore()
|
|
113
|
-
|
|
114
|
-
/** Flush the global cache — called by the tenant accessor when the active
|
|
115
|
-
* tenant changes (replaces the old org-store subscription). */
|
|
116
|
-
export function clearGlobalCache(): void {
|
|
117
|
-
globalCache.clear()
|
|
118
|
-
}
|
package/src/lib/csv.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/** Column descriptor for generic CSV export */
|
|
2
|
-
export interface CSVColumn {
|
|
3
|
-
key: string
|
|
4
|
-
label: string
|
|
5
|
-
format?: (value: any, row: Record<string, any>) => string
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function escapeCSVField(value: unknown): string {
|
|
9
|
-
if (value == null) return ''
|
|
10
|
-
const str = String(value)
|
|
11
|
-
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
|
|
12
|
-
return `"${str.replace(/"/g, '""')}"`
|
|
13
|
-
}
|
|
14
|
-
return str
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Build a CSV string from columns + rows. Each cell runs through `column.format` if provided, then escaping. */
|
|
18
|
-
export function buildCSV(
|
|
19
|
-
columns: CSVColumn[],
|
|
20
|
-
rows: Record<string, any>[],
|
|
21
|
-
): string {
|
|
22
|
-
const header = columns.map((c) => escapeCSVField(c.label)).join(',')
|
|
23
|
-
const body = rows.map((row) =>
|
|
24
|
-
columns
|
|
25
|
-
.map((col) => {
|
|
26
|
-
const raw = row[col.key]
|
|
27
|
-
const formatted = col.format ? col.format(raw, row) : raw
|
|
28
|
-
return escapeCSVField(formatted)
|
|
29
|
-
})
|
|
30
|
-
.join(','),
|
|
31
|
-
)
|
|
32
|
-
return [header, ...body].join('\n')
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Trigger a CSV file download in the browser. */
|
|
36
|
-
export function downloadCSV(csv: string, filename: string): void {
|
|
37
|
-
const bom = '\uFEFF'
|
|
38
|
-
const blob = new Blob([bom + csv], { type: 'text/csv;charset=utf-8;' })
|
|
39
|
-
const url = URL.createObjectURL(blob)
|
|
40
|
-
const a = document.createElement('a')
|
|
41
|
-
a.href = url
|
|
42
|
-
a.download = filename.endsWith('.csv') ? filename : `${filename}.csv`
|
|
43
|
-
a.click()
|
|
44
|
-
URL.revokeObjectURL(url)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Convenience: build + download in one call. */
|
|
48
|
-
export function exportCSV(
|
|
49
|
-
columns: CSVColumn[],
|
|
50
|
-
rows: Record<string, any>[],
|
|
51
|
-
filename: string,
|
|
52
|
-
): void {
|
|
53
|
-
downloadCSV(buildCSV(columns, rows), filename)
|
|
54
|
-
}
|
package/src/lib/format.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { getCurrentLocale } from '../i18n'
|
|
2
|
-
|
|
3
|
-
// Currency inferred from the active locale unless the app sets one explicitly
|
|
4
|
-
// via createSaasApp({ locale: { currency: 'BRL' } }).
|
|
5
|
-
const CURRENCY_BY_LOCALE: Record<string, string> = {
|
|
6
|
-
'pt-BR': 'BRL',
|
|
7
|
-
'pt-PT': 'EUR',
|
|
8
|
-
en: 'USD',
|
|
9
|
-
'en-US': 'USD',
|
|
10
|
-
'en-GB': 'GBP',
|
|
11
|
-
es: 'EUR',
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let _defaultCurrency: string | null = null
|
|
15
|
-
|
|
16
|
-
export function setDefaultCurrency(code: string | undefined): void {
|
|
17
|
-
_defaultCurrency = code ?? null
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function getActiveLocale(): string {
|
|
21
|
-
try {
|
|
22
|
-
return getCurrentLocale() || 'en'
|
|
23
|
-
} catch {
|
|
24
|
-
return 'en'
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function getDefaultCurrency(): string {
|
|
29
|
-
if (_defaultCurrency) return _defaultCurrency
|
|
30
|
-
return CURRENCY_BY_LOCALE[getActiveLocale()] ?? 'USD'
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function formatCurrency(value: unknown, currency?: string): string {
|
|
34
|
-
const num = typeof value === 'number' ? value : parseFloat(String(value))
|
|
35
|
-
if (isNaN(num)) return String(value ?? '')
|
|
36
|
-
return new Intl.NumberFormat(getActiveLocale(), {
|
|
37
|
-
style: 'currency',
|
|
38
|
-
currency: currency ?? getDefaultCurrency(),
|
|
39
|
-
}).format(num)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function formatDate(value: unknown): string {
|
|
43
|
-
if (!value) return ''
|
|
44
|
-
try {
|
|
45
|
-
return new Intl.DateTimeFormat(getActiveLocale(), { dateStyle: 'medium' }).format(new Date(value as string))
|
|
46
|
-
} catch {
|
|
47
|
-
return String(value)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function formatDateTime(value: unknown): string {
|
|
52
|
-
if (!value) return ''
|
|
53
|
-
try {
|
|
54
|
-
return new Intl.DateTimeFormat(getActiveLocale(), { dateStyle: 'medium', timeStyle: 'short' }).format(new Date(value as string))
|
|
55
|
-
} catch {
|
|
56
|
-
return String(value)
|
|
57
|
-
}
|
|
58
|
-
}
|