@karibsen/eponyme 0.8.13 → 0.9.0-nightly.20260808
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 +89 -7
- package/dist/eponyme.d.mts +2 -2
- package/dist/eponyme.mjs +20 -3
- package/dist/module.d.mts +79 -5
- package/dist/module.json +1 -1
- package/dist/module.mjs +94 -2
- package/dist/runtime/assets/dashboard.css +1 -1
- package/dist/runtime/assets.d.ts +2 -0
- package/dist/runtime/components/EponymeRichText.d.ts +40 -0
- package/dist/runtime/components/EponymeRichText.js +11 -0
- package/dist/runtime/components/editor/EponymeCollectionPage.vue +76 -30
- package/dist/runtime/components/editor/EponymeCopy.vue +3 -2
- package/dist/runtime/components/editor/EponymeFolderNav.vue +5 -4
- package/dist/runtime/components/editor/EponymeFolderPage.vue +6 -8
- package/dist/runtime/components/editor/EponymeForm.vue +378 -36
- package/dist/runtime/components/editor/EponymeFormPage.vue +82 -40
- package/dist/runtime/components/editor/EponymeHistoryDialog.vue +54 -21
- package/dist/runtime/components/editor/EponymeNavigationLink.vue +3 -2
- package/dist/runtime/components/editor/EponymePageNavigation.vue +4 -3
- package/dist/runtime/components/editor/EponymePreviewPanel.vue +12 -11
- package/dist/runtime/components/editor/EponymeSidebar.vue +16 -15
- package/dist/runtime/components/editor/EponymeSidebarTree.vue +3 -2
- package/dist/runtime/components/fields/ArrayField.vue +39 -10
- package/dist/runtime/components/fields/DateTimeField.d.vue.ts +18 -0
- package/dist/runtime/components/fields/DateTimeField.vue +64 -0
- package/dist/runtime/components/fields/DateTimeField.vue.d.ts +18 -0
- package/dist/runtime/components/fields/DurationField.d.vue.ts +18 -0
- package/dist/runtime/components/fields/DurationField.vue +103 -0
- package/dist/runtime/components/fields/DurationField.vue.d.ts +18 -0
- package/dist/runtime/components/fields/FieldRenderer.vue +12 -1
- package/dist/runtime/components/fields/MediaPlayerField.vue +6 -5
- package/dist/runtime/components/fields/NumberField.d.vue.ts +2 -0
- package/dist/runtime/components/fields/NumberField.vue +40 -13
- package/dist/runtime/components/fields/NumberField.vue.d.ts +2 -0
- package/dist/runtime/components/fields/RichTextField.vue +47 -28
- package/dist/runtime/components/fields/SectionField.d.vue.ts +1 -0
- package/dist/runtime/components/fields/SectionField.vue +2 -1
- package/dist/runtime/components/fields/SectionField.vue.d.ts +1 -0
- package/dist/runtime/components/fields/TabsField.vue +2 -1
- package/dist/runtime/components/ui/EPAccordion.vue +2 -1
- package/dist/runtime/components/ui/EPAlertDialog.vue +15 -6
- package/dist/runtime/components/ui/EPAvatar.d.vue.ts +1 -0
- package/dist/runtime/components/ui/EPAvatar.vue +10 -4
- package/dist/runtime/components/ui/EPAvatar.vue.d.ts +1 -0
- package/dist/runtime/components/ui/EPColorPicker.vue +4 -3
- package/dist/runtime/components/ui/EPDialog.vue +3 -2
- package/dist/runtime/components/ui/EPImageDialog.d.vue.ts +20 -0
- package/dist/runtime/components/ui/EPImageDialog.vue +114 -0
- package/dist/runtime/components/ui/EPImageDialog.vue.d.ts +20 -0
- package/dist/runtime/components/ui/EPInputPassword.d.vue.ts +12 -0
- package/dist/runtime/components/ui/EPInputPassword.vue +41 -0
- package/dist/runtime/components/ui/EPInputPassword.vue.d.ts +12 -0
- package/dist/runtime/components/ui/EPInputText.d.vue.ts +4 -2
- package/dist/runtime/components/ui/EPInputText.vue +14 -5
- package/dist/runtime/components/ui/EPInputText.vue.d.ts +4 -2
- package/dist/runtime/components/ui/EPLinkDialog.vue +15 -14
- package/dist/runtime/components/ui/EPLinkEditor.vue +7 -6
- package/dist/runtime/components/ui/EPMediaPreview.vue +2 -1
- package/dist/runtime/components/ui/EPSelect.vue +97 -35
- package/dist/runtime/components/ui/EPSlider.d.vue.ts +2 -0
- package/dist/runtime/components/ui/EPSlider.vue +3 -1
- package/dist/runtime/components/ui/EPSlider.vue.d.ts +2 -0
- package/dist/runtime/components/ui/EPTagsInput.vue +2 -1
- package/dist/runtime/components/ui/EPToast.vue +3 -2
- package/dist/runtime/components/ui/EPTooltip.vue +1 -1
- package/dist/runtime/composables/useEponyme.d.ts +4 -2
- package/dist/runtime/composables/useEponyme.js +7 -3
- package/dist/runtime/fields/datetime.d.ts +2 -0
- package/dist/runtime/fields/datetime.js +18 -0
- package/dist/runtime/fields/duration.d.ts +2 -0
- package/dist/runtime/fields/duration.js +16 -0
- package/dist/runtime/fields/index.d.ts +7 -0
- package/dist/runtime/fields/index.js +5 -1
- package/dist/runtime/fields/money.d.ts +160 -0
- package/dist/runtime/fields/money.js +39 -0
- package/dist/runtime/locales/en.json +408 -0
- package/dist/runtime/locales/fallback.d.ts +9 -0
- package/dist/runtime/locales/fallback.js +4 -0
- package/dist/runtime/locales/index.d.ts +441 -0
- package/dist/runtime/locales/index.js +6 -0
- package/dist/runtime/middleware/eponyme-auth.d.ts +1 -1
- package/dist/runtime/middleware/eponyme-owner.d.ts +1 -1
- package/dist/runtime/pages/EponymeChangePasswordPage.d.vue.ts +1 -0
- package/dist/runtime/pages/EponymeChangePasswordPage.vue +18 -19
- package/dist/runtime/pages/EponymeChangePasswordPage.vue.d.ts +1 -0
- package/dist/runtime/pages/EponymeDetailPage.d.vue.ts +1 -0
- package/dist/runtime/pages/EponymeDetailPage.vue +4 -2
- package/dist/runtime/pages/EponymeDetailPage.vue.d.ts +1 -0
- package/dist/runtime/pages/EponymeIndexPage.d.vue.ts +1 -0
- package/dist/runtime/pages/EponymeIndexPage.vue +24 -22
- package/dist/runtime/pages/EponymeIndexPage.vue.d.ts +1 -0
- package/dist/runtime/pages/EponymeLoginPage.d.vue.ts +1 -0
- package/dist/runtime/pages/EponymeLoginPage.vue +12 -10
- package/dist/runtime/pages/EponymeLoginPage.vue.d.ts +1 -0
- package/dist/runtime/pages/EponymeUsersPage.d.vue.ts +1 -0
- package/dist/runtime/pages/EponymeUsersPage.vue +75 -38
- package/dist/runtime/pages/EponymeUsersPage.vue.d.ts +1 -0
- package/dist/runtime/plugins/eponyme-theme.d.ts +2 -0
- package/dist/runtime/plugins/eponyme-theme.js +17 -0
- package/dist/runtime/server/api/eponyme/[name].get.d.ts +2 -0
- package/dist/runtime/server/api/eponyme/[name].get.js +4 -3
- package/dist/runtime/server/api/eponyme/[name].patch.js +31 -8
- package/dist/runtime/server/api/eponyme-auth/change-password.post.js +5 -3
- package/dist/runtime/server/api/eponyme-auth/login.post.js +19 -4
- package/dist/runtime/server/api/eponyme-collections/[path].delete.js +2 -1
- package/dist/runtime/server/api/eponyme-collections/[path].get.js +14 -8
- package/dist/runtime/server/api/eponyme-collections/[path].post.js +5 -3
- package/dist/runtime/server/api/eponyme-forms/[path].delete.js +4 -3
- package/dist/runtime/server/api/eponyme-forms/[path].get.js +4 -3
- package/dist/runtime/server/api/eponyme-forms/[path].post.js +8 -9
- package/dist/runtime/server/api/eponyme-history/[path].get.js +2 -1
- package/dist/runtime/server/api/eponyme-history/[path].patch.js +6 -3
- package/dist/runtime/server/api/eponyme-import.post.js +6 -9
- package/dist/runtime/server/api/eponyme-trash/[path].delete.js +2 -1
- package/dist/runtime/server/api/eponyme-trash/[path].get.js +3 -2
- package/dist/runtime/server/api/eponyme-trash/[path].patch.js +2 -1
- package/dist/runtime/server/api/eponyme-users/[id]/reset-password.post.js +2 -1
- package/dist/runtime/server/api/eponyme-users/[id].patch.js +5 -3
- package/dist/runtime/server/api/eponyme-users/index.post.js +5 -3
- package/dist/runtime/server/plugins/eponyme-sync.js +18 -0
- package/dist/runtime/server/services/eponyme-auth-store.d.ts +1 -2
- package/dist/runtime/server/services/eponyme-auth-store.js +16 -32
- package/dist/runtime/server/services/eponyme-cache-store.d.ts +65 -0
- package/dist/runtime/server/services/eponyme-cache-store.js +68 -0
- package/dist/runtime/server/services/eponyme-form-store.d.ts +25 -2
- package/dist/runtime/server/services/eponyme-form-store.js +45 -3
- package/dist/runtime/server/services/eponyme-rate-limit-service.d.ts +2 -0
- package/dist/runtime/server/services/eponyme-rate-limit-service.js +27 -0
- package/dist/runtime/server/services/eponyme-rate-limit-store.d.ts +103 -0
- package/dist/runtime/server/services/eponyme-rate-limit-store.js +70 -0
- package/dist/runtime/server/services/eponyme-service.js +4 -2
- package/dist/runtime/server/services/eponyme-store.d.ts +72 -16
- package/dist/runtime/server/services/eponyme-store.js +275 -76
- package/dist/runtime/server/utils/auth.js +5 -4
- package/dist/runtime/server/utils/body.d.ts +5 -0
- package/dist/runtime/server/utils/body.js +50 -0
- package/dist/runtime/server/utils/eponyme-cache.d.ts +3 -2
- package/dist/runtime/server/utils/eponyme-form.d.ts +34 -0
- package/dist/runtime/server/utils/eponyme-form.js +18 -0
- package/dist/runtime/server/utils/eponyme-hooks.js +2 -1
- package/dist/runtime/server/utils/eponyme-schedule.d.ts +7 -0
- package/dist/runtime/server/utils/eponyme-schedule.js +23 -0
- package/dist/runtime/server/utils/eponyme-variables.d.ts +3 -0
- package/dist/runtime/server/utils/eponyme-variables.js +4 -1
- package/dist/runtime/server/utils/rate-limit.d.ts +27 -0
- package/dist/runtime/server/utils/rate-limit.js +25 -0
- package/dist/runtime/types/eponyme-config.d.ts +8 -0
- package/dist/runtime/types/eponyme.d.ts +19 -7
- package/dist/runtime/types/field.d.ts +35 -4
- package/dist/runtime/types/hooks.d.ts +8 -0
- package/dist/runtime/types/nuxt.d.ts +8 -0
- package/dist/runtime/utils/date-locale.d.ts +9 -7
- package/dist/runtime/utils/date-locale.js +2 -1
- package/dist/runtime/utils/datetime.d.ts +4 -0
- package/dist/runtime/utils/datetime.js +35 -0
- package/dist/runtime/utils/duration.d.ts +11 -0
- package/dist/runtime/utils/duration.js +50 -0
- package/dist/runtime/utils/eponyme-entry-index.js +2 -2
- package/dist/runtime/utils/eponyme-theme.d.ts +6 -0
- package/dist/runtime/utils/eponyme-theme.js +6 -0
- package/dist/runtime/utils/get-eponyme-schemas.js +8 -3
- package/dist/runtime/utils/get-field-default-value.js +1 -0
- package/dist/runtime/utils/normalize-eponyme-values.d.ts +2 -2
- package/dist/runtime/utils/normalize-eponyme-values.js +7 -2
- package/dist/runtime/utils/rich-text-fields.d.ts +12 -0
- package/dist/runtime/utils/rich-text-fields.js +48 -0
- package/dist/runtime/utils/sanitize-rich-text.d.ts +20 -0
- package/dist/runtime/utils/sanitize-rich-text.js +81 -0
- package/dist/runtime/utils/translate.d.ts +18 -0
- package/dist/runtime/utils/translate.js +23 -0
- package/dist/runtime/utils/validate-eponyme-data.js +85 -65
- package/dist/runtime/utils/variables.d.ts +12 -0
- package/dist/runtime/utils/variables.js +16 -2
- package/dist/types.d.mts +4 -2
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -226,6 +226,43 @@ A phone field is also allowed in a public `form()`.
|
|
|
226
226
|
|
|
227
227
|
Eponyme uses the Prisma client owned by your application. It does not create the connection or run migrations.
|
|
228
228
|
|
|
229
|
+
Install Prisma 7 and its PostgreSQL driver adapter:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
pnpm add @prisma/client@latest @prisma/adapter-pg@latest
|
|
233
|
+
pnpm add --save-dev prisma@latest dotenv@latest
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Generate the client outside `node_modules` and keep the connection URL in Prisma Config:
|
|
237
|
+
|
|
238
|
+
```prisma
|
|
239
|
+
// prisma/schema.prisma
|
|
240
|
+
generator client {
|
|
241
|
+
provider = "prisma-client"
|
|
242
|
+
output = "../generated/prisma"
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
datasource db {
|
|
246
|
+
provider = "postgresql"
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
// prisma.config.ts
|
|
252
|
+
import 'dotenv/config'
|
|
253
|
+
import { defineConfig, env } from 'prisma/config'
|
|
254
|
+
|
|
255
|
+
export default defineConfig({
|
|
256
|
+
schema: 'prisma/schema.prisma',
|
|
257
|
+
migrations: {
|
|
258
|
+
path: 'prisma/migrations',
|
|
259
|
+
},
|
|
260
|
+
datasource: {
|
|
261
|
+
url: env('DATABASE_URL'),
|
|
262
|
+
},
|
|
263
|
+
})
|
|
264
|
+
```
|
|
265
|
+
|
|
229
266
|
Export an initialized client from the path configured in `nuxt.config.ts`. Note the
|
|
230
267
|
double tilde: `~~/` points at the project root, where `server/` lives, while `~/` points
|
|
231
268
|
at the source directory (`app/` in Nuxt 4). A relative path such as
|
|
@@ -233,14 +270,44 @@ at the source directory (`app/` in Nuxt 4). A relative path such as
|
|
|
233
270
|
|
|
234
271
|
```ts
|
|
235
272
|
// server/utils/prisma.ts
|
|
236
|
-
import {
|
|
273
|
+
import { PrismaPg } from '@prisma/adapter-pg'
|
|
274
|
+
import { PrismaClient } from '../../generated/prisma/client'
|
|
275
|
+
|
|
276
|
+
const prismaGlobal = globalThis as typeof globalThis & { prisma?: PrismaClient }
|
|
277
|
+
|
|
278
|
+
function createPrismaClient() {
|
|
279
|
+
const connectionString = process.env.DATABASE_URL
|
|
237
280
|
|
|
238
|
-
|
|
281
|
+
if (!connectionString)
|
|
282
|
+
throw new Error('DATABASE_URL is required to initialise Prisma.')
|
|
283
|
+
|
|
284
|
+
return new PrismaClient({
|
|
285
|
+
adapter: new PrismaPg({ connectionString }),
|
|
286
|
+
})
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const prisma = prismaGlobal.prisma ?? createPrismaClient()
|
|
290
|
+
|
|
291
|
+
if (process.env.NODE_ENV !== 'production')
|
|
292
|
+
prismaGlobal.prisma = prisma
|
|
239
293
|
|
|
240
294
|
export default prisma
|
|
241
295
|
```
|
|
242
296
|
|
|
243
|
-
|
|
297
|
+
Install the published Eponyme CLI, then let it add the required models and immutable migration
|
|
298
|
+
history to your application:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
pnpm add --save-dev @eponyme/cli
|
|
302
|
+
pnpm exec eponyme init
|
|
303
|
+
pnpm prisma migrate deploy
|
|
304
|
+
pnpm prisma generate
|
|
305
|
+
pnpm exec eponyme check --client server/utils/prisma.ts
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
`eponyme init` only writes the host Prisma schema and migration files; it never connects to the
|
|
309
|
+
database. `eponyme check` is read-only and verifies the generated PrismaClient, PostgreSQL tables,
|
|
310
|
+
columns and the Eponyme schema version. The generated models are shown below for reference:
|
|
244
311
|
|
|
245
312
|
```prisma
|
|
246
313
|
model Eponyme {
|
|
@@ -344,12 +411,27 @@ model EponymeFormSubmission {
|
|
|
344
411
|
@@index([formName, createdAt])
|
|
345
412
|
@@map("eponyme_form_submissions")
|
|
346
413
|
}
|
|
347
|
-
```
|
|
348
414
|
|
|
349
|
-
|
|
415
|
+
model EponymeRateLimit {
|
|
416
|
+
key String @id
|
|
417
|
+
count Int
|
|
418
|
+
expiresAt DateTime
|
|
419
|
+
|
|
420
|
+
@@index([expiresAt])
|
|
421
|
+
@@map("eponyme_rate_limits")
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
model EponymeSchema {
|
|
425
|
+
key String @id @default("eponyme")
|
|
426
|
+
version Int
|
|
427
|
+
updatedAt DateTime @updatedAt
|
|
428
|
+
|
|
429
|
+
@@map("_eponyme_schema")
|
|
430
|
+
}
|
|
431
|
+
```
|
|
350
432
|
|
|
351
|
-
|
|
352
|
-
|
|
433
|
+
Keep the generated migrations in source control. On an upgrade, run `eponyme init` again, inspect
|
|
434
|
+
the newly copied migrations, deploy them, regenerate Prisma and finish with `eponyme check`.
|
|
353
435
|
|
|
354
436
|
The playground includes the same models in `playground/prisma/schema.prisma`. Copy `playground/.env.example` to `playground/.env`, set `DATABASE_URL`, then run:
|
|
355
437
|
|
package/dist/eponyme.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EponymeConfig, EponymeSchema, EponymeCollectionOptions, CollectionSlugField, EponymeCollectionDefinition, EponymeFormSchema, EponymeFormOptions, EponymeFormDefinition } from '../dist/runtime/types/index.js';
|
|
2
|
-
export { ArrayFieldDefinition, ArrayFieldOptions, ArrayItemDefinition, ArrayItemFieldDefinition, ArrayItemSchema, ArrayItemValue, BooleanFieldDefinition, BooleanFieldOptions, CheckboxGroupFieldDefinition, CheckboxGroupFieldOptions, CollectionSlugField, ColorFieldDefinition, ColorFieldOptions, DateFieldDefinition, DateFieldOptions, EmailFieldDefinition, EmailFieldOptions, EponymeAuthSession, EponymeAuthUser, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeData, EponymeDataByName, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeManagedUserResult, EponymeName, EponymeRole, EponymeSchema, EponymeVariableDefinition, EponymeVariableSummary, EponymeVariableValue, EponymeVariables, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, MediaPlayerFieldDefinition, MediaPlayerFieldOptions, MediaPlayerProvider, MediaPlayerValue, 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';
|
|
2
|
+
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, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeData, EponymeDataByName, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeManagedUserResult, EponymeName, EponymeRole, EponymeSchema, EponymeVariableDefinition, EponymeVariableSummary, EponymeVariableValue, EponymeVariables, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, 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
3
|
import { EponymeVariables } from '../dist/runtime/types/variables.js';
|
|
4
|
-
export { field, today } from '../dist/runtime/fields/index.js';
|
|
4
|
+
export { field, toMs, today } from '../dist/runtime/fields/index.js';
|
|
5
5
|
export { EPONYME_ROLES, canEditEponyme, isEponymeRole } from '../dist/runtime/types/auth.js';
|
|
6
6
|
export { eponymeMediaEmbedUrl, eponymeMediaThumbnailUrl, parseEponymeMediaUrl } from '../dist/runtime/utils/media-player.js';
|
|
7
7
|
|
package/dist/eponyme.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { field, today } from '../dist/runtime/fields/index.js';
|
|
1
|
+
export { field, toMs, today } from '../dist/runtime/fields/index.js';
|
|
2
2
|
export { EPONYME_ROLES, canEditEponyme, isEponymeRole } from '../dist/runtime/types/auth.js';
|
|
3
3
|
export { eponymeMediaEmbedUrl, eponymeMediaThumbnailUrl, parseEponymeMediaUrl } from '../dist/runtime/utils/media-player.js';
|
|
4
4
|
|
|
@@ -15,14 +15,19 @@ function collection(options) {
|
|
|
15
15
|
const PUBLIC_FIELD_TYPES = ["string", "textarea", "email", "phone", "url", "number", "boolean", "select", "radio", "checkboxGroup"];
|
|
16
16
|
const DEFAULT_HONEYPOT = "_eponyme_hp";
|
|
17
17
|
const DEFAULT_MAX_BODY_BYTES = 64 * 1024;
|
|
18
|
+
const DEFAULT_MAX_STORED_SUBMISSIONS = 1e4;
|
|
19
|
+
const DEFAULT_RETENTION_DAYS = 365;
|
|
18
20
|
function form(options) {
|
|
19
21
|
for (const [name, definition] of Object.entries(options.fields)) {
|
|
20
22
|
const type = definition.type;
|
|
21
23
|
if (!PUBLIC_FIELD_TYPES.includes(type))
|
|
22
24
|
throw new TypeError(`[Eponyme] Form field "${name}" uses field.${type}(), which is not available in a public form. Use one of: ${PUBLIC_FIELD_TYPES.join(", ")}.`);
|
|
23
25
|
}
|
|
26
|
+
const mode = options.submission?.mode ?? "custom";
|
|
27
|
+
const maxStored = positiveIntegerOrFalse(options.submission?.maxStored, DEFAULT_MAX_STORED_SUBMISSIONS, "submission.maxStored");
|
|
28
|
+
const retentionDays = positiveIntegerOrFalse(options.submission?.retentionDays, DEFAULT_RETENTION_DAYS, "submission.retentionDays");
|
|
24
29
|
const honeypot = options.honeypot === void 0 ? DEFAULT_HONEYPOT : options.honeypot;
|
|
25
|
-
if (honeypot &&
|
|
30
|
+
if (honeypot && Object.hasOwn(options.fields, honeypot))
|
|
26
31
|
throw new TypeError(`[Eponyme] Form honeypot "${honeypot}" collides with a declared field. Rename the field or set another honeypot.`);
|
|
27
32
|
return {
|
|
28
33
|
__eponymeForm: true,
|
|
@@ -30,11 +35,23 @@ function form(options) {
|
|
|
30
35
|
description: options.description,
|
|
31
36
|
fields: options.fields,
|
|
32
37
|
// Storing a submission has to be an explicit decision, so `custom` is the default.
|
|
33
|
-
submission: {
|
|
38
|
+
submission: {
|
|
39
|
+
mode,
|
|
40
|
+
store: mode === "managed" || (options.submission?.store ?? false),
|
|
41
|
+
maxStored,
|
|
42
|
+
retentionDays
|
|
43
|
+
},
|
|
34
44
|
honeypot,
|
|
35
45
|
maxBodyBytes: options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES
|
|
36
46
|
};
|
|
37
47
|
}
|
|
48
|
+
function positiveIntegerOrFalse(value, fallback, name) {
|
|
49
|
+
const resolved = value ?? fallback;
|
|
50
|
+
if (resolved === false) return false;
|
|
51
|
+
if (!Number.isSafeInteger(resolved) || resolved < 1)
|
|
52
|
+
throw new TypeError(`[Eponyme] Form ${name} must be a positive integer or false.`);
|
|
53
|
+
return resolved;
|
|
54
|
+
}
|
|
38
55
|
|
|
39
56
|
function defineEponymeVariables(variables) {
|
|
40
57
|
return variables;
|
package/dist/module.d.mts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { EponymeLocaleDefinition } from '../dist/runtime/locales/index.js';
|
|
3
|
+
export { EponymeLocaleDefinition, EponymeMessageKey } from '../dist/runtime/locales/index.js';
|
|
2
4
|
export { collection, defineEponymeConfig, defineEponymeVariables, form } from './eponyme.mjs';
|
|
3
|
-
export { field, today } from '../dist/runtime/fields/index.js';
|
|
5
|
+
export { field, toMs, today } from '../dist/runtime/fields/index.js';
|
|
4
6
|
export { EPONYME_ROLES, canEditEponyme, isEponymeRole } from '../dist/runtime/types/auth.js';
|
|
5
7
|
export { eponymeMediaEmbedUrl, eponymeMediaThumbnailUrl, parseEponymeMediaUrl } from '../dist/runtime/utils/media-player.js';
|
|
6
|
-
export { ArrayFieldDefinition, ArrayFieldOptions, ArrayItemDefinition, ArrayItemFieldDefinition, ArrayItemSchema, ArrayItemValue, BooleanFieldDefinition, BooleanFieldOptions, CheckboxGroupFieldDefinition, CheckboxGroupFieldOptions, CollectionSlugField, ColorFieldDefinition, ColorFieldOptions, DateFieldDefinition, DateFieldOptions, EmailFieldDefinition, EmailFieldOptions, EponymeAuthSession, EponymeAuthUser, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeData, EponymeDataByName, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeManagedUserResult, EponymeName, EponymeRole, EponymeSchema, EponymeVariableDefinition, EponymeVariableSummary, EponymeVariableValue, EponymeVariables, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, MediaPlayerFieldDefinition, MediaPlayerFieldOptions, MediaPlayerProvider, MediaPlayerValue, 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';
|
|
8
|
+
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, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeData, EponymeDataByName, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeManagedUserResult, EponymeName, EponymeRole, EponymeSchema, EponymeVariableDefinition, EponymeVariableSummary, EponymeVariableValue, EponymeVariables, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, 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';
|
|
7
9
|
import '../dist/runtime/types/variables.js';
|
|
8
10
|
|
|
9
11
|
/**
|
|
@@ -88,16 +90,63 @@ interface ModuleOptions {
|
|
|
88
90
|
*/
|
|
89
91
|
sessionDurationDays?: number;
|
|
90
92
|
};
|
|
93
|
+
rateLimits?: {
|
|
94
|
+
/** Login attempts per client address and minute. @default 10 */
|
|
95
|
+
loginPerIp?: number;
|
|
96
|
+
/** Login attempts across the deployment and minute. @default 300 */
|
|
97
|
+
loginGlobal?: number;
|
|
98
|
+
/** Failed login attempts per account and 15 minutes. @default 5 */
|
|
99
|
+
loginAccountFailures?: number;
|
|
100
|
+
/** Managed-form submissions per client address, form and minute. @default 5 */
|
|
101
|
+
formPerIp?: number;
|
|
102
|
+
/** Managed-form submissions per form across the deployment and minute. @default 100 */
|
|
103
|
+
formGlobal?: number;
|
|
104
|
+
};
|
|
91
105
|
/**
|
|
92
|
-
* How long
|
|
106
|
+
* How long content already read may be reused, in seconds. `0` disables it.
|
|
93
107
|
*
|
|
94
108
|
* @remarks
|
|
95
|
-
*
|
|
96
|
-
* still answer with the previous
|
|
109
|
+
* Without `cacheStorage`, the cache is per instance and a save only clears the instance that
|
|
110
|
+
* served it — so this also bounds how long another instance can still answer with the previous
|
|
111
|
+
* content. With `cacheStorage`, an invalidation reaches every instance and this is simply how
|
|
112
|
+
* long a cached read lives.
|
|
97
113
|
*
|
|
98
114
|
* @default 5
|
|
99
115
|
*/
|
|
100
116
|
cacheSeconds?: number;
|
|
117
|
+
/**
|
|
118
|
+
* Name of a Nitro storage mount the content cache is shared through, typically Redis.
|
|
119
|
+
* Left out, the cache stays in the memory of each instance.
|
|
120
|
+
*
|
|
121
|
+
* @remarks
|
|
122
|
+
* This is what makes a publication visible everywhere at once: a shared mount is a cache a
|
|
123
|
+
* write can actually invalidate across instances, which an in-process map cannot be.
|
|
124
|
+
*
|
|
125
|
+
* A small in-process tier is kept in front of it either way — it coalesces the concurrent
|
|
126
|
+
* reads of one render and answers repeats without a network hop — so an instance can still
|
|
127
|
+
* miss an invalidation for up to a second.
|
|
128
|
+
*
|
|
129
|
+
* The mount is declared by the application, and the driver's `base` is what the keys are
|
|
130
|
+
* prefixed with:
|
|
131
|
+
*
|
|
132
|
+
* ```ts
|
|
133
|
+
* // nuxt.config.ts
|
|
134
|
+
* nitro: {
|
|
135
|
+
* storage: {
|
|
136
|
+
* eponyme: { driver: 'redis', url: process.env.REDIS_URL, base: 'eponyme' },
|
|
137
|
+
* },
|
|
138
|
+
* },
|
|
139
|
+
* eponyme: { cacheStorage: 'eponyme', cacheSeconds: 60 },
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* Keys then read `eponyme:row:<name>` and `eponyme:rows:<collection>:<version>`.
|
|
143
|
+
*
|
|
144
|
+
* `unstorage` ships the Redis driver; the application adds `ioredis` itself, so a deployment
|
|
145
|
+
* that caches in memory does not carry a Redis client it never builds.
|
|
146
|
+
*
|
|
147
|
+
* @see https://nitro.build/guide/storage
|
|
148
|
+
*/
|
|
149
|
+
cacheStorage?: string;
|
|
101
150
|
/**
|
|
102
151
|
* Whether the filterable index is rebuilt at startup when the configuration that produced
|
|
103
152
|
* it has changed.
|
|
@@ -135,6 +184,31 @@ interface ModuleOptions {
|
|
|
135
184
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control
|
|
136
185
|
*/
|
|
137
186
|
cdnCacheSeconds?: number;
|
|
187
|
+
/**
|
|
188
|
+
* Language of the dashboard interface, resolved once at build time.
|
|
189
|
+
*
|
|
190
|
+
* @remarks
|
|
191
|
+
* One language per build: the catalogue is merged over English and inlined, so a key the
|
|
192
|
+
* locale does not carry falls back to English rather than showing raw. This never touches
|
|
193
|
+
* content, schema labels, or a host's own `@nuxtjs/i18n` setup.
|
|
194
|
+
*
|
|
195
|
+
* Catalogues live in `@eponyme/locale`, one subpath per language, and each export is a
|
|
196
|
+
* function so it can take overrides. Passing the function itself instead of calling it is
|
|
197
|
+
* refused at setup with a message saying so.
|
|
198
|
+
*
|
|
199
|
+
* @default undefined — English
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* import { fr } from '@eponyme/locale/fr'
|
|
203
|
+
*
|
|
204
|
+
* export default defineNuxtConfig({
|
|
205
|
+
* eponyme: {
|
|
206
|
+
* locale: fr({ 'array.add': 'Ajouter un bloc' }),
|
|
207
|
+
* },
|
|
208
|
+
* })
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
locale?: EponymeLocaleDefinition;
|
|
138
212
|
}
|
|
139
213
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
140
214
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,8 +1,42 @@
|
|
|
1
|
-
import { defineNuxtModule, useLogger, createResolver, findPath, addImports, addImportsDir, addServerImports, addRouteMiddleware, extendViteConfig,
|
|
1
|
+
import { defineNuxtModule, useLogger, createResolver, addTemplate, addTypeTemplate, addPlugin, findPath, addImports, addImportsDir, addComponent, addServerImports, addRouteMiddleware, extendViteConfig, addServerHandler, addServerPlugin, hasNuxtModule, hasNuxtModuleCompatibility, getNuxtModuleVersion } from '@nuxt/kit';
|
|
2
2
|
import pc from 'picocolors';
|
|
3
3
|
import tailwindcss from '@tailwindcss/vite';
|
|
4
|
+
import { EPONYME_DEFAULT_LOCALE, eponymeEnglishMessages } from '../dist/runtime/locales/index.js';
|
|
4
5
|
import { resolve } from 'pathe';
|
|
5
6
|
import { tagPreviewPathRoutes } from '../dist/runtime/utils/cache-tags.js';
|
|
7
|
+
import { EPONYME_THEME_BOOTSTRAP } from '../dist/runtime/utils/eponyme-theme.js';
|
|
8
|
+
|
|
9
|
+
function resolveEponymeLocale(locale, prefix = "[Eponyme]") {
|
|
10
|
+
if (locale === void 0 || locale === null) return { ...EPONYME_DEFAULT_LOCALE, missing: [] };
|
|
11
|
+
if (typeof locale === "function") {
|
|
12
|
+
throw new TypeError(
|
|
13
|
+
`${prefix} eponyme.locale expects the result of a call, not the function itself.
|
|
14
|
+
Write \`locale: fr()\` rather than \`locale: fr\`.`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
const candidate = locale;
|
|
18
|
+
if (typeof locale !== "object" || typeof candidate.code !== "string" || !candidate.code || typeof candidate.messages !== "object" || !candidate.messages) {
|
|
19
|
+
throw new TypeError(
|
|
20
|
+
`${prefix} eponyme.locale must be a locale definition carrying a \`code\` and \`messages\`.
|
|
21
|
+
Import one from @eponyme/locale, for example \`import { fr } from '@eponyme/locale/fr'\`.`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const messages = candidate.messages;
|
|
25
|
+
return {
|
|
26
|
+
...candidate,
|
|
27
|
+
messages: { ...eponymeEnglishMessages, ...messages },
|
|
28
|
+
missing: Object.keys(eponymeEnglishMessages).filter((key) => !(key in messages))
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function renderEponymeLocaleModule(locale, translatorPath) {
|
|
32
|
+
return [
|
|
33
|
+
`import { createEponymeTranslator } from ${JSON.stringify(translatorPath)}`,
|
|
34
|
+
`export const locale = ${JSON.stringify({ code: locale.code, dir: locale.dir ?? "ltr" })}`,
|
|
35
|
+
`const messages = ${JSON.stringify(locale.messages, null, 2)}`,
|
|
36
|
+
`export const t = createEponymeTranslator(messages${locale.plural ? `, ${locale.plural.toString()}` : ""})`,
|
|
37
|
+
""
|
|
38
|
+
].join("\n");
|
|
39
|
+
}
|
|
6
40
|
|
|
7
41
|
const MINIMUM_NUXT_UI = "4.10.0";
|
|
8
42
|
const CLIENT_DEPENDENCIES = [
|
|
@@ -33,6 +67,12 @@ async function warnOnIncompatibleNuxtUi(nuxt, logger) {
|
|
|
33
67
|
build or misbehave somewhere with no obvious link back to this warning.`
|
|
34
68
|
);
|
|
35
69
|
}
|
|
70
|
+
function positiveInteger(value, fallback, name) {
|
|
71
|
+
const resolved = value ?? fallback;
|
|
72
|
+
if (!Number.isSafeInteger(resolved) || resolved < 1)
|
|
73
|
+
throw new TypeError(`${pc.red("[Eponyme]")} ${name} must be a positive integer.`);
|
|
74
|
+
return resolved;
|
|
75
|
+
}
|
|
36
76
|
const module$1 = defineNuxtModule({
|
|
37
77
|
meta: {
|
|
38
78
|
name: "@karibsen/eponyme",
|
|
@@ -49,6 +89,13 @@ const module$1 = defineNuxtModule({
|
|
|
49
89
|
auth: {
|
|
50
90
|
sessionDurationDays: 7
|
|
51
91
|
},
|
|
92
|
+
rateLimits: {
|
|
93
|
+
loginPerIp: 10,
|
|
94
|
+
loginGlobal: 300,
|
|
95
|
+
loginAccountFailures: 5,
|
|
96
|
+
formPerIp: 5,
|
|
97
|
+
formGlobal: 100
|
|
98
|
+
},
|
|
52
99
|
cacheSeconds: 5,
|
|
53
100
|
autoReindex: true,
|
|
54
101
|
browserCacheSeconds: 30,
|
|
@@ -62,6 +109,7 @@ const module$1 = defineNuxtModule({
|
|
|
62
109
|
icons: [
|
|
63
110
|
"mingcute:history-anticlockwise-line",
|
|
64
111
|
"mingcute:eye-2-line",
|
|
112
|
+
"mingcute:eye-close-line",
|
|
65
113
|
"mingcute:layout-leftbar-close-line",
|
|
66
114
|
"mingcute:layout-leftbar-open-line",
|
|
67
115
|
"mingcute:down-small-line",
|
|
@@ -112,12 +160,51 @@ const module$1 = defineNuxtModule({
|
|
|
112
160
|
nuxt.options.runtimeConfig.eponymeAuth = {
|
|
113
161
|
sessionDurationDays: options.auth?.sessionDurationDays ?? 7
|
|
114
162
|
};
|
|
115
|
-
nuxt.options.runtimeConfig.
|
|
163
|
+
nuxt.options.runtimeConfig.eponymeRateLimits = {
|
|
164
|
+
loginPerIp: positiveInteger(options.rateLimits?.loginPerIp, 10, "eponyme.rateLimits.loginPerIp"),
|
|
165
|
+
loginGlobal: positiveInteger(options.rateLimits?.loginGlobal, 300, "eponyme.rateLimits.loginGlobal"),
|
|
166
|
+
loginAccountFailures: positiveInteger(options.rateLimits?.loginAccountFailures, 5, "eponyme.rateLimits.loginAccountFailures"),
|
|
167
|
+
formPerIp: positiveInteger(options.rateLimits?.formPerIp, 5, "eponyme.rateLimits.formPerIp"),
|
|
168
|
+
formGlobal: positiveInteger(options.rateLimits?.formGlobal, 100, "eponyme.rateLimits.formGlobal")
|
|
169
|
+
};
|
|
170
|
+
const eponymeContent = {
|
|
116
171
|
cacheSeconds: options.cacheSeconds ?? 5,
|
|
172
|
+
cacheStorage: options.cacheStorage?.trim() || "",
|
|
117
173
|
autoReindex: options.autoReindex ?? true,
|
|
118
174
|
browserCacheSeconds: options.browserCacheSeconds ?? 30,
|
|
119
175
|
cdnCacheSeconds: options.cdnCacheSeconds ?? 300
|
|
120
176
|
};
|
|
177
|
+
nuxt.options.runtimeConfig.eponymeContent = eponymeContent;
|
|
178
|
+
const locale = resolveEponymeLocale(options.locale, pc.red("[Eponyme]"));
|
|
179
|
+
if (locale.missing.length) {
|
|
180
|
+
logger.warn(
|
|
181
|
+
`The \`${locale.code}\` catalogue is missing ${locale.missing.length} key${locale.missing.length > 1 ? "s" : ""}, which fall back to English:
|
|
182
|
+
` + locale.missing.map((key) => ` - ${key}`).join("\n")
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
const translatorPath = await resolver.resolvePath("./runtime/utils/translate");
|
|
186
|
+
const localeTemplate = addTemplate({
|
|
187
|
+
filename: "eponyme-locale.mjs",
|
|
188
|
+
write: true,
|
|
189
|
+
getContents: () => renderEponymeLocaleModule(locale, translatorPath)
|
|
190
|
+
});
|
|
191
|
+
nuxt.options.alias["#eponyme/locale"] = localeTemplate.dst;
|
|
192
|
+
addTypeTemplate({
|
|
193
|
+
filename: "types/eponyme-locale.d.ts",
|
|
194
|
+
getContents: () => `declare module '#eponyme/locale' {
|
|
195
|
+
import type { EponymeLocaleDefinition, EponymeMessageKey } from ${JSON.stringify(resolver.resolve("./runtime/locales"))}
|
|
196
|
+
import type { EponymeTranslateParams } from ${JSON.stringify(resolver.resolve("./runtime/utils/translate"))}
|
|
197
|
+
export const locale: EponymeLocaleDefinition
|
|
198
|
+
export function t(key: EponymeMessageKey, params?: EponymeTranslateParams): string
|
|
199
|
+
}
|
|
200
|
+
`
|
|
201
|
+
});
|
|
202
|
+
nuxt.options.app.head.script ??= [];
|
|
203
|
+
nuxt.options.app.head.script.unshift({
|
|
204
|
+
key: "eponyme-theme",
|
|
205
|
+
innerHTML: EPONYME_THEME_BOOTSTRAP
|
|
206
|
+
});
|
|
207
|
+
addPlugin(resolver.resolve("./runtime/plugins/eponyme-theme"));
|
|
121
208
|
const tagged = tagPreviewPathRoutes(options.previewPaths ?? {}, nuxt.options.routeRules ??= {});
|
|
122
209
|
if (tagged.length) {
|
|
123
210
|
const width = Math.max(...tagged.map(({ route }) => route.length));
|
|
@@ -152,10 +239,15 @@ Note that '~/' points at ${nuxt.options.srcDir}, so a server module needs '~~/'.
|
|
|
152
239
|
{ name: "eponymeMediaThumbnailUrl", from: resolver.resolve("./runtime/utils/media-player") }
|
|
153
240
|
]);
|
|
154
241
|
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
242
|
+
addComponent({ name: "EponymeRichText", filePath: resolver.resolve("./runtime/components/EponymeRichText") });
|
|
155
243
|
addServerImports([
|
|
156
244
|
{ name: "getEponymeSitemapEntries", from: resolver.resolve("./runtime/server/utils/eponyme-sitemap") },
|
|
157
245
|
{ name: "reindexEponymeEntries", from: resolver.resolve("./runtime/server/utils/eponyme-reindex") },
|
|
246
|
+
{ name: "runEponymeSchedule", from: resolver.resolve("./runtime/server/utils/eponyme-schedule") },
|
|
158
247
|
{ name: "validateEponymeForm", from: resolver.resolve("./runtime/server/utils/eponyme-form") },
|
|
248
|
+
// Lets a route Eponyme does not own feed the dashboard's submission list.
|
|
249
|
+
{ name: "storeEponymeFormSubmission", from: resolver.resolve("./runtime/server/utils/eponyme-form") },
|
|
250
|
+
{ name: "assertEponymeFormRateLimit", from: resolver.resolve("./runtime/server/utils/eponyme-form") },
|
|
159
251
|
{ name: "getEponymeCacheTags", from: resolver.resolve("./runtime/server/utils/eponyme-cache") }
|
|
160
252
|
]);
|
|
161
253
|
addRouteMiddleware({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import "tailwindcss/theme" layer(theme) prefix(ep);@import "tailwindcss/preflight" layer(base);@import "tailwindcss/utilities" layer(utilities) prefix(ep);@source "../components";@source "../pages";@theme{--font-sans:"SF Pro Text",Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--color-theme-ep:#1c1c1c;--color-border-ep:#343434;--color-selected-ep:#262626;--color-text-ep:#e7e7e7;--color-muted-ep:#8d8d8d;--color-success-ep:#72d39a;--color-warning-ep:#e6b85c;--color-danger-ep:#ff8585}:root.dark{--color-
|
|
1
|
+
@import "tailwindcss/theme" layer(theme) prefix(ep);@import "tailwindcss/preflight" layer(base);@import "tailwindcss/utilities" layer(utilities) prefix(ep);@source "../components";@source "../pages";@theme{--font-sans:"SF Pro Text",Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--color-theme-ep:#1c1c1c;--color-border-ep:#343434;--color-selected-ep:#262626;--color-text-ep:#e7e7e7;--color-muted-ep:#8d8d8d;--color-success-ep:#72d39a;--color-warning-ep:#e6b85c;--color-danger-ep:#ff8585;--color-canvas-ep:#fff;--color-inverse-ep:#fff}:root,:root.ep-dark{--ep-color-theme-ep:#1c1c1c;--ep-color-border-ep:#343434;--ep-color-selected-ep:#262626;--ep-color-text-ep:#e7e7e7;--ep-color-muted-ep:#8d8d8d;--ep-color-success-ep:#72d39a;--ep-color-warning-ep:#e6b85c;--ep-color-danger-ep:#ff8585;--ep-color-white:#fff}:root.ep-light{--ep-color-theme-ep:#f7f7f8;--ep-color-border-ep:rgba(172,176,188,.27)!important;--ep-color-selected-ep:#ededf0;--ep-color-text-ep:#1c1d20;--ep-color-muted-ep:#62656d;--ep-color-success-ep:#187443;--ep-color-warning-ep:#ffa700;--ep-color-danger-ep:#b42336;--ep-color-white:#1c1d20}@layer base{.eponyme-portal,.eponyme-root{color-scheme:dark;font-family:var(--ep-font-sans)}:root.ep-light :where(.eponyme-root,.eponyme-portal){color-scheme:light}:where(.eponyme-root,.eponyme-portal),:where(.eponyme-root,.eponyme-portal) *,:where(.eponyme-root,.eponyme-portal) :after,:where(.eponyme-root,.eponyme-portal) :before{border:0 solid;box-sizing:border-box;margin:0;padding:0}}.eponyme-date-input{color-scheme:inherit}
|
package/dist/runtime/assets.d.ts
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders a `field.richText()` value on a public page.
|
|
3
|
+
*
|
|
4
|
+
* The HTML is safe by construction rather than by inspection here: every write path runs it
|
|
5
|
+
* through Eponyme's sanitisation policy before it is stored, and a payload carrying anything
|
|
6
|
+
* the editor cannot produce is refused with a `422`. Re-sanitising in the browser would ship
|
|
7
|
+
* a parser to every visitor to re-check a decision the server already made — and a client
|
|
8
|
+
* that can be skipped is not a security boundary anyway.
|
|
9
|
+
*
|
|
10
|
+
* It exists so a host application never writes `v-html` itself, which is the line between
|
|
11
|
+
* "Eponyme guarantees this" and "the application hopes so".
|
|
12
|
+
*
|
|
13
|
+
* A render function rather than a template: `innerHTML` is what `v-html` compiles to, and
|
|
14
|
+
* writing it directly keeps the one deliberate injection point in a file that explains it.
|
|
15
|
+
*/
|
|
16
|
+
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
17
|
+
html: {
|
|
18
|
+
type: StringConstructor;
|
|
19
|
+
default: string;
|
|
20
|
+
};
|
|
21
|
+
as: {
|
|
22
|
+
type: StringConstructor;
|
|
23
|
+
default: string;
|
|
24
|
+
};
|
|
25
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
28
|
+
html: {
|
|
29
|
+
type: StringConstructor;
|
|
30
|
+
default: string;
|
|
31
|
+
};
|
|
32
|
+
as: {
|
|
33
|
+
type: StringConstructor;
|
|
34
|
+
default: string;
|
|
35
|
+
};
|
|
36
|
+
}>> & Readonly<{}>, {
|
|
37
|
+
html: string;
|
|
38
|
+
as: string;
|
|
39
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
40
|
+
export default _default;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineComponent, h } from "vue";
|
|
2
|
+
export default defineComponent({
|
|
3
|
+
name: "EponymeRichText",
|
|
4
|
+
props: {
|
|
5
|
+
html: { type: String, default: "" },
|
|
6
|
+
as: { type: String, default: "div" }
|
|
7
|
+
},
|
|
8
|
+
setup(props) {
|
|
9
|
+
return () => h(props.as, { class: "eponyme-rich-text", innerHTML: props.html });
|
|
10
|
+
}
|
|
11
|
+
});
|