@micelio/strapi-plugin-core 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 +5 -3
- package/dist/admin/MicelioLayout-Bmu5xCw9.js +1023 -0
- package/dist/admin/MicelioLayout-DMMsKnMo.mjs +1021 -0
- package/dist/admin/PreviewHeaderAction-BaduMvYy.mjs +61 -0
- package/dist/admin/PreviewHeaderAction-CGHycv4I.js +61 -0
- package/dist/admin/{en-D-T8z3qh.js → en-BDVuq0fN.js} +37 -1
- package/dist/admin/{en-C2O-S2ym.mjs → en-Bahc6y6N.mjs} +37 -1
- package/dist/admin/{es-RV0vkOHh.js → es-DStBGkm7.js} +37 -1
- package/dist/admin/{es-CQ2tv9N8.mjs → es-nUHBIoZG.mjs} +37 -1
- package/dist/admin/{index-D3TGbaQ7.js → index-D_Dbvo2F.js} +8 -2
- package/dist/admin/{index-CiSujTES.mjs → index-Dwr15ZsB.mjs} +8 -2
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/permissions-BAI0qDr9.js +24 -0
- package/dist/admin/permissions-CYirM30e.mjs +25 -0
- package/dist/admin/src/components/EyeIcon.d.ts +8 -0
- package/dist/admin/src/components/PreviewFrame.d.ts +47 -0
- package/dist/admin/src/components/PreviewHeaderAction.d.ts +28 -0
- package/dist/admin/src/hooks/useEntry.d.ts +31 -0
- package/dist/admin/src/hooks/usePreviewSource.d.ts +31 -0
- package/dist/admin/src/pages/MicelioLayout.d.ts +2 -1
- package/dist/admin/src/pages/PreviewPage.d.ts +2 -0
- package/dist/admin/src/permissions.d.ts +5 -0
- package/dist/admin/src/translations/en.json.d.ts +37 -1
- package/dist/admin/src/utils/fetchError.d.ts +2 -0
- package/dist/admin/src/utils/previewAction.d.ts +22 -0
- package/dist/admin/src/utils/previewPane.d.ts +59 -0
- package/dist/server/index.js +796 -105
- package/dist/server/index.mjs +796 -105
- package/dist/server/src/constants/preview.d.ts +2 -0
- package/dist/server/src/constants/taxonomy.d.ts +13 -0
- package/dist/server/src/content-types/category/schema.json.d.ts +78 -0
- package/dist/server/src/content-types/index.d.ts +125 -2
- package/dist/server/src/content-types/preview-credential/schema.json.d.ts +7 -6
- package/dist/server/src/content-types/tag/schema.json.d.ts +46 -0
- package/dist/server/src/controllers/index.d.ts +6 -0
- package/dist/server/src/editorial/transitions.d.ts +5 -2
- package/dist/server/src/index.d.ts +140 -2
- package/dist/server/src/migrations/rename-legacy-uids.d.ts +26 -0
- package/dist/server/src/migrations/site-backfill.d.ts +13 -0
- package/dist/server/src/preview/credentials.d.ts +7 -5
- package/dist/server/src/preview/draft-query.d.ts +62 -0
- package/dist/server/src/preview/revocation.d.ts +9 -1
- package/dist/server/src/preview/shortcut.d.ts +24 -0
- package/dist/server/src/routes/index.d.ts +2 -0
- package/dist/server/src/routes/taxonomy.d.ts +12 -0
- package/dist/server/src/services/index.d.ts +6 -0
- package/dist/server/src/services/preview.d.ts +25 -6
- package/dist/server/src/site-scope/documents.d.ts +13 -3
- package/dist/server/src/types/hooks.d.ts +5 -4
- package/dist/server/src/types/preview.d.ts +35 -10
- package/package.json +4 -3
- package/dist/admin/MicelioLayout-3sKGPS_0.mjs +0 -443
- package/dist/admin/MicelioLayout-DXzRS4l3.js +0 -443
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { Core } from '@strapi/strapi';
|
|
2
2
|
/**
|
|
3
|
-
* Revokes every preview token and grant of an admin user
|
|
3
|
+
* Revokes every preview token and grant of an admin user before their logout answers.
|
|
4
4
|
*
|
|
5
5
|
* @remarks
|
|
6
|
+
* Strapi emits `admin.logout` without waiting for its listeners, so a listener can still be
|
|
7
|
+
* revoking when the logout response is sent and a draft request that follows finds the grant. An
|
|
8
|
+
* application middleware, which wraps every request and acts only on the admin's logout route
|
|
9
|
+
* (the route Strapi resolved, not a path, so every spelling the router accepts revokes), awaits
|
|
10
|
+
* `revoke` after the controller has run and before the response leaves, so no grant of the user
|
|
11
|
+
* is served once the logout has answered (ADR-0019, section 3). A failure is logged and does not
|
|
12
|
+
* fail the logout.
|
|
13
|
+
*
|
|
6
14
|
* Losing the right to read a draft revokes its grants when the next exchange or draft request
|
|
7
15
|
* checks the user's abilities again (`stillReadable` in the `preview` service).
|
|
8
16
|
*/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Core } from '@strapi/strapi';
|
|
2
|
+
/** What Strapi hands the `admin.preview` handler: the entry its "Open preview" button was pressed on. */
|
|
3
|
+
interface PreviewHandlerParams {
|
|
4
|
+
documentId?: string;
|
|
5
|
+
locale?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The admin URL of the preview page for an entry, or `undefined` for a type that has no preview.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* A collection type has one when it belongs to a site and has a dynamic zone, the same rule
|
|
12
|
+
* the edit view's action follows. `undefined` makes Strapi answer `204`, and it shows no "Open preview" button.
|
|
13
|
+
*/
|
|
14
|
+
export declare function previewPageUrl(strapi: Core.Strapi, uid: string, { documentId, locale }: PreviewHandlerParams): string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Points Strapi's own "Open preview" button at the plugin's preview page, unless the host has
|
|
17
|
+
* configured `admin.preview` itself.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* The host's `config/admin` wins, `enabled: false` included. Strapi reads the handler on each
|
|
21
|
+
* request, so setting it while the plugin registers is early enough.
|
|
22
|
+
*/
|
|
23
|
+
export declare function registerPreviewShortcut(strapi: Core.Strapi): void;
|
|
24
|
+
export {};
|
|
@@ -2,5 +2,7 @@ declare const _default: {
|
|
|
2
2
|
'content-api': () => import('@strapi/types/dist/core').RouterInput;
|
|
3
3
|
admin: () => import('@strapi/types/dist/core').RouterInput;
|
|
4
4
|
site: import('@strapi/types/dist/core/core-api/router').Router;
|
|
5
|
+
category: import('@strapi/types/dist/core/core-api/router').Router;
|
|
6
|
+
tag: import('@strapi/types/dist/core/core-api/router').Router;
|
|
5
7
|
};
|
|
6
8
|
export default _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The content API routes of the category type: `/api/categories` and `/api/categories/:id`.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* `prefix: ''` drops the `/micelio` segment a plugin's content-api routes get, so the paths are
|
|
6
|
+
* those `micelio-cms` 0.5 and the frontend have (ADR-0017, amendments of 2026-10-21 and
|
|
7
|
+
* 2026-10-26). A host that has routes of its own on these paths keeps them: host routes register
|
|
8
|
+
* first.
|
|
9
|
+
*/
|
|
10
|
+
export declare const categoryRoutes: import('@strapi/types/dist/core/core-api/router').Router;
|
|
11
|
+
/** The content API routes of the tag type: `/api/tags` and `/api/tags/:id`, as {@link categoryRoutes}. */
|
|
12
|
+
export declare const tagRoutes: import('@strapi/types/dist/core/core-api/router').Router;
|
|
@@ -2,6 +2,12 @@ declare const _default: {
|
|
|
2
2
|
site: ({ strapi, }: {
|
|
3
3
|
strapi: import('@strapi/types/dist/core').Strapi;
|
|
4
4
|
}) => Partial<import('@strapi/types/dist/core/core-api/service').Base> & import('@strapi/types/dist/core/core-api/service').Generic & import('@strapi/types/dist/core/core-api/service').Base;
|
|
5
|
+
category: ({ strapi, }: {
|
|
6
|
+
strapi: import('@strapi/types/dist/core').Strapi;
|
|
7
|
+
}) => Partial<import('@strapi/types/dist/core/core-api/service').Base> & import('@strapi/types/dist/core/core-api/service').Generic & import('@strapi/types/dist/core/core-api/service').Base;
|
|
8
|
+
tag: ({ strapi, }: {
|
|
9
|
+
strapi: import('@strapi/types/dist/core').Strapi;
|
|
10
|
+
}) => Partial<import('@strapi/types/dist/core/core-api/service').Base> & import('@strapi/types/dist/core/core-api/service').Generic & import('@strapi/types/dist/core/core-api/service').Base;
|
|
5
11
|
transitions: ({ strapi }: {
|
|
6
12
|
strapi: import('@strapi/types/dist/core').Strapi;
|
|
7
13
|
}) => import('./transitions').TransitionsService;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Core } from '@strapi/strapi';
|
|
2
|
-
import { PreviewBinding, PreviewExpectation, PreviewGrantAnswer, PreviewTokenAnswer } from '../types/preview';
|
|
2
|
+
import { PreviewBinding, PreviewExpectation, PreviewGrantAnswer, PreviewResolvedGrant, PreviewSystemBinding, PreviewTokenAnswer } from '../types/preview';
|
|
3
3
|
/** The `preview` service: `strapi.plugin('micelio').service('preview')`, behind the preview routes. */
|
|
4
4
|
export interface PreviewService {
|
|
5
5
|
/**
|
|
@@ -20,14 +20,33 @@ export interface PreviewService {
|
|
|
20
20
|
*/
|
|
21
21
|
exchange(token: string, siteDocumentId: string): Promise<PreviewGrantAnswer | null>;
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* Makes a system grant for one version of a draft, and returns its value once.
|
|
24
24
|
*
|
|
25
25
|
* @remarks
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* For plugin code that measures a draft at publish (ADR-0019, amendment of 2026-10-25); no
|
|
27
|
+
* route mints one. The grant lives 60 s, is used once, is bound to the site, type, document,
|
|
28
|
+
* locale and `binding.entryVersion`, and has no admin user. It is stored hashed; expired
|
|
29
|
+
* credentials past their retention are removed on the way. The caller sends it to the
|
|
30
|
+
* frontend's weight route only, never to a browser, and never logs it.
|
|
31
|
+
*/
|
|
32
|
+
issueSystemGrant(binding: PreviewSystemBinding): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* What a usable grant names and who it acts for, or `null` for every refusal.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* An `admin` grant checks again that the admin user may read the draft; when they may not,
|
|
38
|
+
* every grant of that user and draft is revoked. A `system` grant is claimed with one
|
|
39
|
+
* conditional update, so of two checks at once one finds it spent, and it has no user to ask.
|
|
40
|
+
* Whether the draft is still the version the system grant was minted for is for the caller to
|
|
41
|
+
* check (`entryVersion`).
|
|
42
|
+
*/
|
|
43
|
+
resolveGrant(grant: string, expected: PreviewExpectation): Promise<PreviewResolvedGrant | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Revokes every unexpired token and grant of an admin user, or only those of one draft.
|
|
46
|
+
*
|
|
47
|
+
* @remarks
|
|
48
|
+
* System grants have no admin user, so this never touches one: 60 s and a single use bound them.
|
|
28
49
|
*/
|
|
29
|
-
resolveGrant(grant: string, expected: PreviewExpectation): Promise<PreviewBinding | null>;
|
|
30
|
-
/** Revokes every unexpired token and grant of an admin user, or only those of one draft. */
|
|
31
50
|
revoke(adminUser: number, entryDocumentId?: string): Promise<void>;
|
|
32
51
|
}
|
|
33
52
|
/** The site of a preview has no frontend origin: the token route answers `409` `previewUnavailable`. */
|
|
@@ -4,8 +4,18 @@ import { Core, Modules } from '@strapi/strapi';
|
|
|
4
4
|
*
|
|
5
5
|
* @remarks
|
|
6
6
|
* Outside a request scoped by the `site-scope` route middleware (the admin, boot steps, other
|
|
7
|
-
* plugins) it only refuses to create an entry without a site or to remove its site.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* plugins) it only refuses to create an entry without a site or to remove its site. An update
|
|
8
|
+
* whose `site` leaves the relation as it is (the Content Manager sends empty `connect` and
|
|
9
|
+
* `disconnect`) does not touch it. An update that adds a locale to an entry gives it the site of
|
|
10
|
+
* the entry's other locales, because Strapi's i18n does not copy a relation, and is refused with
|
|
11
|
+
* "site is required" when those rows name different sites or none and the update names none, or with
|
|
12
|
+
* "site must be the site of the other locales" when it names another one. An update may change the
|
|
13
|
+
* site of an existing locale only when no other locale of the entry stays on another site, and is
|
|
14
|
+
* refused otherwise ("site cannot change while other locales of the document stay on another
|
|
15
|
+
* site"); an entry of a single locale moves freely. Inside a scoped request, it also filters every read by the
|
|
16
|
+
* request's site after Strapi has sanitised the query, gives a new entry the request's site and
|
|
17
|
+
* keeps an updated one there whatever `site` the body names, and answers "not found" for a write
|
|
18
|
+
* to another site's entry, before anything else is read. Publishing or discarding the draft of a
|
|
19
|
+
* locale keeps its site on the row Strapi rebuilds.
|
|
10
20
|
*/
|
|
11
21
|
export declare function siteScopeDocuments(strapi: Core.Strapi): Modules.Documents.Middleware.Middleware;
|
|
@@ -85,12 +85,13 @@ export interface HookPayloads {
|
|
|
85
85
|
*/
|
|
86
86
|
afterTransition: TransitionPayload;
|
|
87
87
|
/**
|
|
88
|
-
* Runs after an entry's version goes live: today, after `in_review → published
|
|
89
|
-
* `scheduled → published
|
|
88
|
+
* Runs after an entry's version goes live: today, after `in_review → published`,
|
|
89
|
+
* `scheduled → published` and `published → published` (republish), following `afterTransition`.
|
|
90
90
|
*
|
|
91
91
|
* @remarks
|
|
92
|
-
* Treat it as "this version is now live", not "first publication":
|
|
93
|
-
*
|
|
92
|
+
* Treat it as "this version is now live", not "first publication": `published → published`
|
|
93
|
+
* puts the edits of a published entry live (ADR-0017, amendment of 2026-10-25), and this hook
|
|
94
|
+
* fires for it too, with `afterTransition` carrying `published` as both `from` and `to`. A
|
|
94
95
|
* handler that publishes elsewhere (the fediverse, a static rebuild) must be idempotent per
|
|
95
96
|
* `documentId` and `locale`.
|
|
96
97
|
*/
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
/** What
|
|
2
|
-
export interface
|
|
3
|
-
/** The `id` of the admin user who asked for the token. */
|
|
4
|
-
adminUser: number;
|
|
5
|
-
/** The origin of the admin page that asked, which the frontend frames itself for. */
|
|
6
|
-
adminOrigin: string;
|
|
1
|
+
/** What every preview credential is bound to: one document of one site. */
|
|
2
|
+
export interface PreviewTarget {
|
|
7
3
|
/** The `documentId` of the site. */
|
|
8
4
|
siteDocumentId: string;
|
|
9
5
|
/** The content type UID. */
|
|
@@ -12,19 +8,48 @@ export interface PreviewBinding {
|
|
|
12
8
|
/** The locale of the draft; `null` for a type that is not localised. */
|
|
13
9
|
entryLocale: string | null;
|
|
14
10
|
}
|
|
15
|
-
/**
|
|
16
|
-
export
|
|
11
|
+
/** What a preview token or grant is bound to (ADR-0019, section 3). */
|
|
12
|
+
export interface PreviewBinding extends PreviewTarget {
|
|
13
|
+
/** The `id` of the admin user who asked for the token. */
|
|
14
|
+
adminUser: number;
|
|
15
|
+
/** The origin of the admin page that asked, which the frontend frames itself for. */
|
|
16
|
+
adminOrigin: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* What a system grant is bound to (ADR-0019, amendment of 2026-10-25): a document and the version
|
|
20
|
+
* of its draft, and no admin user.
|
|
21
|
+
*/
|
|
22
|
+
export interface PreviewSystemBinding extends PreviewTarget {
|
|
23
|
+
/** The `updatedAt` of the draft at the moment of minting, as an ISO 8601 date. */
|
|
24
|
+
entryVersion: string;
|
|
25
|
+
}
|
|
26
|
+
/** Which of the credentials a record is: a token, a grant, or the plugin's own system grant. */
|
|
27
|
+
export type PreviewCredentialKind = 'token' | 'grant' | 'system';
|
|
28
|
+
/** Who a grant acts for: an admin user, or the plugin itself. */
|
|
29
|
+
export type PreviewActor = 'admin' | 'system';
|
|
17
30
|
/** A credential as the store keeps it: never its value, only the hash. */
|
|
18
|
-
export interface PreviewCredentialRecord extends
|
|
31
|
+
export interface PreviewCredentialRecord extends PreviewTarget {
|
|
19
32
|
kind: PreviewCredentialKind;
|
|
20
33
|
/** SHA-256 of the value, in hex. */
|
|
21
34
|
hash: string;
|
|
35
|
+
/** The admin user a token or grant is bound to; `null` for a system grant. */
|
|
36
|
+
adminUser: number | null;
|
|
37
|
+
/** The admin origin a token or grant is bound to; `null` for a system grant. */
|
|
38
|
+
adminOrigin: string | null;
|
|
39
|
+
/** The `updatedAt` of the draft a system grant was minted for; `null` for the other kinds. */
|
|
40
|
+
entryVersion: string | null;
|
|
22
41
|
expiresAt: Date;
|
|
23
|
-
/** When a token was exchanged; `null` while unused, and always `null` for a grant. */
|
|
42
|
+
/** When a token was exchanged or a system grant was used; `null` while unused, and always `null` for a grant. */
|
|
24
43
|
usedAt: Date | null;
|
|
25
44
|
/** When logging out or losing the right to read the document ended it. */
|
|
26
45
|
revokedAt: Date | null;
|
|
27
46
|
}
|
|
47
|
+
/** The grant a request presented, once it checked out: what it names and who it acts for. */
|
|
48
|
+
export interface PreviewResolvedGrant extends PreviewTarget {
|
|
49
|
+
actor: PreviewActor;
|
|
50
|
+
/** The version a `system` grant was minted for; `null` for an `admin` grant. */
|
|
51
|
+
entryVersion: string | null;
|
|
52
|
+
}
|
|
28
53
|
/** What a request presents a credential for. Absent fields are not checked. */
|
|
29
54
|
export interface PreviewExpectation {
|
|
30
55
|
siteDocumentId: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@micelio/strapi-plugin-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Micelio's core as a Strapi 5 plugin: sites, blocks, the editorial workflow, hooks and the host check.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"micelio"
|
|
15
15
|
],
|
|
16
16
|
"engines": {
|
|
17
|
-
"node": ">=22.
|
|
17
|
+
"node": ">=22.19.0"
|
|
18
18
|
},
|
|
19
19
|
"micelio": "0.6",
|
|
20
20
|
"strapi": {
|
|
@@ -100,6 +100,7 @@
|
|
|
100
100
|
"@micelio/tsconfig": "^0.1.0",
|
|
101
101
|
"@strapi/design-system": "^2.2.4",
|
|
102
102
|
"@strapi/icons": "^2.2.4",
|
|
103
|
+
"@strapi/plugin-users-permissions": "^5.59.0",
|
|
103
104
|
"@strapi/sdk-plugin": "^6.1.1",
|
|
104
105
|
"@strapi/strapi": "^5.59.0",
|
|
105
106
|
"@strapi/typescript-utils": "^5.59.0",
|
|
@@ -110,7 +111,7 @@
|
|
|
110
111
|
"better-sqlite3": "12.11.1",
|
|
111
112
|
"eslint": "^10.12.0",
|
|
112
113
|
"jiti": "^2.7.0",
|
|
113
|
-
"playwright": "
|
|
114
|
+
"playwright": "1.64.1",
|
|
114
115
|
"postcss": "^8.5.31",
|
|
115
116
|
"prettier": "^3.9.10",
|
|
116
117
|
"react": "^18.3.1",
|