includio-cms 0.7.1 → 0.13.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 (157) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/ROADMAP.md +44 -2
  3. package/dist/admin/api/generate-styles.d.ts +2 -0
  4. package/dist/admin/api/generate-styles.js +32 -0
  5. package/dist/admin/api/handler.js +33 -0
  6. package/dist/admin/api/media-gc.js +10 -4
  7. package/dist/admin/api/rest/handler.js +17 -0
  8. package/dist/admin/api/rest/routes/collections.js +25 -13
  9. package/dist/admin/api/rest/routes/entries.d.ts +1 -1
  10. package/dist/admin/api/rest/routes/entries.js +10 -10
  11. package/dist/admin/api/rest/routes/media.d.ts +2 -0
  12. package/dist/admin/api/rest/routes/media.js +9 -0
  13. package/dist/admin/api/rest/routes/schema.d.ts +5 -0
  14. package/dist/admin/api/rest/routes/schema.js +152 -0
  15. package/dist/admin/api/rest/routes/singletons.d.ts +1 -1
  16. package/dist/admin/api/rest/routes/singletons.js +8 -7
  17. package/dist/admin/api/rest/routes/upload.d.ts +2 -0
  18. package/dist/admin/api/rest/routes/upload.js +28 -0
  19. package/dist/admin/api/upload.js +13 -0
  20. package/dist/admin/client/collection/collection-entries.svelte +19 -6
  21. package/dist/admin/client/entry/entry.svelte +21 -23
  22. package/dist/admin/client/entry/header/a11y-validator.js +2 -2
  23. package/dist/admin/client/entry/header/publish-panel.svelte +33 -85
  24. package/dist/admin/client/entry/header/status-badge.svelte +2 -2
  25. package/dist/admin/client/entry/header/version-history-sheet.svelte +9 -9
  26. package/dist/admin/client/entry/header/visibility.svelte +16 -10
  27. package/dist/admin/client/entry/utils.d.ts +3 -0
  28. package/dist/admin/client/entry/utils.js +22 -4
  29. package/dist/admin/client/form/form-submission/form-submission-page.svelte +4 -1
  30. package/dist/admin/client/form/form-submission/submission-field.svelte +10 -0
  31. package/dist/admin/client/index.d.ts +1 -0
  32. package/dist/admin/client/index.js +1 -0
  33. package/dist/admin/client/maintenance/maintenance-page.svelte +146 -2
  34. package/dist/admin/components/fields/blocks-field.svelte +9 -10
  35. package/dist/admin/components/fields/field-renderer.svelte +4 -8
  36. package/dist/admin/components/fields/object-field.svelte +7 -12
  37. package/dist/admin/components/fields/select-field.svelte +8 -2
  38. package/dist/admin/components/fields/seo-field.svelte +40 -93
  39. package/dist/admin/components/fields/simple-array-field.svelte +5 -5
  40. package/dist/admin/components/fields/text-field-wrapper.svelte +52 -197
  41. package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
  42. package/dist/admin/components/fields/url-field-wrapper.svelte +15 -25
  43. package/dist/admin/components/fields/url-field.svelte +61 -72
  44. package/dist/admin/components/media/file-upload.svelte +5 -1
  45. package/dist/admin/components/media/file-upload.svelte.d.ts +1 -0
  46. package/dist/admin/components/media/media-library.svelte +109 -37
  47. package/dist/admin/components/media/media-selector.svelte +79 -11
  48. package/dist/admin/components/media/tag-sidebar.svelte +10 -6
  49. package/dist/admin/components/media/tag-sidebar.svelte.d.ts +7 -2
  50. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +21 -93
  51. package/dist/admin/components/tiptap/inline-block-node.js +6 -5
  52. package/dist/admin/components/tiptap/link-dialog.svelte +10 -11
  53. package/dist/admin/components/tiptap/slash-command.js +1 -1
  54. package/dist/admin/remote/entry.remote.d.ts +2 -5
  55. package/dist/admin/remote/entry.remote.js +22 -27
  56. package/dist/admin/remote/media.remote.d.ts +15 -0
  57. package/dist/admin/remote/media.remote.js +18 -2
  58. package/dist/admin/remote/preview.remote.js +3 -1
  59. package/dist/admin/utils/entryLabel.js +9 -6
  60. package/dist/admin/utils/translationStatus.js +1 -2
  61. package/dist/cli/create-user.d.ts +2 -0
  62. package/dist/cli/create-user.js +81 -0
  63. package/dist/cli/index.js +5 -0
  64. package/dist/cli/scaffold/admin.js +34 -2
  65. package/dist/cms/runtime/api.d.ts +16 -12
  66. package/dist/cms/runtime/api.js +7 -6
  67. package/dist/cms/runtime/remote.js +2 -2
  68. package/dist/cms/runtime/schemas.d.ts +1 -1
  69. package/dist/cms/runtime/schemas.js +1 -1
  70. package/dist/cms/runtime/types.d.ts +118 -112
  71. package/dist/cms/runtime/types.js +0 -12
  72. package/dist/core/cms.d.ts +3 -1
  73. package/dist/core/cms.js +30 -0
  74. package/dist/core/fields/fieldSchemaToTs.js +9 -15
  75. package/dist/core/fields/formFieldSchemaToTs.js +7 -0
  76. package/dist/core/server/entries/operations/create.js +10 -4
  77. package/dist/core/server/entries/operations/get.d.ts +1 -0
  78. package/dist/core/server/entries/operations/get.js +186 -191
  79. package/dist/core/server/entries/operations/update.d.ts +6 -7
  80. package/dist/core/server/entries/operations/update.js +20 -38
  81. package/dist/core/server/fields/populateEntry.js +16 -52
  82. package/dist/core/server/fields/resolveImageFields.js +69 -120
  83. package/dist/core/server/fields/resolveRelationFields.js +30 -51
  84. package/dist/core/server/fields/resolveRichtextLinks.js +46 -100
  85. package/dist/core/server/fields/resolveTypographyOrphans.bench.d.ts +1 -0
  86. package/dist/core/server/fields/resolveTypographyOrphans.bench.js +87 -0
  87. package/dist/core/server/fields/resolveTypographyOrphans.d.ts +3 -0
  88. package/dist/core/server/fields/resolveTypographyOrphans.js +128 -0
  89. package/dist/core/server/fields/resolveUrlFields.js +47 -56
  90. package/dist/core/server/fields/utils/fixOrphans.d.ts +5 -0
  91. package/dist/core/server/fields/utils/fixOrphans.js +12 -0
  92. package/dist/core/server/fields/utils/imageStyles.d.ts +4 -2
  93. package/dist/core/server/fields/utils/imageStyles.js +41 -25
  94. package/dist/core/server/fields/utils/resolveMedia.js +1 -6
  95. package/dist/core/server/forms/submissions/operations/delete.js +26 -2
  96. package/dist/core/server/forms/submissions/utils/parseMultipart.d.ts +2 -0
  97. package/dist/core/server/forms/submissions/utils/parseMultipart.js +75 -0
  98. package/dist/core/server/generator/fields.d.ts +6 -0
  99. package/dist/core/server/generator/fields.js +43 -5
  100. package/dist/core/server/generator/formFieldSchemaToString.js +10 -0
  101. package/dist/core/server/generator/formFields.js +1 -0
  102. package/dist/core/server/generator/generator.js +98 -30
  103. package/dist/core/server/media/operations/getFiles.d.ts +5 -0
  104. package/dist/core/server/media/operations/getFiles.js +6 -0
  105. package/dist/core/server/media/operations/uploadPrivateFile.d.ts +4 -0
  106. package/dist/core/server/media/operations/uploadPrivateFile.js +8 -0
  107. package/dist/core/server/media/styles/operations/batchGenerateStyles.d.ts +16 -0
  108. package/dist/core/server/media/styles/operations/batchGenerateStyles.js +144 -0
  109. package/dist/db-postgres/index.js +303 -37
  110. package/dist/db-postgres/schema/entry.d.ts +0 -94
  111. package/dist/db-postgres/schema/entry.js +0 -6
  112. package/dist/db-postgres/schema/entryVersion.d.ts +17 -0
  113. package/dist/db-postgres/schema/entryVersion.js +1 -0
  114. package/dist/entity/index.d.ts +9 -4
  115. package/dist/entity/index.js +24 -24
  116. package/dist/files-local/index.js +43 -0
  117. package/dist/sveltekit/components/preview.svelte +2 -326
  118. package/dist/sveltekit/components/preview.svelte.d.ts +5 -16
  119. package/dist/sveltekit/server/index.d.ts +2 -1
  120. package/dist/sveltekit/server/index.js +2 -1
  121. package/dist/sveltekit/server/preview.js +4 -7
  122. package/dist/types/adapters/db.d.ts +15 -1
  123. package/dist/types/adapters/files.d.ts +6 -0
  124. package/dist/types/cms.d.ts +5 -0
  125. package/dist/types/entries.d.ts +54 -18
  126. package/dist/types/fields.d.ts +14 -24
  127. package/dist/types/formFields.d.ts +7 -2
  128. package/dist/types/index.d.ts +2 -2
  129. package/dist/types/structured-content.d.ts +5 -0
  130. package/dist/updates/0.10.0/index.d.ts +2 -0
  131. package/dist/updates/0.10.0/index.js +15 -0
  132. package/dist/updates/0.11.0/index.d.ts +2 -0
  133. package/dist/updates/0.11.0/index.js +12 -0
  134. package/dist/updates/0.12.0/index.d.ts +2 -0
  135. package/dist/updates/0.12.0/index.js +12 -0
  136. package/dist/updates/0.13.0/index.d.ts +2 -0
  137. package/dist/updates/0.13.0/index.js +10 -0
  138. package/dist/updates/0.7.2/index.d.ts +2 -0
  139. package/dist/updates/0.7.2/index.js +10 -0
  140. package/dist/updates/0.7.3/index.d.ts +2 -0
  141. package/dist/updates/0.7.3/index.js +10 -0
  142. package/dist/updates/0.8.0/index.d.ts +2 -0
  143. package/dist/updates/0.8.0/index.js +18 -0
  144. package/dist/updates/0.8.0/migrate.d.ts +2 -0
  145. package/dist/updates/0.8.0/migrate.js +101 -0
  146. package/dist/updates/0.9.0/index.d.ts +2 -0
  147. package/dist/updates/0.9.0/index.js +38 -0
  148. package/dist/updates/index.js +9 -1
  149. package/package.json +7 -6
  150. package/dist/admin/components/fields/image-field.svelte +0 -198
  151. package/dist/admin/components/fields/image-field.svelte.d.ts +0 -8
  152. package/dist/admin/components/fields/richtext-field.svelte +0 -13
  153. package/dist/admin/components/fields/richtext-field.svelte.d.ts +0 -8
  154. package/dist/admin/components/tiptap.svelte +0 -11
  155. package/dist/admin/components/tiptap.svelte.d.ts +0 -6
  156. package/dist/core/server/entries/utils/getEntryTranslation.d.ts +0 -1
  157. package/dist/core/server/entries/utils/getEntryTranslation.js +0 -18
