@donotdev/crud 0.0.6 → 0.0.7
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 +18 -2
- package/dist/CrudService.d.ts +91 -8
- package/dist/CrudService.d.ts.map +1 -1
- package/dist/CrudService.js +1 -1
- package/dist/CrudStore.d.ts +45 -2
- package/dist/CrudStore.d.ts.map +1 -1
- package/dist/CrudStore.js +1 -1
- package/dist/FieldRegistry.d.ts +56 -20
- package/dist/FieldRegistry.d.ts.map +1 -1
- package/dist/FieldRegistry.js +1 -1
- package/dist/adapters/FirestoreAdapter.d.ts +4 -4
- package/dist/adapters/FirestoreAdapter.d.ts.map +1 -1
- package/dist/adapters/FirestoreAdapter.js +1 -1
- package/dist/adapters/FunctionsAdapter.d.ts +3 -2
- package/dist/adapters/FunctionsAdapter.d.ts.map +1 -1
- package/dist/adapters/FunctionsAdapter.js +1 -1
- package/dist/builtinFieldTypes.d.ts +4 -0
- package/dist/builtinFieldTypes.d.ts.map +1 -1
- package/dist/builtinFieldTypes.js +1 -1
- package/dist/components/CrudButton.d.ts +1 -1
- package/dist/components/CrudButton.d.ts.map +1 -1
- package/dist/components/CrudButton.js +1 -1
- package/dist/components/DisplayFieldRenderer.d.ts +15 -11
- package/dist/components/DisplayFieldRenderer.d.ts.map +1 -1
- package/dist/components/DisplayFieldRenderer.js +1 -1
- package/dist/components/EntityCardList.d.ts +27 -0
- package/dist/components/EntityCardList.d.ts.map +1 -0
- package/dist/components/EntityCardList.js +1 -0
- package/dist/components/EntityDisplayRenderer.d.ts +43 -0
- package/dist/components/EntityDisplayRenderer.d.ts.map +1 -0
- package/dist/components/EntityDisplayRenderer.js +1 -0
- package/dist/components/EntityFormRenderer.d.ts +21 -26
- package/dist/components/EntityFormRenderer.d.ts.map +1 -1
- package/dist/components/EntityFormRenderer.js +1 -5
- package/dist/components/EntityList.d.ts +24 -0
- package/dist/components/EntityList.d.ts.map +1 -0
- package/dist/components/EntityList.js +1 -0
- package/dist/components/FormFieldRenderer.d.ts +3 -10
- package/dist/components/FormFieldRenderer.d.ts.map +1 -1
- package/dist/components/FormFieldRenderer.js +1 -1
- package/dist/components/FormLayout.d.ts +1 -9
- package/dist/components/FormLayout.d.ts.map +1 -1
- package/dist/components/controlled/complex/ControlledAddressField.d.ts +8 -0
- package/dist/components/controlled/complex/ControlledAddressField.d.ts.map +1 -0
- package/dist/components/controlled/complex/ControlledAddressField.js +1 -0
- package/dist/components/controlled/complex/ControlledDateField.d.ts +8 -0
- package/dist/components/controlled/complex/ControlledDateField.d.ts.map +1 -0
- package/dist/components/controlled/complex/ControlledDateField.js +1 -0
- package/dist/components/controlled/complex/ControlledGeoPointField.d.ts +8 -0
- package/dist/components/controlled/complex/ControlledGeoPointField.d.ts.map +1 -0
- package/dist/components/controlled/complex/ControlledGeoPointField.js +1 -0
- package/dist/components/controlled/complex/ControlledMapField.d.ts +8 -0
- package/dist/components/controlled/complex/ControlledMapField.d.ts.map +1 -0
- package/dist/components/controlled/complex/ControlledMapField.js +1 -0
- package/dist/components/controlled/complex/ControlledMultiInputField.d.ts +8 -0
- package/dist/components/controlled/complex/ControlledMultiInputField.d.ts.map +1 -0
- package/dist/components/controlled/complex/ControlledMultiInputField.js +1 -0
- package/dist/components/controlled/complex/ControlledRichTextField.d.ts +8 -0
- package/dist/components/controlled/complex/ControlledRichTextField.d.ts.map +1 -0
- package/dist/components/controlled/complex/ControlledRichTextField.js +1 -0
- package/dist/components/controlled/complex/ControlledTimestampField.d.ts +8 -0
- package/dist/components/controlled/complex/ControlledTimestampField.d.ts.map +1 -0
- package/dist/components/controlled/complex/ControlledTimestampField.js +1 -0
- package/dist/components/controlled/complex/index.d.ts +8 -0
- package/dist/components/controlled/complex/index.d.ts.map +1 -0
- package/dist/components/controlled/complex/index.js +1 -0
- package/dist/components/controlled/file/ControlledDocumentField.d.ts +8 -0
- package/dist/components/controlled/file/ControlledDocumentField.d.ts.map +1 -0
- package/dist/components/controlled/file/ControlledDocumentField.js +1 -0
- package/dist/components/controlled/file/ControlledFileField.d.ts +8 -0
- package/dist/components/controlled/file/ControlledFileField.d.ts.map +1 -0
- package/dist/components/controlled/file/ControlledFileField.js +1 -0
- package/dist/components/controlled/file/ControlledImageField.d.ts +8 -0
- package/dist/components/controlled/file/ControlledImageField.d.ts.map +1 -0
- package/dist/components/controlled/file/ControlledImageField.js +1 -0
- package/dist/components/controlled/file/ControlledMultiDocumentField.d.ts +8 -0
- package/dist/components/controlled/file/ControlledMultiDocumentField.d.ts.map +1 -0
- package/dist/components/controlled/file/ControlledMultiDocumentField.js +1 -0
- package/dist/components/controlled/file/ControlledMultiFileField.d.ts +8 -0
- package/dist/components/controlled/file/ControlledMultiFileField.d.ts.map +1 -0
- package/dist/components/controlled/file/ControlledMultiFileField.js +1 -0
- package/dist/components/controlled/file/ControlledMultiImageField.d.ts +8 -0
- package/dist/components/controlled/file/ControlledMultiImageField.d.ts.map +1 -0
- package/dist/components/controlled/file/ControlledMultiImageField.js +1 -0
- package/dist/components/controlled/file/index.d.ts +7 -0
- package/dist/components/controlled/file/index.d.ts.map +1 -0
- package/dist/components/controlled/file/index.js +1 -0
- package/dist/components/controlled/index.d.ts +12 -0
- package/dist/components/controlled/index.d.ts.map +1 -0
- package/dist/components/controlled/index.js +1 -0
- package/dist/components/controlled/input/ControlledCheckboxField.d.ts +8 -0
- package/dist/components/controlled/input/ControlledCheckboxField.d.ts.map +1 -0
- package/dist/components/controlled/input/ControlledCheckboxField.js +1 -0
- package/dist/components/controlled/input/ControlledNumberField.d.ts +8 -0
- package/dist/components/controlled/input/ControlledNumberField.d.ts.map +1 -0
- package/dist/components/controlled/input/ControlledNumberField.js +1 -0
- package/dist/components/controlled/input/ControlledPasswordField.d.ts +8 -0
- package/dist/components/controlled/input/ControlledPasswordField.d.ts.map +1 -0
- package/dist/components/controlled/input/ControlledPasswordField.js +1 -0
- package/dist/components/controlled/input/ControlledPhoneField.d.ts +8 -0
- package/dist/components/controlled/input/ControlledPhoneField.d.ts.map +1 -0
- package/dist/components/controlled/input/ControlledPhoneField.js +1 -0
- package/dist/components/controlled/input/ControlledRangeField.d.ts +8 -0
- package/dist/components/controlled/input/ControlledRangeField.d.ts.map +1 -0
- package/dist/components/controlled/input/ControlledRangeField.js +1 -0
- package/dist/components/controlled/input/ControlledSwitchField.d.ts +8 -0
- package/dist/components/controlled/input/ControlledSwitchField.d.ts.map +1 -0
- package/dist/components/controlled/input/ControlledSwitchField.js +1 -0
- package/dist/components/controlled/input/ControlledTextField.d.ts +8 -0
- package/dist/components/controlled/input/ControlledTextField.d.ts.map +1 -0
- package/dist/components/controlled/input/ControlledTextField.js +1 -0
- package/dist/components/controlled/input/ControlledTextareaField.d.ts +8 -0
- package/dist/components/controlled/input/ControlledTextareaField.d.ts.map +1 -0
- package/dist/components/controlled/input/ControlledTextareaField.js +1 -0
- package/dist/components/controlled/input/index.d.ts +9 -0
- package/dist/components/controlled/input/index.d.ts.map +1 -0
- package/dist/components/controlled/input/index.js +1 -0
- package/dist/components/controlled/select/ControlledComboboxField.d.ts +9 -0
- package/dist/components/controlled/select/ControlledComboboxField.d.ts.map +1 -0
- package/dist/components/controlled/select/ControlledComboboxField.js +1 -0
- package/dist/components/controlled/select/ControlledDropdownField.d.ts +9 -0
- package/dist/components/controlled/select/ControlledDropdownField.d.ts.map +1 -0
- package/dist/components/controlled/select/ControlledDropdownField.js +1 -0
- package/dist/components/controlled/select/ControlledMultiDropdownField.d.ts +9 -0
- package/dist/components/controlled/select/ControlledMultiDropdownField.d.ts.map +1 -0
- package/dist/components/controlled/select/ControlledMultiDropdownField.js +1 -0
- package/dist/components/controlled/select/ControlledRadioField.d.ts +9 -0
- package/dist/components/controlled/select/ControlledRadioField.d.ts.map +1 -0
- package/dist/components/controlled/select/ControlledRadioField.js +1 -0
- package/dist/components/controlled/select/index.d.ts +5 -0
- package/dist/components/controlled/select/index.d.ts.map +1 -0
- package/dist/components/controlled/select/index.js +1 -0
- package/dist/components/controlled/types.d.ts +23 -0
- package/dist/components/controlled/types.d.ts.map +1 -0
- package/dist/components/controlled/types.js +1 -0
- package/dist/components/form/fields/AddressFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/AddressFieldComponent.js +1 -1
- package/dist/components/form/fields/AvatarFieldComponent.d.ts +2 -2
- package/dist/components/form/fields/BadgeFieldComponent.d.ts +2 -2
- package/dist/components/form/fields/ButtonFieldComponent.d.ts +1 -9
- package/dist/components/form/fields/ButtonFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/ButtonFieldComponent.js +1 -1
- package/dist/components/form/fields/ComboboxComponent.d.ts.map +1 -1
- package/dist/components/form/fields/CurrencyFieldComponent.d.ts +1 -9
- package/dist/components/form/fields/CurrencyFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/CurrencyFieldComponent.js +1 -1
- package/dist/components/form/fields/DateFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/DateFieldComponent.js +1 -1
- package/dist/components/form/fields/DocumentFieldComponent.d.ts +47 -0
- package/dist/components/form/fields/DocumentFieldComponent.d.ts.map +1 -0
- package/dist/components/form/fields/DocumentFieldComponent.js +1 -0
- package/dist/components/form/fields/DropdownComponent.d.ts.map +1 -1
- package/dist/components/form/fields/DropdownComponent.js +1 -1
- package/dist/components/form/fields/FileFieldComponent.d.ts +31 -15
- package/dist/components/form/fields/FileFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/FileFieldComponent.js +1 -1
- package/dist/components/form/fields/GeoPointFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/GeoPointFieldComponent.js +1 -1
- package/dist/components/form/fields/HiddenFieldComponent.d.ts +1 -1
- package/dist/components/form/fields/HiddenFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/HiddenFieldComponent.js +1 -1
- package/dist/components/form/fields/ImageFieldComponent.d.ts +8 -14
- package/dist/components/form/fields/ImageFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/ImageFieldComponent.js +1 -1
- package/dist/components/form/fields/MapFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/MapFieldComponent.js +1 -1
- package/dist/components/form/fields/MultiDropdownComponent.js +1 -1
- package/dist/components/form/fields/MultiInputTextFieldComponent.d.ts +1 -9
- package/dist/components/form/fields/MultiInputTextFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/MultiInputTextFieldComponent.js +1 -1
- package/dist/components/form/fields/NumberFieldComponent.d.ts +2 -0
- package/dist/components/form/fields/NumberFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/NumberFieldComponent.js +1 -1
- package/dist/components/form/fields/PasswordFieldComponent.d.ts +1 -9
- package/dist/components/form/fields/PasswordFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/PhoneNumberComponent.d.ts +1 -9
- package/dist/components/form/fields/PhoneNumberComponent.d.ts.map +1 -1
- package/dist/components/form/fields/PhoneNumberComponent.js +1 -1
- package/dist/components/form/fields/RadioFieldComponent.d.ts +1 -9
- package/dist/components/form/fields/RadioFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/ReferenceFieldComponent.d.ts +33 -12
- package/dist/components/form/fields/ReferenceFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/ReferenceFieldComponent.js +1 -1
- package/dist/components/form/fields/RichTextComponent.d.ts +32 -0
- package/dist/components/form/fields/RichTextComponent.d.ts.map +1 -0
- package/dist/components/form/fields/RichTextComponent.js +1 -0
- package/dist/components/form/fields/SwitchFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/TextAreaComponent.d.ts +1 -9
- package/dist/components/form/fields/TextAreaComponent.d.ts.map +1 -1
- package/dist/components/form/fields/TextAreaComponent.js +1 -1
- package/dist/components/form/fields/TextFieldComponent.d.ts +1 -9
- package/dist/components/form/fields/TextFieldComponent.d.ts.map +1 -1
- package/dist/components/form/fields/index.d.ts +4 -2
- package/dist/components/form/fields/index.d.ts.map +1 -1
- package/dist/components/form/fields/index.js +1 -1
- package/dist/components/form/fields/internal/TiptapEditor.d.ts +13 -0
- package/dist/components/form/fields/internal/TiptapEditor.d.ts.map +1 -0
- package/dist/components/form/fields/internal/TiptapEditor.js +52 -0
- package/dist/components/form/index.d.ts +10 -0
- package/dist/components/form/index.d.ts.map +1 -0
- package/dist/components/form/index.js +1 -0
- package/dist/components/form/internal/ImageViewerDialog.d.ts +1 -1
- package/dist/components/form/internal/ImageViewerDialog.d.ts.map +1 -1
- package/dist/components/index.d.ts +8 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/contexts/UploadContext.d.ts +16 -0
- package/dist/contexts/UploadContext.d.ts.map +1 -0
- package/dist/contexts/UploadContext.js +1 -0
- package/dist/contexts/index.d.ts +3 -0
- package/dist/contexts/index.d.ts.map +1 -0
- package/dist/contexts/index.js +1 -0
- package/dist/forms/hooks/index.d.ts +2 -0
- package/dist/forms/hooks/index.d.ts.map +1 -1
- package/dist/forms/hooks/index.js +1 -1
- package/dist/forms/hooks/useController.d.ts +29 -0
- package/dist/forms/hooks/useController.d.ts.map +1 -0
- package/dist/forms/hooks/useController.js +1 -0
- package/dist/forms/hooks/useEntityField.d.ts.map +1 -1
- package/dist/forms/hooks/useEntityField.js +1 -1
- package/dist/forms/hooks/useEntityForm.d.ts +8 -76
- package/dist/forms/hooks/useEntityForm.d.ts.map +1 -1
- package/dist/forms/hooks/useEntityForm.js +1 -1
- package/dist/forms/index.d.ts +6 -4
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +1 -1
- package/dist/forms/types.d.ts +31 -5
- package/dist/forms/types.d.ts.map +1 -1
- package/dist/forms/utils/getFieldsForOperation.d.ts +5 -5
- package/dist/forms/utils/getFieldsForOperation.d.ts.map +1 -1
- package/dist/forms/utils/getFieldsForOperation.js +1 -1
- package/dist/forms/utils/index.d.ts +9 -5
- package/dist/forms/utils/index.d.ts.map +1 -1
- package/dist/forms/utils/index.js +1 -1
- package/dist/forms/utils/isFieldEditable.d.ts +0 -8
- package/dist/forms/utils/isFieldEditable.d.ts.map +1 -1
- package/dist/forms/utils/optionHelpers.d.ts +54 -0
- package/dist/forms/utils/optionHelpers.d.ts.map +1 -0
- package/dist/forms/utils/optionHelpers.js +1 -0
- package/dist/forms/utils/translateFieldLabel.d.ts +70 -0
- package/dist/forms/utils/translateFieldLabel.d.ts.map +1 -0
- package/dist/forms/utils/translateFieldLabel.js +1 -0
- package/dist/forms/utils/validateEntity.d.ts +5 -2
- package/dist/forms/utils/validateEntity.d.ts.map +1 -1
- package/dist/forms/utils/validateEntity.js +1 -1
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useFileUpload.d.ts +67 -0
- package/dist/hooks/useFileUpload.d.ts.map +1 -0
- package/dist/hooks/useFileUpload.js +1 -0
- package/dist/index.d.ts +15 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/stores/FormStore.d.ts +78 -0
- package/dist/stores/FormStore.d.ts.map +1 -0
- package/dist/stores/FormStore.js +1 -0
- package/dist/stores/UploadStore.d.ts +105 -0
- package/dist/stores/UploadStore.d.ts.map +1 -0
- package/dist/stores/UploadStore.js +1 -0
- package/dist/stores/index.d.ts +11 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/useCrud.d.ts +32 -74
- package/dist/useCrud.d.ts.map +1 -1
- package/dist/useCrud.js +1 -1
- package/dist/useCrudCardList.d.ts +62 -0
- package/dist/useCrudCardList.d.ts.map +1 -0
- package/dist/useCrudCardList.js +1 -0
- package/dist/useCrudList.d.ts +61 -0
- package/dist/useCrudList.d.ts.map +1 -0
- package/dist/useCrudList.js +1 -0
- package/dist/utils/fileStorage.d.ts +58 -0
- package/dist/utils/fileStorage.d.ts.map +1 -0
- package/dist/utils/fileStorage.js +1 -0
- package/dist/utils/imageProcessing.d.ts +1 -1
- package/dist/utils/imageProcessing.d.ts.map +1 -1
- package/dist/utils/imageProcessing.js +1 -1
- package/dist/utils/imageStorage.d.ts +1 -10
- package/dist/utils/imageStorage.d.ts.map +1 -1
- package/dist/utils/imageStorage.js +1 -1
- package/dist/utils/mergeWithOptimistic.d.ts +27 -0
- package/dist/utils/mergeWithOptimistic.d.ts.map +1 -0
- package/dist/utils/mergeWithOptimistic.js +1 -0
- package/dist/utils/uploadValidation.d.ts +37 -0
- package/dist/utils/uploadValidation.d.ts.map +1 -0
- package/dist/utils/uploadValidation.js +1 -0
- package/package.json +22 -5
- package/dist/components/ControlledFields.d.ts +0 -49
- package/dist/components/ControlledFields.d.ts.map +0 -1
- package/dist/components/ControlledFields.js +0 -1
- package/dist/context/FormUploadContext.d.ts +0 -36
- package/dist/context/FormUploadContext.d.ts.map +0 -1
- package/dist/context/FormUploadContext.js +0 -1
- package/dist/context/index.d.ts +0 -2
- package/dist/context/index.d.ts.map +0 -1
- package/dist/context/index.js +0 -1
- package/dist/forms/utils/createEntitySchema.d.ts +0 -53
- package/dist/forms/utils/createEntitySchema.d.ts.map +0 -1
- package/dist/forms/utils/createEntitySchema.js +0 -1
- package/dist/forms/utils/normalizeToFieldConfig.d.ts +0 -47
- package/dist/forms/utils/normalizeToFieldConfig.d.ts.map +0 -1
- package/dist/forms/utils/normalizeToFieldConfig.js +0 -1
package/README.md
CHANGED
|
@@ -130,8 +130,24 @@ const UserEntity = {
|
|
|
130
130
|
|
|
131
131
|
### FirestoreAdapter
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
**ONLY for:** `backend: 'firestore'` mode (direct client access, no functions)
|
|
134
|
+
|
|
135
|
+
Direct Firestore SDK operations with real-time subscriptions. Use for simple client-side data
|
|
136
|
+
like user preferences or settings. Adds technical fields client-side (no server to generate them).
|
|
137
|
+
|
|
138
|
+
**When to use:**
|
|
139
|
+
- User preferences, settings, client-only data
|
|
140
|
+
- Simple data that doesn't require server-side security
|
|
141
|
+
- Prototyping without functions
|
|
142
|
+
|
|
143
|
+
**When NOT to use:**
|
|
144
|
+
- Production data requiring server-side security
|
|
145
|
+
- Sensitive data needing admin checks
|
|
146
|
+
- When functions are available (use `FunctionsAdapter` instead)
|
|
134
147
|
|
|
135
148
|
### FunctionsAdapter
|
|
136
149
|
|
|
137
|
-
|
|
150
|
+
**ONLY for:** `backend: 'functions'` mode (server-side security)
|
|
151
|
+
|
|
152
|
+
Firebase Functions HTTP endpoints for CRUD operations. Server generates technical fields and
|
|
153
|
+
enforces security rules. Use for production data requiring validation, auth checks, and audit logs.
|
package/dist/CrudService.d.ts
CHANGED
|
@@ -1,27 +1,60 @@
|
|
|
1
|
+
import type { dndevSchema, QueryClient } from '@donotdev/core';
|
|
1
2
|
import type { QueryOptions } from './adapters/FirestoreAdapter';
|
|
2
3
|
import type { BackendType, CrudState, CrudActions } from './CrudStore';
|
|
3
4
|
/** Store API type for CrudService - typed instead of any */
|
|
4
5
|
type CrudStoreApi = {
|
|
5
6
|
getState: () => CrudState & CrudActions;
|
|
6
7
|
};
|
|
8
|
+
/** Cache options for read operations */
|
|
9
|
+
export interface CacheOptions {
|
|
10
|
+
/** Bypass cache and fetch directly from adapter */
|
|
11
|
+
noCache?: boolean;
|
|
12
|
+
/** Custom stale time in ms (default: Infinity) */
|
|
13
|
+
staleTime?: number;
|
|
14
|
+
}
|
|
7
15
|
export type { QueryOptions };
|
|
8
|
-
import type { dndevSchema } from '@donotdev/core';
|
|
9
16
|
export interface CrudServiceInterface {
|
|
10
17
|
initialize(backend: BackendType): Promise<void>;
|
|
11
|
-
|
|
18
|
+
setStore(store: CrudStoreApi): void;
|
|
19
|
+
/** Schema accepts unknown since OperationSchemas stores dndevSchema<unknown>. T is for return type. */
|
|
20
|
+
getListQueryOptions<T>(collection: string, queryOptions: QueryOptions, schema: dndevSchema<unknown>, cacheOptions?: CacheOptions, schemaType?: 'list' | 'listCard'): {
|
|
21
|
+
queryKey: readonly string[];
|
|
22
|
+
queryFn: () => Promise<T[]>;
|
|
23
|
+
staleTime: number;
|
|
24
|
+
};
|
|
25
|
+
/** Schema accepts unknown since OperationSchemas stores dndevSchema<unknown>. T is for return type. */
|
|
26
|
+
getDocQueryOptions<T>(collection: string, id: string, schema: dndevSchema<unknown>, cacheOptions?: CacheOptions): {
|
|
27
|
+
queryKey: readonly string[];
|
|
28
|
+
queryFn: () => Promise<T | null>;
|
|
29
|
+
staleTime: number;
|
|
30
|
+
};
|
|
31
|
+
get<T>(collection: string, id: string, schema: dndevSchema<T>, options?: CacheOptions): Promise<T | null>;
|
|
32
|
+
query<T>(collection: string, options: QueryOptions, schema: dndevSchema<T>, cacheOptions?: CacheOptions, schemaType?: 'list' | 'listCard'): Promise<T[]>;
|
|
12
33
|
set<T>(collection: string, id: string, data: T, schema: dndevSchema<T>): Promise<void>;
|
|
13
34
|
update<T>(collection: string, id: string, data: Partial<T>): Promise<void>;
|
|
14
35
|
delete(collection: string, id: string): Promise<void>;
|
|
15
36
|
add<T>(collection: string, data: T, schema: dndevSchema<T>): Promise<string>;
|
|
16
|
-
query<T>(collection: string, options: QueryOptions, schema: dndevSchema<T>): Promise<T[]>;
|
|
17
37
|
subscribe<T>(collection: string, id: string, callback: (data: T | null, error?: Error) => void, schema: dndevSchema<T>): () => void;
|
|
18
38
|
subscribeToCollection<T>(collection: string, options: QueryOptions, callback: (data: T[], error?: Error) => void, schema: dndevSchema<T>): () => void;
|
|
19
|
-
|
|
39
|
+
/** Add with optimistic update - shows item immediately, confirms/rolls back after server */
|
|
40
|
+
addOptimistic<T extends {
|
|
41
|
+
id?: string;
|
|
42
|
+
}>(collection: string, data: T, schema: dndevSchema<T>): Promise<T & {
|
|
43
|
+
id: string;
|
|
44
|
+
}>;
|
|
45
|
+
/** Update with optimistic update - shows change immediately, confirms/rolls back after server */
|
|
46
|
+
updateOptimistic<T>(collection: string, id: string, data: Partial<T>, schema: dndevSchema<T>): Promise<T>;
|
|
47
|
+
/** Delete with optimistic update - hides item immediately, confirms/restores after server */
|
|
48
|
+
deleteOptimistic(collection: string, id: string): Promise<void>;
|
|
49
|
+
/** Invalidate all cached queries for a collection */
|
|
50
|
+
invalidateCollection(collection: string): Promise<void>;
|
|
51
|
+
/** Get the shared QueryClient instance from @donotdev/hooks */
|
|
52
|
+
getQueryClient(): QueryClient;
|
|
20
53
|
}
|
|
21
54
|
/**
|
|
22
|
-
* Complete CRUD orchestrator
|
|
55
|
+
* Complete CRUD orchestrator with TanStack Query caching
|
|
23
56
|
*
|
|
24
|
-
* @version 0.0.
|
|
57
|
+
* @version 0.0.4
|
|
25
58
|
* @since 0.0.1
|
|
26
59
|
* @author AMBROISE PARK Consulting
|
|
27
60
|
*/
|
|
@@ -31,14 +64,64 @@ declare class CrudService implements CrudServiceInterface {
|
|
|
31
64
|
private store;
|
|
32
65
|
setStore(store: CrudStoreApi): void;
|
|
33
66
|
initialize(backend: BackendType): Promise<void>;
|
|
34
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Get shared QueryClient instance from @donotdev/hooks.
|
|
69
|
+
* Uses singleton on client, new instance per request on server (SSR-safe).
|
|
70
|
+
*/
|
|
71
|
+
getQueryClient(): QueryClient;
|
|
72
|
+
/**
|
|
73
|
+
* Get query options for list queries. Use with useQuery() in hooks.
|
|
74
|
+
* Returns reactive loading states via TanStack Query.
|
|
75
|
+
* @param schema - Accepts dndevSchema<unknown> since OperationSchemas uses unknown. T is for return type.
|
|
76
|
+
*/
|
|
77
|
+
getListQueryOptions<T>(collection: string, queryOptions: QueryOptions, schema: dndevSchema<unknown>, cacheOptions?: CacheOptions, schemaType?: 'list' | 'listCard'): {
|
|
78
|
+
queryKey: readonly ["crud", string, "query", "list" | "listCard", string];
|
|
79
|
+
queryFn: () => Promise<T[]>;
|
|
80
|
+
staleTime: number;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Get query options for single document queries. Use with useQuery() in hooks.
|
|
84
|
+
* Returns reactive loading states via TanStack Query.
|
|
85
|
+
* @param schema - Accepts dndevSchema<unknown> since OperationSchemas uses unknown. T is for return type.
|
|
86
|
+
*/
|
|
87
|
+
getDocQueryOptions<T>(collection: string, id: string, schema: dndevSchema<unknown>, cacheOptions?: CacheOptions): {
|
|
88
|
+
queryKey: readonly ["crud", string, "get", string];
|
|
89
|
+
queryFn: () => Promise<T | null>;
|
|
90
|
+
staleTime: number;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Update single document GET cache after mutation.
|
|
94
|
+
* Key format: ['crud', collection, 'get', id]
|
|
95
|
+
*/
|
|
96
|
+
private _updateGetCache;
|
|
97
|
+
/**
|
|
98
|
+
* Update all caches after mutation (list queries + single document GET cache).
|
|
99
|
+
* Automatically syncs both list and document caches for consistency.
|
|
100
|
+
*/
|
|
101
|
+
private _updateListCaches;
|
|
102
|
+
/**
|
|
103
|
+
* Invalidate all cached queries for a collection
|
|
104
|
+
*/
|
|
105
|
+
invalidateCollection(collection: string): Promise<void>;
|
|
106
|
+
get<T>(collection: string, id: string, schema: dndevSchema<T>, options?: CacheOptions): Promise<T | null>;
|
|
107
|
+
/** Internal: fetch from adapter with store updates */
|
|
108
|
+
private _getFromAdapter;
|
|
109
|
+
query<T>(collection: string, options: QueryOptions, schema: dndevSchema<T>, cacheOptions?: CacheOptions, schemaType?: 'list' | 'listCard'): Promise<T[]>;
|
|
110
|
+
/** Internal: query from adapter with store updates */
|
|
111
|
+
private _queryFromAdapter;
|
|
35
112
|
set<T>(collection: string, id: string, data: T, schema: dndevSchema<T>): Promise<void>;
|
|
36
113
|
update<T>(collection: string, id: string, data: Partial<T>): Promise<void>;
|
|
37
114
|
delete(collection: string, id: string): Promise<void>;
|
|
38
115
|
add<T>(collection: string, data: T, schema: dndevSchema<T>): Promise<string>;
|
|
39
|
-
query<T>(collection: string, options: QueryOptions, schema: dndevSchema<T>): Promise<T[]>;
|
|
40
116
|
subscribe<T>(collection: string, id: string, callback: (data: T | null, error?: Error) => void, schema: dndevSchema<T>): () => void;
|
|
41
117
|
subscribeToCollection<T>(collection: string, options: QueryOptions, callback: (data: T[], error?: Error) => void, schema: dndevSchema<T>): () => void;
|
|
118
|
+
addOptimistic<T extends {
|
|
119
|
+
id?: string;
|
|
120
|
+
}>(collection: string, data: T, schema: dndevSchema<T>): Promise<T & {
|
|
121
|
+
id: string;
|
|
122
|
+
}>;
|
|
123
|
+
updateOptimistic<T>(collection: string, id: string, data: Partial<T>, schema: dndevSchema<T>): Promise<T>;
|
|
124
|
+
deleteOptimistic(collection: string, id: string): Promise<void>;
|
|
42
125
|
}
|
|
43
126
|
/**
|
|
44
127
|
* Get or create CrudService singleton instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrudService.d.ts","sourceRoot":"","sources":["../src/CrudService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CrudService.d.ts","sourceRoot":"","sources":["../src/CrudService.ts"],"names":[],"mappings":"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"}
|
package/dist/CrudService.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toast as
|
|
1
|
+
import{toast as f}from"@donotdev/components";import{createSingleton as p,handleError as u,getQueryClient as g}from"@donotdev/core";import{FirestoreAdapter as y}from"./adapters/FirestoreAdapter";import{FunctionsAdapter as w}from"./adapters/FunctionsAdapter";const d=1/0,z=1e3*60*30;class S{adapter=null;backend=null;store=null;setStore(t){this.store=t}async initialize(t){if(!(this.backend===t&&this.adapter)){if(this.backend=t,t==="functions")this.adapter=new w;else if(t==="firestore")this.adapter=new y;else throw new Error(`Unknown backend: ${t}`);this.store&&(this.store.getState().setBackend(t),this.store.getState().setCrudService(this))}}getQueryClient(){return g()}getListQueryOptions(t,e,s,a,r="list"){const i=this.adapter,h=()=>this.initialize("firestore");return{queryKey:["crud",t,"query",r,JSON.stringify(e)],queryFn:async()=>{if(i||await h(),!this.adapter)throw new Error("Adapter not initialized");return this.adapter.query(t,e,s)},staleTime:a?.staleTime??d}}getDocQueryOptions(t,e,s,a){const r=this.adapter,i=()=>this.initialize("firestore");return{queryKey:["crud",t,"get",e],queryFn:async()=>{if(r||await i(),!this.adapter)throw new Error("Adapter not initialized");return this.adapter.get(t,e,s)},staleTime:a?.staleTime??d}}_updateGetCache(t,e,s,a){const r=this.getQueryClient(),i=["crud",t,"get",e];a==="delete"?r.removeQueries({queryKey:i}):(a==="update"||a==="add")&&s&&r.setQueryData(i,h=>h?{...h,...s}:s)}_updateListCaches(t,e,s,a){const r=this.getQueryClient();this._updateGetCache(t,e,s,a),r.setQueriesData({queryKey:["crud",t]},i=>Array.isArray(i)?a==="delete"?i.filter(h=>h.id!==e):a==="add"&&s?[...i,{...s,id:e}]:a==="update"&&s&&i.some(o=>o.id===e)?i.map(o=>o.id===e?{...o,...s}:o):i:i)}async invalidateCollection(t){await this.getQueryClient().invalidateQueries({queryKey:["crud",t]})}async get(t,e,s,a){if(this.adapter||await this.initialize("firestore"),a?.noCache)return this._getFromAdapter(t,e,s);this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{return await this.getQueryClient().fetchQuery({queryKey:["crud",t,"get",e],queryFn:()=>this._getFromAdapter(t,e,s,!1),staleTime:a?.staleTime??d})}catch(r){const i=u(r,{userMessage:`Failed to fetch ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,i),i}finally{this.store&&this.store.getState().setLoading(t,!1)}}async _getFromAdapter(t,e,s,a=!0){this.store&&a&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{if(!this.adapter)throw new Error("Adapter not initialized");const r=await this.adapter.get(t,e,s);return this.store&&r&&this.store.getState().setData(t,e,r),r}catch(r){const i=u(r,{userMessage:`Failed to fetch ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,i),i}finally{this.store&&a&&this.store.getState().setLoading(t,!1)}}async query(t,e,s,a,r="list"){if(this.adapter||await this.initialize("firestore"),a?.noCache)return this._queryFromAdapter(t,e,s);this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{return await this.getQueryClient().fetchQuery({queryKey:["crud",t,"query",r,JSON.stringify(e)],queryFn:()=>this._queryFromAdapter(t,e,s,!1),staleTime:a?.staleTime??d})}catch(i){const h=u(i,{userMessage:`Failed to query ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,h),h}finally{this.store&&this.store.getState().setLoading(t,!1)}}async _queryFromAdapter(t,e,s,a=!0){this.store&&a&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{if(!this.adapter)throw new Error("Adapter not initialized");const r=await this.adapter.query(t,e,s);if(this.store){const i=[];for(const h of r){const o=h;o.id&&i.push({id:o.id,data:h})}i.length>0&&this.store.getState().setDataBatch(t,i)}return r}catch(r){const i=u(r,{userMessage:`Failed to query ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,i),i}finally{this.store&&a&&this.store.getState().setLoading(t,!1)}}async set(t,e,s,a){this.adapter||await this.initialize("firestore"),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const r=this.store?.getState().getData(t,e);this.store&&this.store.getState().updateOptimistic(t,e,s,r);try{if(!this.adapter)throw new Error("Adapter not initialized");await this.adapter.set(t,e,s,a),this.store&&(this.store.getState().confirmUpdate(t,e),this.store.getState().setData(t,e,s)),this._updateListCaches(t,e,s,"update"),f("success",`${t} saved successfully`)}catch(i){this.store&&this.store.getState().rejectUpdate(t,e);const h=u(i,{userMessage:`Failed to save ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,h),h}finally{this.store&&this.store.getState().setLoading(t,!1)}}async update(t,e,s){this.adapter||await this.initialize("firestore"),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));let a=null;this.store&&(a=this.store.getState().getData(t,e));const r=a?{...a,...s}:{...s,id:e};this.store&&a&&this.store.getState().updateOptimistic(t,e,r,a);try{if(!this.adapter)throw new Error("Adapter not initialized");await this.adapter.update(t,e,s),this.store&&(this.store.getState().confirmUpdate(t,e),this.store.getState().setData(t,e,r)),this._updateListCaches(t,e,r,"update"),f("success",`${t} updated successfully`)}catch(i){this.store&&this.store.getState().rejectUpdate(t,e);const h=u(i,{userMessage:`Failed to update ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,h),h}finally{this.store&&this.store.getState().setLoading(t,!1)}}async delete(t,e){this.adapter||await this.initialize("firestore"),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const s=this.store?.getState().getData(t,e);this.store&&s&&this.store.getState().deleteOptimistic(t,e,s);try{if(!this.adapter)throw new Error("Adapter not initialized");await this.adapter.delete(t,e),this.store&&this.store.getState().confirmDelete(t,e),this._updateListCaches(t,e,null,"delete"),f("success",`${t} deleted successfully`)}catch(a){this.store&&this.store.getState().rejectDelete(t,e);const r=u(a,{userMessage:`Failed to delete ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,r),r}finally{this.store&&this.store.getState().setLoading(t,!1)}}async add(t,e,s){this.adapter||await this.initialize("firestore"),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const a=`temp_${crypto.randomUUID()}`;this.store&&this.store.getState().addOptimistic(t,a,{...e,id:a});try{if(!this.adapter)throw new Error("Adapter not initialized");const r=await this.adapter.add(t,e,s);return this.store&&this.store.getState().confirmOptimistic(t,a,r,{...e,id:r}),this._updateListCaches(t,r,{...e,id:r},"add"),f("success",`${t} created successfully`),r}catch(r){this.store&&this.store.getState().rejectOptimistic(t,a);const i=u(r,{userMessage:`Failed to create ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,i),i}finally{this.store&&this.store.getState().setLoading(t,!1)}}subscribe(t,e,s,a){this.adapter||this.initialize("firestore").catch(()=>{});try{return this.adapter?this.adapter.subscribe(t,e,(r,i)=>{r&&this.store&&this.store.getState().setData(t,e,r),r&&this.getQueryClient().setQueryData(["crud",t,"get",e],r),s(r,i)},a):(s(null,new Error("Adapter not initialized")),()=>{})}catch(r){return s(null,u(r)),()=>{}}}subscribeToCollection(t,e,s,a){this.adapter||this.initialize("firestore").catch(()=>{});try{return this.adapter?this.adapter.subscribeToCollection(t,e,(r,i)=>{if(r&&this.store){const h=[];for(const o of r){const n=o;n.id&&h.push({id:n.id,data:o})}h.length>0&&this.store.getState().setDataBatch(t,h)}r&&this.getQueryClient().setQueryData(["crud",t,"query",JSON.stringify(e)],r),s(r,i)},a):(s([],new Error("Adapter not initialized")),()=>{})}catch(r){return s([],u(r)),()=>{}}}async addOptimistic(t,e,s){this.adapter||await this.initialize("firestore");const a=`temp_${crypto.randomUUID()}`,r={...e,id:a,_optimistic:!0};this.store&&this.store.getState().addOptimistic(t,a,r);try{if(!this.adapter)throw new Error("Adapter not initialized");const i=await this.adapter.add(t,e,s),h={...e,id:i};return this.store&&this.store.getState().confirmOptimistic(t,a,i,h),this._updateListCaches(t,i,h,"add"),f("success",`${t} created successfully`),h}catch(i){throw this.store&&this.store.getState().rejectOptimistic(t,a),u(i,{userMessage:`Failed to create ${t}`,showNotification:!0})}}async updateOptimistic(t,e,s,a){this.adapter||await this.initialize("firestore");let r=null;this.store&&(r=this.store.getState().getData(t,e));const i=r?{...r,...s,_optimistic:!0}:{...s,id:e,_optimistic:!0};this.store&&r&&this.store.getState().updateOptimistic(t,e,i,r);try{if(!this.adapter)throw new Error("Adapter not initialized");return await this.adapter.update(t,e,s),this.store&&(this.store.getState().confirmUpdate(t,e),this.store.getState().setData(t,e,{...i,_optimistic:void 0})),this._updateListCaches(t,e,i,"update"),f("success",`${t} updated successfully`),i}catch(h){throw this.store&&this.store.getState().rejectUpdate(t,e),u(h,{userMessage:`Failed to update ${t}`,showNotification:!0})}}async deleteOptimistic(t,e){this.adapter||await this.initialize("firestore");let s=null;this.store&&(s=this.store.getState().getData(t,e)),this.store&&s&&this.store.getState().deleteOptimistic(t,e,s);try{if(!this.adapter)throw new Error("Adapter not initialized");await this.adapter.delete(t,e),this.store&&this.store.getState().confirmDelete(t,e),this._updateListCaches(t,e,null,"delete"),f("success",`${t} deleted successfully`)}catch(a){throw this.store&&this.store.getState().rejectDelete(t,e),u(a,{userMessage:`Failed to delete ${t}`,showNotification:!0})}}}const A=p(()=>new S);export{A as getCrudService};
|
package/dist/CrudStore.d.ts
CHANGED
|
@@ -7,10 +7,23 @@ import type { CrudServiceInterface } from './CrudService';
|
|
|
7
7
|
* @author AMBROISE PARK Consulting
|
|
8
8
|
*/
|
|
9
9
|
export type BackendType = 'functions' | 'firestore';
|
|
10
|
+
/**
|
|
11
|
+
* Optimistic operation status
|
|
12
|
+
*/
|
|
13
|
+
export type OptimisticStatus = 'pending' | 'confirmed' | 'failed';
|
|
14
|
+
/**
|
|
15
|
+
* Optimistic operation metadata
|
|
16
|
+
*/
|
|
17
|
+
export interface OptimisticMeta {
|
|
18
|
+
tempId: string;
|
|
19
|
+
originalData: unknown | null;
|
|
20
|
+
status: OptimisticStatus;
|
|
21
|
+
operation: 'add' | 'update' | 'delete';
|
|
22
|
+
}
|
|
10
23
|
/**
|
|
11
24
|
* CRUD store state interface
|
|
12
25
|
*
|
|
13
|
-
* @version 0.0.
|
|
26
|
+
* @version 0.0.2
|
|
14
27
|
* @since 0.0.1
|
|
15
28
|
* @author AMBROISE PARK Consulting
|
|
16
29
|
*/
|
|
@@ -22,12 +35,14 @@ export interface CrudState {
|
|
|
22
35
|
error: Error | null;
|
|
23
36
|
data: Record<string, unknown>;
|
|
24
37
|
lastUpdated: number;
|
|
38
|
+
/** Optimistic operation metadata keyed by document id */
|
|
39
|
+
optimistic: Record<string, OptimisticMeta>;
|
|
25
40
|
}>;
|
|
26
41
|
}
|
|
27
42
|
/**
|
|
28
43
|
* CRUD store actions interface
|
|
29
44
|
*
|
|
30
|
-
* @version 0.0.
|
|
45
|
+
* @version 0.0.2
|
|
31
46
|
* @since 0.0.1
|
|
32
47
|
* @author AMBROISE PARK Consulting
|
|
33
48
|
*/
|
|
@@ -45,9 +60,37 @@ export interface CrudActions {
|
|
|
45
60
|
removeData: (collection: string, id: string) => void;
|
|
46
61
|
clearCollection: (collection: string) => void;
|
|
47
62
|
clearError: (collection: string) => void;
|
|
63
|
+
/** Add item optimistically (before server confirms) */
|
|
64
|
+
addOptimistic: (collection: string, tempId: string, data: unknown) => void;
|
|
65
|
+
/** Confirm optimistic add - replace temp item with real item */
|
|
66
|
+
confirmOptimistic: (collection: string, tempId: string, realId: string, realData: unknown) => void;
|
|
67
|
+
/** Reject optimistic add - remove temp item */
|
|
68
|
+
rejectOptimistic: (collection: string, tempId: string) => void;
|
|
69
|
+
/** Update item optimistically */
|
|
70
|
+
updateOptimistic: (collection: string, id: string, data: unknown, originalData: unknown) => void;
|
|
71
|
+
/** Confirm optimistic update */
|
|
72
|
+
confirmUpdate: (collection: string, id: string) => void;
|
|
73
|
+
/** Reject optimistic update - restore original data */
|
|
74
|
+
rejectUpdate: (collection: string, id: string) => void;
|
|
75
|
+
/** Delete item optimistically (hide but keep for rollback) */
|
|
76
|
+
deleteOptimistic: (collection: string, id: string, originalData: unknown) => void;
|
|
77
|
+
/** Confirm optimistic delete - remove completely */
|
|
78
|
+
confirmDelete: (collection: string, id: string) => void;
|
|
79
|
+
/** Reject optimistic delete - restore item */
|
|
80
|
+
rejectDelete: (collection: string, id: string) => void;
|
|
48
81
|
getLoading: (collection: string) => boolean;
|
|
49
82
|
getError: (collection: string) => Error | null;
|
|
50
83
|
getData: (collection: string, id: string) => unknown | null;
|
|
84
|
+
/** Check if item is optimistic (not yet confirmed by server) */
|
|
85
|
+
isOptimistic: (collection: string, id: string) => boolean;
|
|
86
|
+
/** Get optimistic status for an item */
|
|
87
|
+
getOptimisticStatus: (collection: string, id: string) => OptimisticStatus | null;
|
|
88
|
+
/** Get all items in collection (including optimistic, excluding deleted) */
|
|
89
|
+
getCollectionData: (collection: string) => Array<{
|
|
90
|
+
id: string;
|
|
91
|
+
data: unknown;
|
|
92
|
+
isOptimistic: boolean;
|
|
93
|
+
}>;
|
|
51
94
|
}
|
|
52
95
|
/**
|
|
53
96
|
* CRUD store hook for accessing CRUD state and actions
|
package/dist/CrudStore.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrudStore.d.ts","sourceRoot":"","sources":["../src/CrudStore.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IAExB,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAGzC,WAAW,EAAE,MAAM,CACjB,MAAM,EACN;QACE,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,WAAW,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"CrudStore.d.ts","sourceRoot":"","sources":["../src/CrudStore.ts"],"names":[],"mappings":"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"}
|
package/dist/CrudStore.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createDoNotDevStore as d}from"@donotdev/core";const
|
|
1
|
+
import{createDoNotDevStore as d}from"@donotdev/core";const m={backend:null,crudService:null,collections:{}},D=d({name:"crud-store",createStore:(l,r)=>({...m,setCrudService:t=>{l({crudService:t})},setBackend:t=>{l({backend:t})},setLoading:(t,i)=>{l(c=>{const o=c.collections[t]||{loading:!1,error:null,data:{},lastUpdated:0,optimistic:{}};return{collections:{...c.collections,[t]:{...o,loading:i}}}})},setError:(t,i)=>{l(c=>{const o=c.collections[t]||{loading:!1,error:null,data:{},lastUpdated:0,optimistic:{}};return{collections:{...c.collections,[t]:{...o,error:i,loading:!1}}}})},setData:(t,i,c)=>{l(o=>{const n=o.collections[t]||{loading:!1,error:null,data:{},lastUpdated:0,optimistic:{}};return{collections:{...o.collections,[t]:{...n,data:{...n.data,[i]:c},lastUpdated:Date.now(),error:null}}}})},setDataBatch:(t,i)=>{i.length!==0&&l(c=>{const o=c.collections[t]||{loading:!1,error:null,data:{},lastUpdated:0,optimistic:{}},n={...o.data};for(const{id:e,data:a}of i)n[e]=a;return{collections:{...c.collections,[t]:{...o,data:n,lastUpdated:Date.now(),error:null}}}})},removeData:(t,i)=>{l(c=>{const o=c.collections[t];if(!o)return c;const{[i]:n,...e}=o.data;return{collections:{...c.collections,[t]:{...o,data:e,lastUpdated:Date.now()}}}})},clearCollection:t=>{l(i=>{const{[t]:c,...o}=i.collections;return{collections:o}})},clearError:t=>{l(i=>{const c=i.collections[t];return c?{collections:{...i.collections,[t]:{...c,error:null}}}:i})},addOptimistic:(t,i,c)=>{l(o=>{const n=o.collections[t]||{loading:!1,error:null,data:{},lastUpdated:0,optimistic:{}};return{collections:{...o.collections,[t]:{...n,data:{...n.data,[i]:c},optimistic:{...n.optimistic,[i]:{tempId:i,originalData:null,status:"pending",operation:"add"}},lastUpdated:Date.now()}}}})},confirmOptimistic:(t,i,c,o)=>{l(n=>{const e=n.collections[t];if(!e)return n;const{[i]:a,...s}=e.data,{[i]:u,...p}=e.optimistic;return{collections:{...n.collections,[t]:{...e,data:{...s,[c]:o},optimistic:p,lastUpdated:Date.now()}}}})},rejectOptimistic:(t,i)=>{l(c=>{const o=c.collections[t];if(!o)return c;const{[i]:n,...e}=o.data,{[i]:a,...s}=o.optimistic;return{collections:{...c.collections,[t]:{...o,data:e,optimistic:s,lastUpdated:Date.now()}}}})},updateOptimistic:(t,i,c,o)=>{l(n=>{const e=n.collections[t]||{loading:!1,error:null,data:{},lastUpdated:0,optimistic:{}};return{collections:{...n.collections,[t]:{...e,data:{...e.data,[i]:c},optimistic:{...e.optimistic,[i]:{tempId:i,originalData:o,status:"pending",operation:"update"}},lastUpdated:Date.now()}}}})},confirmUpdate:(t,i)=>{l(c=>{const o=c.collections[t];if(!o)return c;const{[i]:n,...e}=o.optimistic;return{collections:{...c.collections,[t]:{...o,optimistic:e}}}})},rejectUpdate:(t,i)=>{l(c=>{const o=c.collections[t];if(!o)return c;const n=o.optimistic[i];if(!n||n.operation!=="update")return c;const{[i]:e,...a}=o.optimistic;return{collections:{...c.collections,[t]:{...o,data:{...o.data,[i]:n.originalData},optimistic:a,lastUpdated:Date.now()}}}})},deleteOptimistic:(t,i,c)=>{l(o=>{const n=o.collections[t];if(!n)return o;const{[i]:e,...a}=n.data;return{collections:{...o.collections,[t]:{...n,data:a,optimistic:{...n.optimistic,[i]:{tempId:i,originalData:c,status:"pending",operation:"delete"}},lastUpdated:Date.now()}}}})},confirmDelete:(t,i)=>{l(c=>{const o=c.collections[t];if(!o)return c;const{[i]:n,...e}=o.optimistic;return{collections:{...c.collections,[t]:{...o,optimistic:e}}}})},rejectDelete:(t,i)=>{l(c=>{const o=c.collections[t];if(!o)return c;const n=o.optimistic[i];if(!n||n.operation!=="delete")return c;const{[i]:e,...a}=o.optimistic;return{collections:{...c.collections,[t]:{...o,data:{...o.data,[i]:n.originalData},optimistic:a,lastUpdated:Date.now()}}}})},getLoading:t=>r().collections[t]?.loading||!1,getError:t=>r().collections[t]?.error||null,getData:(t,i)=>r().collections[t]?.data[i]||null,isOptimistic:(t,i)=>r().collections[t]?.optimistic[i]?.status==="pending",getOptimisticStatus:(t,i)=>r().collections[t]?.optimistic[i]?.status??null,getCollectionData:t=>{const i=r().collections[t];return i?Object.entries(i.data).map(([c,o])=>({id:c,data:o,isOptimistic:i.optimistic[c]?.status==="pending"})):[]}})});export{D as useCrudStore};
|
package/dist/FieldRegistry.d.ts
CHANGED
|
@@ -6,17 +6,20 @@
|
|
|
6
6
|
* @since 0.0.1
|
|
7
7
|
* @author AMBROISE PARK Consulting
|
|
8
8
|
*/
|
|
9
|
+
import type { EntityField, FieldType, ValueTypeForField } from '@donotdev/core';
|
|
9
10
|
import type { ComponentType } from 'react';
|
|
10
11
|
import type { Control, ControllerRenderProps, FieldErrors, FieldValues, Path } from 'react-hook-form';
|
|
11
|
-
import type { BaseSchema, BaseIssue } from 'valibot';
|
|
12
|
-
import type { FieldConfig, FieldType, EntityField, ValueTypeForField } from '@donotdev/core';
|
|
13
12
|
/**
|
|
14
13
|
* Props for controlled field components (react-hook-form)
|
|
14
|
+
*
|
|
15
|
+
* Use framework's `useController` hook (from @donotdev/crud) instead of react-hook-form's useController
|
|
16
|
+
* to ensure type compatibility.
|
|
15
17
|
*/
|
|
16
18
|
export interface ControlledFieldProps<T extends FieldValues = FieldValues, FT extends FieldType = FieldType> {
|
|
19
|
+
/** Control object from react-hook-form - use with framework's useController hook */
|
|
17
20
|
control: Control<T>;
|
|
18
21
|
errors: FieldErrors<T>;
|
|
19
|
-
fieldConfig:
|
|
22
|
+
fieldConfig: EntityField<FT>;
|
|
20
23
|
t: (key: string, options?: Record<string, unknown>) => string;
|
|
21
24
|
onChange?: (value: ValueTypeForField<FT>) => void;
|
|
22
25
|
placeholder?: string;
|
|
@@ -31,6 +34,8 @@ export interface ControlledFieldProps<T extends FieldValues = FieldValues, FT ex
|
|
|
31
34
|
isTouched: boolean;
|
|
32
35
|
invalid: boolean;
|
|
33
36
|
};
|
|
37
|
+
/** Form ID for upload tracking - used by file upload fields */
|
|
38
|
+
formId?: string;
|
|
34
39
|
}
|
|
35
40
|
/**
|
|
36
41
|
* Props for uncontrolled field components
|
|
@@ -43,20 +48,16 @@ export interface UncontrolledFieldProps<FT extends FieldType = FieldType> {
|
|
|
43
48
|
error?: string;
|
|
44
49
|
helperText?: string;
|
|
45
50
|
t: (key: string) => string;
|
|
46
|
-
config:
|
|
51
|
+
config: EntityField<FT>;
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
49
|
-
*
|
|
50
|
-
|
|
51
|
-
export type SchemaGenerator = (field: EntityField<FieldType>) => BaseSchema<unknown, unknown, BaseIssue<unknown>>;
|
|
52
|
-
/**
|
|
53
|
-
* Full registration for custom field types
|
|
54
|
+
* Registration for custom field types (UI components only)
|
|
55
|
+
* Schemas must be defined in entity.validation.schema
|
|
54
56
|
*/
|
|
55
57
|
export interface FieldTypeRegistration<FT extends string = string> {
|
|
56
58
|
type: FT;
|
|
57
59
|
controlledComponent: ComponentType<ControlledFieldProps<any, any>>;
|
|
58
60
|
uncontrolledComponent?: ComponentType<UncontrolledFieldProps>;
|
|
59
|
-
schemaGenerator: SchemaGenerator;
|
|
60
61
|
}
|
|
61
62
|
/**
|
|
62
63
|
* Field Registry - UI components only
|
|
@@ -70,8 +71,8 @@ declare class FieldRegistry {
|
|
|
70
71
|
*/
|
|
71
72
|
registerComponent(type: string, controlled: ComponentType<ControlledFieldProps<any, any>>, uncontrolled?: ComponentType<UncontrolledFieldProps>): void;
|
|
72
73
|
/**
|
|
73
|
-
* Register a custom field type
|
|
74
|
-
*
|
|
74
|
+
* Register a custom field type (UI components only)
|
|
75
|
+
* Schemas must be defined in entity.validation.schema
|
|
75
76
|
*/
|
|
76
77
|
register<FT extends string>(registration: FieldTypeRegistration<FT>): void;
|
|
77
78
|
/**
|
|
@@ -97,23 +98,58 @@ declare class FieldRegistry {
|
|
|
97
98
|
}
|
|
98
99
|
/**
|
|
99
100
|
* Get the field registry singleton
|
|
101
|
+
*
|
|
102
|
+
* Note: Built-in field types are auto-registered via side-effect import in FormFieldRenderer
|
|
103
|
+
* This ensures they're registered when the registry is first used, without tree-shaking issues
|
|
100
104
|
*/
|
|
101
105
|
export declare function getFieldRegistry(): FieldRegistry;
|
|
102
106
|
/**
|
|
103
|
-
* Register a custom field type
|
|
107
|
+
* Register a custom field type (UI component only)
|
|
108
|
+
* Schema must be defined in entity.validation.schema
|
|
104
109
|
*
|
|
105
110
|
* @example
|
|
106
111
|
* ```ts
|
|
112
|
+
* import { useController, registerFieldType } from '@donotdev/crud';
|
|
113
|
+
* import type { ControlledFieldProps } from '@donotdev/crud';
|
|
107
114
|
* import * as v from 'valibot';
|
|
108
|
-
* import { registerFieldType } from '@donotdev/crud';
|
|
109
115
|
*
|
|
116
|
+
* // Custom controlled component MUST use framework's useController (not react-hook-form)
|
|
117
|
+
* function ControlledRepairOperationsField({
|
|
118
|
+
* fieldConfig,
|
|
119
|
+
* control,
|
|
120
|
+
* errors,
|
|
121
|
+
* t,
|
|
122
|
+
* }: ControlledFieldProps) {
|
|
123
|
+
* // REQUIRED: Use framework's useController - ensures type compatibility
|
|
124
|
+
* const { field, fieldState } = useController({
|
|
125
|
+
* name: fieldConfig.name,
|
|
126
|
+
* control: control,
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* // Use field.value and field.onChange
|
|
130
|
+
* return (
|
|
131
|
+
* <div>
|
|
132
|
+
* Your custom UI here
|
|
133
|
+
* </div>
|
|
134
|
+
* );
|
|
135
|
+
* }
|
|
136
|
+
*
|
|
137
|
+
* // Register UI component
|
|
110
138
|
* registerFieldType({
|
|
111
|
-
* type: '
|
|
112
|
-
* controlledComponent:
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
139
|
+
* type: 'repairOperations',
|
|
140
|
+
* controlledComponent: ControlledRepairOperationsField,
|
|
141
|
+
* });
|
|
142
|
+
*
|
|
143
|
+
* // Then define schema in entity
|
|
144
|
+
* const carEntity = defineEntity({
|
|
145
|
+
* fields: {
|
|
146
|
+
* repairs: {
|
|
147
|
+
* type: 'repairOperations',
|
|
148
|
+
* validation: {
|
|
149
|
+
* schema: v.array(v.object({ operation: v.string(), cost: v.number() }))
|
|
150
|
+
* }
|
|
151
|
+
* }
|
|
152
|
+
* }
|
|
117
153
|
* });
|
|
118
154
|
* ```
|
|
119
155
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldRegistry.d.ts","sourceRoot":"","sources":["../src/FieldRegistry.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"FieldRegistry.d.ts","sourceRoot":"","sources":["../src/FieldRegistry.ts"],"names":[],"mappings":"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"}
|
package/dist/FieldRegistry.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";
|
|
1
|
+
"use client";class i{components=new Map;registerComponent(e,n,o){this.components.set(e,{controlled:n,uncontrolled:o})}register(e){const{type:n,controlledComponent:o,uncontrolledComponent:l}=e;this.components.set(n,{controlled:o,uncontrolled:l})}getControlledComponent(e){return this.components.get(e)?.controlled}getUncontrolledComponent(e){return this.components.get(e)?.uncontrolled}has(e){return this.components.has(e)}getRegisteredTypes(){return Array.from(this.components.keys())}clear(){this.components.clear()}}let r=null;function s(){return r||(r=new i),r}function c(t){s().register(t)}function p(t){return s().has(t)}export{s as getFieldRegistry,p as isFieldTypeRegistered,c as registerFieldType};
|
|
@@ -51,13 +51,13 @@ export declare class FirestoreAdapter {
|
|
|
51
51
|
private firestore;
|
|
52
52
|
private ensureFirestore;
|
|
53
53
|
private getCollectionRef;
|
|
54
|
-
get<T>(collectionName: string, id: string, schema: dndevSchema<
|
|
54
|
+
get<T>(collectionName: string, id: string, schema: dndevSchema<unknown>): Promise<T | null>;
|
|
55
55
|
set<T>(collectionName: string, id: string, data: T, schema: dndevSchema<T>): Promise<void>;
|
|
56
56
|
update<T>(collectionName: string, id: string, data: Partial<T>): Promise<void>;
|
|
57
57
|
delete(collectionName: string, id: string): Promise<void>;
|
|
58
58
|
add<T>(collectionName: string, data: T, schema: dndevSchema<T>): Promise<string>;
|
|
59
|
-
query<T>(collectionName: string, options: QueryOptions, schema: dndevSchema<
|
|
60
|
-
subscribe<T>(collectionName: string, id: string, callback: SubscriptionCallback<T>, schema: dndevSchema<
|
|
61
|
-
subscribeToCollection<T>(collectionName: string, options: QueryOptions, callback: CollectionSubscriptionCallback<T>, schema: dndevSchema<
|
|
59
|
+
query<T>(collectionName: string, options: QueryOptions, schema: dndevSchema<unknown>): Promise<T[]>;
|
|
60
|
+
subscribe<T>(collectionName: string, id: string, callback: SubscriptionCallback<T>, schema: dndevSchema<unknown>): Unsubscribe;
|
|
61
|
+
subscribeToCollection<T>(collectionName: string, options: QueryOptions, callback: CollectionSubscriptionCallback<T>, schema: dndevSchema<unknown>): Unsubscribe;
|
|
62
62
|
}
|
|
63
63
|
//# sourceMappingURL=FirestoreAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirestoreAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/FirestoreAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FirestoreAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/FirestoreAdapter.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAqBL,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAQ5B;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB,IAAI,GACJ,IAAI,GACJ,GAAG,GACH,IAAI,GACJ,GAAG,GACH,IAAI,GACJ,gBAAgB,GAChB,IAAI,GACJ,QAAQ,CAAC;AAEb;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,iBAAiB,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9E,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI,CACpC,IAAI,EAAE,CAAC,GAAG,IAAI,EACd,KAAK,CAAC,EAAE,cAAc,KACnB,IAAI,CAAC;AACV;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,CAAC,CAAC,IAAI,CAC9C,IAAI,EAAE,CAAC,EAAE,EACT,KAAK,CAAC,EAAE,cAAc,KACnB,IAAI,CAAC;AAEV;;;;;;;GAOG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAwB;IAEzC,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,gBAAgB;IAKlB,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAC3B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IA2Bd,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,IAAI,CAAC;IAYV,MAAM,CAAC,CAAC,EACZ,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GACf,OAAO,CAAC,IAAI,CAAC;IAWV,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzD,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,MAAM,CAAC;IA+CZ,KAAK,CAAC,CAAC,EACX,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAC3B,OAAO,CAAC,CAAC,EAAE,CAAC;IAoEf,SAAS,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,EACjC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAC3B,WAAW;IA2Bd,qBAAqB,CAAC,CAAC,EACrB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,8BAA8B,CAAC,CAAC,CAAC,EAC3C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAC3B,WAAW;CAgDf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import*as f from"valibot";import{handleError as p}from"@donotdev/core";import{getFirestore as R,getFirebaseSDK as I,doc as l,getDoc as B,getDocs as q,setDoc as x,updateDoc as C,deleteDoc as E,addDoc as v,collection as S,query as F,where as g,orderBy as w,limit as m,onSnapshot as A}from"@donotdev/firebase";import{transformFirestoreData as h,prepareForFirestore as y}from"@donotdev/firebase";class L{firestore;ensureFirestore(){if(this.firestore)return!0;try{return this.firestore=R(),!0}catch{return!1}}getCollectionRef(s){return!this.ensureFirestore()||!this.firestore?null:S(this.firestore,s)}async get(s,e,r){if(!this.ensureFirestore()||!this.firestore)return null;try{const i=l(this.firestore,s,e),t=await B(i);if(!t.exists())return null;let o=t.data();return o=h(o),{...f.parse(r,o),id:e}}catch(i){return p(i,{context:{operation:"FirestoreAdapter.get",collection:s,docId:e},severity:"warning"}),null}}async set(s,e,r,i){if(!(!this.ensureFirestore()||!this.firestore))try{f.parse(i,r);const t=l(this.firestore,s,e),o=y(r);await x(t,o)}catch(t){throw t}}async update(s,e,r){if(!(!this.ensureFirestore()||!this.firestore))try{const i=l(this.firestore,s,e),t=y(r);await C(i,t)}catch(i){throw i}}async delete(s,e){if(!(!this.ensureFirestore()||!this.firestore))try{const r=l(this.firestore,s,e);await E(r)}catch(r){throw r}}async add(s,e,r){if(!this.ensureFirestore())return"";try{f.parse(r,e);const i=this.getCollectionRef(s);if(!i)return"";const t=new Date().toISOString(),o=I().getCurrentUser()?.uid||"anonymous",c={...e,createdAt:t,updatedAt:t,createdById:o,updatedById:o},a=y(c);return(await v(i,a)).id}catch(i){throw i}}async query(s,e,r){if(!this.ensureFirestore())return[];const i=this.getCollectionRef(s);if(!i)return[];try{const t=[];if(e.where)for(const n of e.where)t.push(g(n.field,n.operator,n.value));if(e.orderBy)for(const n of e.orderBy)t.push(w(n.field,n.direction||"asc"));e.limit&&t.push(m(e.limit));const o=F(i,...t),c=await q(o),a=[];return c.forEach(n=>{try{let d=n.data();if(!d)return;d=h(d);const u=f.parse(r,d);a.push({...u,id:n.id})}catch(d){p(d,{context:{operation:"FirestoreAdapter.query.parse",docId:n.id,collection:s},showNotification:!1})}}),a}catch(t){throw p(t,{context:{operation:"FirestoreAdapter.query",collection:s,options:e}}),t}}subscribe(s,e,r,i){if(!this.ensureFirestore()||!this.firestore)return()=>{};const t=l(this.firestore,s,e);return A(t,o=>{try{if(!o.exists()){r(null);return}let c=o.data();c=h(c);const a=f.parse(i,c);r({...a,id:e})}catch(c){r(null,c)}},o=>{r(null,o)})}subscribeToCollection(s,e,r,i){if(!this.ensureFirestore())return()=>{};const t=this.getCollectionRef(s);if(!t)return()=>{};try{const o=[];if(e.where)for(const a of e.where)o.push(g(a.field,a.operator,a.value));if(e.orderBy)for(const a of e.orderBy)o.push(w(a.field,a.direction||"asc"));e.limit&&o.push(m(e.limit));const c=F(t,...o);return A(c,a=>{try{const n=[];a.forEach(d=>{let u=d.data();u=h(u);const D=f.parse(i,u);n.push({...D,id:d.id})}),r(n)}catch(n){r([],n)}},a=>{r([],a)})}catch(o){return r([],o),()=>{}}}}export{L as FirestoreAdapter};
|
|
@@ -32,12 +32,13 @@ export declare class FunctionsAdapter {
|
|
|
32
32
|
private region;
|
|
33
33
|
constructor();
|
|
34
34
|
private ensureFunctions;
|
|
35
|
-
get<T>(collectionName: string, id: string, schema: dndevSchema<
|
|
35
|
+
get<T>(collectionName: string, id: string, schema: dndevSchema<unknown>): Promise<T | null>;
|
|
36
36
|
set<T>(collectionName: string, id: string, data: T, schema: dndevSchema<T>): Promise<void>;
|
|
37
37
|
update<T>(collectionName: string, id: string, data: Partial<T>): Promise<void>;
|
|
38
38
|
delete(collectionName: string, id: string): Promise<void>;
|
|
39
39
|
add<T>(collectionName: string, data: T, schema: dndevSchema<T>): Promise<string>;
|
|
40
|
-
query<T>(collectionName: string, options: FunctionsQueryOptions, schema: dndevSchema<
|
|
40
|
+
query<T>(collectionName: string, options: FunctionsQueryOptions, schema: dndevSchema<unknown>): Promise<T[]>;
|
|
41
|
+
listCard<T>(collectionName: string, options: FunctionsQueryOptions, schema: dndevSchema<T>): Promise<T[]>;
|
|
41
42
|
subscribe<T>(): () => void;
|
|
42
43
|
subscribeToCollection<T>(): () => void;
|
|
43
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FunctionsAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/FunctionsAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FunctionsAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/FunctionsAdapter.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,MAAM,CAAS;;YAOT,eAAe;IAUvB,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAC3B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAed,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,IAAI,CAAC;IAeV,MAAM,CAAC,CAAC,EACZ,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GACf,OAAO,CAAC,IAAI,CAAC;IAcV,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAczD,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,MAAM,CAAC;IAgBZ,KAAK,CAAC,CAAC,EACX,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAC3B,OAAO,CAAC,CAAC,EAAE,CAAC;IA+CT,QAAQ,CAAC,CAAC,EACd,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,CAAC,EAAE,CAAC;IAgDf,SAAS,CAAC,CAAC,KAAK,MAAM,IAAI;IAM1B,qBAAqB,CAAC,CAAC,KAAK,MAAM,IAAI;CAKvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{httpsCallable as
|
|
1
|
+
import{httpsCallable as a}from"firebase/functions";import*as o from"valibot";import{getPlatformEnvVar as h}from"@donotdev/core";import{getFirebaseFunctions as l}from"@donotdev/firebase";class F{functions;region;constructor(){this.region=h("FIREBASE_FUNCTIONS_REGION")||"europe-west1"}async ensureFunctions(){if(this.functions)return!0;try{return this.functions=await l(this.region),!0}catch{return!1}}async get(n,t,s){if(!await this.ensureFunctions())return null;try{const r=`get_${n}`;return(await a(this.functions,r)({id:t})).data}catch(r){throw r}}async set(n,t,s,r){if(await this.ensureFunctions())try{o.parse(r,s);const e=`update_${n}`;await a(this.functions,e)({id:t,payload:s})}catch(e){throw e}}async update(n,t,s){if(await this.ensureFunctions())try{const r=`update_${n}`;await a(this.functions,r)({id:t,payload:s})}catch(r){throw r}}async delete(n,t){if(await this.ensureFunctions())try{const s=`delete_${n}`;await a(this.functions,s)({id:t})}catch(s){throw s}}async add(n,t,s){if(!await this.ensureFunctions())return"";try{o.parse(s,t);const r=`create_${n}`;return(await a(this.functions,r)({payload:t})).data.id}catch(r){throw r}}async query(n,t,s){if(!await this.ensureFunctions())return[];try{const r=`list_${n}`,e={};return t.where&&(e.where=t.where.map(i=>[i.field,i.operator,i.value])),t.orderBy&&(e.orderBy=t.orderBy.map(i=>[i.field,i.direction||"asc"])),t.limit&&(e.limit=t.limit),(await a(this.functions,r)(e)).data.items}catch(r){throw r}}async listCard(n,t,s){if(!await this.ensureFunctions())return[];try{const r=`listCard_${n}`,e={};return t.where&&(e.where=t.where.map(i=>[i.field,i.operator,i.value])),t.orderBy&&(e.orderBy=t.orderBy.map(i=>[i.field,i.direction||"asc"])),t.limit&&(e.limit=t.limit),(await a(this.functions,r)(e)).data.items}catch(r){throw r}}subscribe(){throw new Error("Subscriptions are not supported with Functions backend. Use Firestore backend for real-time features.")}subscribeToCollection(){throw new Error("Subscriptions are not supported with Functions backend. Use Firestore backend for real-time features.")}}export{F as FunctionsAdapter};
|