@karibsen/eponyme 0.9.0-nightly.20260912 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/eponyme.d.mts +5 -2
  2. package/dist/eponyme.mjs +3 -1
  3. package/dist/module.d.mts +78 -3
  4. package/dist/module.json +2 -2
  5. package/dist/module.mjs +52 -5
  6. package/dist/runtime/components/editor/EponymeFormPage.vue +94 -0
  7. package/dist/runtime/components/fields/FieldRenderer.vue +16 -3
  8. package/dist/runtime/components/fields/ImageField.d.vue.ts +27 -0
  9. package/dist/runtime/components/fields/ImageField.vue +352 -0
  10. package/dist/runtime/components/fields/ImageField.vue.d.ts +27 -0
  11. package/dist/runtime/components/fields/RelationField.vue +22 -2
  12. package/dist/runtime/components/image/EponymeImage.d.vue.ts +19 -0
  13. package/dist/runtime/components/image/EponymeImage.vue +25 -0
  14. package/dist/runtime/components/image/EponymeImage.vue.d.ts +19 -0
  15. package/dist/runtime/components/image/EponymeNuxtImage.d.vue.ts +23 -0
  16. package/dist/runtime/components/image/EponymeNuxtImage.vue +26 -0
  17. package/dist/runtime/components/image/EponymeNuxtImage.vue.d.ts +23 -0
  18. package/dist/runtime/components/media/EponymeFocalPicker.d.vue.ts +29 -0
  19. package/dist/runtime/components/media/EponymeFocalPicker.vue +137 -0
  20. package/dist/runtime/components/media/EponymeFocalPicker.vue.d.ts +29 -0
  21. package/dist/runtime/components/media/EponymeImageCrops.d.vue.ts +10 -0
  22. package/dist/runtime/components/media/EponymeImageCrops.vue +44 -0
  23. package/dist/runtime/components/media/EponymeImageCrops.vue.d.ts +10 -0
  24. package/dist/runtime/components/media/EponymeMediaDetailsDialog.d.vue.ts +16 -0
  25. package/dist/runtime/components/media/EponymeMediaDetailsDialog.vue +134 -0
  26. package/dist/runtime/components/media/EponymeMediaDetailsDialog.vue.d.ts +16 -0
  27. package/dist/runtime/components/media/EponymeMediaGrid.d.vue.ts +4 -0
  28. package/dist/runtime/components/media/EponymeMediaGrid.vue +18 -6
  29. package/dist/runtime/components/media/EponymeMediaGrid.vue.d.ts +4 -0
  30. package/dist/runtime/composables/useEponyme.d.ts +14 -6
  31. package/dist/runtime/composables/useEponyme.js +5 -3
  32. package/dist/runtime/composables/useEponymeCollection.d.ts +12 -5
  33. package/dist/runtime/composables/useEponymeCollection.js +10 -6
  34. package/dist/runtime/composables/useEponymeImage.d.ts +19 -0
  35. package/dist/runtime/composables/useEponymeImage.js +5 -0
  36. package/dist/runtime/composables/useEponymeMedia.d.ts +13 -1
  37. package/dist/runtime/composables/useEponymeMedia.js +32 -1
  38. package/dist/runtime/composables/useEponymeReferrers.d.ts +25 -0
  39. package/dist/runtime/composables/useEponymeReferrers.js +22 -0
  40. package/dist/runtime/composables/useEponymeSeo.d.ts +36 -0
  41. package/dist/runtime/composables/useEponymeSeo.js +47 -0
  42. package/dist/runtime/fields/image.d.ts +7 -2
  43. package/dist/runtime/fields/image.js +12 -2
  44. package/dist/runtime/fields/relation.d.ts +5 -2
  45. package/dist/runtime/fields/seo.d.ts +49 -11
  46. package/dist/runtime/fields/seo.js +63 -5
  47. package/dist/runtime/locales/en.json +41 -0
  48. package/dist/runtime/locales/index.d.ts +41 -0
  49. package/dist/runtime/pages/EponymeMediaPage.vue +13 -1
  50. package/dist/runtime/server/api/eponyme/[name].get.d.ts +3 -2
  51. package/dist/runtime/server/api/eponyme/[name].get.js +12 -2
  52. package/dist/runtime/server/api/eponyme-auth/login.post.js +3 -1
  53. package/dist/runtime/server/api/eponyme-collections/[path].get.js +10 -9
  54. package/dist/runtime/server/api/eponyme-form-export/[path].get.d.ts +6 -0
  55. package/dist/runtime/server/api/eponyme-form-export/[path].get.js +46 -0
  56. package/dist/runtime/server/api/eponyme-media/meta.get.d.ts +3 -0
  57. package/dist/runtime/server/api/eponyme-media/meta.get.js +9 -0
  58. package/dist/runtime/server/api/eponyme-media/meta.put.d.ts +6 -0
  59. package/dist/runtime/server/api/eponyme-media/meta.put.js +26 -0
  60. package/dist/runtime/server/api/eponyme-media/object.delete.js +5 -2
  61. package/dist/runtime/server/api/eponyme-referrers/[path].get.d.ts +8 -0
  62. package/dist/runtime/server/api/eponyme-referrers/[path].get.js +32 -0
  63. package/dist/runtime/server/plugins/eponyme-cdn.d.ts +15 -0
  64. package/dist/runtime/server/plugins/eponyme-cdn.js +97 -0
  65. package/dist/runtime/server/services/eponyme-form-store.d.ts +39 -3
  66. package/dist/runtime/server/services/eponyme-form-store.js +65 -4
  67. package/dist/runtime/server/services/eponyme-rate-limit-service.js +2 -1
  68. package/dist/runtime/server/services/eponyme-rate-limit-store.d.ts +14 -0
  69. package/dist/runtime/server/services/eponyme-rate-limit-store.js +35 -0
  70. package/dist/runtime/server/services/eponyme-store.d.ts +44 -0
  71. package/dist/runtime/server/services/eponyme-store.js +170 -15
  72. package/dist/runtime/server/utils/eponyme-cdn.d.ts +81 -0
  73. package/dist/runtime/server/utils/eponyme-cdn.js +164 -0
  74. package/dist/runtime/server/utils/eponyme-form-export.d.ts +21 -0
  75. package/dist/runtime/server/utils/eponyme-form-export.js +66 -0
  76. package/dist/runtime/server/utils/eponyme-media.d.ts +12 -1
  77. package/dist/runtime/server/utils/eponyme-media.js +75 -9
  78. package/dist/runtime/server/utils/eponyme-populate-route.d.ts +20 -0
  79. package/dist/runtime/server/utils/eponyme-populate-route.js +39 -0
  80. package/dist/runtime/server/utils/eponyme-read.d.ts +118 -0
  81. package/dist/runtime/server/utils/eponyme-read.js +150 -0
  82. package/dist/runtime/server/utils/rate-limit.d.ts +2 -0
  83. package/dist/runtime/server/utils/rate-limit.js +4 -0
  84. package/dist/runtime/types/cdn.d.ts +51 -0
  85. package/dist/runtime/types/cdn.js +0 -0
  86. package/dist/runtime/types/eponyme.d.ts +2 -2
  87. package/dist/runtime/types/field.d.ts +75 -9
  88. package/dist/runtime/types/hooks.d.ts +10 -0
  89. package/dist/runtime/types/index.d.ts +2 -0
  90. package/dist/runtime/types/index.js +2 -0
  91. package/dist/runtime/types/nuxt.d.ts +2 -0
  92. package/dist/runtime/types/permissions.d.ts +1 -1
  93. package/dist/runtime/types/permissions.js +1 -0
  94. package/dist/runtime/types/relations.d.ts +59 -0
  95. package/dist/runtime/types/relations.js +0 -0
  96. package/dist/runtime/types/storage.d.ts +16 -0
  97. package/dist/runtime/utils/cache-tags.d.ts +2 -0
  98. package/dist/runtime/utils/cache-tags.js +1 -1
  99. package/dist/runtime/utils/cdn-tags.d.ts +28 -0
  100. package/dist/runtime/utils/cdn-tags.js +73 -0
  101. package/dist/runtime/utils/eponyme-csv.d.ts +9 -0
  102. package/dist/runtime/utils/eponyme-csv.js +23 -0
  103. package/dist/runtime/utils/eponyme-populate.d.ts +40 -0
  104. package/dist/runtime/utils/eponyme-populate.js +74 -0
  105. package/dist/runtime/utils/eponyme-relations.d.ts +2 -0
  106. package/dist/runtime/utils/eponyme-relations.js +16 -0
  107. package/dist/runtime/utils/eponyme-seo-head.d.ts +53 -0
  108. package/dist/runtime/utils/eponyme-seo-head.js +42 -0
  109. package/dist/runtime/utils/get-field-default-value.js +3 -0
  110. package/dist/runtime/utils/hydration-cache.d.ts +1 -1
  111. package/dist/runtime/utils/image-value.d.ts +62 -0
  112. package/dist/runtime/utils/image-value.js +122 -0
  113. package/dist/runtime/utils/normalize-eponyme-values.js +2 -0
  114. package/dist/runtime/utils/populate-depth.d.ts +4 -0
  115. package/dist/runtime/utils/populate-depth.js +2 -0
  116. package/dist/runtime/utils/preview.d.ts +2 -0
  117. package/dist/runtime/utils/preview.js +3 -0
  118. package/dist/runtime/utils/serialize-eponyme-filter.d.ts +12 -0
  119. package/dist/runtime/utils/serialize-eponyme-filter.js +20 -0
  120. package/dist/runtime/utils/validate-eponyme-data.d.ts +10 -1
  121. package/dist/runtime/utils/validate-eponyme-data.js +55 -11
  122. package/dist/storage.d.mts +1 -1
  123. package/dist/types.d.mts +9 -3
  124. package/package.json +20 -14
