@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.
Files changed (54) hide show
  1. package/README.md +5 -3
  2. package/dist/admin/MicelioLayout-Bmu5xCw9.js +1023 -0
  3. package/dist/admin/MicelioLayout-DMMsKnMo.mjs +1021 -0
  4. package/dist/admin/PreviewHeaderAction-BaduMvYy.mjs +61 -0
  5. package/dist/admin/PreviewHeaderAction-CGHycv4I.js +61 -0
  6. package/dist/admin/{en-D-T8z3qh.js → en-BDVuq0fN.js} +37 -1
  7. package/dist/admin/{en-C2O-S2ym.mjs → en-Bahc6y6N.mjs} +37 -1
  8. package/dist/admin/{es-RV0vkOHh.js → es-DStBGkm7.js} +37 -1
  9. package/dist/admin/{es-CQ2tv9N8.mjs → es-nUHBIoZG.mjs} +37 -1
  10. package/dist/admin/{index-D3TGbaQ7.js → index-D_Dbvo2F.js} +8 -2
  11. package/dist/admin/{index-CiSujTES.mjs → index-Dwr15ZsB.mjs} +8 -2
  12. package/dist/admin/index.js +1 -1
  13. package/dist/admin/index.mjs +1 -1
  14. package/dist/admin/permissions-BAI0qDr9.js +24 -0
  15. package/dist/admin/permissions-CYirM30e.mjs +25 -0
  16. package/dist/admin/src/components/EyeIcon.d.ts +8 -0
  17. package/dist/admin/src/components/PreviewFrame.d.ts +47 -0
  18. package/dist/admin/src/components/PreviewHeaderAction.d.ts +28 -0
  19. package/dist/admin/src/hooks/useEntry.d.ts +31 -0
  20. package/dist/admin/src/hooks/usePreviewSource.d.ts +31 -0
  21. package/dist/admin/src/pages/MicelioLayout.d.ts +2 -1
  22. package/dist/admin/src/pages/PreviewPage.d.ts +2 -0
  23. package/dist/admin/src/permissions.d.ts +5 -0
  24. package/dist/admin/src/translations/en.json.d.ts +37 -1
  25. package/dist/admin/src/utils/fetchError.d.ts +2 -0
  26. package/dist/admin/src/utils/previewAction.d.ts +22 -0
  27. package/dist/admin/src/utils/previewPane.d.ts +59 -0
  28. package/dist/server/index.js +796 -105
  29. package/dist/server/index.mjs +796 -105
  30. package/dist/server/src/constants/preview.d.ts +2 -0
  31. package/dist/server/src/constants/taxonomy.d.ts +13 -0
  32. package/dist/server/src/content-types/category/schema.json.d.ts +78 -0
  33. package/dist/server/src/content-types/index.d.ts +125 -2
  34. package/dist/server/src/content-types/preview-credential/schema.json.d.ts +7 -6
  35. package/dist/server/src/content-types/tag/schema.json.d.ts +46 -0
  36. package/dist/server/src/controllers/index.d.ts +6 -0
  37. package/dist/server/src/editorial/transitions.d.ts +5 -2
  38. package/dist/server/src/index.d.ts +140 -2
  39. package/dist/server/src/migrations/rename-legacy-uids.d.ts +26 -0
  40. package/dist/server/src/migrations/site-backfill.d.ts +13 -0
  41. package/dist/server/src/preview/credentials.d.ts +7 -5
  42. package/dist/server/src/preview/draft-query.d.ts +62 -0
  43. package/dist/server/src/preview/revocation.d.ts +9 -1
  44. package/dist/server/src/preview/shortcut.d.ts +24 -0
  45. package/dist/server/src/routes/index.d.ts +2 -0
  46. package/dist/server/src/routes/taxonomy.d.ts +12 -0
  47. package/dist/server/src/services/index.d.ts +6 -0
  48. package/dist/server/src/services/preview.d.ts +25 -6
  49. package/dist/server/src/site-scope/documents.d.ts +13 -3
  50. package/dist/server/src/types/hooks.d.ts +5 -4
  51. package/dist/server/src/types/preview.d.ts +35 -10
  52. package/package.json +4 -3
  53. package/dist/admin/MicelioLayout-3sKGPS_0.mjs +0 -443
  54. package/dist/admin/MicelioLayout-DXzRS4l3.js +0 -443
