@quazardous/qdadm 1.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/package.json +101 -0
- package/src/assets/logo.svg +6 -0
- package/src/auth/SessionAuthAdapter.ts +459 -0
- package/src/auth/index.ts +15 -0
- package/src/chain/ActiveStack.ts +154 -0
- package/src/chain/StackHydrator.ts +292 -0
- package/src/chain/index.ts +25 -0
- package/src/chain/useActiveStack.ts +120 -0
- package/src/chain/useStackHydrator.ts +155 -0
- package/src/components/BoolCell.vue +34 -0
- package/src/components/InfoBanner.vue +73 -0
- package/src/components/QdadmRoot.vue +52 -0
- package/src/components/SeverityTag.vue +86 -0
- package/src/components/dialogs/BulkStatusDialog.vue +60 -0
- package/src/components/dialogs/MultiStepDialog.vue +331 -0
- package/src/components/dialogs/SimpleDialog.vue +122 -0
- package/src/components/dialogs/UnsavedChangesDialog.vue +80 -0
- package/src/components/display/BannerZone.vue +65 -0
- package/src/components/display/CardsGrid.vue +72 -0
- package/src/components/display/CopyableId.vue +84 -0
- package/src/components/display/EmptyState.vue +62 -0
- package/src/components/display/IntensityBar.vue +190 -0
- package/src/components/display/RichCardsGrid.vue +101 -0
- package/src/components/edit/FormActions.vue +78 -0
- package/src/components/edit/FormField.vue +82 -0
- package/src/components/edit/FormInput.vue +158 -0
- package/src/components/edit/FormPage.vue +260 -0
- package/src/components/edit/FormTab.vue +217 -0
- package/src/components/edit/FormTabs.vue +120 -0
- package/src/components/edit/LookupField.vue +406 -0
- package/src/components/edit/LookupPickerDialog.vue +230 -0
- package/src/components/editors/JsonEditorFoldable.vue +470 -0
- package/src/components/editors/JsonStructuredField.vue +264 -0
- package/src/components/editors/JsonViewer.vue +51 -0
- package/src/components/editors/KeyValueEditor.vue +314 -0
- package/src/components/editors/LanguageEditor.vue +259 -0
- package/src/components/editors/PermissionEditor.vue +558 -0
- package/src/components/editors/ScopeEditor.vue +372 -0
- package/src/components/editors/VanillaJsonEditor.vue +183 -0
- package/src/components/index.ts +83 -0
- package/src/components/item/FieldGroups.vue +392 -0
- package/src/components/layout/AppLayout.vue +1032 -0
- package/src/components/layout/BaseLayout.vue +190 -0
- package/src/components/layout/Breadcrumb.vue +55 -0
- package/src/components/layout/DashboardLayout.vue +104 -0
- package/src/components/layout/FormLayout.vue +256 -0
- package/src/components/layout/ListLayout.vue +278 -0
- package/src/components/layout/PageHeader.vue +156 -0
- package/src/components/layout/PageLayout.vue +126 -0
- package/src/components/layout/PageNav.vue +192 -0
- package/src/components/layout/SidebarBox.vue +87 -0
- package/src/components/layout/Zone.vue +182 -0
- package/src/components/layout/defaults/DefaultBreadcrumb.vue +149 -0
- package/src/components/layout/defaults/DefaultFooter.vue +89 -0
- package/src/components/layout/defaults/DefaultFormActions.vue +67 -0
- package/src/components/layout/defaults/DefaultHeader.vue +78 -0
- package/src/components/layout/defaults/DefaultMenu.vue +188 -0
- package/src/components/layout/defaults/DefaultPagination.vue +75 -0
- package/src/components/layout/defaults/DefaultTable.vue +137 -0
- package/src/components/layout/defaults/DefaultUserInfo.vue +111 -0
- package/src/components/layout/defaults/index.ts +16 -0
- package/src/components/lists/ActionButtons.vue +49 -0
- package/src/components/lists/ActionColumn.vue +40 -0
- package/src/components/lists/FilterBar.vue +54 -0
- package/src/components/lists/ListPage.vue +467 -0
- package/src/components/pages/LoginPage.vue +334 -0
- package/src/components/pages/NotFoundPage.vue +98 -0
- package/src/components/show/ShowDisplay.vue +343 -0
- package/src/components/show/ShowField.vue +67 -0
- package/src/components/show/ShowPage.vue +431 -0
- package/src/composables/index.ts +155 -0
- package/src/composables/useApp.ts +67 -0
- package/src/composables/useAuth.ts +98 -0
- package/src/composables/useBareForm.ts +319 -0
- package/src/composables/useBreadcrumb.ts +252 -0
- package/src/composables/useChildPage.ts +113 -0
- package/src/composables/useCurrentEntity.ts +60 -0
- package/src/composables/useDeferred.ts +94 -0
- package/src/composables/useDirtyState.ts +138 -0
- package/src/composables/useEntityItemFormPage.ts +942 -0
- package/src/composables/useEntityItemFormPage.types.ts +451 -0
- package/src/composables/useEntityItemPage.ts +438 -0
- package/src/composables/useEntityItemShowPage.ts +722 -0
- package/src/composables/useFieldManager.ts +692 -0
- package/src/composables/useForm.ts +544 -0
- package/src/composables/useGuardStore.ts +53 -0
- package/src/composables/useHooks.ts +56 -0
- package/src/composables/useInfoBanner.ts +217 -0
- package/src/composables/useJsonSyntax.ts +122 -0
- package/src/composables/useLayoutResolver.ts +329 -0
- package/src/composables/useListPage.ts +1535 -0
- package/src/composables/useListPage.types.ts +437 -0
- package/src/composables/useListPage.utils.ts +101 -0
- package/src/composables/useNavContext.ts +439 -0
- package/src/composables/useNavigation.ts +216 -0
- package/src/composables/useOptionsLookup.ts +323 -0
- package/src/composables/usePageTitle.ts +84 -0
- package/src/composables/useSSEBridge.ts +142 -0
- package/src/composables/useSemanticBreadcrumb.ts +222 -0
- package/src/composables/useSidebarState.ts +24 -0
- package/src/composables/useSignals.ts +52 -0
- package/src/composables/useUnsavedChangesGuard.ts +155 -0
- package/src/composables/useUserImpersonator.ts +317 -0
- package/src/composables/useZoneRegistry.ts +252 -0
- package/src/core/bundles.ts +558 -0
- package/src/core/decorator.ts +420 -0
- package/src/core/extension.ts +470 -0
- package/src/core/index.ts +59 -0
- package/src/deferred/DeferredRegistry.ts +353 -0
- package/src/deferred/index.ts +15 -0
- package/src/editors/index.ts +12 -0
- package/src/entity/EntityManager.cache.ts +530 -0
- package/src/entity/EntityManager.crud.ts +615 -0
- package/src/entity/EntityManager.interface.ts +78 -0
- package/src/entity/EntityManager.query.ts +221 -0
- package/src/entity/EntityManager.relations.ts +151 -0
- package/src/entity/EntityManager.ts +944 -0
- package/src/entity/EntityManager.types.ts +288 -0
- package/src/entity/auth/CompositeAuthAdapter.ts +194 -0
- package/src/entity/auth/EntityAuthAdapter.ts +119 -0
- package/src/entity/auth/PermissiveAdapter.ts +43 -0
- package/src/entity/auth/RoleHierarchy.ts +128 -0
- package/src/entity/auth/SecurityChecker.ts +202 -0
- package/src/entity/auth/factory.ts +203 -0
- package/src/entity/auth/index.ts +47 -0
- package/src/entity/factory.test.js +189 -0
- package/src/entity/factory.ts +146 -0
- package/src/entity/index.ts +49 -0
- package/src/entity/storage/ApiStorage.ts +228 -0
- package/src/entity/storage/IStorage.ts +100 -0
- package/src/entity/storage/LocalStorage.ts +200 -0
- package/src/entity/storage/MemoryStorage.ts +184 -0
- package/src/entity/storage/MockApiStorage.ts +318 -0
- package/src/entity/storage/SdkStorage.ts +377 -0
- package/src/entity/storage/factory.test.js +159 -0
- package/src/entity/storage/factory.ts +209 -0
- package/src/entity/storage/index.ts +75 -0
- package/src/gen/FieldMapper.ts +122 -0
- package/src/gen/StorageProfileFactory.ts +93 -0
- package/src/gen/connectors/BaseConnector.ts +150 -0
- package/src/gen/connectors/ManualConnector.test.js +499 -0
- package/src/gen/connectors/ManualConnector.ts +414 -0
- package/src/gen/connectors/OpenAPIConnector.test.js +836 -0
- package/src/gen/connectors/OpenAPIConnector.ts +693 -0
- package/src/gen/connectors/__fixtures__/sample-openapi.json +311 -0
- package/src/gen/connectors/index.ts +27 -0
- package/src/gen/createManagers.ts +245 -0
- package/src/gen/decorators.ts +134 -0
- package/src/gen/generateManagers.test.js +540 -0
- package/src/gen/generateManagers.ts +398 -0
- package/src/gen/index.ts +66 -0
- package/src/gen/schema.ts +248 -0
- package/src/gen/vite-plugin.ts +114 -0
- package/src/generated/managers/testManager.js +45 -0
- package/src/generated/managers/testManager.ts +46 -0
- package/src/hooks/HookRegistry.ts +16 -0
- package/src/hooks/index.ts +15 -0
- package/src/i18n/I18n.ts +344 -0
- package/src/i18n/IncrementalDomainProvider.ts +153 -0
- package/src/i18n/InlineTranslationProvider.ts +4 -0
- package/src/i18n/LazyTranslationProvider.ts +102 -0
- package/src/i18n/MessagesRegistry.ts +4 -0
- package/src/i18n/Resolver.ts +4 -0
- package/src/i18n/__tests__/I18n.test.ts +169 -0
- package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
- package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
- package/src/i18n/__tests__/Resolver.test.ts +271 -0
- package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
- package/src/i18n/defaults/core.en.yml +55 -0
- package/src/i18n/defaults/core.fr.yml +55 -0
- package/src/i18n/index.ts +55 -0
- package/src/i18n/loaders/raw-modules.d.ts +15 -0
- package/src/i18n/loaders/yaml.ts +35 -0
- package/src/i18n/strategies.ts +4 -0
- package/src/i18n/types.ts +34 -0
- package/src/i18n/useI18n.ts +34 -0
- package/src/index.ts +453 -0
- package/src/kernel/EventRouter.ts +23 -0
- package/src/kernel/Kernel.api.ts +79 -0
- package/src/kernel/Kernel.auth.ts +120 -0
- package/src/kernel/Kernel.i18n.ts +29 -0
- package/src/kernel/Kernel.modules.ts +170 -0
- package/src/kernel/Kernel.registries.ts +237 -0
- package/src/kernel/Kernel.routing.ts +334 -0
- package/src/kernel/Kernel.ts +460 -0
- package/src/kernel/Kernel.types.ts +263 -0
- package/src/kernel/Kernel.vue.ts +304 -0
- package/src/kernel/KernelContext.entities.ts +80 -0
- package/src/kernel/KernelContext.events.ts +57 -0
- package/src/kernel/KernelContext.i18n.ts +37 -0
- package/src/kernel/KernelContext.permissions.ts +38 -0
- package/src/kernel/KernelContext.routing.ts +280 -0
- package/src/kernel/KernelContext.ts +252 -0
- package/src/kernel/KernelContext.types.ts +173 -0
- package/src/kernel/KernelContext.zones.ts +54 -0
- package/src/kernel/Module.ts +169 -0
- package/src/kernel/ModuleLoader.ts +645 -0
- package/src/kernel/SSEBridge.ts +11 -0
- package/src/kernel/SignalBus.ts +48 -0
- package/src/kernel/index.ts +56 -0
- package/src/module/index.ts +33 -0
- package/src/module/moduleRegistry.ts +492 -0
- package/src/modules/debug/AuthCollector.ts +501 -0
- package/src/modules/debug/Collector.ts +20 -0
- package/src/modules/debug/DebugBridge.ts +14 -0
- package/src/modules/debug/DebugModule.ts +220 -0
- package/src/modules/debug/EntitiesCollector.ts +839 -0
- package/src/modules/debug/ErrorCollector.ts +4 -0
- package/src/modules/debug/I18nCollector.ts +9 -0
- package/src/modules/debug/LocalStorageAdapter.ts +7 -0
- package/src/modules/debug/RouterCollector.ts +449 -0
- package/src/modules/debug/SignalCollector.ts +4 -0
- package/src/modules/debug/ToastCollector.ts +4 -0
- package/src/modules/debug/ZonesCollector.ts +447 -0
- package/src/modules/debug/components/DebugBar.vue +31 -0
- package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
- package/src/modules/debug/components/index.ts +9 -0
- package/src/modules/debug/components/panels/AuthPanel.vue +267 -0
- package/src/modules/debug/components/panels/EntitiesPanel.vue +572 -0
- package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
- package/src/modules/debug/components/panels/RouterPanel.vue +440 -0
- package/src/modules/debug/components/panels/ZonesPanel.vue +133 -0
- package/src/modules/debug/components/panels/index.ts +16 -0
- package/src/modules/debug/index.ts +58 -0
- package/src/modules/debug/styles.scss +2671 -0
- package/src/notifications/NotificationBadge.vue +35 -0
- package/src/notifications/NotificationListener.vue +71 -0
- package/src/notifications/NotificationModule.ts +76 -0
- package/src/notifications/NotificationPanel.vue +478 -0
- package/src/notifications/NotificationStore.ts +288 -0
- package/src/notifications/index.ts +42 -0
- package/src/notifications/styles.scss +32 -0
- package/src/orchestrator/Orchestrator.ts +427 -0
- package/src/orchestrator/index.ts +8 -0
- package/src/orchestrator/useOrchestrator.ts +80 -0
- package/src/plugin.ts +251 -0
- package/src/query/FilterQuery.ts +306 -0
- package/src/query/QueryExecutor.ts +341 -0
- package/src/query/index.ts +16 -0
- package/src/security/EntityRolesProvider.ts +385 -0
- package/src/security/PermissionMatcher.ts +152 -0
- package/src/security/PermissionRegistry.ts +273 -0
- package/src/security/PersistableRolesProvider.ts +584 -0
- package/src/security/RolesManager.ts +136 -0
- package/src/security/RolesProvider.ts +167 -0
- package/src/security/RolesProviderStorage.ts +211 -0
- package/src/security/SecurityModule.ts +94 -0
- package/src/security/StaticRolesProvider.ts +117 -0
- package/src/security/UsersManager.ts +163 -0
- package/src/security/index.ts +77 -0
- package/src/security/pages/RoleForm.vue +276 -0
- package/src/security/pages/RoleList.vue +123 -0
- package/src/styles/_alerts.scss +95 -0
- package/src/styles/_buttons.scss +391 -0
- package/src/styles/_cards.scss +241 -0
- package/src/styles/_code.scss +78 -0
- package/src/styles/_dialogs.scss +55 -0
- package/src/styles/_filter-bar.scss +70 -0
- package/src/styles/_forms.scss +434 -0
- package/src/styles/_helpers.scss +153 -0
- package/src/styles/_lists.scss +225 -0
- package/src/styles/_main.scss +356 -0
- package/src/styles/_markdown.scss +88 -0
- package/src/styles/_responsive.scss +255 -0
- package/src/styles/_show-pages.scss +186 -0
- package/src/styles/_sidebar.scss +380 -0
- package/src/styles/_states.scss +115 -0
- package/src/styles/_stats.scss +47 -0
- package/src/styles/_variables.scss +224 -0
- package/src/styles/index.scss +38 -0
- package/src/styles/theme/_components.scss +331 -0
- package/src/styles/theme/_index.scss +10 -0
- package/src/styles/theme/_tokens.scss +147 -0
- package/src/styles/theme/_utilities.scss +175 -0
- package/src/toast/ToastBridgeModule.ts +68 -0
- package/src/toast/ToastListener.vue +55 -0
- package/src/toast/index.ts +26 -0
- package/src/toast/useSignalToast.ts +154 -0
- package/src/types/index.ts +285 -0
- package/src/types/pluralize.d.ts +19 -0
- package/src/types/quarkernel.d.ts +50 -0
- package/src/utils/formatters.ts +174 -0
- package/src/utils/index.ts +35 -0
- package/src/utils/transformers.ts +131 -0
- package/src/vite/qdadmDebugPlugin.ts +401 -0
- package/src/vite-env.d.ts +50 -0
- package/src/zones/ZoneRegistry.ts +934 -0
- package/src/zones/index.ts +29 -0
- package/src/zones/zones.ts +191 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Factory/Resolver Pattern
|
|
3
|
+
*
|
|
4
|
+
* Enables declarative storage configuration with auto-resolution.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { IStorage } from './IStorage'
|
|
8
|
+
import { ApiStorage } from './ApiStorage'
|
|
9
|
+
import { LocalStorage } from './LocalStorage'
|
|
10
|
+
import { MemoryStorage } from './MemoryStorage'
|
|
11
|
+
import { MockApiStorage } from './MockApiStorage'
|
|
12
|
+
import { SdkStorage } from './SdkStorage'
|
|
13
|
+
import type { EntityRecord } from '../../types'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Storage class type
|
|
17
|
+
*/
|
|
18
|
+
type StorageClass = typeof IStorage
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Storage type registry - maps type names to storage classes
|
|
22
|
+
*/
|
|
23
|
+
export const storageTypes: Record<string, StorageClass> = {
|
|
24
|
+
api: ApiStorage as unknown as StorageClass,
|
|
25
|
+
local: LocalStorage as unknown as StorageClass,
|
|
26
|
+
memory: MemoryStorage as unknown as StorageClass,
|
|
27
|
+
mock: MockApiStorage as unknown as StorageClass,
|
|
28
|
+
sdk: SdkStorage as unknown as StorageClass,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parsed storage pattern result
|
|
33
|
+
*/
|
|
34
|
+
export interface ParsedStoragePattern {
|
|
35
|
+
type: string
|
|
36
|
+
endpoint?: string
|
|
37
|
+
key?: string
|
|
38
|
+
entityName?: string
|
|
39
|
+
[key: string]: unknown
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Storage configuration object
|
|
44
|
+
*/
|
|
45
|
+
export interface StorageConfig {
|
|
46
|
+
type?: string
|
|
47
|
+
endpoint?: string
|
|
48
|
+
key?: string
|
|
49
|
+
entityName?: string
|
|
50
|
+
initialData?: unknown[]
|
|
51
|
+
[key: string]: unknown
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Storage resolver function type
|
|
56
|
+
*/
|
|
57
|
+
export type StorageResolver = <T extends EntityRecord = EntityRecord>(
|
|
58
|
+
config: StorageConfig,
|
|
59
|
+
entityName: string
|
|
60
|
+
) => IStorage<T>
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Parse string pattern 'type:endpoint' into config object
|
|
64
|
+
*/
|
|
65
|
+
export function parseStoragePattern(pattern: string): ParsedStoragePattern | null {
|
|
66
|
+
if (typeof pattern !== 'string') return null
|
|
67
|
+
|
|
68
|
+
// Pattern: 'type:value'
|
|
69
|
+
const match = pattern.match(/^(\w+):(.+)$/)
|
|
70
|
+
if (match && match[1] && match[2]) {
|
|
71
|
+
const type = match[1]
|
|
72
|
+
const value = match[2]
|
|
73
|
+
// For local/mock, value is key/name; for api/sdk, value is endpoint
|
|
74
|
+
if (type === 'local' || type === 'memory') {
|
|
75
|
+
return { type, key: value }
|
|
76
|
+
}
|
|
77
|
+
if (type === 'mock') {
|
|
78
|
+
return { type, entityName: value }
|
|
79
|
+
}
|
|
80
|
+
return { type, endpoint: value }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Plain string starting with '/' → assume API endpoint
|
|
84
|
+
if (pattern.startsWith('/')) {
|
|
85
|
+
return { type: 'api', endpoint: pattern }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Default storage resolver - creates storage instance from config
|
|
93
|
+
*/
|
|
94
|
+
export function defaultStorageResolver<T extends EntityRecord = EntityRecord>(
|
|
95
|
+
config: StorageConfig,
|
|
96
|
+
entityName: string
|
|
97
|
+
): IStorage<T> {
|
|
98
|
+
const { type, ...rest } = config
|
|
99
|
+
|
|
100
|
+
if (!type) {
|
|
101
|
+
throw new Error('Storage config must have a type property')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const StorageClass = storageTypes[type]
|
|
105
|
+
if (!StorageClass) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Unknown storage type: "${type}". Available: ${Object.keys(storageTypes).join(', ')}`
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Add entityName to config if not present (useful for mock/memory)
|
|
112
|
+
const resolvedConfig = { ...rest }
|
|
113
|
+
if (!resolvedConfig.entityName && !resolvedConfig.key) {
|
|
114
|
+
if (type === 'local' || type === 'memory') {
|
|
115
|
+
resolvedConfig.key = entityName
|
|
116
|
+
} else if (type === 'mock') {
|
|
117
|
+
resolvedConfig.entityName = entityName
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// @ts-expect-error - StorageClass constructor accepts options object
|
|
122
|
+
return new StorageClass(resolvedConfig) as IStorage<T>
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Duck-typed storage interface for detection
|
|
127
|
+
*/
|
|
128
|
+
interface DuckTypedStorage {
|
|
129
|
+
list: (...args: unknown[]) => Promise<unknown>
|
|
130
|
+
get: (...args: unknown[]) => Promise<unknown>
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Storage factory - normalizes input and delegates to resolver
|
|
135
|
+
*
|
|
136
|
+
* Handles:
|
|
137
|
+
* - IStorage instance → return directly
|
|
138
|
+
* - String pattern 'type:endpoint' → parse and resolve
|
|
139
|
+
* - Plain string '/endpoint' → treat as API endpoint
|
|
140
|
+
* - Config object → normalize and resolve
|
|
141
|
+
*/
|
|
142
|
+
export function storageFactory<T extends EntityRecord = EntityRecord>(
|
|
143
|
+
config: IStorage<T> | string | StorageConfig,
|
|
144
|
+
entityName: string,
|
|
145
|
+
resolver: StorageResolver = defaultStorageResolver
|
|
146
|
+
): IStorage<T> {
|
|
147
|
+
// Already a Storage instance → return directly
|
|
148
|
+
if (config instanceof IStorage) {
|
|
149
|
+
return config
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Also check for duck-typed storage (has list method and isn't a class)
|
|
153
|
+
if (
|
|
154
|
+
config &&
|
|
155
|
+
typeof config === 'object' &&
|
|
156
|
+
typeof (config as unknown as DuckTypedStorage).list === 'function' &&
|
|
157
|
+
typeof (config as unknown as DuckTypedStorage).get === 'function'
|
|
158
|
+
) {
|
|
159
|
+
return config as unknown as IStorage<T>
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// String pattern → parse
|
|
163
|
+
if (typeof config === 'string') {
|
|
164
|
+
const parsed = parseStoragePattern(config)
|
|
165
|
+
if (!parsed) {
|
|
166
|
+
throw new Error(`Invalid storage pattern: "${config}". Use 'type:value' or '/api/endpoint'`)
|
|
167
|
+
}
|
|
168
|
+
return resolver(parsed, entityName)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Config object → normalize
|
|
172
|
+
if (config && typeof config === 'object') {
|
|
173
|
+
let normalizedConfig = config as StorageConfig
|
|
174
|
+
// If no type, infer from properties
|
|
175
|
+
if (!normalizedConfig.type) {
|
|
176
|
+
if (normalizedConfig.endpoint) {
|
|
177
|
+
normalizedConfig = { type: 'api', ...normalizedConfig }
|
|
178
|
+
} else if (normalizedConfig.key) {
|
|
179
|
+
normalizedConfig = { type: 'local', ...normalizedConfig }
|
|
180
|
+
} else if (normalizedConfig.initialData) {
|
|
181
|
+
normalizedConfig = { type: 'mock', ...normalizedConfig }
|
|
182
|
+
} else {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Cannot infer storage type from config: ${JSON.stringify(config)}. Add 'type' property.`
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return resolver(normalizedConfig, entityName)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
throw new Error(
|
|
192
|
+
`Invalid storage config: ${typeof config}. Expected string, object, or Storage instance.`
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Create a custom storage factory with overridden resolver
|
|
198
|
+
*/
|
|
199
|
+
export function createStorageFactory(
|
|
200
|
+
customResolver: StorageResolver
|
|
201
|
+
): <T extends EntityRecord = EntityRecord>(
|
|
202
|
+
config: IStorage<T> | string | StorageConfig,
|
|
203
|
+
entityName: string
|
|
204
|
+
) => IStorage<T> {
|
|
205
|
+
return <T extends EntityRecord = EntityRecord>(
|
|
206
|
+
config: IStorage<T> | string | StorageConfig,
|
|
207
|
+
entityName: string
|
|
208
|
+
) => storageFactory(config, entityName, customResolver)
|
|
209
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Adapters
|
|
3
|
+
*
|
|
4
|
+
* Boilerplate implementations for common storage backends.
|
|
5
|
+
* EntityManagers can use these or implement their own storage.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { StorageCapabilities } from '../../types'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Default capabilities for storages that don't declare their own.
|
|
12
|
+
* All capabilities default to false for safe degradation.
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_STORAGE_CAPABILITIES: StorageCapabilities = {
|
|
15
|
+
supportsTotal: false,
|
|
16
|
+
supportsFilters: false,
|
|
17
|
+
supportsPagination: false,
|
|
18
|
+
supportsCaching: false,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Read capabilities from a storage instance.
|
|
23
|
+
* Accesses static `capabilities` property via constructor with fallback to defaults.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const caps = getStorageCapabilities(myStorage)
|
|
27
|
+
* if (caps.supportsTotal) {
|
|
28
|
+
* // Storage provides accurate total count
|
|
29
|
+
* }
|
|
30
|
+
*/
|
|
31
|
+
export function getStorageCapabilities(
|
|
32
|
+
storage: { constructor?: { capabilities?: Partial<StorageCapabilities> } } | null | undefined
|
|
33
|
+
): StorageCapabilities {
|
|
34
|
+
const declared = storage?.constructor?.capabilities || {}
|
|
35
|
+
return {
|
|
36
|
+
...DEFAULT_STORAGE_CAPABILITIES,
|
|
37
|
+
...declared,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Base class
|
|
42
|
+
export { IStorage } from './IStorage'
|
|
43
|
+
|
|
44
|
+
// Factory/Resolver
|
|
45
|
+
export {
|
|
46
|
+
storageFactory,
|
|
47
|
+
defaultStorageResolver,
|
|
48
|
+
createStorageFactory,
|
|
49
|
+
parseStoragePattern,
|
|
50
|
+
storageTypes,
|
|
51
|
+
} from './factory'
|
|
52
|
+
export type { ParsedStoragePattern, StorageConfig, StorageResolver } from './factory'
|
|
53
|
+
|
|
54
|
+
// Storage adapters
|
|
55
|
+
export { ApiStorage, createApiStorage } from './ApiStorage'
|
|
56
|
+
export type { HttpClient, RoutingContext, ApiStorageOptions } from './ApiStorage'
|
|
57
|
+
|
|
58
|
+
export { LocalStorage, createLocalStorage } from './LocalStorage'
|
|
59
|
+
export type { LocalStorageOptions } from './LocalStorage'
|
|
60
|
+
|
|
61
|
+
export { MemoryStorage, createMemoryStorage, StorageError } from './MemoryStorage'
|
|
62
|
+
export type { MemoryStorageOptions } from './MemoryStorage'
|
|
63
|
+
|
|
64
|
+
export { MockApiStorage, createMockApiStorage } from './MockApiStorage'
|
|
65
|
+
export type { MockApiStorageOptions } from './MockApiStorage'
|
|
66
|
+
|
|
67
|
+
export { SdkStorage, createSdkStorage } from './SdkStorage'
|
|
68
|
+
export type {
|
|
69
|
+
SdkInstance,
|
|
70
|
+
SdkMethodConfig,
|
|
71
|
+
SdkMethodTransforms,
|
|
72
|
+
SdkResponseFormat,
|
|
73
|
+
SdkMethods,
|
|
74
|
+
SdkStorageOptions,
|
|
75
|
+
} from './SdkStorage'
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field Type Mapper
|
|
3
|
+
*
|
|
4
|
+
* Maps JSON Schema types and formats to UnifiedFieldSchema types.
|
|
5
|
+
* Extracted from Skybot and Faketual to eliminate duplication.
|
|
6
|
+
*
|
|
7
|
+
* Mapping priority:
|
|
8
|
+
* 1. Enum detection (schema.enum present -> 'select')
|
|
9
|
+
* 2. Custom mappings (user-provided)
|
|
10
|
+
* 3. Format-specific mappings (e.g., string + format:email -> email)
|
|
11
|
+
* 4. Base type mappings (e.g., string -> text)
|
|
12
|
+
*
|
|
13
|
+
* @module gen/FieldMapper
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { UnifiedFieldType } from './schema'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Base type mappings: JSON Schema type -> UnifiedFieldSchema type
|
|
20
|
+
*/
|
|
21
|
+
export const BASE_TYPE_MAPPINGS: Readonly<Record<string, UnifiedFieldType>> = Object.freeze({
|
|
22
|
+
string: 'text',
|
|
23
|
+
integer: 'number',
|
|
24
|
+
number: 'number',
|
|
25
|
+
boolean: 'boolean',
|
|
26
|
+
array: 'array',
|
|
27
|
+
object: 'object',
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Format-specific mappings: JSON Schema format -> UnifiedFieldSchema type
|
|
32
|
+
*
|
|
33
|
+
* These take precedence over base type mappings when a format is specified.
|
|
34
|
+
*/
|
|
35
|
+
export const FORMAT_MAPPINGS: Readonly<Record<string, UnifiedFieldType>> = Object.freeze({
|
|
36
|
+
email: 'email',
|
|
37
|
+
'date-time': 'datetime',
|
|
38
|
+
date: 'date',
|
|
39
|
+
uri: 'url',
|
|
40
|
+
url: 'url',
|
|
41
|
+
uuid: 'uuid',
|
|
42
|
+
password: 'text',
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Custom mappings override structure
|
|
47
|
+
*/
|
|
48
|
+
export interface CustomMappings {
|
|
49
|
+
/** Custom type mappings { jsonSchemaType: unifiedType } */
|
|
50
|
+
types?: Record<string, string>
|
|
51
|
+
/** Custom format mappings { jsonSchemaFormat: unifiedType } */
|
|
52
|
+
formats?: Record<string, string>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Minimal JSON Schema property definition for type detection
|
|
57
|
+
*/
|
|
58
|
+
export interface SchemaProperty {
|
|
59
|
+
/** JSON Schema type (string, integer, number, boolean, array, object) */
|
|
60
|
+
type?: string
|
|
61
|
+
/** JSON Schema format (email, date-time, uuid, etc.) */
|
|
62
|
+
format?: string
|
|
63
|
+
/** Enumeration values */
|
|
64
|
+
enum?: unknown[]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get the UnifiedFieldSchema type for a JSON Schema property
|
|
69
|
+
*
|
|
70
|
+
* @param schema - JSON Schema property definition
|
|
71
|
+
* @param customMappings - Optional custom type/format mappings
|
|
72
|
+
* @returns Unified field type
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // Basic type mapping
|
|
76
|
+
* getDefaultType({ type: 'string' }) // 'text'
|
|
77
|
+
* getDefaultType({ type: 'integer' }) // 'number'
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* // Format takes precedence
|
|
81
|
+
* getDefaultType({ type: 'string', format: 'email' }) // 'email'
|
|
82
|
+
* getDefaultType({ type: 'string', format: 'uuid' }) // 'uuid'
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* // Enum detection
|
|
86
|
+
* getDefaultType({ type: 'string', enum: ['a', 'b'] }) // 'select'
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* // Custom mappings
|
|
90
|
+
* getDefaultType({ type: 'string', format: 'phone' }, {
|
|
91
|
+
* formats: { phone: 'text' }
|
|
92
|
+
* }) // 'text'
|
|
93
|
+
*/
|
|
94
|
+
export function getDefaultType(
|
|
95
|
+
schema: SchemaProperty | null | undefined,
|
|
96
|
+
customMappings: CustomMappings = {}
|
|
97
|
+
): UnifiedFieldType | 'select' {
|
|
98
|
+
const { type, format } = schema || {}
|
|
99
|
+
|
|
100
|
+
// Check for enum pattern first (returns 'select')
|
|
101
|
+
if (Array.isArray(schema?.enum) && schema.enum.length > 0) {
|
|
102
|
+
return 'select'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Check custom format mapping
|
|
106
|
+
if (format && customMappings.formats?.[format]) {
|
|
107
|
+
return customMappings.formats[format] as UnifiedFieldType
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check default format mapping
|
|
111
|
+
if (format && FORMAT_MAPPINGS[format]) {
|
|
112
|
+
return FORMAT_MAPPINGS[format]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Check custom type mapping
|
|
116
|
+
if (type && customMappings.types?.[type]) {
|
|
117
|
+
return customMappings.types[type] as UnifiedFieldType
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Fall back to base type mapping, default to 'text'
|
|
121
|
+
return (type && BASE_TYPE_MAPPINGS[type]) || 'text'
|
|
122
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Profile Factory Pattern
|
|
3
|
+
*
|
|
4
|
+
* A storage profile factory is a function that creates storage instances for a given endpoint.
|
|
5
|
+
* This pattern enables DRY backend configuration by centralizing storage creation logic
|
|
6
|
+
* (API client, base URL, headers, error handling) in one place.
|
|
7
|
+
*
|
|
8
|
+
* Instead of configuring each entity's storage individually, you define a profile factory
|
|
9
|
+
* once and pass it to createManagers(), which calls it with each entity's endpoint.
|
|
10
|
+
*
|
|
11
|
+
* @module gen/StorageProfileFactory
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { IStorage } from '../entity/storage/IStorage'
|
|
15
|
+
import type { EntityRecord } from '../types'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Storage Profile Factory Options
|
|
19
|
+
*
|
|
20
|
+
* Per-entity options passed when creating storage from a profile factory.
|
|
21
|
+
* Allows overriding profile defaults for specific entities.
|
|
22
|
+
*/
|
|
23
|
+
export interface StorageProfileOptions {
|
|
24
|
+
/** Entity name (e.g., 'users', 'posts') */
|
|
25
|
+
entity?: string
|
|
26
|
+
/** Override the profile's HTTP client for this entity */
|
|
27
|
+
client?: unknown
|
|
28
|
+
/** Additional headers for this entity */
|
|
29
|
+
headers?: Record<string, string>
|
|
30
|
+
/** Force read-only mode (no create/update/delete) */
|
|
31
|
+
readOnly?: boolean
|
|
32
|
+
/** Custom per-entity options */
|
|
33
|
+
extensions?: Record<string, unknown>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Storage Profile Factory
|
|
38
|
+
*
|
|
39
|
+
* A function that creates storage instances for a given endpoint.
|
|
40
|
+
* The factory encapsulates common storage configuration (API client, auth, base URL)
|
|
41
|
+
* and creates properly-configured storage adapters for each entity.
|
|
42
|
+
*
|
|
43
|
+
* @example Basic factory using ApiStorage
|
|
44
|
+
* ```ts
|
|
45
|
+
* import axios from 'axios'
|
|
46
|
+
* import { ApiStorage } from '@quazardous/qdadm'
|
|
47
|
+
*
|
|
48
|
+
* // Define profile factory with shared configuration
|
|
49
|
+
* const apiProfile: StorageProfileFactory = (endpoint, options = {}) => {
|
|
50
|
+
* return new ApiStorage({
|
|
51
|
+
* endpoint,
|
|
52
|
+
* client: axios.create({
|
|
53
|
+
* baseURL: 'https://api.example.com',
|
|
54
|
+
* headers: { 'Authorization': `Bearer ${getToken()}` }
|
|
55
|
+
* }),
|
|
56
|
+
* ...options
|
|
57
|
+
* })
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* // Use with createManagers (T00317)
|
|
61
|
+
* const managers = createManagers(schemas, {
|
|
62
|
+
* storageProfile: apiProfile
|
|
63
|
+
* })
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @example Factory with dynamic client resolution
|
|
67
|
+
* ```ts
|
|
68
|
+
* // For Vue/inject pattern - client resolved at call time
|
|
69
|
+
* const lazyApiProfile: StorageProfileFactory = (endpoint, options = {}) => {
|
|
70
|
+
* return new ApiStorage({
|
|
71
|
+
* endpoint,
|
|
72
|
+
* getClient: () => inject('apiClient'),
|
|
73
|
+
* ...options
|
|
74
|
+
* })
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @example Factory for local development
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { MemoryStorage } from '@quazardous/qdadm'
|
|
81
|
+
*
|
|
82
|
+
* const memoryProfile: StorageProfileFactory = (endpoint, options = {}) => {
|
|
83
|
+
* const entity = options.entity || endpoint.replace(/^\//, '')
|
|
84
|
+
* return new MemoryStorage({
|
|
85
|
+
* initialData: mockData[entity] || []
|
|
86
|
+
* })
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export type StorageProfileFactory = (
|
|
91
|
+
endpoint: string,
|
|
92
|
+
options?: StorageProfileOptions
|
|
93
|
+
) => IStorage<EntityRecord>
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Connector Interface
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for schema connectors. Connectors parse various sources
|
|
5
|
+
* (OpenAPI specs, manual definitions, etc.) into UnifiedEntitySchema format.
|
|
6
|
+
*
|
|
7
|
+
* Subclasses must implement the `parse(source)` method with source-specific logic.
|
|
8
|
+
*
|
|
9
|
+
* @module gen/connectors/BaseConnector
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { UnifiedEntitySchema } from '../schema'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Connector options for customizing parsing behavior
|
|
16
|
+
*/
|
|
17
|
+
export interface ConnectorOptions {
|
|
18
|
+
/** Connector instance name for debugging */
|
|
19
|
+
name?: string
|
|
20
|
+
/** Throw on validation errors instead of warning (default: false) */
|
|
21
|
+
strict?: boolean
|
|
22
|
+
/** Custom extension data passed to output schemas */
|
|
23
|
+
extensions?: Record<string, unknown>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Warning encountered during parsing
|
|
28
|
+
*/
|
|
29
|
+
export interface ParseWarning {
|
|
30
|
+
/** Location in source where issue occurred */
|
|
31
|
+
path: string
|
|
32
|
+
/** Description of the issue */
|
|
33
|
+
message: string
|
|
34
|
+
/** Warning code for programmatic handling */
|
|
35
|
+
code?: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Parse result with parsed schemas and any encountered issues
|
|
40
|
+
*/
|
|
41
|
+
export interface ParseResult {
|
|
42
|
+
/** Parsed entity schemas */
|
|
43
|
+
schemas: UnifiedEntitySchema[]
|
|
44
|
+
/** Non-fatal issues encountered during parsing */
|
|
45
|
+
warnings: ParseWarning[]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Base connector class for parsing schema sources into UnifiedEntitySchema format.
|
|
50
|
+
*
|
|
51
|
+
* @abstract
|
|
52
|
+
* @example
|
|
53
|
+
* // Extending BaseConnector
|
|
54
|
+
* class ManualConnector extends BaseConnector {
|
|
55
|
+
* parse(source) {
|
|
56
|
+
* // Parse inline definitions
|
|
57
|
+
* return source.entities.map(e => this.transformEntity(e))
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* // Using a connector
|
|
63
|
+
* const connector = new ManualConnector({ strict: true })
|
|
64
|
+
* const schemas = connector.parse(manualDefinitions)
|
|
65
|
+
*/
|
|
66
|
+
export abstract class BaseConnector {
|
|
67
|
+
/** Connector instance name */
|
|
68
|
+
name: string
|
|
69
|
+
|
|
70
|
+
/** Whether to throw on validation errors */
|
|
71
|
+
strict: boolean
|
|
72
|
+
|
|
73
|
+
/** Custom extension data */
|
|
74
|
+
extensions: Record<string, unknown>
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create a new connector instance
|
|
78
|
+
*
|
|
79
|
+
* @param options - Connector configuration options
|
|
80
|
+
*/
|
|
81
|
+
constructor(options: ConnectorOptions = {}) {
|
|
82
|
+
this.name = options.name || this.constructor.name
|
|
83
|
+
this.strict = options.strict ?? false
|
|
84
|
+
this.extensions = options.extensions || {}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Parse a schema source into UnifiedEntitySchema format.
|
|
89
|
+
*
|
|
90
|
+
* This method must be implemented by subclasses to handle source-specific
|
|
91
|
+
* parsing logic. The source parameter format depends on the connector type:
|
|
92
|
+
* - ManualConnector: Object with entity/field definitions
|
|
93
|
+
* - OpenAPIConnector: OpenAPI 3.x specification object
|
|
94
|
+
*
|
|
95
|
+
* @abstract
|
|
96
|
+
* @param source - Source data to parse (format depends on connector type)
|
|
97
|
+
* @returns Parsed entity schemas
|
|
98
|
+
* @throws If parsing fails (in strict mode) or source is invalid
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // ManualConnector source format
|
|
102
|
+
* connector.parse({
|
|
103
|
+
* entities: [
|
|
104
|
+
* { name: 'users', endpoint: '/api/users', fields: { ... } }
|
|
105
|
+
* ]
|
|
106
|
+
* })
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* // OpenAPIConnector source format
|
|
110
|
+
* connector.parse({
|
|
111
|
+
* openapi: '3.0.0',
|
|
112
|
+
* paths: { '/api/users': { ... } },
|
|
113
|
+
* components: { schemas: { ... } }
|
|
114
|
+
* })
|
|
115
|
+
*/
|
|
116
|
+
abstract parse(source: unknown): UnifiedEntitySchema[]
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Parse with detailed result including warnings
|
|
120
|
+
*
|
|
121
|
+
* Alternative to `parse()` that returns warnings along with schemas.
|
|
122
|
+
* Useful when you want to handle non-fatal issues without strict mode.
|
|
123
|
+
*
|
|
124
|
+
* Default implementation wraps `parse()` with empty warnings array.
|
|
125
|
+
* Subclasses can override for more detailed reporting.
|
|
126
|
+
*
|
|
127
|
+
* @param source - Source data to parse
|
|
128
|
+
* @returns Schemas and any warnings encountered
|
|
129
|
+
*/
|
|
130
|
+
parseWithWarnings(source: unknown): ParseResult {
|
|
131
|
+
return {
|
|
132
|
+
schemas: this.parse(source),
|
|
133
|
+
warnings: [],
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Validate connector is properly configured before parsing
|
|
139
|
+
*
|
|
140
|
+
* Override in subclasses to add custom validation.
|
|
141
|
+
*
|
|
142
|
+
* @returns True if connector is valid
|
|
143
|
+
* @throws If connector configuration is invalid
|
|
144
|
+
*/
|
|
145
|
+
validate(): boolean {
|
|
146
|
+
return true
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default BaseConnector
|