@@ -1,5 +1,5 @@
1
1
  import type { ConsentLogData } from '../consent.js';
2
- import type { DbEntry, DbEntryInsert, DbEntryVersion, DbEntryVersionInsert, GetDbEntriesOptions, GetDbEntryVersionsOptions, PaginationOptions } from '../entries.js';
2
+ import type { DbEntry, DbEntryInsert, DbEntryVersion, DbEntryVersionInsert, GetDbEntriesOptions, GetDbEntryVersionsOptions, GetPaginatedEntriesOptions, PaginatedEntryRow, PaginationOptions } from '../entries.js';
3
3
  import type { ImageFieldStyle } from '../fields.js';
4
4
  import type { FormSubmission } from '../forms.js';
5
5
  import type { ImageStyle, MediaFile, MediaTag, UploadedMediaFile } from '../media.js';
@@ -20,6 +20,8 @@ export interface DatabaseAdapter {
20
20
  getFormSubmission: GetFormSubmission;
21
21
  updateFormSubmission: UpdateFormSubmission;
22
22
  deleteFormSubmission: DeleteFormSubmission;
23
+ getPaginatedEntries?: GetPaginatedEntries;
24
+ countPaginatedEntries?: CountPaginatedEntries;
23
25
  createConsentLog: CreateConsentLog;
24
26
  getMediaTags: GetMediaTags;
25
27
  createMediaTag: CreateMediaTag;
@@ -35,6 +37,8 @@ export interface DatabaseAdapter {
35
37
  getAllImageStyles: GetAllImageStyles;
36
38
  deleteAllImageStyles: DeleteAllImageStyles;
37
39
  getMediaFiles: GetMediaFiles;
40
+ countMediaFiles: CountMediaFiles;
41
+ getMediaTagsWithCounts: GetMediaTagsWithCounts;
38
42
  getMediaFile: GetMediaFile;
39
43
  updateMediaFile: UpdateMediaFile;
40
44
  deleteMediaFile: DeleteMediaFile;
@@ -49,6 +53,8 @@ export type UpdateEntry = (data: {
49
53
  export type DeleteEntry = (data: {
50
54
  id: string;
51
55
  }) => Promise<void>;
56
+ export type GetPaginatedEntries = (data: GetPaginatedEntriesOptions) => Promise<PaginatedEntryRow[]>;
57
+ export type CountPaginatedEntries = (data: Omit<GetPaginatedEntriesOptions, 'limit' | 'offset' | 'orderBy'>) => Promise<number>;
52
58
  export type ArchiveEntry = (data: {
53
59
  id: string;
54
60
  archivedAt?: Date;
@@ -80,9 +86,17 @@ export interface GetMediaFilesOptions {
80
86
  ids?: string[];
81
87
  mimeTypes?: string[];
82
88
  search?: string;
89
+ untagged?: boolean;
90
+ limit?: number;
91
+ offset?: number;
83
92
  };
84
93
  }
85
94
  export type GetMediaFiles = (data: GetMediaFilesOptions) => Promise<MediaFile[]>;
95
+ export type CountMediaFiles = (data: GetMediaFilesOptions) => Promise<number>;
96
+ export type GetMediaTagsWithCounts = () => Promise<{
97
+ tag: MediaTag;
98
+ count: number;
99
+ }[]>;
86
100
  export interface GetMediaFileOptions {
87
101
  data: {
88
102
  id?: string;
@@ -5,6 +5,12 @@ export interface FilesAdapter {
5
5
  renameFile: RenameFile;
6
6
  deleteFile: DeleteFile;
7
7
  listFiles: ListFiles;
8
+ uploadPrivateFile?: (file: File) => Promise<{
9
+ filename: string;
10
+ url: string;
11
+ }>;
12
+ downloadPrivateFile?: (filename: string) => Promise<File | null>;
13
+ deletePrivateFile?: (filename: string) => Promise<void>;
8
14
  }
9
15
  export type DownloadFile = (id: string) => Promise<File | null>;
10
16
  export type UploadFile = (file: File) => Promise<UploadedMediaFile>;
@@ -36,6 +36,9 @@ export interface ApiKeyConfig {
36
36
  name?: string;
37
37
  role?: 'admin' | 'editor';
38
38
  }
39
+ export interface TypographyConfig {
40
+ fixOrphans?: boolean;
41
+ }
39
42
  export interface CMSConfig {
40
43
  languages: Language[];
41
44
  collections?: CollectionConfig[];
@@ -49,6 +52,7 @@ export interface CMSConfig {
49
52
  ai?: AIAdapter;
50
53
  media?: MediaConfig;
51
54
  apiKeys?: ApiKeyConfig[];
55
+ typography?: TypographyConfig;
52
56
  }
53
57
  export interface ICMS {
54
58
  collections: Record<string, CollectionConfigWithType>;
@@ -64,4 +68,5 @@ export interface ICMS {
64
68
  aiAdapter: AIAdapter | null;
65
69
  mediaConfig: MediaConfig;
66
70
  apiKeys: ApiKeyConfig[];
71
+ typographyConfig: TypographyConfig;
67
72
  }
@@ -12,44 +12,40 @@ export interface DbEntry {
12
12
  id: string;
13
13
  slug: string;
14
14
  type: EntryType;
15
- availableLocales: string[] | null;
16
15
  createdAt: Date;
17
16
  updatedAt: Date;
18
17
  archivedAt: Date | null;
19
- publishedAt: Date | null;
20
- publishedVersionId: string | null;
21
- publishedBy: string | null;
22
18
  sortOrder: number | null;
23
19
  }
24
20
  export interface DbEntryInsert {
25
21
  slug: string;
26
22
  type: EntryType;
27
- availableLocales?: string[] | null;
28
23
  createdAt?: Date;
29
24
  updatedAt?: Date;
30
25
  archivedAt?: Date | null;
31
- publishedAt?: Date | null;
32
- publishedVersionId?: string | null;
33
- publishedBy?: string | null;
34
26
  sortOrder?: number | null;
35
27
  }
36
28
  export interface RawEntry extends DbEntry {
37
29
  collection: CollectionConfigWithType | SingleConfigWithType;
38
30
  versions: DbEntryVersion[];
39
- publishedVersion: DbEntryVersion | null;
40
- scheduledVersion: DbEntryVersion | null;
41
- draftVersion: DbEntryVersion | null;
42
- }
43
- export interface Entry {
44
- id: string;
45
- data: PopulatedEntryData;
46
- slug: string;
47
- type: EntryType;
48
- publishedAt?: Date | null;
31
+ /** Per-language published versions */
32
+ publishedVersions: Record<string, DbEntryVersion | null>;
33
+ /** Per-language scheduled versions */
34
+ scheduledVersions: Record<string, DbEntryVersion | null>;
35
+ /** Per-language latest draft versions */
36
+ draftVersions: Record<string, DbEntryVersion | null>;
49
37
  }
38
+ export type Entry = {
39
+ _id: string;
40
+ _slug: string;
41
+ _type: EntryType;
42
+ _publishedAt?: Date | null;
43
+ _url?: string;
44
+ } & Record<string, unknown>;
50
45
  export interface DbEntryVersion {
51
46
  id: string;
52
47
  entryId: string;
48
+ lang: string;
53
49
  versionNumber: number;
54
50
  data: EntryData;
55
51
  createdAt: Date;
@@ -59,6 +55,7 @@ export interface DbEntryVersion {
59
55
  }
60
56
  export interface DbEntryVersionInsert {
61
57
  entryId: string;
58
+ lang: string;
62
59
  versionNumber?: number;
63
60
  data: EntryData;
64
61
  createdAt?: Date;
@@ -73,6 +70,10 @@ export interface PaginationOptions {
73
70
  column: 'createdAt' | 'updatedAt' | 'sortOrder';
74
71
  direction: 'asc' | 'desc';
75
72
  };
73
+ dataOrderBy?: {
74
+ field: string;
75
+ direction: 'asc' | 'desc';
76
+ };
76
77
  }
77
78
  export interface GetDbEntriesOptions extends PaginationOptions {
78
79
  ids?: string[];
@@ -103,30 +104,65 @@ export interface GetEntriesOptions {
103
104
  slug?: string;
104
105
  dataValues?: Record<string, unknown>;
105
106
  dataLike?: Record<string, unknown>;
107
+ dataILikeOr?: Record<string, unknown>;
106
108
  language?: string;
107
109
  status?: EntryStatus;
108
110
  orderBy?: {
109
111
  column: 'createdAt' | 'updatedAt' | 'sortOrder';
110
112
  direction: 'asc' | 'desc';
111
113
  };
114
+ dataOrderBy?: {
115
+ field: string;
116
+ direction: 'asc' | 'desc';
117
+ };
118
+ limit?: number;
119
+ offset?: number;
112
120
  }
113
121
  export interface GetEntryOptions {
114
122
  id?: string;
115
123
  slug?: string;
116
124
  dataValues?: Record<string, unknown>;
117
125
  dataLike?: Record<string, unknown>;
126
+ dataILikeOr?: Record<string, unknown>;
118
127
  language?: string;
119
128
  status?: EntryStatus;
120
129
  }
121
130
  export interface GetDbEntryVersionsOptions {
122
131
  ids?: string[];
123
132
  entryIds?: string[];
133
+ lang?: string;
124
134
  dataValues?: Record<string, unknown>;
125
135
  dataLike?: Record<string, unknown>;
136
+ dataILikeOr?: Record<string, unknown>;
126
137
  }
127
138
  export interface GetDbEntryVersionOptions {
128
139
  id?: string;
129
140
  entryId?: string;
141
+ lang?: string;
130
142
  dataValues?: Record<string, unknown>;
131
143
  dataLike?: Record<string, unknown>;
144
+ dataILikeOr?: Record<string, unknown>;
145
+ }
146
+ export interface GetPaginatedEntriesOptions {
147
+ slug?: string;
148
+ ids?: string[];
149
+ language: string;
150
+ status: EntryStatus;
151
+ dataValues?: Record<string, unknown>;
152
+ dataLike?: Record<string, unknown>;
153
+ dataILikeOr?: Record<string, unknown>;
154
+ orderBy?: {
155
+ column: 'createdAt' | 'updatedAt' | 'sortOrder';
156
+ direction: 'asc' | 'desc';
157
+ };
158
+ dataOrderBy?: {
159
+ field: string;
160
+ direction: 'asc' | 'desc';
161
+ };
162
+ limit: number;
163
+ offset: number;
164
+ }
165
+ export interface PaginatedEntryRow {
166
+ entry: DbEntry;
167
+ version: DbEntryVersion;
132
168
  }
@@ -2,7 +2,7 @@ import type { FormatEnum } from 'sharp';
2
2
  import type { ImageStyle, MediaFile } from './media.js';
3
3
  import type { Localized } from './languages.js';
4
4
  import type { StructuredContentDoc } from './structured-content.js';
5
- export type FieldType = 'text' | 'richtext' | 'content' | 'number' | 'boolean' | 'date' | 'datetime' | 'file' | 'image' | 'media' | 'select' | 'radio' | 'checkboxes' | 'relation' | 'object' | 'array' | 'blocks' | 'slug' | 'seo' | 'url' | 'custom';
5
+ export type FieldType = 'text' | 'content' | 'number' | 'boolean' | 'date' | 'datetime' | 'file' | 'media' | 'select' | 'radio' | 'checkboxes' | 'relation' | 'object' | 'array' | 'blocks' | 'slug' | 'seo' | 'url' | 'custom';
6
6
  export interface FieldCondition {
7
7
  field: string;
8
8
  equals?: string | string[];
@@ -26,12 +26,6 @@ export interface TextField extends BaseField {
26
26
  multiline?: boolean;
27
27
  defaultValue?: string;
28
28
  }
29
- export interface RichtextField extends BaseField {
30
- type: 'richtext';
31
- allowedTags?: string[];
32
- allowedFormats?: string[];
33
- defaultValue?: string;
34
- }
35
29
  export interface ContentField extends BaseField {
36
30
  type: 'content';
37
31
  inlineBlocks?: ObjectField[];
@@ -67,18 +61,6 @@ export interface FileField extends BaseField {
67
61
  multiple?: boolean;
68
62
  defaultValue?: string | string[];
69
63
  }
70
- export interface ImageField extends BaseField {
71
- type: 'image';
72
- accept?: string;
73
- maxSizeMB?: number;
74
- multiple?: boolean;
75
- width?: number;
76
- height?: number;
77
- aspectRatio?: number;
78
- thumbnail?: boolean;
79
- defaultValue?: string | string[];
80
- styles?: ImageFieldStyle[];
81
- }
82
64
  export interface ImageFieldStyle {
83
65
  name: string;
84
66
  width?: number;
@@ -109,6 +91,15 @@ export interface VideoFieldData {
109
91
  audioDescription: MediaFile | null;
110
92
  }
111
93
  export type MediaFieldData = ImageFieldData | VideoFieldData;
94
+ export type FlatImageFieldData = MediaFile & {
95
+ _styles: Record<string, ImageStyle>;
96
+ _blurDataUrl?: string | null;
97
+ };
98
+ export type FlatVideoFieldData = MediaFile & {
99
+ _transcript: MediaFile | null;
100
+ _audioDescription: MediaFile | null;
101
+ };
102
+ export type FlatMediaFieldData = FlatImageFieldData | FlatVideoFieldData;
112
103
  export interface SelectField extends BaseField {
113
104
  type: 'select';
114
105
  options: {
@@ -149,11 +140,10 @@ export interface ObjectField extends BaseField {
149
140
  defaultValue?: ObjectFieldData;
150
141
  thumbnail?: string;
151
142
  }
152
- export interface ObjectFieldData {
143
+ export type ObjectFieldData = {
153
144
  _id?: string;
154
- slug?: string;
155
- data: Record<string, unknown>;
156
- }
145
+ _slug?: string;
146
+ } & Record<string, unknown>;
157
147
  export type SimpleArrayItemType = 'text' | 'number' | 'url';
158
148
  export interface ArrayField extends BaseField {
159
149
  type: 'array';
@@ -211,4 +201,4 @@ export interface CustomField extends BaseField {
211
201
  /** Plugin-specific configuration, opaque to core */
212
202
  config?: Record<string, unknown>;
213
203
  }
214
- export type Field = TextField | RichtextField | ContentField | NumberField | BooleanField | DateField | DateTimeField | FileField | ImageField | MediaField | SelectField | RadioField | CheckboxesField | RelationField | ObjectField | ArrayField | BlocksField | SlugField | SeoField | UrlField | CustomField;
204
+ export type Field = TextField | ContentField | NumberField | BooleanField | DateField | DateTimeField | FileField | MediaField | SelectField | RadioField | CheckboxesField | RelationField | ObjectField | ArrayField | BlocksField | SlugField | SeoField | UrlField | CustomField;
@@ -1,5 +1,5 @@
1
1
  import type { Localized } from './languages.js';
2
- export type FormFieldType = 'text' | 'email' | 'textarea' | 'checkbox' | 'select';
2
+ export type FormFieldType = 'text' | 'email' | 'textarea' | 'checkbox' | 'select' | 'file';
3
3
  export interface FormBaseField {
4
4
  slug: string;
5
5
  label?: Localized;
@@ -37,4 +37,9 @@ export interface FormSelectField extends FormBaseField {
37
37
  }[];
38
38
  defaultValue?: string;
39
39
  }
40
- export type FormField = FormTextField | FormEmailField | FormTextareaField | FormCheckboxField | FormSelectField;
40
+ export interface FormFileField extends FormBaseField {
41
+ type: 'file';
42
+ accept?: string;
43
+ maxSize?: number;
44
+ }
45
+ export type FormField = FormTextField | FormEmailField | FormTextareaField | FormCheckboxField | FormSelectField | FormFileField;
@@ -1,5 +1,5 @@
1
1
  export * from './fields.js';
2
- export { type StructuredContentDoc, type SCNode, type SCMark, type SCInlineBlockAttrs, type SCFigureAttrs, type SCVideoAttrs } from './structured-content.js';
2
+ export { type StructuredContentDoc, type SCNode, type SCMark, type SCInlineBlockAttrs, type SCTypedInlineBlock, type SCFigureAttrs, type SCVideoAttrs } from './structured-content.js';
3
3
  export { type MediaFile, type MediaFileType, type ImageStyle, type MediaTag } from './media.js';
4
4
  export { type ConsentLogData } from './consent.js';
5
5
  export { type Entry, type EntryType, type EntryStatus, type EntryVersionStatus } from './entries.js';
@@ -9,7 +9,7 @@ export { type CollectionConfig } from './collections.js';
9
9
  export { type SingleConfig } from './singles.js';
10
10
  export { type FormConfig, type FormSubmission } from './forms.js';
11
11
  export { type FormField, type FormFieldType, type FormBaseField, type FormTextField, type FormEmailField, type FormTextareaField, type FormCheckboxField, type FormSelectField } from './formFields.js';
12
- export { type CMSConfig, type ApiKeyConfig, type AuthConfig } from './cms.js';
12
+ export { type CMSConfig, type ApiKeyConfig, type AuthConfig, type TypographyConfig } from './cms.js';
13
13
  export { type PluginConfig, type CustomFieldDefinition } from './plugins.js';
14
14
  export { type Language, type Localized } from './languages.js';
15
15
  export { type Layout, type LayoutNode, type LayoutPreset, type LayoutNodeType, type ColumnRatio, type SectionNode, type ColumnsNode, type CardNode, type AccordionNode, type StackNode } from './layout.js';
@@ -57,6 +57,11 @@ export interface SCInlineBlockAttrs {
57
57
  blockData: Record<string, unknown>;
58
58
  blockId: string;
59
59
  }
60
+ export interface SCTypedInlineBlock<T = Record<string, unknown>> {
61
+ blockType: string;
62
+ blockData: T;
63
+ blockId: string;
64
+ }
60
65
  export interface StructuredContentDoc {
61
66
  type: 'doc';
62
67
  content: SCNode[];
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,15 @@
1
+ export const update = {
2
+ version: '0.10.0',
3
+ date: '2026-03-18',
4
+ description: 'Remove image, video, richtext field types — consolidate to media and content',
5
+ features: [],
6
+ fixes: [],
7
+ breakingChanges: [
8
+ 'Removed `image` field type — use `media` with `accept: "image/*"` instead',
9
+ 'Removed `richtext` field type — use `content` (structured ProseMirror JSON) instead',
10
+ 'Removed `ImageField` and `RichtextField` TypeScript interfaces',
11
+ '`image-field.svelte` and `richtext-field.svelte` components removed',
12
+ '`tiptap.svelte` (HTML richtext wrapper) removed'
13
+ ],
14
+ notes: 'No automatic data migration. Replace `type: "image"` with `type: "media", accept: "image/*"` in your collection/singleton configs. Replace `type: "richtext"` with `type: "content"`. Existing stored data (media UUIDs, ProseMirror docs) remains compatible.'
15
+ };
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,12 @@
1
+ export const update = {
2
+ version: '0.11.0',
3
+ date: '2026-03-18',
4
+ description: 'Codegen overhaul and REST API consolidation',
5
+ features: [
6
+ 'Codegen: flat entry types, inline block types, `countEntries` query helper, simplified API surface',
7
+ 'REST API: catch-all route handler, file upload endpoint, media endpoint, schema template endpoints',
8
+ 'Admin scaffold updated for new REST route structure'
9
+ ],
10
+ fixes: [],
11
+ breakingChanges: []
12
+ };
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,12 @@
1
+ export const update = {
2
+ version: '0.12.0',
3
+ date: '2026-03-18',
4
+ description: 'File field type, dataOrderBy, and _url population',
5
+ features: [
6
+ 'File field type with multipart upload, file validation, and rate limiting',
7
+ '`dataOrderBy` — sort entries by JSON data fields in queries',
8
+ 'Auto-populate `_url` field on entries from slug resolver and `pathTemplate`'
9
+ ],
10
+ fixes: [],
11
+ breakingChanges: []
12
+ };
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,10 @@
1
+ export const update = {
2
+ version: '0.13.0',
3
+ date: '2026-03-19',
4
+ description: 'Private file uploads for form submissions',
5
+ features: [
6
+ 'Private file uploads — form submissions can upload files to a non-public directory with access control'
7
+ ],
8
+ fixes: [],
9
+ breakingChanges: []
10
+ };
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,10 @@
1
+ export const update = {
2
+ version: '0.7.2',
3
+ date: '2026-03-16',
4
+ description: 'CLI create-user command',
5
+ features: [
6
+ 'CLI `create-user` command — interactive user creation with email, password (auto-generate option), name, and role via better-auth'
7
+ ],
8
+ fixes: [],
9
+ breakingChanges: []
10
+ };
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,10 @@
1
+ export const update = {
2
+ version: '0.7.3',
3
+ date: '2026-03-17',
4
+ description: 'Typography orphan fix for Polish conjunctions',
5
+ features: [
6
+ 'Read-time orphan fix — replace space after single-letter Polish conjunctions (i, w, z, o, u, a) with non-breaking space `\\u00A0`'
7
+ ],
8
+ fixes: [],
9
+ breakingChanges: []
10
+ };
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,18 @@
1
+ export const update = {
2
+ version: '0.8.0',
3
+ date: '2026-03-17',
4
+ description: 'Flat entry format — remove data wrapper from objects/blocks',
5
+ features: [
6
+ 'Flat entry format: objects use `_slug` + spread fields instead of `slug` + `data` wrapper',
7
+ 'Blocks use `_slug` instead of `slug` with flat fields',
8
+ 'Entry type unified: `FlatEntry` renamed to `Entry`, old `Entry` removed'
9
+ ],
10
+ fixes: [],
11
+ breakingChanges: [
12
+ 'Object field data format: `{ slug, data: {...} }` → `{ _slug, ...fields }`',
13
+ 'Blocks field data format: `{ _id, slug, data: {...} }` → `{ _id, _slug, ...fields }`',
14
+ '`FlatEntry` type removed — use `Entry` instead',
15
+ '`flattenEntry`/`flattenFields` removed — data is flat from resolve functions'
16
+ ],
17
+ notes: 'Run `includio update` to migrate existing entry data in the database.'
18
+ };
@@ -0,0 +1,2 @@
1
+ import type { DatabaseAdapter } from '../../types/adapters/db.js';
2
+ export declare function migrateEntryData(db: DatabaseAdapter): Promise<number>;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Migrate entry version data from wrapped format to flat format.
3
+ *
4
+ * Objects: { slug, data: {...} } → { _slug, ...fields }
5
+ * Blocks: [{ _id, slug, data: {...} }] → [{ _id, _slug, ...fields }]
6
+ * Content inline blocks: blockData with nested objects/blocks also transformed.
7
+ */
8
+ function isWrappedObject(val) {
9
+ return (val != null &&
10
+ typeof val === 'object' &&
11
+ 'slug' in val &&
12
+ 'data' in val &&
13
+ typeof val.slug === 'string' &&
14
+ typeof val.data === 'object' &&
15
+ val.data !== null);
16
+ }
17
+ function migrateValue(val) {
18
+ if (val == null)
19
+ return val;
20
+ if (Array.isArray(val)) {
21
+ return val.map((item) => {
22
+ if (isWrappedObject(item)) {
23
+ const { slug, data, _id, ...rest } = item;
24
+ const flatData = migrateRecord(data);
25
+ return {
26
+ ...rest,
27
+ ...(_id != null ? { _id } : {}),
28
+ _slug: slug,
29
+ ...flatData
30
+ };
31
+ }
32
+ return migrateValue(item);
33
+ });
34
+ }
35
+ if (typeof val === 'object') {
36
+ // Check if this is a wrapped object (not an array)
37
+ if (isWrappedObject(val)) {
38
+ const { slug, data, _id, ...rest } = val;
39
+ const flatData = migrateRecord(data);
40
+ return {
41
+ ...rest,
42
+ ...(_id != null ? { _id } : {}),
43
+ _slug: slug,
44
+ ...flatData
45
+ };
46
+ }
47
+ // Check if this is a structured content doc — recurse into inline blocks
48
+ if ('type' in val && val.type === 'doc') {
49
+ return migrateStructuredDoc(val);
50
+ }
51
+ // Generic object — recurse into values
52
+ return migrateRecord(val);
53
+ }
54
+ return val;
55
+ }
56
+ function migrateRecord(record) {
57
+ const result = {};
58
+ for (const [key, value] of Object.entries(record)) {
59
+ result[key] = migrateValue(value);
60
+ }
61
+ return result;
62
+ }
63
+ function migrateStructuredDoc(doc) {
64
+ if (!doc.content || !Array.isArray(doc.content))
65
+ return doc;
66
+ return {
67
+ ...doc,
68
+ content: doc.content.map((node) => {
69
+ if (node.type === 'inlineBlock' && node.attrs) {
70
+ const attrs = { ...node.attrs };
71
+ if (attrs.blockData && typeof attrs.blockData === 'object') {
72
+ attrs.blockData = migrateRecord(attrs.blockData);
73
+ }
74
+ return { ...node, attrs };
75
+ }
76
+ // Recurse into child content
77
+ if (node.content && Array.isArray(node.content)) {
78
+ return migrateStructuredDoc(node);
79
+ }
80
+ return node;
81
+ })
82
+ };
83
+ }
84
+ export async function migrateEntryData(db) {
85
+ // Get all entries
86
+ const entries = await db.getEntries({});
87
+ let migratedCount = 0;
88
+ for (const entry of entries) {
89
+ const versions = await db.getEntryVersions({ entryIds: [entry.id] });
90
+ for (const version of versions) {
91
+ const originalData = version.data;
92
+ const migratedData = migrateRecord(originalData);
93
+ // Only update if data actually changed
94
+ if (JSON.stringify(originalData) !== JSON.stringify(migratedData)) {
95
+ await db.updateEntryVersion(version.id, { data: migratedData });
96
+ migratedCount++;
97
+ }
98
+ }
99
+ }
100
+ return migratedCount;
101
+ }
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,38 @@
1
+ export const update = {
2
+ version: '0.9.0',
3
+ date: '2026-03-17',
4
+ description: 'Per-language entry versions — separate entry_version per language',
5
+ features: [
6
+ 'Per-language entry versions: each language gets its own entry_version with flat data',
7
+ 'Per-language publication: publish/unpublish each language independently',
8
+ 'Simplified data format: no more nested `{ pl: "X", en: "Y" }` — values are flat strings',
9
+ 'Language switching in admin loads different version data'
10
+ ],
11
+ fixes: [],
12
+ breakingChanges: [
13
+ '`entry_version` table: new `lang` column (NOT NULL)',
14
+ '`entry` table: removed `published_at`, `published_version_id`, `published_by`, `available_locales` columns',
15
+ '`RawEntry`: `publishedVersion`/`draftVersion`/`scheduledVersion` replaced with per-lang `publishedVersions`/`draftVersions`/`scheduledVersions` records',
16
+ '`DbEntryVersion`/`DbEntryVersionInsert`: new required `lang` field',
17
+ '`translateObject` removed — data is single-language per version',
18
+ 'Resolve functions (relation, media, url, richtext) expect flat content/richtext values, not `Record<lang, value>`',
19
+ '`upsertDraftVersion` and `pruneOldDraftVersions` now require `lang` parameter',
20
+ '`unpublishEntry` renamed to `unpublishEntryLang` with required `lang` parameter'
21
+ ],
22
+ sql: `-- Step 1: Add lang column as nullable
23
+ ALTER TABLE entry_version ADD COLUMN lang TEXT;
24
+
25
+ -- Step 2: Run migration script to split multi-lang versions (scripts/migrate-lang-versions.ts)
26
+ -- After migration, set NOT NULL:
27
+ ALTER TABLE entry_version ALTER COLUMN lang SET NOT NULL;
28
+
29
+ -- Step 3: Create index for performance
30
+ CREATE INDEX idx_entry_version_publish ON entry_version(entry_id, lang, published_at);
31
+
32
+ -- Step 4: Remove entry-level publish columns
33
+ ALTER TABLE entry DROP COLUMN IF EXISTS published_at;
34
+ ALTER TABLE entry DROP COLUMN IF EXISTS published_version_id;
35
+ ALTER TABLE entry DROP COLUMN IF EXISTS published_by;
36
+ ALTER TABLE entry DROP COLUMN IF EXISTS available_locales;`,
37
+ notes: 'Run the migration script BEFORE setting lang to NOT NULL. See scripts/migrate-lang-versions.ts for data migration.'
38
+ };
@@ -25,7 +25,15 @@ import { update as update061 } from './0.6.1/index.js';
25
25
  import { update as update062 } from './0.6.2/index.js';
26
26
  import { update as update070 } from './0.7.0/index.js';
27
27
  import { update as update071 } from './0.7.1/index.js';
28
- export const updates = [update0065, update0066, update0067, update0068, update0069, update010, update011, update012, update013, update014, update015, update020, update022, update050, update051, update052, update053, update054, update055, update056, update057, update058, update060, update061, update062, update070, update071];
28
+ import { update as update072 } from './0.7.2/index.js';
29
+ import { update as update073 } from './0.7.3/index.js';
30
+ import { update as update080 } from './0.8.0/index.js';
31
+ import { update as update090 } from './0.9.0/index.js';
32
+ import { update as update0100 } from './0.10.0/index.js';
33
+ import { update as update0110 } from './0.11.0/index.js';
34
+ import { update as update0120 } from './0.12.0/index.js';
35
+ import { update as update0130 } from './0.13.0/index.js';
36
+ export const updates = [update0065, update0066, update0067, update0068, update0069, update010, update011, update012, update013, update014, update015, update020, update022, update050, update051, update052, update053, update054, update055, update056, update057, update058, update060, update061, update062, update070, update071, update072, update073, update080, update090, update0100, update0110, update0120, update0130];
29
37
  export const getUpdatesFrom = (fromVersion) => {
30
38
  const fromParts = fromVersion.split('.').map(Number);
31
39
  return updates.filter((update) => {