@karibsen/eponyme 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -16
- package/dist/eponyme.d.mts +22 -2
- package/dist/eponyme.mjs +5 -1
- package/dist/module.d.mts +3 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +73 -43
- package/dist/runtime/components/editor/EponymeCollectionPage.vue +81 -19
- package/dist/runtime/components/editor/EponymeForm.vue +3 -3
- package/dist/runtime/components/editor/EponymeFormPage.vue +7 -3
- package/dist/runtime/components/editor/EponymeSidebar.vue +25 -33
- package/dist/runtime/components/editor/EponymeSidebarTree.d.vue.ts +2 -0
- package/dist/runtime/components/editor/EponymeSidebarTree.vue +3 -1
- package/dist/runtime/components/editor/EponymeSidebarTree.vue.d.ts +2 -0
- package/dist/runtime/components/fields/RichTextField.vue +80 -8
- package/dist/runtime/components/ui/EPLinkDialog.d.vue.ts +15 -0
- package/dist/runtime/components/ui/EPLinkDialog.vue +142 -0
- package/dist/runtime/components/ui/EPLinkDialog.vue.d.ts +15 -0
- package/dist/runtime/components/ui/EPLinkEditor.vue +10 -91
- package/dist/runtime/composables/useEponyme.d.ts +2 -0
- package/dist/runtime/composables/useEponyme.js +7 -5
- package/dist/runtime/composables/useEponymeCollection.d.ts +12 -2
- package/dist/runtime/composables/useEponymeCollection.js +15 -5
- package/dist/runtime/composables/useEponymeForm.js +4 -1
- package/dist/runtime/composables/useEponymeHistory.d.ts +2 -2
- package/dist/runtime/composables/useEponymeHistory.js +2 -1
- package/dist/runtime/composables/useEponymeVariables.d.ts +3 -0
- package/dist/runtime/composables/useEponymeVariables.js +5 -0
- package/dist/runtime/pages/EponymeDetailPage.vue +1 -1
- package/dist/runtime/pages/EponymeIndexPage.vue +173 -10
- package/dist/runtime/server/api/eponyme/[name].get.d.ts +5 -1
- package/dist/runtime/server/api/eponyme/[name].get.js +3 -1
- package/dist/runtime/server/api/eponyme/[name].patch.js +17 -1
- package/dist/runtime/server/api/eponyme-collections/[path].delete.js +7 -2
- package/dist/runtime/server/api/eponyme-collections/[path].get.d.ts +1 -3
- package/dist/runtime/server/api/eponyme-collections/[path].get.js +31 -4
- package/dist/runtime/server/api/eponyme-export.get.d.ts +2 -0
- package/dist/runtime/server/api/eponyme-export.get.js +11 -0
- package/dist/runtime/server/api/eponyme-forms/[path].post.js +14 -1
- package/dist/runtime/server/api/eponyme-history/[path].patch.d.ts +1 -1
- package/dist/runtime/server/api/eponyme-history/[path].patch.js +14 -2
- package/dist/runtime/server/api/eponyme-import.post.d.ts +2 -0
- package/dist/runtime/server/api/eponyme-import.post.js +31 -0
- package/dist/runtime/server/api/eponyme-trash/[path].delete.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-trash/[path].delete.js +16 -0
- package/dist/runtime/server/api/eponyme-trash/[path].get.d.ts +2 -0
- package/dist/runtime/server/api/eponyme-trash/[path].get.js +11 -0
- package/dist/runtime/server/api/eponyme-trash/[path].patch.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-trash/[path].patch.js +16 -0
- package/dist/runtime/server/services/eponyme-form-store.d.ts +1 -0
- package/dist/runtime/server/services/eponyme-store.d.ts +91 -3
- package/dist/runtime/server/services/eponyme-store.js +272 -9
- package/dist/runtime/server/utils/eponyme-entry.d.ts +9 -0
- package/dist/runtime/server/utils/eponyme-entry.js +7 -0
- package/dist/runtime/server/utils/eponyme-hooks.d.ts +16 -0
- package/dist/runtime/server/utils/eponyme-hooks.js +24 -0
- package/dist/runtime/server/utils/eponyme-variables.d.ts +5 -0
- package/dist/runtime/server/utils/eponyme-variables.js +5 -0
- package/dist/runtime/types/eponyme-config.d.ts +7 -0
- package/dist/runtime/types/field.d.ts +1 -0
- package/dist/runtime/types/hooks.d.ts +67 -0
- package/dist/runtime/types/hooks.js +0 -0
- package/dist/runtime/types/index.d.ts +1 -0
- package/dist/runtime/types/index.js +1 -0
- package/dist/runtime/types/nuxt.d.ts +10 -0
- package/dist/runtime/types/variables.d.ts +17 -0
- package/dist/runtime/types/variables.js +0 -0
- package/dist/runtime/utils/build-navigation-tree.d.ts +22 -0
- package/dist/runtime/utils/build-navigation-tree.js +30 -0
- package/dist/runtime/utils/date-locale.d.ts +10 -0
- package/dist/runtime/utils/date-locale.js +1 -0
- package/dist/runtime/utils/downloadable-link.d.ts +2 -0
- package/dist/runtime/utils/downloadable-link.js +35 -0
- package/dist/runtime/utils/empty-variables.d.ts +2 -0
- package/dist/runtime/utils/empty-variables.js +1 -0
- package/dist/runtime/utils/filter-navigation-tree.d.ts +7 -0
- package/dist/runtime/utils/filter-navigation-tree.js +39 -0
- package/dist/runtime/utils/get-field-default-value.js +1 -1
- package/dist/runtime/utils/hydration-cache.d.ts +11 -0
- package/dist/runtime/utils/hydration-cache.js +3 -0
- package/dist/runtime/utils/validate-eponyme-data.js +1 -1
- package/dist/runtime/utils/variables.d.ts +18 -0
- package/dist/runtime/utils/variables.js +52 -0
- package/dist/types.d.mts +2 -2
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -15,11 +15,13 @@ Define your content in `eponyme.config.ts`. Eponyme provides defaults, validatio
|
|
|
15
15
|
- Declarative defaults and validation
|
|
16
16
|
- Conditional fields, character counters, and sortable arrays
|
|
17
17
|
- Private drafts with explicit publishing
|
|
18
|
-
- Collections for articles, pages, and other repeatable content
|
|
18
|
+
- Collections for articles, pages, and other repeatable content, with sorting, limiting and pagination
|
|
19
19
|
- Public forms with typed schemas, server-side validation, and stored submissions
|
|
20
|
+
- Content variables such as `{{ currentYear }}`, resolved when the page is served
|
|
20
21
|
- Persistent version history with dashboard restoration
|
|
21
22
|
- Draft previews for configured public routes
|
|
22
23
|
- A general sitemap metadata endpoint for configured public routes
|
|
24
|
+
- Content export and import between environments, guarded by a schema fingerprint
|
|
23
25
|
- A generated dashboard at `/__eponyme`
|
|
24
26
|
- Server sessions with `owner`, `editor`, and `viewer` roles
|
|
25
27
|
- PostgreSQL and Prisma persistence using JSONB
|
|
@@ -46,7 +48,7 @@ Add it to `nuxt.config.ts`:
|
|
|
46
48
|
export default defineNuxtConfig({
|
|
47
49
|
modules: ['@karibsen/eponyme'],
|
|
48
50
|
eponyme: {
|
|
49
|
-
prismaClient: '
|
|
51
|
+
prismaClient: '~~/server/utils/prisma',
|
|
50
52
|
dashboardPath: '/__eponyme',
|
|
51
53
|
previewPaths: {
|
|
52
54
|
homepage: '/',
|
|
@@ -89,6 +91,7 @@ export default defineEponymeConfig({
|
|
|
89
91
|
href: '/contact',
|
|
90
92
|
type: 'internal',
|
|
91
93
|
openInNewTab: false,
|
|
94
|
+
download: false,
|
|
92
95
|
},
|
|
93
96
|
}),
|
|
94
97
|
published: field.boolean({
|
|
@@ -153,7 +156,10 @@ field.string({
|
|
|
153
156
|
|
|
154
157
|
Eponyme uses the Prisma client owned by your application. It does not create the connection or run migrations.
|
|
155
158
|
|
|
156
|
-
Export an initialized client from the path configured in `nuxt.config.ts
|
|
159
|
+
Export an initialized client from the path configured in `nuxt.config.ts`. Note the
|
|
160
|
+
double tilde: `~~/` points at the project root, where `server/` lives, while `~/` points
|
|
161
|
+
at the source directory (`app/` in Nuxt 4). A relative path such as
|
|
162
|
+
`./server/utils/prisma` works too.
|
|
157
163
|
|
|
158
164
|
```ts
|
|
159
165
|
// server/utils/prisma.ts
|
|
@@ -168,12 +174,14 @@ Add the required models to your Prisma schema:
|
|
|
168
174
|
|
|
169
175
|
```prisma
|
|
170
176
|
model Eponyme {
|
|
171
|
-
name String
|
|
172
|
-
data Json
|
|
173
|
-
createdAt DateTime
|
|
174
|
-
updatedAt DateTime
|
|
177
|
+
name String @id
|
|
178
|
+
data Json @db.JsonB
|
|
179
|
+
createdAt DateTime @default(now())
|
|
180
|
+
updatedAt DateTime @updatedAt
|
|
181
|
+
deletedAt DateTime?
|
|
175
182
|
versions EponymeVersion[]
|
|
176
183
|
|
|
184
|
+
@@index([deletedAt])
|
|
177
185
|
@@map("eponyme_entries")
|
|
178
186
|
}
|
|
179
187
|
|
|
@@ -238,6 +246,9 @@ model EponymeFormSubmission {
|
|
|
238
246
|
|
|
239
247
|
Run the migration with the workflow used by your application.
|
|
240
248
|
|
|
249
|
+
Upgrading from 0.1.1 requires one migration: `Eponyme.deletedAt`, which backs the trash.
|
|
250
|
+
Deleting a collection entry no longer destroys it.
|
|
251
|
+
|
|
241
252
|
The playground includes the same models in `playground/prisma/schema.prisma`. Copy `playground/.env.example` to `playground/.env`, set `DATABASE_URL`, then run:
|
|
242
253
|
|
|
243
254
|
```bash
|
|
@@ -312,6 +323,58 @@ GET /api/eponyme-collections/articles
|
|
|
312
323
|
|
|
313
324
|
It returns published entries by default. Pass `version=draft` from an authenticated request to read dashboard content.
|
|
314
325
|
|
|
326
|
+
### Sorting and limiting
|
|
327
|
+
|
|
328
|
+
Collections accept `take`, `skip`, `orderBy` and `order`:
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
const { entries, total } = useEponymeCollection('articles', {
|
|
332
|
+
orderBy: 'date',
|
|
333
|
+
order: 'desc',
|
|
334
|
+
take: 4,
|
|
335
|
+
})
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
`orderBy` accepts the `updatedAt`, `publishedAt`, `title` and `slug` metadata as well
|
|
339
|
+
as **any field of the collection**, which is what lets articles be ordered by their own
|
|
340
|
+
date rather than by when they were last edited. The key is typed from the schema, so a
|
|
341
|
+
misspelled field fails to compile.
|
|
342
|
+
|
|
343
|
+
`total` counts every matching entry *before* `take` and `skip`, so it can drive a pager.
|
|
344
|
+
Sorting runs after unpublished entries are filtered out, meaning a limit never spends a
|
|
345
|
+
slot on an entry that would have been dropped. Entries with a missing or empty value sort
|
|
346
|
+
last in both directions. The default order remains `updatedAt` descending.
|
|
347
|
+
|
|
348
|
+
The same options work over HTTP, where the response is `{ entries, total }`:
|
|
349
|
+
|
|
350
|
+
```http
|
|
351
|
+
GET /api/eponyme-collections/articles?orderBy=date&order=desc&take=4
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
`take` is capped at 200, and an unknown `orderBy` answers `400` with the accepted keys
|
|
355
|
+
rather than returning an arbitrary order.
|
|
356
|
+
|
|
357
|
+
### Trash
|
|
358
|
+
|
|
359
|
+
Deleting a collection entry moves it to a trash rather than destroying it. The entry
|
|
360
|
+
disappears from the dashboard, from the public API and from the sitemap, but its content
|
|
361
|
+
and its whole version history are kept, so it can be brought back.
|
|
362
|
+
|
|
363
|
+
The collection page lists the trash behind a **Trash** button and offers **Restore** and
|
|
364
|
+
**Delete for good**. Restoring is available to editors and owners; deleting for good is
|
|
365
|
+
reserved to owners, since it is the only irreversible content operation — the entry's
|
|
366
|
+
history goes with it.
|
|
367
|
+
|
|
368
|
+
```http
|
|
369
|
+
GET /api/eponyme-trash/articles # trashed entries of a collection
|
|
370
|
+
PATCH /api/eponyme-trash/articles/my-article # restore
|
|
371
|
+
DELETE /api/eponyme-trash/articles/my-article # delete for good, owner only
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
A trashed entry keeps its row, so it keeps its slug. Creating an entry with that slug is
|
|
375
|
+
refused with a message pointing at the trash rather than silently overwriting what is
|
|
376
|
+
waiting there. Restore the entry or delete it for good to free its slug.
|
|
377
|
+
|
|
315
378
|
## Entries
|
|
316
379
|
|
|
317
380
|
`useEponyme()` is auto-imported and infers its data from `eponyme.config.ts`:
|
|
@@ -345,6 +408,67 @@ The dashboard uses explicit saves. `Ctrl+S` or `Cmd+S` stores a draft. Publish r
|
|
|
345
408
|
|
|
346
409
|
The `errors` ref contains field errors returned with HTTP `422`. Eponyme creates missing singleton rows from configured defaults. It also reconciles stored JSONB data when fields are added or removed from the schema.
|
|
347
410
|
|
|
411
|
+
### Export and import
|
|
412
|
+
|
|
413
|
+
The dashboard overview at `/__eponyme` carries **Export** and **Import**, so content
|
|
414
|
+
prepared on one environment can be moved to another instead of being retyped.
|
|
415
|
+
|
|
416
|
+
Export downloads a JSON file holding every singleton and every live collection entry
|
|
417
|
+
with its complete state — draft, published version, status and publication date — plus a
|
|
418
|
+
fingerprint of the schema each entry was written against. The trash, form submissions and
|
|
419
|
+
users are never part of it.
|
|
420
|
+
|
|
421
|
+
Import applies that file on top of the current content: each entry it carries overwrites
|
|
422
|
+
its counterpart, entries it does not mention are left untouched, and nothing is ever
|
|
423
|
+
deleted. Before the first write, the fingerprints are compared with the local
|
|
424
|
+
configuration; a single divergence refuses the whole file and names what diverged, so an
|
|
425
|
+
import can never land half of its entries into a schema that no longer matches. The
|
|
426
|
+
dashboard first runs the import as a dry run and shows what it would create, overwrite
|
|
427
|
+
and skip. An entry whose slug waits in the trash is skipped rather than resurrected.
|
|
428
|
+
|
|
429
|
+
Every imported entry is written to the version history, so an import stays reversible
|
|
430
|
+
entry by entry from the timeline.
|
|
431
|
+
|
|
432
|
+
```http
|
|
433
|
+
GET /api/eponyme-export # editors and owners
|
|
434
|
+
POST /api/eponyme-import # owners only
|
|
435
|
+
POST /api/eponyme-import?dryRun=1 # report the counts without writing
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## Content variables
|
|
439
|
+
|
|
440
|
+
Editors can drop `{{ currentYear }}` into any text or rich-text field. Variables are
|
|
441
|
+
resolved when the page is served, so a year stays current without anyone re-saving the
|
|
442
|
+
content.
|
|
443
|
+
|
|
444
|
+
The built-ins cover dates: `currentYear`, `nextYear`, `previousYear`, `currentMonth`,
|
|
445
|
+
`currentDay`, `today` and `currentDate`.
|
|
446
|
+
|
|
447
|
+
Add your own in `eponyme.variables.ts` at the project root:
|
|
448
|
+
|
|
449
|
+
```ts
|
|
450
|
+
export default defineEponymeVariables({
|
|
451
|
+
clubName: 'AS Chelles Athlétisme',
|
|
452
|
+
season: {
|
|
453
|
+
label: 'Season',
|
|
454
|
+
description: 'The season spanning two calendar years.',
|
|
455
|
+
value: () => `${new Date().getFullYear()}-${new Date().getFullYear() + 1}`,
|
|
456
|
+
},
|
|
457
|
+
})
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
A plain value is fixed; a function is called on every read. Declaring a name that
|
|
461
|
+
matches a built-in overrides it. The rich text editor lists every variable behind a
|
|
462
|
+
toolbar button, with a preview of what it currently resolves to.
|
|
463
|
+
|
|
464
|
+
**Names only, never expressions.** `{{ currentYear }}` works, `{{ new Date().getFullYear() }}`
|
|
465
|
+
is left as-is. Content comes from the database and is editable from the dashboard, so
|
|
466
|
+
evaluating it would grant arbitrary code execution on the server. An unknown name is also
|
|
467
|
+
left untouched, so a typo is visible on the page instead of silently deleting text.
|
|
468
|
+
|
|
469
|
+
The dashboard reads content with `?raw=1` and therefore shows the source form, keeping
|
|
470
|
+
variables editable. Public reads receive the resolved values.
|
|
471
|
+
|
|
348
472
|
## Preview
|
|
349
473
|
|
|
350
474
|
Map a configured entry to its public route:
|
|
@@ -352,7 +476,7 @@ Map a configured entry to its public route:
|
|
|
352
476
|
```ts
|
|
353
477
|
export default defineNuxtConfig({
|
|
354
478
|
eponyme: {
|
|
355
|
-
prismaClient: '
|
|
479
|
+
prismaClient: '~~/server/utils/prisma',
|
|
356
480
|
previewPaths: {
|
|
357
481
|
'homepage': '/',
|
|
358
482
|
'pages/contact': '/contact',
|
|
@@ -391,7 +515,7 @@ Singleton entries use their exact `previewPaths` value. Collections use a dynami
|
|
|
391
515
|
```ts
|
|
392
516
|
export default defineNuxtConfig({
|
|
393
517
|
eponyme: {
|
|
394
|
-
prismaClient: '
|
|
518
|
+
prismaClient: '~~/server/utils/prisma',
|
|
395
519
|
previewPaths: {
|
|
396
520
|
homepage: '/',
|
|
397
521
|
articles: '/articles/:slug',
|
|
@@ -544,17 +668,75 @@ Two protections apply to the public submission route:
|
|
|
544
668
|
- a **body size limit**, 64 KB by default, configurable with `maxBodyBytes`. An oversized
|
|
545
669
|
body is refused with `413` before it is parsed.
|
|
546
670
|
|
|
547
|
-
|
|
671
|
+
A captcha is not part of the module. A public form is a normal POST route, so adding
|
|
672
|
+
Turnstile, hCaptcha or anything else is done in the host application: render the widget
|
|
673
|
+
on the page, send its token, and verify it in your own handler before calling
|
|
674
|
+
`validateEponymeForm()`.
|
|
675
|
+
|
|
676
|
+
Rate limiting and file uploads are not implemented yet.
|
|
677
|
+
|
|
678
|
+
## Hooks
|
|
679
|
+
|
|
680
|
+
Eponyme emits Nitro hooks around every content write and form submission. Listen to
|
|
681
|
+
them from a server plugin:
|
|
682
|
+
|
|
683
|
+
```ts
|
|
684
|
+
// server/plugins/eponyme.ts
|
|
685
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
686
|
+
nitroApp.hooks.hook('eponyme:entry:published', async ({ name, collection, data }) => {
|
|
687
|
+
await purgeCdnCache(collection ? `/${collection.name}/${collection.slug}` : `/${name}`)
|
|
688
|
+
})
|
|
689
|
+
|
|
690
|
+
nitroApp.hooks.hook('eponyme:form:submitted', async ({ form, data, id }) => {
|
|
691
|
+
if (form === 'contact') await sendEmail(data)
|
|
692
|
+
})
|
|
693
|
+
})
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
| Hook | When |
|
|
697
|
+
|---|---|
|
|
698
|
+
| `eponyme:entry:beforeSave` | Before a draft save or a publication |
|
|
699
|
+
| `eponyme:entry:saved` | After a draft save |
|
|
700
|
+
| `eponyme:entry:published` | After a publication |
|
|
701
|
+
| `eponyme:entry:restored` | After a history version was restored |
|
|
702
|
+
| `eponyme:entry:trashed` | After a collection entry was moved to the trash |
|
|
703
|
+
| `eponyme:entry:untrashed` | After a collection entry was taken back out of the trash |
|
|
704
|
+
| `eponyme:entry:purged` | After a collection entry and its history were deleted for good |
|
|
705
|
+
| `eponyme:form:beforeSubmit` | Before a managed submission is stored |
|
|
706
|
+
| `eponyme:form:submitted` | After a managed submission was stored |
|
|
707
|
+
|
|
708
|
+
The `before` hooks can **reject or amend** the operation. Throwing rejects it with a
|
|
709
|
+
`422` carrying your message, which is the way to enforce a rule the schema cannot
|
|
710
|
+
express. Mutating `context.data` changes what gets written:
|
|
711
|
+
|
|
712
|
+
```ts
|
|
713
|
+
nitroApp.hooks.hook('eponyme:entry:beforeSave', ({ data, collection }) => {
|
|
714
|
+
if (collection?.name === 'articles' && !data.excerpt) throw new Error('An excerpt is required.')
|
|
715
|
+
data.updatedBy = 'automation'
|
|
716
|
+
})
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
`eponyme:form:beforeSubmit` runs **after** validation, so a listener never sees a
|
|
720
|
+
payload the schema would have rejected.
|
|
721
|
+
|
|
722
|
+
The other hooks are notifications: the write already happened, so a listener that
|
|
723
|
+
throws is logged and swallowed. A failing webhook must not report a successful save as
|
|
724
|
+
an error the editor cannot act on.
|
|
725
|
+
|
|
726
|
+
Entries belonging to a collection carry `collection: { name, slug }`, so a listener can
|
|
727
|
+
branch without re-parsing the entry name. The three trash hooks only ever concern
|
|
728
|
+
collection entries, so their `collection` is always present; they carry no content, since
|
|
729
|
+
a trash move leaves the entry itself untouched.
|
|
548
730
|
|
|
549
731
|
## Current status
|
|
550
732
|
|
|
551
|
-
Eponyme is at version `0.1.
|
|
733
|
+
Eponyme is at version `0.1.1`. It is ready for controlled projects and production pilots. A few workflows still need hardening before a broad public release:
|
|
552
734
|
|
|
553
|
-
-
|
|
554
|
-
-
|
|
555
|
-
-
|
|
556
|
-
-
|
|
557
|
-
-
|
|
735
|
+
- Client revision tokens for long-running concurrent edits: the current `updatedAt` check protects overlapping writes within one request, not two editors who loaded the same older revision. A deletion is not guarded by a revision either
|
|
736
|
+
- Retention controls for the trash: entries stay there until someone empties it
|
|
737
|
+
- Rate limiting and file uploads for public forms
|
|
738
|
+
- Filtering, export and retention controls for stored submissions
|
|
739
|
+
- Pagination or a sitemap index beyond 50,000 URLs
|
|
558
740
|
|
|
559
741
|
## Development
|
|
560
742
|
|
package/dist/eponyme.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
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, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, 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, 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, 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
|
+
import { EponymeVariables } from '../dist/runtime/types/variables.js';
|
|
3
4
|
export { field, today } from '../dist/runtime/fields/index.js';
|
|
4
5
|
export { EPONYME_ROLES, canEditEponyme, isEponymeRole } from '../dist/runtime/types/auth.js';
|
|
5
6
|
|
|
@@ -12,4 +13,23 @@ declare function collection<const T extends EponymeSchema>(options: CollectionOp
|
|
|
12
13
|
|
|
13
14
|
declare function form<const T extends EponymeFormSchema>(options: EponymeFormOptions<T>): EponymeFormDefinition<T>;
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Declares the variables editors can drop into rich text with `{{ name }}`.
|
|
18
|
+
* Place them in `eponyme.variables.ts` at the project root:
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* export default defineEponymeVariables({
|
|
22
|
+
* clubName: 'AS Chelles Athlétisme',
|
|
23
|
+
* season: {
|
|
24
|
+
* label: 'Season',
|
|
25
|
+
* value: () => `${new Date().getFullYear()}-${new Date().getFullYear() + 1}`,
|
|
26
|
+
* },
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* A function is called on every read, so the value stays current without anyone
|
|
31
|
+
* re-saving the content.
|
|
32
|
+
*/
|
|
33
|
+
declare function defineEponymeVariables<const T extends EponymeVariables>(variables: T): T;
|
|
34
|
+
|
|
35
|
+
export { collection, defineEponymeConfig, defineEponymeVariables, form };
|
package/dist/eponyme.mjs
CHANGED
package/dist/module.d.mts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
export { collection, defineEponymeConfig, form } from './eponyme.mjs';
|
|
2
|
+
export { collection, defineEponymeConfig, defineEponymeVariables, form } from './eponyme.mjs';
|
|
3
3
|
export { field, today } from '../dist/runtime/fields/index.js';
|
|
4
4
|
export { EPONYME_ROLES, canEditEponyme, isEponymeRole } from '../dist/runtime/types/auth.js';
|
|
5
|
-
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, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, 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';
|
|
5
|
+
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, 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';
|
|
6
|
+
import '../dist/runtime/types/variables.js';
|
|
6
7
|
|
|
7
8
|
interface ModuleOptions {
|
|
8
9
|
dashboardPath?: string;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineNuxtModule, useLogger, createResolver,
|
|
1
|
+
import { defineNuxtModule, useLogger, createResolver, findPath, addImports, addImportsDir, addServerImports, addRouteMiddleware, addTypeTemplate, addServerHandler, addServerPlugin } from '@nuxt/kit';
|
|
2
2
|
import pc from 'picocolors';
|
|
3
3
|
import tailwindcss from '@tailwindcss/vite';
|
|
4
4
|
import { resolve } from 'node:path';
|
|
@@ -17,6 +17,46 @@ const module$1 = defineNuxtModule({
|
|
|
17
17
|
sessionDurationDays: 7
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
|
+
moduleDependencies: {
|
|
21
|
+
"@nuxt/icon": {
|
|
22
|
+
overrides: {
|
|
23
|
+
serverBundle: { collections: ["mingcute"] },
|
|
24
|
+
clientBundle: {
|
|
25
|
+
icons: [
|
|
26
|
+
"mingcute:history-anticlockwise-line",
|
|
27
|
+
"mingcute:eye-2-line",
|
|
28
|
+
"mingcute:layout-leftbar-close-line",
|
|
29
|
+
"mingcute:layout-leftbar-open-line",
|
|
30
|
+
"mingcute:down-small-line",
|
|
31
|
+
"mingcute:search-line",
|
|
32
|
+
"mingcute:close-line",
|
|
33
|
+
"mingcute:arrow-right-line",
|
|
34
|
+
"mingcute:align-arrow-right-line",
|
|
35
|
+
"mingcute:link-2-line",
|
|
36
|
+
"mingcute:settings-3-line",
|
|
37
|
+
"mingcute:code-line",
|
|
38
|
+
"mingcute:refresh-2-line",
|
|
39
|
+
"mingcute:external-link-line",
|
|
40
|
+
"mingcute:paragraph-line",
|
|
41
|
+
"mingcute:heading-2-line",
|
|
42
|
+
"mingcute:heading-3-line",
|
|
43
|
+
"mingcute:bold-line",
|
|
44
|
+
"mingcute:italic-line",
|
|
45
|
+
"mingcute:strikethrough-line",
|
|
46
|
+
"mingcute:link-line",
|
|
47
|
+
"mingcute:pic-line",
|
|
48
|
+
"mingcute:list-check-line",
|
|
49
|
+
"mingcute:list-ordered-line",
|
|
50
|
+
"mingcute:quote-left-line",
|
|
51
|
+
"mingcute:back-2-line",
|
|
52
|
+
"mingcute:forward-2-line",
|
|
53
|
+
"mingcute:download-2-line",
|
|
54
|
+
"mingcute:upload-2-line"
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
20
60
|
async setup(options, nuxt) {
|
|
21
61
|
const logger = useLogger("eponyme");
|
|
22
62
|
const resolver = createResolver(import.meta.url);
|
|
@@ -30,53 +70,26 @@ const module$1 = defineNuxtModule({
|
|
|
30
70
|
nuxt.options.runtimeConfig.eponymeAuth = {
|
|
31
71
|
sessionDurationDays: options.auth?.sessionDurationDays ?? 7
|
|
32
72
|
};
|
|
33
|
-
await installModule("@nuxt/icon", {
|
|
34
|
-
serverBundle: { collections: ["mingcute"] },
|
|
35
|
-
clientBundle: {
|
|
36
|
-
// Explicit list: an icon missing here is not bundled and renders blank in production.
|
|
37
|
-
icons: [
|
|
38
|
-
"mingcute:history-anticlockwise-line",
|
|
39
|
-
"mingcute:eye-2-line",
|
|
40
|
-
"mingcute:layout-leftbar-close-line",
|
|
41
|
-
"mingcute:layout-leftbar-open-line",
|
|
42
|
-
"mingcute:down-small-line",
|
|
43
|
-
"mingcute:search-line",
|
|
44
|
-
"mingcute:close-line",
|
|
45
|
-
"mingcute:arrow-right-line",
|
|
46
|
-
"mingcute:align-arrow-right-line",
|
|
47
|
-
"mingcute:link-2-line",
|
|
48
|
-
"mingcute:settings-3-line",
|
|
49
|
-
"mingcute:refresh-2-line",
|
|
50
|
-
"mingcute:external-link-line",
|
|
51
|
-
"mingcute:paragraph-line",
|
|
52
|
-
"mingcute:heading-2-line",
|
|
53
|
-
"mingcute:heading-3-line",
|
|
54
|
-
"mingcute:bold-line",
|
|
55
|
-
"mingcute:italic-line",
|
|
56
|
-
"mingcute:strikethrough-line",
|
|
57
|
-
"mingcute:link-line",
|
|
58
|
-
"mingcute:pic-line",
|
|
59
|
-
"mingcute:list-check-line",
|
|
60
|
-
"mingcute:list-ordered-line",
|
|
61
|
-
"mingcute:quote-left-line",
|
|
62
|
-
"mingcute:back-2-line",
|
|
63
|
-
"mingcute:forward-2-line"
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
}, nuxt);
|
|
67
73
|
const preparing = Boolean(nuxt.options._prepare);
|
|
68
74
|
if (!options.prismaClient) {
|
|
69
75
|
if (!preparing) throw new Error(`${pc.red("[Eponyme]")} eponyme.prismaClient is required.`);
|
|
70
76
|
logger.info("No prismaClient configured, skipping wiring (prepare).");
|
|
71
77
|
return;
|
|
72
78
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
const prismaSpecifier = options.prismaClient.replace(/^[~@]{2}\//, `${nuxt.options.rootDir}/`).replace(/^[~@]\//, `${nuxt.options.srcDir}/`);
|
|
80
|
+
const prismaPath = await findPath(resolve(nuxt.options.rootDir, prismaSpecifier));
|
|
81
|
+
if (!prismaPath) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`${pc.red("[Eponyme]")} Prisma client module not found: ${options.prismaClient}
|
|
84
|
+
Expected a module exporting a PrismaClient as its default export, for example '~~/server/utils/prisma'.
|
|
85
|
+
Note that '~/' points at ${nuxt.options.srcDir}, so a server module needs '~~/'.`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
76
88
|
addImports([
|
|
77
89
|
{ name: "defineEponymeConfig", from: resolver.resolve("./config/config") },
|
|
78
90
|
{ name: "collection", from: resolver.resolve("./config/collection") },
|
|
79
91
|
{ name: "form", from: resolver.resolve("./config/form") },
|
|
92
|
+
{ name: "defineEponymeVariables", from: resolver.resolve("./config/variables") },
|
|
80
93
|
{ name: "field", from: resolver.resolve("./runtime/fields") },
|
|
81
94
|
{ name: "today", from: resolver.resolve("./runtime/fields") }
|
|
82
95
|
]);
|
|
@@ -96,6 +109,12 @@ const module$1 = defineNuxtModule({
|
|
|
96
109
|
path: resolver.resolve("./runtime/middleware/eponyme-owner")
|
|
97
110
|
});
|
|
98
111
|
nuxt.options.build.transpile.push("reka-ui");
|
|
112
|
+
nuxt.options.vite.optimizeDeps ??= {};
|
|
113
|
+
nuxt.options.vite.optimizeDeps.include = [
|
|
114
|
+
...nuxt.options.vite.optimizeDeps.include ?? [],
|
|
115
|
+
"slugify",
|
|
116
|
+
"sortablejs"
|
|
117
|
+
];
|
|
99
118
|
nuxt.options.css.push(resolver.resolve("./runtime/assets/dashboard.css"));
|
|
100
119
|
nuxt.hook("vite:extendConfig", (viteConfig) => {
|
|
101
120
|
const plugins = viteConfig.plugins;
|
|
@@ -109,23 +128,34 @@ const module$1 = defineNuxtModule({
|
|
|
109
128
|
}
|
|
110
129
|
nuxt.options.alias["#eponyme/config"] = configPath;
|
|
111
130
|
nuxt.options.alias["#eponyme/prisma"] = prismaPath;
|
|
131
|
+
const variablesPath = await findPath(resolve(nuxt.options.rootDir, "eponyme.variables.ts"));
|
|
132
|
+
nuxt.options.alias["#eponyme/variables"] = variablesPath ?? resolver.resolve("./runtime/utils/empty-variables");
|
|
112
133
|
addTypeTemplate({
|
|
113
134
|
filename: "types/eponyme-config.d.ts",
|
|
114
135
|
getContents: () => `declare module '#eponyme/config' {
|
|
115
136
|
const config: typeof import(${JSON.stringify(configPath)})['default']
|
|
116
137
|
export default config
|
|
117
138
|
}
|
|
139
|
+
declare module '#eponyme/variables' {
|
|
140
|
+
const variables: typeof import(${JSON.stringify(nuxt.options.alias["#eponyme/variables"])})['default']
|
|
141
|
+
export default variables
|
|
142
|
+
}
|
|
118
143
|
`
|
|
119
144
|
});
|
|
120
145
|
addServerHandler({ route: "/api/eponyme/**", handler: resolver.resolve("./runtime/server/api/eponyme/[name].get") });
|
|
121
146
|
addServerHandler({ route: "/api/eponyme/**", method: "patch", handler: resolver.resolve("./runtime/server/api/eponyme/[name].patch") });
|
|
122
147
|
addServerHandler({ route: "/api/eponyme-statuses", handler: resolver.resolve("./runtime/server/api/eponyme-statuses.get") });
|
|
123
148
|
addServerHandler({ route: "/api/eponyme-sitemap", handler: resolver.resolve("./runtime/server/api/eponyme-sitemap.get") });
|
|
149
|
+
addServerHandler({ route: "/api/eponyme-export", handler: resolver.resolve("./runtime/server/api/eponyme-export.get") });
|
|
150
|
+
addServerHandler({ route: "/api/eponyme-import", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-import.post") });
|
|
124
151
|
addServerHandler({ route: "/api/eponyme-history/**", handler: resolver.resolve("./runtime/server/api/eponyme-history/[path].get") });
|
|
125
152
|
addServerHandler({ route: "/api/eponyme-history/**", method: "patch", handler: resolver.resolve("./runtime/server/api/eponyme-history/[path].patch") });
|
|
126
153
|
addServerHandler({ route: "/api/eponyme-collections/**", handler: resolver.resolve("./runtime/server/api/eponyme-collections/[path].get") });
|
|
127
154
|
addServerHandler({ route: "/api/eponyme-collections/**", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-collections/[path].post") });
|
|
128
155
|
addServerHandler({ route: "/api/eponyme-collections/**", method: "delete", handler: resolver.resolve("./runtime/server/api/eponyme-collections/[path].delete") });
|
|
156
|
+
addServerHandler({ route: "/api/eponyme-trash/**", handler: resolver.resolve("./runtime/server/api/eponyme-trash/[path].get") });
|
|
157
|
+
addServerHandler({ route: "/api/eponyme-trash/**", method: "patch", handler: resolver.resolve("./runtime/server/api/eponyme-trash/[path].patch") });
|
|
158
|
+
addServerHandler({ route: "/api/eponyme-trash/**", method: "delete", handler: resolver.resolve("./runtime/server/api/eponyme-trash/[path].delete") });
|
|
129
159
|
addServerHandler({ route: "/api/eponyme-forms/**", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].get") });
|
|
130
160
|
addServerHandler({ route: "/api/eponyme-forms/**", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].post") });
|
|
131
161
|
addServerHandler({ route: "/api/eponyme-forms/**", method: "delete", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].delete") });
|
|
@@ -140,11 +170,11 @@ const module$1 = defineNuxtModule({
|
|
|
140
170
|
addServerPlugin(resolver.resolve("./runtime/server/plugins/eponyme-sync"));
|
|
141
171
|
nuxt.hook("pages:extend", (pages) => {
|
|
142
172
|
pages.push(
|
|
143
|
-
{ name: "eponyme-login", path: `${dashboardPath}/login`, file: resolver.resolve("./runtime/pages/EponymeLoginPage.vue") },
|
|
144
|
-
{ name: "eponyme-change-password", path: `${dashboardPath}/change-password`, file: resolver.resolve("./runtime/pages/EponymeChangePasswordPage.vue"), meta: { middleware: ["eponyme-auth"] } },
|
|
145
|
-
{ name: "eponyme-users", path: `${dashboardPath}/users`, file: resolver.resolve("./runtime/pages/EponymeUsersPage.vue"), meta: { middleware: ["eponyme-auth", "eponyme-owner"] } },
|
|
146
|
-
{ name: "eponyme-index", path: dashboardPath, file: resolver.resolve("./runtime/pages/EponymeIndexPage.vue"), meta: { middleware: ["eponyme-auth"] } },
|
|
147
|
-
{ name: "eponyme-detail", path: `${dashboardPath}/:eponyme(.*)*`, file: resolver.resolve("./runtime/pages/EponymeDetailPage.vue"), meta: { middleware: ["eponyme-auth"] } }
|
|
173
|
+
{ name: "eponyme-login", path: `${dashboardPath}/login`, file: resolver.resolve("./runtime/pages/EponymeLoginPage.vue"), meta: { layout: false } },
|
|
174
|
+
{ name: "eponyme-change-password", path: `${dashboardPath}/change-password`, file: resolver.resolve("./runtime/pages/EponymeChangePasswordPage.vue"), meta: { layout: false, middleware: ["eponyme-auth"] } },
|
|
175
|
+
{ name: "eponyme-users", path: `${dashboardPath}/users`, file: resolver.resolve("./runtime/pages/EponymeUsersPage.vue"), meta: { layout: false, middleware: ["eponyme-auth", "eponyme-owner"] } },
|
|
176
|
+
{ name: "eponyme-index", path: dashboardPath, file: resolver.resolve("./runtime/pages/EponymeIndexPage.vue"), meta: { layout: false, middleware: ["eponyme-auth"] } },
|
|
177
|
+
{ name: "eponyme-detail", path: `${dashboardPath}/:eponyme(.*)*`, file: resolver.resolve("./runtime/pages/EponymeDetailPage.vue"), meta: { layout: false, middleware: ["eponyme-auth"] } }
|
|
148
178
|
);
|
|
149
179
|
});
|
|
150
180
|
logger.debug(`config loaded: ${configPath}`);
|