@@ -1,12 +1,15 @@
1
1
  import { SectionSchema, FieldVisibilityCondition, SectionFieldDefinition, EponymeCustomFieldTypeDefinition } from '../dist/runtime/types/field.js';
2
2
  import { EponymeConfig, EponymeSchema, EponymeCollectionOptions, CollectionSlugField, EponymeCollectionDefinition, EponymeFormSchema, EponymeFormOptions, EponymeFormDefinition } from '../dist/runtime/types/index.js';
3
- export { ArrayFieldDefinition, ArrayFieldOptions, ArrayItemDefinition, ArrayItemFieldDefinition, ArrayItemSchema, ArrayItemValue, BooleanFieldDefinition, BooleanFieldOptions, CheckboxGroupFieldDefinition, CheckboxGroupFieldOptions, CollectionSlugField, ColorFieldDefinition, ColorFieldOptions, DateFieldDefinition, DateFieldOptions, DateTimeFieldDefinition, DateTimeFieldOptions, DurationFieldDefinition, DurationFieldOptions, DurationInput, EmailFieldDefinition, EmailFieldOptions, EponymeAuthSession, EponymeAuthUser, EponymeCacheFailureContext, EponymeCacheOperation, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeCustomFieldComponentProps, EponymeCustomFieldDefinition, EponymeCustomFieldOptions, EponymeCustomFieldTypeDefinition, EponymeCustomFieldValues, EponymeData, EponymeDataByName, EponymeEntryBeforeSaveContext, EponymeEntryContext, EponymeEntryTrashContext, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeFormSubmissionContext, EponymeHooks, EponymeManagedUserResult, EponymeName, EponymePermissionAction, EponymePermissionRule, EponymePermissionTarget, EponymeResource, EponymeResourceKind, EponymeRole, EponymeRoleDefinition, EponymeRoleDefinitions, EponymeRoleOption, EponymeSchema, EponymeSystemResource, EponymeVariableDefinition, EponymeVariableSummary, EponymeVariableValue, EponymeVariables, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, ImageSource, InferEponymeCustomFieldOptions, InferEponymeCustomFieldValue, MediaPlayerFieldDefinition, MediaPlayerFieldOptions, MediaPlayerProvider, MediaPlayerValue, NormalizedDurationFieldOptions, NumberFieldDefinition, NumberFieldOptions, RadioFieldDefinition, RadioFieldOptions, RichTextFieldDefinition, RichTextFieldOptions, SectionFieldDefinition, SectionFieldOptions, SectionItemFieldDefinition, SectionItemValue, SectionSchema, SectionValue, SelectFieldDefinition, SelectFieldOptions, SelectOption, SlugFieldDefinition, SlugFieldOptions, StringFieldDefinition, StringFieldOptions, TabDefinition, TabFieldDefinition, TabFieldOptions, TabsSchema, TabsValue, TextareaFieldDefinition, TextareaFieldOptions, TodayDateDefault, UrlFieldDefinition, UrlFieldOptions, UrlType, UrlValue } from '../dist/runtime/types/index.js';
3
+ export { ArrayFieldDefinition, ArrayFieldOptions, ArrayItemDefinition, ArrayItemFieldDefinition, ArrayItemSchema, ArrayItemValue, BooleanFieldDefinition, BooleanFieldOptions, CheckboxGroupFieldDefinition, CheckboxGroupFieldOptions, CollectionSlugField, ColorFieldDefinition, ColorFieldOptions, DateFieldDefinition, DateFieldOptions, DateTimeFieldDefinition, DateTimeFieldOptions, DurationFieldDefinition, DurationFieldOptions, DurationInput, EmailFieldDefinition, EmailFieldOptions, EponymeAuthSession, EponymeAuthUser, EponymeCacheFailureContext, EponymeCacheOperation, EponymeCdnDependency, EponymeCdnProvider, EponymeCdnPurgeContext, EponymeCdnPurgeFailedContext, EponymeCdnPurgeRequest, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeCustomFieldComponentProps, EponymeCustomFieldDefinition, EponymeCustomFieldOptions, EponymeCustomFieldTypeDefinition, EponymeCustomFieldValues, EponymeData, EponymeDataByName, EponymeEntryBeforeSaveContext, EponymeEntryContext, EponymeEntryTrashContext, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeFormSubmissionContext, EponymeHooks, EponymeImageCrop, EponymeImageFocal, EponymeImageInput, EponymeImageRatio, EponymeImageValue, EponymeManagedUserResult, EponymeName, EponymePermissionAction, EponymePermissionRule, EponymePermissionTarget, EponymeResource, EponymeResourceKind, EponymeRole, EponymeRoleDefinition, EponymeRoleDefinitions, EponymeRoleOption, EponymeSchema, EponymeSystemResource, EponymeVariableDefinition, EponymeVariableSummary, EponymeVariableValue, EponymeVariables, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, ImageSource, InferEponymeCustomFieldOptions, InferEponymeCustomFieldValue, MediaPlayerFieldDefinition, MediaPlayerFieldOptions, MediaPlayerProvider, MediaPlayerValue, NormalizedDurationFieldOptions, NumberFieldDefinition, NumberFieldOptions, RadioFieldDefinition, RadioFieldOptions, RichTextFieldDefinition, RichTextFieldOptions, SectionFieldDefinition, SectionFieldOptions, SectionItemFieldDefinition, SectionItemValue, SectionSchema, SectionValue, SelectFieldDefinition, SelectFieldOptions, SelectOption, SlugFieldDefinition, SlugFieldOptions, StringFieldDefinition, StringFieldOptions, TabDefinition, TabFieldDefinition, TabFieldOptions, TabsSchema, TabsValue, TextareaFieldDefinition, TextareaFieldOptions, TodayDateDefault, UrlFieldDefinition, UrlFieldOptions, UrlType, UrlValue } from '../dist/runtime/types/index.js';
4
4
  import { EponymeVariables } from '../dist/runtime/types/variables.js';