@@ -10,6 +10,8 @@ export declare const PREVIEW_GRANT_HEADER = "x-micelio-preview-grant";
10
10
  export declare const PREVIEW_TOKEN_TTL_SECONDS = 60;
11
11
  /** How long a preview grant is valid, in seconds. */
12
12
  export declare const PREVIEW_GRANT_TTL_SECONDS: number;
13
+ /** How long a system grant is valid, in seconds (ADR-0019, amendment of 2026-10-25). */
14
+ export declare const PREVIEW_SYSTEM_GRANT_TTL_SECONDS = 60;
13
15
  /** How long an expired credential stays in the store before the next token request removes it. */
14
16
  export declare const PREVIEW_CREDENTIAL_RETENTION_SECONDS: number;
15
17
  /** The window of the rate limits, in seconds. */
@@ -0,0 +1,13 @@
1
+ /** UID of the `category` content type: the topics an entry is filed under. */
2
+ export declare const CATEGORY_UID = "plugin::micelio.category";
3
+ /** UID of the `tag` content type: the labels an entry carries. */
4
+ export declare const TAG_UID = "plugin::micelio.tag";
5
+ /**
6
+ * Content API actions a read-only token needs for the taxonomy types.
7
+ *
8
+ * @remarks
9
+ * A distribution spreads them into its token lists, so this plugin stays the source of truth for
10
+ * its own UIDs. Role and token grants stay in the host: a plugin's `bootstrap` has no order
11
+ * relative to the other plugins' (ADR-0017, amendment of 2026-10-23).
12
+ */
13
+ export declare const READ_ACTIONS: readonly ["plugin::micelio.category.find", "plugin::micelio.tag.find"];
@@ -0,0 +1,78 @@
1
+ declare const _default: {
2
+ "kind": "collectionType",
3
+ "collectionName": "categories",
4
+ "info": {
5
+ "singularName": "category",
6
+ "pluralName": "categories",
7
+ "displayName": "Category",
8
+ "description": "Organize your content into categories"
9
+ },
10
+ "options": {
11
+ "draftAndPublish": false
12
+ },
13
+ "pluginOptions": {
14
+ "content-manager": {
15
+ "visible": true
16
+ },
17
+ "i18n": {
18
+ "localized": true
19
+ }
20
+ },
21
+ "attributes": {
22
+ "name": {
23
+ "type": "string",
24
+ "pluginOptions": {
25
+ "i18n": {
26
+ "localized": true
27
+ }
28
+ }
29
+ },
30
+ "slug": {
31
+ "type": "uid",
32
+ "regex": "^(?!\\.{1,2}$)[A-Za-z0-9-_.~]*$",
33
+ "pluginOptions": {
34
+ "i18n": {
35
+ "localized": false
36
+ }
37
+ }
38
+ },
39
+ "description": {
40
+ "type": "text",
41
+ "pluginOptions": {
42
+ "i18n": {
43
+ "localized": true
44
+ }
45
+ }
46
+ },
47
+ "order": {
48
+ "type": "integer",
49
+ "pluginOptions": {
50
+ "i18n": {
51
+ "localized": false
52
+ }
53
+ }
54
+ },
55
+ "featured": {
56
+ "type": "boolean",
57
+ "default": false,
58
+ "pluginOptions": {
59
+ "i18n": {
60
+ "localized": false
61
+ }
62
+ }
63
+ },
64
+ "color": {
65
+ "type": "integer",
66
+ "min": 1,
67
+ "max": 5,
68
+ "pluginOptions": {
69
+ "i18n": {
70
+ "localized": false
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ ;
77
+
78
+ export default _default;
@@ -259,6 +259,128 @@ declare const _default: {
259
259
  };
260
260
  };
261
261
  };
262
+ category: {
263
+ schema: {
264
+ kind: string;
265
+ collectionName: string;
266
+ info: {
267
+ singularName: string;
268
+ pluralName: string;
269
+ displayName: string;
270
+ description: string;
271
+ };
272
+ options: {
273
+ draftAndPublish: boolean;
274
+ };
275
+ pluginOptions: {
276
+ "content-manager": {
277
+ visible: boolean;
278
+ };
279
+ i18n: {
280
+ localized: boolean;
281
+ };
282
+ };
283
+ attributes: {
284
+ name: {
285
+ type: string;
286
+ pluginOptions: {
287
+ i18n: {
288
+ localized: boolean;
289
+ };
290
+ };
291
+ };
292
+ slug: {
293
+ type: string;
294
+ regex: string;
295
+ pluginOptions: {
296
+ i18n: {
297
+ localized: boolean;
298
+ };
299
+ };
300
+ };
301
+ description: {
302
+ type: string;
303
+ pluginOptions: {
304
+ i18n: {
305
+ localized: boolean;
306
+ };
307
+ };
308
+ };
309
+ order: {
310
+ type: string;
311
+ pluginOptions: {
312
+ i18n: {
313
+ localized: boolean;
314
+ };
315
+ };
316
+ };
317
+ featured: {
318
+ type: string;
319
+ default: boolean;
320
+ pluginOptions: {
321
+ i18n: {
322
+ localized: boolean;
323
+ };
324
+ };
325
+ };
326
+ color: {
327
+ type: string;
328
+ min: number;
329
+ max: number;
330
+ pluginOptions: {
331
+ i18n: {
332
+ localized: boolean;
333
+ };
334
+ };
335
+ };
336
+ };
337
+ };
338
+ };
339
+ tag: {
340
+ schema: {
341
+ kind: string;
342
+ collectionName: string;
343
+ info: {
344
+ singularName: string;
345
+ pluralName: string;
346
+ displayName: string;
347
+ description: string;
348
+ };
349
+ options: {
350
+ draftAndPublish: boolean;
351
+ };
352
+ pluginOptions: {
353
+ "content-manager": {
354
+ visible: boolean;
355
+ };
356
+ i18n: {
357
+ localized: boolean;
358
+ };
359
+ };
360
+ attributes: {
361
+ name: {
362
+ type: string;
363
+ required: boolean;
364
+ pluginOptions: {
365
+ i18n: {
366
+ localized: boolean;
367
+ };
368
+ };
369
+ };
370
+ slug: {
371
+ type: string;
372
+ regex: string;
373
+ targetField: string;
374
+ required: boolean;
375
+ pluginOptions: {
376
+ i18n: {
377
+ localized: boolean;
378
+ };
379
+ };
380
+ };
381
+ };
382
+ };
383
+ };
262
384
  'preview-credential': {
263
385
  schema: {
264
386
  kind: string;
@@ -300,11 +422,12 @@ declare const _default: {
300
422
  };
301
423
  adminUser: {
302
424
  type: string;
303
- required: boolean;
304
425
  };
305
426
  adminOrigin: {
306
427
  type: string;
307
- required: boolean;
428
+ };
429
+ entryVersion: {
430
+ type: string;
308
431
  };
309
432
  siteDocumentId: {
310
433
  type: string;
@@ -5,7 +5,7 @@ declare const _default: {
5
5
  "singularName": "preview-credential",
6
6
  "pluralName": "preview-credentials",
7
7
  "displayName": "Preview credential",
8
- "description": "A preview token or grant of ADR-0019, stored as the hash of its value and bound to one admin user and one draft"
8
+ "description": "A preview token, grant or system grant of ADR-0019, stored as the hash of its value and bound to one draft (and, but for a system grant, to one admin user)"
9
9
  },
10
10
  "options": {
11
11
  "draftAndPublish": false
@@ -27,7 +27,7 @@ declare const _default: {
27
27
  "attributes": {
28
28
  "kind": {
29
29
  "type": "enumeration",
30
- "enum": ["token", "grant"],
30
+ "enum": ["token", "grant", "system"],
31
31
  "required": true
32
32
  },
33
33
  "hash": {
@@ -37,12 +37,13 @@ declare const _default: {
37
37
  "private": true
38
38
  },
39
39
  "adminUser": {
40
- "type": "integer",
41
- "required": true
40
+ "type": "integer"
42
41
  },
43
42
  "adminOrigin": {
44
- "type": "string",
45
- "required": true
43
+ "type": "string"
44
+ },
45
+ "entryVersion": {
46
+ "type": "string"
46
47
  },
47
48
  "siteDocumentId": {
48
49
  "type": "string",
@@ -0,0 +1,46 @@
1
+ declare const _default: {
2
+ "kind": "collectionType",
3
+ "collectionName": "tags",
4
+ "info": {
5
+ "singularName": "tag",
6
+ "pluralName": "tags",
7
+ "displayName": "Tag",
8
+ "description": "Topics an article covers, used to filter the blog"
9
+ },
10
+ "options": {
11
+ "draftAndPublish": false
12
+ },
13
+ "pluginOptions": {
14
+ "content-manager": {
15
+ "visible": true
16
+ },
17
+ "i18n": {
18
+ "localized": true
19
+ }
20
+ },
21
+ "attributes": {
22
+ "name": {
23
+ "type": "string",
24
+ "required": true,
25
+ "pluginOptions": {
26
+ "i18n": {
27
+ "localized": true
28
+ }
29
+ }
30
+ },
31
+ "slug": {
32
+ "type": "uid",
33
+ "regex": "^(?!\\.{1,2}$)[A-Za-z0-9-_.~]*$",
34
+ "targetField": "name",
35
+ "required": true,
36
+ "pluginOptions": {
37
+ "i18n": {
38
+ "localized": false
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ ;
45
+
46
+ export default _default;
@@ -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/controller').Base> & import('@strapi/types/dist/core/core-api/controller').Generic & import('@strapi/types/dist/core/core-api/controller').Base;
5
+ category: ({ strapi, }: {
6
+ strapi: import('@strapi/types/dist/core').Strapi;
7
+ }) => Partial<import('@strapi/types/dist/core/core-api/controller').Base> & import('@strapi/types/dist/core/core-api/controller').Generic & import('@strapi/types/dist/core/core-api/controller').Base;
8
+ tag: ({ strapi, }: {
9
+ strapi: import('@strapi/types/dist/core').Strapi;
10
+ }) => Partial<import('@strapi/types/dist/core/core-api/controller').Base> & import('@strapi/types/dist/core/core-api/controller').Generic & import('@strapi/types/dist/core/core-api/controller').Base;
5
11
  blocks: () => {
6
12
  find(ctx: import('koa').Context): void;
7
13
  };
@@ -44,12 +44,15 @@ export declare class TransitionError extends Error {
44
44
  * The transition must exist in the state machine, the actor must be allowed by the policy of the
45
45
  * entry's site, and `isPermitted` must agree. Moving to `published` is the one call that publishes
46
46
  * the entry in Strapi, and moving from `published` to `draft` the one that unpublishes it: the
47
- * editorial state never contradicts `publishedAt`. `reviewedBy` records the user who moved the
47
+ * editorial state never contradicts `publishedAt`. `published -> published` (republish) puts the
48
+ * entry's current draft live over the published version with one `publish`, never unpublishing
49
+ * first, so a reader of the content API always gets a published version; it sets `publishedBy` to
50
+ * the republisher and leaves `reviewedBy` alone. `reviewedBy` records the user who moved the
48
51
  * entry out of `in_review`, and `publishedBy` the one who published it (empty for the scheduler).
49
52
  *
50
53
  * It runs the hooks of the transition (`docs/hooks.md`): `beforeTransition` once every check has
51
54
  * passed and before anything is written, then `afterTransition` and, when the entry was published
52
- * or unpublished, `afterPublish` or `afterUnpublish`. Every caller, the scheduler included, fires
55
+ * (a republish included) or unpublished, `afterPublish` or `afterUnpublish`. Every caller, the scheduler included, fires
53
56
  * them by calling this function.
54
57
  *
55
58
  * @throws {@link TransitionError} when the transition is refused, with its status and code.
@@ -1,5 +1,6 @@
1
1
  export { SITE_ATTRIBUTE, SITE_SCOPE_MIDDLEWARE, withSiteScope } from './site-scope';
2
2
  export { SITE_UID } from './constants/site';
3
+ export { CATEGORY_UID, READ_ACTIONS, TAG_UID } from './constants/taxonomy';
3
4
  export { withEditorial } from './editorial';
4
5
  export { EDITORIAL_STATES, type EditorialState } from './constants/editorial';
5
6
  export { missingLocales } from './extensions';
@@ -23,6 +24,12 @@ declare const _default: {
23
24
  site: ({ strapi, }: {
24
25
  strapi: import('@strapi/types/dist/core').Strapi;
25
26
  }) => Partial<import('@strapi/types/dist/core/core-api/controller').Base> & import('@strapi/types/dist/core/core-api/controller').Generic & import('@strapi/types/dist/core/core-api/controller').Base;
27
+ category: ({ strapi, }: {
28
+ strapi: import('@strapi/types/dist/core').Strapi;
29
+ }) => Partial<import('@strapi/types/dist/core/core-api/controller').Base> & import('@strapi/types/dist/core/core-api/controller').Generic & import('@strapi/types/dist/core/core-api/controller').Base;
30
+ tag: ({ strapi, }: {
31
+ strapi: import('@strapi/types/dist/core').Strapi;
32
+ }) => Partial<import('@strapi/types/dist/core/core-api/controller').Base> & import('@strapi/types/dist/core/core-api/controller').Generic & import('@strapi/types/dist/core/core-api/controller').Base;
26
33
  blocks: () => {
27
34
  find(ctx: import('koa').Context): void;
28
35
  };
@@ -45,11 +52,19 @@ declare const _default: {
45
52
  'content-api': () => import('@strapi/types/dist/core').RouterInput;
46
53
  admin: () => import('@strapi/types/dist/core').RouterInput;
47
54
  site: import('@strapi/types/dist/core/core-api/router').Router;
55
+ category: import('@strapi/types/dist/core/core-api/router').Router;
56
+ tag: import('@strapi/types/dist/core/core-api/router').Router;
48
57
  };
49
58
  services: {
50
59
  site: ({ strapi, }: {
51
60
  strapi: import('@strapi/types/dist/core').Strapi;
52
61
  }) => 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;
62
+ category: ({ strapi, }: {
63
+ strapi: import('@strapi/types/dist/core').Strapi;
64
+ }) => 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;
65
+ tag: ({ strapi, }: {
66
+ strapi: import('@strapi/types/dist/core').Strapi;
67
+ }) => 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;
53
68
  transitions: ({ strapi }: {
54
69
  strapi: import('@strapi/types/dist/core').Strapi;
55
70
  }) => import('./services/transitions').TransitionsService;
@@ -333,6 +348,128 @@ declare const _default: {
333
348
  };
334
349
  };
335
350
  };
351
+ category: {
352
+ schema: {
353
+ kind: string;
354
+ collectionName: string;
355
+ info: {
356
+ singularName: string;
357
+ pluralName: string;
358
+ displayName: string;
359
+ description: string;
360
+ };
361
+ options: {
362
+ draftAndPublish: boolean;
363
+ };
364
+ pluginOptions: {
365
+ "content-manager": {
366
+ visible: boolean;
367
+ };
368
+ i18n: {
369
+ localized: boolean;
370
+ };
371
+ };
372
+ attributes: {
373
+ name: {
374
+ type: string;
375
+ pluginOptions: {
376
+ i18n: {
377
+ localized: boolean;
378
+ };
379
+ };
380
+ };
381
+ slug: {
382
+ type: string;
383
+ regex: string;
384
+ pluginOptions: {
385
+ i18n: {
386
+ localized: boolean;
387
+ };
388
+ };
389
+ };
390
+ description: {
391
+ type: string;
392
+ pluginOptions: {
393
+ i18n: {
394
+ localized: boolean;
395
+ };
396
+ };
397
+ };
398
+ order: {
399
+ type: string;
400
+ pluginOptions: {
401
+ i18n: {
402
+ localized: boolean;
403
+ };
404
+ };
405
+ };
406
+ featured: {
407
+ type: string;
408
+ default: boolean;
409
+ pluginOptions: {
410
+ i18n: {
411
+ localized: boolean;
412
+ };
413
+ };
414
+ };
415
+ color: {
416
+ type: string;
417
+ min: number;
418
+ max: number;
419
+ pluginOptions: {
420
+ i18n: {
421
+ localized: boolean;
422
+ };
423
+ };
424
+ };
425
+ };
426
+ };
427
+ };
428
+ tag: {
429
+ schema: {
430
+ kind: string;
431
+ collectionName: string;
432
+ info: {
433
+ singularName: string;
434
+ pluralName: string;
435
+ displayName: string;
436
+ description: string;
437
+ };
438
+ options: {
439
+ draftAndPublish: boolean;
440
+ };
441
+ pluginOptions: {
442
+ "content-manager": {
443
+ visible: boolean;
444
+ };
445
+ i18n: {
446
+ localized: boolean;
447
+ };
448
+ };
449
+ attributes: {
450
+ name: {
451
+ type: string;
452
+ required: boolean;
453
+ pluginOptions: {
454
+ i18n: {
455
+ localized: boolean;
456
+ };
457
+ };
458
+ };
459
+ slug: {
460
+ type: string;
461
+ regex: string;
462
+ targetField: string;
463
+ required: boolean;
464
+ pluginOptions: {
465
+ i18n: {
466
+ localized: boolean;
467
+ };
468
+ };
469
+ };
470
+ };
471
+ };
472
+ };
336
473
  'preview-credential': {
337
474
  schema: {
338
475
  kind: string;
@@ -374,11 +511,12 @@ declare const _default: {
374
511
  };
375
512
  adminUser: {
376
513
  type: string;
377
- required: boolean;
378
514
  };
379
515
  adminOrigin: {
380
516
  type: string;
381
- required: boolean;
517
+ };
518
+ entryVersion: {
519
+ type: string;
382
520
  };
383
521
  siteDocumentId: {
384
522
  type: string;
@@ -0,0 +1,26 @@
1
+ import { Core } from '@strapi/strapi';
2
+ /** How many rows each place changed. */
3
+ export interface RenameReport {
4
+ /** Role and API token permissions (`api::category.category.find` to `plugin::micelio.category.find`). */
5
+ actions: number;
6
+ /** Admin role permissions whose subject is the content type. */
7
+ subjects: number;
8
+ /** Content manager layouts stored under the old UID. */
9
+ layouts: number;
10
+ }
11
+ /**
12
+ * Moves what Strapi stored under the UIDs `api::category.category` and `api::tag.tag` to the
13
+ * UIDs of the plugin: permissions of roles and API tokens, admin role subjects and content
14
+ * manager layouts. Idempotent: a second run finds nothing, and a row that already exists under
15
+ * the new UID wins over its old twin, which is deleted.
16
+ *
17
+ * @remarks
18
+ * Must run before `users-permissions` bootstraps: its `syncPermissions()` deletes every
19
+ * permission whose action no longer exists, which would silently take category and tag read
20
+ * access away from the public role. It is registered on `strapi::content-types.beforeSync`,
21
+ * which runs before every plugin's `bootstrap`, whatever the plugin order. A table that does not
22
+ * exist yet (a fresh database) has nothing to migrate. A UID that is still a registered content
23
+ * type (a host with its own `api::category.category`) is skipped and logged: its rows are the
24
+ * host's.
25
+ */
26
+ export declare function renameLegacyUids(strapi: Core.Strapi): Promise<RenameReport>;
@@ -0,0 +1,13 @@
1
+ import { Core } from '@strapi/strapi';
2
+ /**
3
+ * Gives every category and tag with no site the default site.
4
+ *
5
+ * @remarks
6
+ * The rows `micelio-cms` 0.5 wrote have no `site`, because that version had no sites. Every locale
7
+ * of an entry is a row of its own, and each one is linked. Idempotent: a row that has a site is
8
+ * never touched, so a second run changes nothing, and a site the admin panel chose is kept. Run it
9
+ * after the default site exists; without a default site there is nothing to give.
10
+ *
11
+ * @returns How many rows got the default site.
12
+ */
13
+ export declare function backfillSite(strapi: Core.Strapi): Promise<number>;
@@ -1,18 +1,20 @@
1
- import { PreviewBinding, PreviewCredentialKind, PreviewCredentialRecord, PreviewExpectation } from '../types/preview';
1
+ import { PreviewBinding, PreviewCredentialKind, PreviewCredentialRecord, PreviewExpectation, PreviewSystemBinding } from '../types/preview';
2
2
  /** The hash a credential is stored and looked up by: SHA-256 of its value, in hex. */
3
3
  export declare function hashCredential(value: string): string;
4
4
  /**
5
- * Makes a preview token or grant: a random, opaque value and the record to store for it.
5
+ * Makes a preview token, grant or system grant: a random, opaque value and the record to store for it.
6
6
  *
7
7
  * @remarks
8
8
  * The value is 256 random bits, not a JWT and not derived from the binding. The record holds only
9
9
  * its hash, so a read of the store cannot replay a credential. The caller hands out `value` once
10
10
  * and never logs it.
11
11
  *
12
- * @param now - The moment of issue; the credential expires 60 s later for a token and 15 min
13
- * later for a grant.
12
+ * @param binding - An admin user's binding for a token or grant; a system grant's for `system`,
13
+ * which has no admin user and holds the draft's version instead.
14
+ * @param now - The moment of issue; the credential expires 60 s later for a token or a system
15
+ * grant and 15 min later for a grant.
14
16
  */
15
- export declare function issueCredential(kind: PreviewCredentialKind, binding: PreviewBinding, now?: Date): {
17
+ export declare function issueCredential(kind: PreviewCredentialKind, binding: PreviewBinding | PreviewSystemBinding, now?: Date): {
16
18
  value: string;
17
19
  record: PreviewCredentialRecord;
18
20
  };
@@ -0,0 +1,62 @@
1
+ import { Core, Schema, UID } from '@strapi/strapi';
2
+ type Entry = Record<string, unknown>;
3
+ /** A `populate` the draft read accepts: the names it asks for, or every first-level relation (`*`). */
4
+ export interface PopulateSpec {
5
+ /** The `*` populate: no names, the first level of every relation, component and media. */
6
+ all: boolean;
7
+ children: Map<string, PopulateNode>;
8
+ }
9
+ /** What is asked of one populated attribute. */
10
+ export interface PopulateNode {
11
+ /** The fields of the attribute's entry, or all of its scalar fields when absent. */
12
+ fields?: string[];
13
+ /** Under a component, its own populate; under a relation, only media attributes of the related entry. */
14
+ populate?: PopulateSpec;
15
+ /** For a dynamic zone, the options of each component fragment, by component UID. */
16
+ on?: Map<string, PopulateNode>;
17
+ }
18
+ /** The answer of {@link readDraftQuery}: why the query cannot be served, or what it asks for. */
19
+ export type DraftQuery = {
20
+ problem: string;
21
+ } | {
22
+ populate: PopulateSpec;
23
+ };
24
+ /**
25
+ * Reads the query of the draft route against the draft's schema, and answers what it may populate or why it is refused.
26
+ *
27
+ * @remarks
28
+ * The route serves one document its grant names (ADR-0019, section 3), so the query is an allowlist
29
+ * and not Strapi's whole query language: only `populate` (and `site`, which the site-scope
30
+ * middleware has already read) is accepted; `filters`, `sort`, `fields`, `pagination` and any other
31
+ * key are refused, because a filter that follows a relation tells whether an entry the answer leaves
32
+ * out matches. A `populate` may name the attributes of the draft and, inside its components and
33
+ * dynamic zones, of those, at any depth. Through a relation it goes one level: the `fields` of the
34
+ * related entry and, as `populate`, its media attributes with `fields` only. Through a media
35
+ * attribute it is `fields` only, so the file's `related` relation is never reached. A name that is
36
+ * not an attribute, a private attribute and a relation to an admin user or to no type are refused.
37
+ *
38
+ * @returns The reason when the query is refused, else the populate to serve.
39
+ */
40
+ export declare function readDraftQuery(strapi: Core.Strapi, query: Record<string, unknown>, schema: Schema.ContentType): DraftQuery;
41
+ /**
42
+ * Reads the draft of a document with the populate {@link readDraftQuery} accepted, and answers `null` when there is none.
43
+ *
44
+ * @remarks
45
+ * The draft itself is read as the grant says. Every entry it populates through a relation is then
46
+ * read again as its **published** version, with the fields the client asked for: a grant serves the
47
+ * draft of the one document it names and never the draft of another. A related entry that has no
48
+ * published version, one of another site and a polymorphic relation are left out. The API token's
49
+ * abilities still decide which relations the answer keeps (`sanitize.query` and `sanitize.output`).
50
+ *
51
+ * @param auth - The content API's authentication of the request, for the token's abilities.
52
+ * @throws `ValidationError` or `PaginationError` when Strapi refuses the query after all; the caller answers `400`.
53
+ */
54
+ export declare function readDraft(strapi: Core.Strapi, options: {
55
+ uid: UID.ContentType;
56
+ documentId: string;
57
+ locale: string | undefined;
58
+ populate: PopulateSpec;
59
+ siteDocumentId: string;
60
+ auth: unknown;
61
+ }): Promise<Entry | null>;
62
+ export {};