5
5
  export { field, toMs, today } from '../dist/runtime/fields/index.js';
6
- export { EponymeSeoDefinition, EponymeSeoValue, SeoFieldOptions, resolveEponymeSeo } from '../dist/runtime/fields/seo.js';
6
+ export { EponymeResolvedSeo, EponymeSeoDefinition, EponymeSeoValue, SeoFieldOptions, isEponymeSeoExcludedFromSitemap, resolveEponymeSeo } from '../dist/runtime/fields/seo.js';
7
+ export { EponymeSeoHead, EponymeSeoHeadOptions, buildEponymeSeoHead } from '../dist/runtime/utils/eponyme-seo-head.js';
7
8
  import { EponymeRoleDefinitions, EponymePermissionAction, EponymePermissionTarget, EponymePermissionRule } from '../dist/runtime/types/permissions.js';
8
9
  export { EPONYME_DEFAULT_ROLES, EPONYME_PERMISSION_ACTIONS, EPONYME_SYSTEM_RESOURCES } from '../dist/runtime/types/permissions.js';
9
10
  export { eponymeMediaEmbedUrl, eponymeMediaThumbnailUrl, parseEponymeMediaUrl } from '../dist/runtime/utils/media-player.js';
11
+ export { EponymeImageAttrs, EponymeImageAttrsOptions, eponymeImageAttrs, eponymeImageObjectPosition, eponymeImageSrc, parseEponymeImageRatio, toEponymeImageValue } from '../dist/runtime/utils/image-value.js';
12
+ export { EponymePopulateDepth, EponymePopulatedData, EponymeReferrer, EponymeRelationTarget, EponymeSchemaByName } from '../dist/runtime/types/relations.js';
10
13
 
11
14
  interface EponymeBlockOptions<T extends SectionSchema> {
12
15
  name: string;
package/dist/eponyme.mjs CHANGED
@@ -1,9 +1,11 @@
1
1
  import { section } from '../dist/runtime/fields/section.js';
2
2
  import { e as eponymeConfigInteger } from './shared/eponyme.BLMX8x9_.mjs';
3
3
  export { field, toMs, today } from '../dist/runtime/fields/index.js';
4
- export { resolveEponymeSeo } from '../dist/runtime/fields/seo.js';
4
+ export { isEponymeSeoExcludedFromSitemap, resolveEponymeSeo } from '../dist/runtime/fields/seo.js';
5
+ export { buildEponymeSeoHead } from '../dist/runtime/utils/eponyme-seo-head.js';
5
6
  export { EPONYME_DEFAULT_ROLES, EPONYME_PERMISSION_ACTIONS, EPONYME_SYSTEM_RESOURCES } from '../dist/runtime/types/permissions.js';
6
7
  export { eponymeMediaEmbedUrl, eponymeMediaThumbnailUrl, parseEponymeMediaUrl } from '../dist/runtime/utils/media-player.js';
8
+ export { eponymeImageAttrs, eponymeImageObjectPosition, eponymeImageSrc, parseEponymeImageRatio, toEponymeImageValue } from '../dist/runtime/utils/image-value.js';
7
9
 
8
10
  function defineBlock(block) {
9
11
  return (overrides = {}) => ({
package/dist/module.d.mts CHANGED
@@ -2,12 +2,16 @@ import * as _nuxt_schema from '@nuxt/schema';
2
2
  import { EponymeLocaleDefinition } from '../dist/runtime/locales/index.js';
3
3
  export { EponymeLocaleDefinition, EponymeMessageKey } from '../dist/runtime/locales/index.js';
4
4
  import { EponymePublicationOption } from '../dist/runtime/utils/eponyme-publication.js';
5
+ import { EponymeCdnProvider, EponymeCdnDependency } from '../dist/runtime/types/cdn.js';
5
6
  export { EponymeBlock, EponymeBlockDefinition, EponymeBlockOptions, EponymeBlockOverrides, collection, defineBlock, defineEponymeConfig, defineEponymeField, defineEponymeRoles, defineEponymeVariables, form, permission } from './eponyme.mjs';
6
7
  export { field, toMs, today } from '../dist/runtime/fields/index.js';
7
- export { EponymeSeoDefinition, EponymeSeoValue, SeoFieldOptions, resolveEponymeSeo } from '../dist/runtime/fields/seo.js';
8
+ export { EponymeResolvedSeo, EponymeSeoDefinition, EponymeSeoValue, SeoFieldOptions, isEponymeSeoExcludedFromSitemap, resolveEponymeSeo } from '../dist/runtime/fields/seo.js';
9
+ export { EponymeSeoHead, EponymeSeoHeadOptions, buildEponymeSeoHead } from '../dist/runtime/utils/eponyme-seo-head.js';
8
10
  export { EPONYME_DEFAULT_ROLES, EPONYME_PERMISSION_ACTIONS, EPONYME_SYSTEM_RESOURCES } from '../dist/runtime/types/permissions.js';
9
11
  export { eponymeMediaEmbedUrl, eponymeMediaThumbnailUrl, parseEponymeMediaUrl } from '../dist/runtime/utils/media-player.js';
10
- export { ArrayFieldDefinition, ArrayFieldOptions, ArrayItemDefinition, ArrayItemFieldDefinition, ArrayItemSchema, ArrayItemValue, BooleanFieldDefinition, BooleanFieldOptions, CheckboxGroupFieldDefinition, CheckboxGroupFieldOptions, CollectionSlugField, ColorFieldDefinition, ColorFieldOptions, DateFieldDefinition, DateFieldOptions, DateTimeFieldDefinition, DateTimeFieldOptions, DurationFieldDefinition, DurationFieldOptions, DurationInput, EmailFieldDefinition, EmailFieldOptions, EponymeAuthSession, EponymeAuthUser, EponymeCacheFailureContext, EponymeCacheOperation, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeCustomFieldComponentProps, EponymeCustomFieldDefinition, EponymeCustomFieldOptions, EponymeCustomFieldTypeDefinition, EponymeCustomFieldValues, EponymeData, EponymeDataByName, EponymeEntryBeforeSaveContext, EponymeEntryContext, EponymeEntryTrashContext, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeFormSubmissionContext, EponymeHooks, EponymeManagedUserResult, EponymeName, EponymePermissionAction, EponymePermissionRule, EponymePermissionTarget, EponymeResource, EponymeResourceKind, EponymeRole, EponymeRoleDefinition, EponymeRoleDefinitions, EponymeRoleOption, EponymeSchema, EponymeSystemResource, EponymeVariableDefinition, EponymeVariableSummary, EponymeVariableValue, EponymeVariables, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, ImageSource, InferEponymeCustomFieldOptions, InferEponymeCustomFieldValue, MediaPlayerFieldDefinition, MediaPlayerFieldOptions, MediaPlayerProvider, MediaPlayerValue, NormalizedDurationFieldOptions, NumberFieldDefinition, NumberFieldOptions, RadioFieldDefinition, RadioFieldOptions, RichTextFieldDefinition, RichTextFieldOptions, SectionFieldDefinition, SectionFieldOptions, SectionItemFieldDefinition, SectionItemValue, SectionSchema, SectionValue, SelectFieldDefinition, SelectFieldOptions, SelectOption, SlugFieldDefinition, SlugFieldOptions, StringFieldDefinition, StringFieldOptions, TabDefinition, TabFieldDefinition, TabFieldOptions, TabsSchema, TabsValue, TextareaFieldDefinition, TextareaFieldOptions, TodayDateDefault, UrlFieldDefinition, UrlFieldOptions, UrlType, UrlValue } from '../dist/runtime/types/index.js';
12
+ export { EponymeImageAttrs, EponymeImageAttrsOptions, eponymeImageAttrs, eponymeImageObjectPosition, eponymeImageSrc, parseEponymeImageRatio, toEponymeImageValue } from '../dist/runtime/utils/image-value.js';
13
+ export { ArrayFieldDefinition, ArrayFieldOptions, ArrayItemDefinition, ArrayItemFieldDefinition, ArrayItemSchema, ArrayItemValue, BooleanFieldDefinition, BooleanFieldOptions, CheckboxGroupFieldDefinition, CheckboxGroupFieldOptions, CollectionSlugField, ColorFieldDefinition, ColorFieldOptions, DateFieldDefinition, DateFieldOptions, DateTimeFieldDefinition, DateTimeFieldOptions, DurationFieldDefinition, DurationFieldOptions, DurationInput, EmailFieldDefinition, EmailFieldOptions, EponymeAuthSession, EponymeAuthUser, EponymeCacheFailureContext, EponymeCacheOperation, EponymeCdnDependency, EponymeCdnProvider, EponymeCdnPurgeContext, EponymeCdnPurgeFailedContext, EponymeCdnPurgeRequest, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeCustomFieldComponentProps, EponymeCustomFieldDefinition, EponymeCustomFieldOptions, EponymeCustomFieldTypeDefinition, EponymeCustomFieldValues, EponymeData, EponymeDataByName, EponymeEntryBeforeSaveContext, EponymeEntryContext, EponymeEntryTrashContext, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeFormSubmissionContext, EponymeHooks, EponymeImageCrop, EponymeImageFocal, EponymeImageInput, EponymeImageRatio, EponymeImageValue, EponymeManagedUserResult, EponymeName, EponymePermissionAction, EponymePermissionRule, EponymePermissionTarget, EponymeResource, EponymeResourceKind, EponymeRole, EponymeRoleDefinition, EponymeRoleDefinitions, EponymeRoleOption, EponymeSchema, EponymeSystemResource, EponymeVariableDefinition, EponymeVariableSummary, EponymeVariableValue, EponymeVariables, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, ImageSource, InferEponymeCustomFieldOptions, InferEponymeCustomFieldValue, MediaPlayerFieldDefinition, MediaPlayerFieldOptions, MediaPlayerProvider, MediaPlayerValue, NormalizedDurationFieldOptions, NumberFieldDefinition, NumberFieldOptions, RadioFieldDefinition, RadioFieldOptions, RichTextFieldDefinition, RichTextFieldOptions, SectionFieldDefinition, SectionFieldOptions, SectionItemFieldDefinition, SectionItemValue, SectionSchema, SectionValue, SelectFieldDefinition, SelectFieldOptions, SelectOption, SlugFieldDefinition, SlugFieldOptions, StringFieldDefinition, StringFieldOptions, TabDefinition, TabFieldDefinition, TabFieldOptions, TabsSchema, TabsValue, TextareaFieldDefinition, TextareaFieldOptions, TodayDateDefault, UrlFieldDefinition, UrlFieldOptions, UrlType, UrlValue } from '../dist/runtime/types/index.js';
14
+ export { EponymePopulateDepth, EponymePopulatedData, EponymeReferrer, EponymeRelationTarget, EponymeSchemaByName } from '../dist/runtime/types/relations.js';
11
15
  import '../dist/runtime/types/field.js';
12
16
  import '../dist/runtime/types/variables.js';
13
17
 
@@ -187,6 +191,16 @@ interface ModuleOptions {
187
191
  * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control
188
192
  */
189
193
  cdnCacheSeconds?: number;
194
+ /** How far a read may resolve relations with `depth`. */
195
+ relations?: {
196
+ /**
197
+ * Deepest `depth` a read may ask for, server helpers included. A deeper request is refused rather than
198
+ * silently cut short. At most 5.
199
+ *
200
+ * @default 3
201
+ */
202
+ maxDepth?: number;
203
+ };
190
204
  /**
191
205
  * Language of the dashboard interface, resolved once at build time.
192
206
  *
@@ -202,8 +216,69 @@ interface ModuleOptions {
202
216
  * ```
203
217
  */
204
218
  locale?: EponymeLocaleDefinition;
219
+ /**
220
+ * Public origin of the site, used to make canonical and sharing URLs absolute (`useEponymeSeo`). Falls
221
+ * back to `runtimeConfig.public.siteUrl`, then to the origin of the request.
222
+ *
223
+ * @example 'https://example.com'
224
+ */
225
+ siteUrl?: string;
226
+ /**
227
+ * Purges the CDN on its own when content changes: publication, unpublication, scheduling, restore,
228
+ * trash and deletion. Off unless a provider is set. Credentials are read from the environment only:
229
+ * `EPONYME_CDN_CLOUDFLARE_API_TOKEN` and `EPONYME_CDN_CLOUDFLARE_ZONE_ID` for Cloudflare, nothing for
230
+ * Vercel, which hands its purge API to the function itself.
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * cdn: {
235
+ * provider: 'vercel',
236
+ * dependencies: [
237
+ * { on: ['club'], routes: ['/**'] },
238
+ * { on: '*', routes: ['/sitemap.xml'] },
239
+ * ],
240
+ * }
241
+ * ```
242
+ */
243
+ cdn?: EponymeCdnOptions;
244
+ }
245
+ interface EponymeCdnOptions {
246
+ /** `custom` sends every purge to the `eponyme:cdn:purge` Nitro hook instead of an API. */
247
+ provider: EponymeCdnProvider;
248
+ /** Cached responses that show content without carrying its tags: layouts, listings, aggregates. */
249
+ dependencies?: EponymeCdnDependency[];
250
+ /** Tags purged on every change, whatever changed. */
251
+ alwaysPurge?: string[];
252
+ /**
253
+ * Tags public responses at request time, from `previewPaths` and `dependencies`, and on Vercel tags the
254
+ * ISR entry itself, which a response header does not do.
255
+ *
256
+ * @default true
257
+ */
258
+ tagResponses?: boolean;
259
+ /** How long a purge waits for others to merge with, in milliseconds. @default 250 */
260
+ debounceMs?: number;
261
+ /** Further attempts after a failed purge. @default 2 */
262
+ retries?: number;
263
+ /** Longest one attempt may take, in milliseconds. @default 10000 */
264
+ timeoutMs?: number;
265
+ /**
266
+ * Makes the write wait for its purge. Only useful on a serverless platform without `waitUntil`, where
267
+ * the function would otherwise stop before the purge leaves; Vercel has one.
268
+ *
269
+ * @default false
270
+ */
271
+ await?: boolean;
272
+ vercel?: {
273
+ /** `invalidate` serves the stale copy once while it regenerates; `delete` drops it. @default 'invalidate' */
274
+ mode?: 'invalidate' | 'delete';
275
+ };
276
+ cloudflare?: {
277
+ /** Not a secret, so it may be written here. `EPONYME_CDN_CLOUDFLARE_ZONE_ID` takes precedence. */
278
+ zoneId?: string;
279
+ };
205
280
  }
206
281
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
207
282
 
208
283
  export { _default as default };
209
- export type { ModuleOptions };
284
+ export type { EponymeCdnOptions, ModuleOptions };
package/dist/module.json CHANGED
@@ -4,9 +4,9 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.5.1"
6
6
  },
7
- "version": "0.9.0-nightly.20260912",
7
+ "version": "1.0.0",
8
8
  "builder": {
9
- "@nuxt/module-builder": "1.0.2",
9
+ "@nuxt/module-builder": "1.0.4",
10
10
  "unbuild": "3.6.1"
11
11
  }
12
12
  }
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { defineNuxtModule, useLogger, createResolver, addTemplate, addTypeTemplate, updateTemplates, findPath, extendViteConfig, addPlugin, addImports, addImportsDir, addComponent, addServerImports, addRouteMiddleware, addServerHandler, addServerPlugin, hasNuxtModule, hasNuxtModuleCompatibility, getNuxtModuleVersion } from '@nuxt/kit';
1
+ import { defineNuxtModule, useLogger, createResolver, addTemplate, addTypeTemplate, updateTemplates, findPath, extendViteConfig, addPlugin, addImports, addImportsDir, addComponent, hasNuxtModule, addServerImports, addRouteMiddleware, addServerHandler, addServerPlugin, hasNuxtModuleCompatibility, getNuxtModuleVersion } from '@nuxt/kit';
2
2
  import pc from 'picocolors';
3
3
  import tailwindcss from '@tailwindcss/vite';
4
4
  import { e as eponymeConfigInteger } from './shared/eponyme.BLMX8x9_.mjs';
@@ -6,6 +6,7 @@ import { EPONYME_DEFAULT_LOCALE, eponymeEnglishMessages } from '../dist/runtime/
6
6
  import { resolve } from 'pathe';
7
7
  import { tagPreviewPathRoutes } from '../dist/runtime/utils/cache-tags.js';
8
8
  import { createEponymeThemeBootstrap } from '../dist/runtime/utils/eponyme-theme.js';
9
+ import { EPONYME_DEFAULT_POPULATE_DEPTH, EPONYME_MAX_POPULATE_DEPTH } from '../dist/runtime/utils/populate-depth.js';
9
10
  import { readdir } from 'node:fs/promises';
10
11
 
11
12
  function resolveEponymeLocale(locale, prefix = "[Eponyme]") {
@@ -145,6 +146,35 @@ function positiveInteger(value, fallback, name) {
145
146
  function integerInRange(value, fallback, name, min, max) {
146
147
  return eponymeConfigInteger(name, value, { fallback, min, max, prefix: pc.red("[Eponyme]") });
147
148
  }
149
+ const CDN_PROVIDERS = ["vercel", "cloudflare", "custom"];
150
+ function resolveCdnOptions(cdn, logger) {
151
+ const provider = cdn?.provider && CDN_PROVIDERS.includes(cdn.provider) ? cdn.provider : "";
152
+ if (cdn?.provider && !provider)
153
+ logger.warn(`eponyme.cdn.provider is "${cdn.provider}", which is none of ${CDN_PROVIDERS.join(", ")}. Nothing will be purged.`);
154
+ const dependencies = (cdn?.dependencies ?? []).flatMap((dependency, index) => {
155
+ const on = dependency.on === "*" ? "*" : Array.isArray(dependency.on) ? dependency.on.filter((name) => typeof name === "string" && name) : [];
156
+ if (on !== "*" && !on.length) {
157
+ logger.warn(`eponyme.cdn.dependencies[${index}] has no \`on\`, so nothing would ever purge it. It was ignored.`);
158
+ return [];
159
+ }
160
+ const routes = (dependency.routes ?? []).filter((route) => route.startsWith("/"));
161
+ if (routes.length !== (dependency.routes ?? []).length)
162
+ logger.warn(`eponyme.cdn.dependencies[${index}].routes must start with "/". The others were ignored.`);
163
+ return [{ on, routes, tags: dependency.tags ?? [], prefixes: dependency.prefixes ?? [] }];
164
+ });
165
+ return {
166
+ provider,
167
+ dependencies,
168
+ alwaysPurge: cdn?.alwaysPurge ?? [],
169
+ debounceMs: integerInRange(cdn?.debounceMs, 250, "eponyme.cdn.debounceMs", 0, 6e4),
170
+ retries: integerInRange(cdn?.retries, 2, "eponyme.cdn.retries", 0, 10),
171
+ timeoutMs: integerInRange(cdn?.timeoutMs, 1e4, "eponyme.cdn.timeoutMs", 100, 12e4),
172
+ awaitPurge: cdn?.await === true,
173
+ tagResponses: cdn?.tagResponses !== false,
174
+ vercelMode: cdn?.vercel?.mode === "delete" ? "delete" : "invalidate",
175
+ cloudflareZoneId: cdn?.cloudflare?.zoneId ?? ""
176
+ };
177
+ }
148
178
  const module$1 = defineNuxtModule({
149
179
  meta: {
150
180
  name: "@karibsen/eponyme",
@@ -297,7 +327,8 @@ const module$1 = defineNuxtModule({
297
327
  publication: options.publication ?? true,
298
328
  storage: storageEnabled,
299
329
  storageAccept,
300
- storageMaxSize
330
+ storageMaxSize,
331
+ siteUrl: (options.siteUrl ?? "").replace(/\/+$/, "")
301
332
  };
302
333
  nuxt.options.runtimeConfig.eponymeStorage = {
303
334
  prefix: storagePrefix,
@@ -332,9 +363,11 @@ const module$1 = defineNuxtModule({
332
363
  cacheStorage: options.cacheStorage?.trim() || "",
333
364
  autoReindex: options.autoReindex ?? true,
334
365
  browserCacheSeconds: integerInRange(options.browserCacheSeconds, 30, "eponyme.browserCacheSeconds", 0, MAX_CACHE_SECONDS),
335
- cdnCacheSeconds: integerInRange(options.cdnCacheSeconds, 300, "eponyme.cdnCacheSeconds", 0, MAX_CACHE_SECONDS)
366
+ cdnCacheSeconds: integerInRange(options.cdnCacheSeconds, 300, "eponyme.cdnCacheSeconds", 0, MAX_CACHE_SECONDS),
367
+ relationsMaxDepth: integerInRange(options.relations?.maxDepth, EPONYME_DEFAULT_POPULATE_DEPTH, "eponyme.relations.maxDepth", 0, EPONYME_MAX_POPULATE_DEPTH)
336
368
  };
337
369
  nuxt.options.runtimeConfig.eponymeContent = eponymeContent;
370
+ nuxt.options.runtimeConfig.eponymeCdn = resolveCdnOptions(options.cdn, logger);
338
371
  const locale = resolveEponymeLocale(options.locale, pc.red("[Eponyme]"));
339
372
  if (locale.missing.length) {
340
373
  logger.warn(
@@ -416,10 +449,18 @@ Note that '~/' points at ${nuxt.options.srcDir}, so a server module needs '~~/'.
416
449
  { name: "field", from: resolver.resolve("./runtime/fields") },
417
450
  { name: "today", from: resolver.resolve("./runtime/fields") },
418
451
  { name: "eponymeMediaEmbedUrl", from: resolver.resolve("./runtime/utils/media-player") },
419
- { name: "eponymeMediaThumbnailUrl", from: resolver.resolve("./runtime/utils/media-player") }
452
+ { name: "eponymeMediaThumbnailUrl", from: resolver.resolve("./runtime/utils/media-player") },
453
+ { name: "eponymeImageSrc", from: resolver.resolve("./runtime/utils/image-value") }
420
454
  ]);
421
455
  addImportsDir(resolver.resolve("./runtime/composables"));
422
456
  addComponent({ name: "EponymeRichText", filePath: resolver.resolve("./runtime/components/EponymeRichText") });
457
+ nuxt.hook("modules:done", () => {
458
+ const withNuxtImage = hasNuxtModule("@nuxt/image", nuxt);
459
+ addComponent({
460
+ name: "EponymeImage",
461
+ filePath: resolver.resolve(withNuxtImage ? "./runtime/components/image/EponymeNuxtImage.vue" : "./runtime/components/image/EponymeImage.vue")
462
+ });
463
+ });
423
464
  addServerImports([
424
465
  { name: "getEponymeSitemapEntries", from: resolver.resolve("./runtime/server/utils/eponyme-sitemap") },
425
466
  { name: "reindexEponymeEntries", from: resolver.resolve("./runtime/server/utils/eponyme-reindex") },
@@ -427,7 +468,8 @@ Note that '~/' points at ${nuxt.options.srcDir}, so a server module needs '~~/'.
427
468
  { name: "validateEponymeForm", from: resolver.resolve("./runtime/server/utils/eponyme-form") },
428
469
  { name: "storeEponymeFormSubmission", from: resolver.resolve("./runtime/server/utils/eponyme-form") },
429
470
  { name: "assertEponymeFormRateLimit", from: resolver.resolve("./runtime/server/utils/eponyme-form") },
430
- { name: "getEponymeCacheTags", from: resolver.resolve("./runtime/server/utils/eponyme-cache") }
471
+ { name: "getEponymeCacheTags", from: resolver.resolve("./runtime/server/utils/eponyme-cache") },
472
+ ...["getEponymeEntry", "getEponymeSingleton", "queryEponymeCollection", "getEponymeReferrers"].map((name) => ({ name, from: resolver.resolve("./runtime/server/utils/eponyme-read") }))
431
473
  ]);
432
474
  addRouteMiddleware({
433
475
  name: "eponyme-auth",
@@ -500,6 +542,8 @@ declare module '#eponyme/storage' {
500
542
  addServerHandler({ route: "/api/eponyme-forms/**", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].get") });
501
543
  addServerHandler({ route: "/api/eponyme-forms/**", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].post") });
502
544
  addServerHandler({ route: "/api/eponyme-forms/**", method: "delete", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].delete") });
545
+ addServerHandler({ route: "/api/eponyme-form-export/**", handler: resolver.resolve("./runtime/server/api/eponyme-form-export/[path].get") });
546
+ addServerHandler({ route: "/api/eponyme-referrers/**", handler: resolver.resolve("./runtime/server/api/eponyme-referrers/[path].get") });
503
547
  addServerHandler({ route: "/api/eponyme-auth/session", handler: resolver.resolve("./runtime/server/api/eponyme-auth/session.get") });
504
548
  addServerHandler({ route: "/api/eponyme-auth/login", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-auth/login.post") });
505
549
  addServerHandler({ route: "/api/eponyme-auth/logout", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-auth/logout.post") });
@@ -518,10 +562,13 @@ declare module '#eponyme/storage' {
518
562
  addServerHandler({ route: "/api/eponyme-media/object", method: "put", handler: resolver.resolve("./runtime/server/api/eponyme-media/object.put") });
519
563
  addServerHandler({ route: "/api/eponyme-media/object", method: "delete", handler: resolver.resolve("./runtime/server/api/eponyme-media/object.delete") });
520
564
  addServerHandler({ route: "/api/eponyme-media/raw/**", handler: resolver.resolve("./runtime/server/api/eponyme-media/raw/[path].get") });
565
+ addServerHandler({ route: "/api/eponyme-media/meta", method: "get", handler: resolver.resolve("./runtime/server/api/eponyme-media/meta.get") });
566
+ addServerHandler({ route: "/api/eponyme-media/meta", method: "put", handler: resolver.resolve("./runtime/server/api/eponyme-media/meta.put") });
521
567
  logger.info(`Storage enabled from ${storagePath}, media library at ${dashboardPath}/media.`);
522
568
  }
523
569
  addServerPlugin(resolver.resolve("./runtime/server/plugins/eponyme-sync"));
524
570
  addServerPlugin(resolver.resolve("./runtime/server/plugins/eponyme-role-registry"));
571
+ if (options.cdn?.provider) addServerPlugin(resolver.resolve("./runtime/server/plugins/eponyme-cdn"));
525
572
  if (!process.env.EPONYME_CRON_SECRET) {
526
573
  logger.info(
527
574
  "Audit retention is a scheduled route: set EPONYME_CRON_SECRET and call /api/eponyme-audit/prune with it as a bearer token. Until then, audit events are kept for ever."
@@ -13,6 +13,7 @@ import EPButton from "../ui/EPButton.vue";
13
13
  import EPCheckbox from "../ui/EPCheckbox.vue";
14
14
  import EPDialog from "../ui/EPDialog.vue";
15
15
  import EPInputText from "../ui/EPInputText.vue";
16
+ import EPRadioButton from "../ui/EPRadioButton.vue";
16
17
  import { EPONYME_DATE_LOCALE } from "../../utils/date-locale";
17
18
  const props = defineProps({
18
19
  name: { type: String, required: true },
@@ -22,6 +23,7 @@ const requestFetch = useRequestFetch();
22
23
  const auth = useEponymeAuth();
23
24
  const formResource = computed(() => ({ kind: "form", name: props.name }));
24
25
  const canDelete = computed(() => auth.can("submissions.delete", formResource.value));
26
+ const canExport = computed(() => auth.can("submissions.export", formResource.value));
25
27
  const collects = computed(() => props.definition.submission.store);
26
28
  const page = ref(1);
27
29
  const search = ref("");
@@ -33,6 +35,22 @@ const submissionAction = ref();
33
35
  const submissionActionPending = ref(false);
34
36
  const submissionActionError = ref("");
35
37
  const label = computed(() => props.definition.label || humanizeLabel(props.name.split("/").at(-1) || props.name));
38
+ const exportOpen = ref(false);
39
+ const exportFrom = ref("");
40
+ const exportTo = ref("");
41
+ const exportFormat = ref("csv");
42
+ const exportFormats = [
43
+ { label: t("submissions.exportCsv"), value: "csv" },
44
+ { label: t("submissions.exportJson"), value: "json" }
45
+ ];
46
+ const exportRangeInvalid = computed(() => Boolean(exportFrom.value && exportTo.value && exportFrom.value > exportTo.value));
47
+ const exportUrl = computed(() => {
48
+ const query = new URLSearchParams({ format: exportFormat.value });
49
+ if (exportFrom.value) query.set("from", exportFrom.value);
50
+ if (exportTo.value) query.set("to", exportTo.value);
51
+ if (debouncedSearch.value.trim()) query.set("search", debouncedSearch.value.trim());
52
+ return `/api/eponyme-form-export/${props.name}?${query}`;
53
+ });
36
54
  const hasSubmissions = ref(false);
37
55
  const { data: response, pending, refresh } = useAsyncData(
38
56
  () => `eponyme:form:${props.name}`,
@@ -223,6 +241,14 @@ async function confirmSubmissionAction() {
223
241
  <EPBadge :variant="collects ? 'managed' : 'neutral'">
224
242
  {{ t(definition.submission.mode === "managed" ? "submissions.modeManaged" : "submissions.modeCustom") }}
225
243
  </EPBadge>
244
+ <EPButton
245
+ v-if="collects && canExport && (hasSubmissions || total > 0)"
246
+ size="sm"
247
+ icon="mingcute:download-2-line"
248
+ @click="exportOpen = true"
249
+ >
250
+ {{ t("submissions.export") }}
251
+ </EPButton>
226
252
  <EPButton
227
253
  v-if="collects && canDelete && total > 0"
228
254
  size="sm"
@@ -447,6 +473,74 @@ async function confirmSubmissionAction() {
447
473
  </dl>
448
474
  </EPDialog>
449
475
 
476
+ <EPDialog
477
+ :open="exportOpen"
478
+ :title="t('submissions.exportTitle')"
479
+ :description="t('submissions.exportDescription')"
480
+ @update:open="(value) => exportOpen = value"
481
+ >
482
+ <form
483
+ class="ep:grid ep:gap-4"
484
+ @submit.prevent
485
+ >
486
+ <div class="ep:grid ep:gap-3 ep:sm:grid-cols-2">
487
+ <label class="ep:grid ep:gap-1 ep:text-xs ep:font-medium ep:text-text-muted">
488
+ {{ t("submissions.exportFrom") }}
489
+ <EPInputText
490
+ v-model="exportFrom"
491
+ type="date"
492
+ size="sm"
493
+ />
494
+ </label>
495
+ <label class="ep:grid ep:gap-1 ep:text-xs ep:font-medium ep:text-text-muted">
496
+ {{ t("submissions.exportTo") }}
497
+ <EPInputText
498
+ v-model="exportTo"
499
+ type="date"
500
+ size="sm"
501
+ :invalid="exportRangeInvalid"
502
+ />
503
+ </label>
504
+ </div>
505
+ <fieldset class="ep:m-0 ep:grid ep:gap-2 ep:border-0 ep:p-0">
506
+ <legend class="ep:mb-1 ep:p-0 ep:text-xs ep:font-medium ep:text-text-muted">
507
+ {{ t("submissions.exportFormat") }}
508
+ </legend>
509
+ <EPRadioButton
510
+ v-model="exportFormat"
511
+ :options="exportFormats"
512
+ />
513
+ </fieldset>
514
+ <p
515
+ v-if="debouncedSearch.trim()"
516
+ class="ep:m-0 ep:text-xs ep:text-text-muted"
517
+ >
518
+ {{ t("submissions.exportSearch", { query: debouncedSearch.trim() }) }}
519
+ </p>
520
+ <p
521
+ v-if="exportRangeInvalid"
522
+ role="alert"
523
+ class="ep:m-0 ep:rounded-lg ep:bg-danger/10 ep:p-3 ep:text-sm ep:text-danger"
524
+ >
525
+ {{ t("submissions.exportInvalidRange") }}
526
+ </p>
527
+ <a
528
+ v-else
529
+ :href="exportUrl"
530
+ download
531
+ class="ep:inline-flex ep:h-10 ep:items-center ep:justify-center ep:gap-2 ep:justify-self-start ep:rounded-lg ep:border ep:border-contrast/80 ep:bg-contrast ep:px-5 ep:text-sm ep:font-medium ep:text-surface-raised ep:no-underline ep:hover:bg-text-default ep:focus-visible:outline-none ep:focus-visible:ring-2 ep:focus-visible:ring-contrast/30"
532
+ @click="exportOpen = false"
533
+ >
534
+ <Icon
535
+ name="mingcute:download-2-line"
536
+ size="16"
537
+ aria-hidden="true"
538
+ />
539
+ {{ t("submissions.exportDownload") }}
540
+ </a>
541
+ </form>
542
+ </EPDialog>
543
+
450
544
  <EPAlertDialog
451
545
  :open="Boolean(submissionAction)"
452
546
  :label="submissionAction ? t(actionCopy.title) : ''"
@@ -7,6 +7,7 @@ import DateField from "./DateField.vue";
7
7
  import DateTimeField from "./DateTimeField.vue";
8
8
  import DurationField from "./DurationField.vue";
9
9
  import FileField from "./FileField.vue";
10
+ import ImageField from "./ImageField.vue";
10
11
  import MediaPlayerField from "./MediaPlayerField.vue";
11
12
  import NumberField from "./NumberField.vue";
12
13
  import PhoneField from "./PhoneField.vue";
@@ -74,8 +75,9 @@ const component = computed(() => {
74
75
  case "duration":
75
76
  return DurationField;
76
77
  case "file":
77
- case "image":
78
78
  return FileField;
79
+ case "image":
80
+ return ImageField;
79
81
  case "color":
80
82
  return ColorField;
81
83
  case "relation":
@@ -136,13 +138,24 @@ const specificProps = computed(() => {
136
138
  case "boolean":
137
139
  return {};
138
140
  case "file":
141
+ return {
142
+ placeholder: field.options.placeholder,
143
+ accept: field.options.accept,
144
+ maxSize: field.options.maxSize
145
+ };
139
146
  case "image":
140
147
  return {
141
148
  placeholder: field.options.placeholder,
142
149
  accept: field.options.accept,
143
150
  maxSize: field.options.maxSize,
144
- preview: field.type === "image",
145
- sources: field.type === "image" ? field.options.sources : void 0
151
+ sources: field.options.sources,
152
+ requireAlt: field.options.requireAlt,
153
+ caption: field.options.caption,
154
+ focal: field.options.focal ?? true,
155
+ // A definition written by hand, without `field.image()`, has no normalised list.
156
+ crops: (field.options.crops ?? []).map((crop) => typeof crop === "object" ? crop : { ratio: crop }),
157
+ minWidth: field.options.minWidth,
158
+ minHeight: field.options.minHeight
146
159
  };
147
160
  case "color":
148
161
  return { presets: field.options.presets, allowCustom: field.options.allowCustom };
@@ -0,0 +1,27 @@
1
+ import type { EponymeImageCrop, EponymeImageValue, ImageSource } from '../../types/field.js';
2
+ type __VLS_Props = {
3
+ id: string;
4
+ modelValue?: unknown;
5
+ label: string;
6
+ description?: string;
7
+ required?: boolean;
8
+ placeholder?: string;
9
+ accept?: string[];
10
+ maxSize?: number;
11
+ sources?: readonly ImageSource[];
12
+ requireAlt?: boolean;
13
+ caption?: boolean;
14
+ focal?: boolean;
15
+ crops?: readonly EponymeImageCrop[];
16
+ minWidth?: number;
17
+ minHeight?: number;
18
+ errors?: string[];
19
+ disabled?: boolean;
20
+ };
21
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
22
+ "update:modelValue": (value: EponymeImageValue | null) => any;
23
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
24
+ "onUpdate:modelValue"?: ((value: EponymeImageValue | null) => any) | undefined;
25
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
26
+ declare const _default: typeof __VLS_export;
27
+ export default _default;