includio-cms 0.21.0 → 0.23.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 (81) hide show
  1. package/API.md +20 -20
  2. package/CHANGELOG.md +111 -0
  3. package/DOCS.md +1169 -146
  4. package/README.md +138 -32
  5. package/ROADMAP.md +8 -330
  6. package/dist/admin/api/rest/handler.d.ts +13 -1
  7. package/dist/admin/api/rest/handler.js +13 -1
  8. package/dist/admin/api/rest/middleware/generateApiKey.d.ts +9 -0
  9. package/dist/admin/api/rest/middleware/generateApiKey.js +9 -0
  10. package/dist/admin/client/collection/collection-entries.svelte +1 -1
  11. package/dist/admin/client/collection/empty-state.svelte +1 -1
  12. package/dist/admin/client/collection/row-actions.svelte +3 -3
  13. package/dist/admin/client/collection/table-toolbar.svelte +3 -1
  14. package/dist/admin/client/entry/entry-header.svelte +3 -1
  15. package/dist/admin/client/users/create-user-dialog.svelte +4 -4
  16. package/dist/admin/client/users/delete-user-dialog.svelte +2 -0
  17. package/dist/admin/client/users/users-page.svelte +3 -2
  18. package/dist/admin/components/media/file-upload.svelte +2 -0
  19. package/dist/ai-claude/index.d.ts +9 -1
  20. package/dist/ai-claude/index.js +9 -1
  21. package/dist/ai-openai/index.d.ts +9 -1
  22. package/dist/ai-openai/index.js +9 -1
  23. package/dist/cli/index.js +115 -13
  24. package/dist/cms/runtime/schema.d.ts +2 -0
  25. package/dist/cms/runtime/schema.js +4 -0
  26. package/dist/cms/runtime/types.d.ts +1 -1
  27. package/dist/core/cms.d.ts +13 -1
  28. package/dist/core/cms.js +13 -1
  29. package/dist/core/errors.d.ts +71 -0
  30. package/dist/core/errors.js +179 -0
  31. package/dist/core/server/consentLogs/operations/create.d.ts +13 -1
  32. package/dist/core/server/consentLogs/operations/create.js +13 -1
  33. package/dist/core/server/entries/operations/create.js +6 -1
  34. package/dist/core/server/entries/operations/get.js +14 -3
  35. package/dist/core/server/entries/operations/resolveEntry.d.ts +32 -1
  36. package/dist/core/server/entries/operations/resolveEntry.js +36 -4
  37. package/dist/core/server/entries/operations/update.js +5 -1
  38. package/dist/core/server/fields/utils/resolveMedia.d.ts +18 -1
  39. package/dist/core/server/fields/utils/resolveMedia.js +13 -1
  40. package/dist/core/server/forms/submissions/operations/create.d.ts +21 -1
  41. package/dist/core/server/forms/submissions/operations/create.js +18 -2
  42. package/dist/core/server/forms/submissions/utils/parseMultipart.d.ts +15 -1
  43. package/dist/core/server/forms/submissions/utils/parseMultipart.js +15 -1
  44. package/dist/db-postgres/index.d.ts +10 -0
  45. package/dist/db-postgres/index.js +10 -0
  46. package/dist/email-nodemailer/index.d.ts +13 -1
  47. package/dist/email-nodemailer/index.js +13 -1
  48. package/dist/entity/index.d.ts +16 -1
  49. package/dist/entity/index.js +16 -1
  50. package/dist/files-local/index.d.ts +12 -1
  51. package/dist/files-local/index.js +12 -1
  52. package/dist/paraglide/messages/_index.d.ts +3 -36
  53. package/dist/paraglide/messages/_index.js +3 -71
  54. package/dist/paraglide/messages/hello_world.d.ts +5 -0
  55. package/dist/paraglide/messages/hello_world.js +33 -0
  56. package/dist/paraglide/messages/login_hello.d.ts +16 -0
  57. package/dist/paraglide/messages/login_hello.js +34 -0
  58. package/dist/paraglide/messages/login_please_login.d.ts +16 -0
  59. package/dist/paraglide/messages/login_please_login.js +34 -0
  60. package/dist/server/auth.d.ts +11 -0
  61. package/dist/server/auth.js +11 -0
  62. package/dist/sveltekit/config.d.ts +67 -4
  63. package/dist/sveltekit/config.js +73 -4
  64. package/dist/sveltekit/server/handle.d.ts +15 -1
  65. package/dist/sveltekit/server/handle.js +15 -1
  66. package/dist/sveltekit/server/layout.d.ts +12 -1
  67. package/dist/sveltekit/server/layout.js +12 -1
  68. package/dist/sveltekit/server/preview.d.ts +21 -1
  69. package/dist/sveltekit/server/preview.js +21 -1
  70. package/dist/types/cms.schema.d.ts +452 -0
  71. package/dist/types/cms.schema.js +629 -0
  72. package/dist/updates/0.22.0/index.d.ts +2 -0
  73. package/dist/updates/0.22.0/index.js +75 -0
  74. package/dist/updates/0.23.0/index.d.ts +2 -0
  75. package/dist/updates/0.23.0/index.js +21 -0
  76. package/dist/updates/index.js +3 -1
  77. package/package.json +4 -1
  78. package/dist/paraglide/messages/en.d.ts +0 -5
  79. package/dist/paraglide/messages/en.js +0 -14
  80. package/dist/paraglide/messages/pl.d.ts +0 -5
  81. package/dist/paraglide/messages/pl.js +0 -14
package/API.md CHANGED
@@ -1,4 +1,4 @@
1
- # includio-cms — Public API v0.21.0
1
+ # includio-cms — Public API v0.23.0
2
2
 
3
3
  > Auto-generated by `scripts/generate-api-md.ts`. Do not edit by hand.
4
4
 
@@ -13,19 +13,19 @@ Tags:
13
13
 
14
14
  ### `includio-cms`
15
15
 
16
- - `createEntityAPI(cms: CMS, opts?: EntityAPIOptions): <inferred>` — Creates a high-level Entity API (CRUD + publish/archive) bound to a CMS instance and a user.
16
+ - `createEntityAPI(cms: CMS, opts?: EntityAPIOptions): <inferred>` — Creates a high-level Entity API (CRUD + publish/archive) bound to a CMS
17
17
  - `getAuth(): <inferred>` — Returns the underlying `better-auth` instance from the initialized CMS.
18
- - `getCMS(): CMS` — Returns the singleton CMS instance. Must be called after `includioCMS()` initializes the CMS in `hooks.server.ts`.
19
- - `interface ResolvedMedia`
20
- - `resolveMediaWithStyles(mediaIds: string[], styles?: ImageFieldStyle[]): Promise<Record<string, ResolvedMedia>>` — Resolve media files by IDs and generate image styles. Useful for plugins resolving media references (e.g. photo-grid).
18
+ - `getCMS(): CMS` — Returns the singleton CMS instance. Must be called after `includioCMS()`
19
+ - `interface ResolvedMedia` — Resolved media file plus its image styles + blur placeholder. Returned by
20
+ - `resolveMediaWithStyles(mediaIds: string[], styles?: ImageFieldStyle[]): Promise<Record<string, ResolvedMedia>>` — Resolve media files by IDs and generate image styles. Useful for plugins or
21
21
 
22
22
  ### `includio-cms/core`
23
23
 
24
- - `createEntityAPI(cms: CMS, opts?: EntityAPIOptions): <inferred>` — Creates a high-level Entity API (CRUD + publish/archive) bound to a CMS instance and a user.
24
+ - `createEntityAPI(cms: CMS, opts?: EntityAPIOptions): <inferred>` — Creates a high-level Entity API (CRUD + publish/archive) bound to a CMS
25
25
  - `getAuth(): <inferred>` — Returns the underlying `better-auth` instance from the initialized CMS.
26
- - `getCMS(): CMS` — Returns the singleton CMS instance. Must be called after `includioCMS()` initializes the CMS in `hooks.server.ts`.
27
- - `interface ResolvedMedia`
28
- - `resolveMediaWithStyles(mediaIds: string[], styles?: ImageFieldStyle[]): Promise<Record<string, ResolvedMedia>>` — Resolve media files by IDs and generate image styles. Useful for plugins resolving media references (e.g. photo-grid).
26
+ - `getCMS(): CMS` — Returns the singleton CMS instance. Must be called after `includioCMS()`
27
+ - `interface ResolvedMedia` — Resolved media file plus its image styles + blur placeholder. Returned by
28
+ - `resolveMediaWithStyles(mediaIds: string[], styles?: ImageFieldStyle[]): Promise<Record<string, ResolvedMedia>>` — Resolve media files by IDs and generate image styles. Useful for plugins or
29
29
 
30
30
  ### `includio-cms/types`
31
31
 
@@ -239,11 +239,11 @@ Tags:
239
239
  ### `includio-cms/sveltekit`
240
240
 
241
241
  - `const CmsProvider: LegacyComponentType`
242
- - `defineCollection(config: CollectionInput): CollectionConfig` — Defines a collection (multi-entry content type).
242
+ - `defineCollection(config: CollectionInput): CollectionConfig` — Defines a collection (multi-entry content type, e.g. blog posts, products).
243
243
  - `defineConfig(config: CMSConfig): CMSConfig` — Defines the root CMS configuration. Pass to `includioCMS()` in `hooks.server.ts`.
244
- - `defineForm(config: FormConfig): FormConfig` — Defines a public form (submitted via `/api/forms/[slug]/submit`).
245
- - `defineObject(config: Omit<ObjectField, 'type'>): ObjectField` — Defines a reusable object field (nested record). Use inside `fields[]`.
246
- - `defineSingle(config: SingleInput): SingleConfig` — Defines a singleton (single-entry content type, e.g. site settings).
244
+ - `defineForm(config: FormConfig): FormConfig` — Defines a public form (submitted via `POST /api/forms/[slug]/submit`).
245
+ - `defineObject(config: Omit<ObjectField, 'type'>): ObjectField` — Defines a reusable object field (nested record). Use inline inside `fields[]`
246
+ - `defineSingle(config: SingleInput): SingleConfig` — Defines a singleton (single-entry content type, e.g. site settings, homepage).
247
247
  - `enableHybridEditing(): <inferred>` — Call in a layout/component script to enable data-hybrid-path rendering for all descendant HybridTarget/Image/Video.
248
248
  - `extractBlocks(doc: StructuredContentDoc, type?: string): SCNode[]` — Extract block-level nodes, optionally filtered by type.
249
249
  - `extractInlineBlocks(doc: StructuredContentDoc, blockType?: string): SCInlineBlockAttrs[]` — Extract inline block nodes, optionally filtered by blockType.
@@ -267,16 +267,16 @@ Tags:
267
267
 
268
268
  ### `includio-cms/sveltekit/server`
269
269
 
270
- - `cmsLayoutLoad(event: RequestEvent): <inferred>` — Returns `cmsContext` from `event.locals` for use in a SvelteKit layout `load`. Drop into your `+layout.server.ts`.
271
- - `countEntries(opts: CountEntriesOptions): Promise<number>` — Count entries matching the same filters as `resolveEntries`, without populating.
270
+ - `cmsLayoutLoad(event: RequestEvent): <inferred>` — Returns `cmsContext` from `event.locals` for use in a SvelteKit layout
271
+ - `countEntries(opts: CountEntriesOptions): Promise<number>` — Count entries matching the same filters as `resolveEntries`, without
272
272
  - `type CountEntriesOptions = Omit< ResolveEntriesOptions, 'limit' | 'offset' | 'populate' | 'orderBy' | 'dataOrderBy' >`
273
273
  - `const createConsentLog: <inferred>`
274
274
  - `const createFormSubmission: <inferred>`
275
- - `createRestApiHandler(): <inferred>` — REST API handler factory. Returns `{ GET, POST, PUT, DELETE }` `RequestHandler`s authenticated via `x-api-key` header. Mount in `src/routes/admin/api/rest/[...restPath]/+server.ts`.
275
+ - `createRestApiHandler(): <inferred>` — REST API handler factory. Returns `{ GET, POST, PUT, DELETE }`
276
276
  - `generateApiKey(): string` — Generate a cryptographically random API key (32 bytes, base64url-encoded).
277
- - `getPreviewEntry(event: RequestEvent, options: { language: string }): Promise<Entry | null>` — Resolves the preview entry from a `?preview=<versionId>` query param. Requires an authenticated session — throws `Unauthorized` otherwise.
278
- - `includioCMS(cmsConfig: CMSConfig): Handle[]` — SvelteKit `Handle[]` array that initializes the CMS, generates runtime artifacts, wires auth/admin guards, and exposes `event.locals.cmsContext`. Compose with `sequence()` in `hooks.server.ts`.
279
- - `parseFormDataForSubmission(formData: FormData, fields: FormField[]): Promise<Record<string, unknown>>` — Parses multipart `FormData` into a typed record of field values, handling file uploads via the configured files adapter.
277
+ - `getPreviewEntry(event: RequestEvent, options: { language: string }): Promise<Entry | null>` — Resolves the preview entry from a `?preview=<versionId>` query param.
278
+ - `includioCMS(cmsConfig: CMSConfig): Handle[]` — SvelteKit `Handle[]` array that initializes the CMS, generates runtime
279
+ - `parseFormDataForSubmission(formData: FormData, fields: FormField[]): Promise<Record<string, unknown>>` — Parses multipart `FormData` into a typed record of field values, handling
280
280
  - `type PopulateConfig = { /** Hard cap on relation depth. Default 5. Use `0` to keep all relations as raw IDs. */ maxDept...` — Recursion + per-field opt-out config for relation population.
281
281
  - `resolveEntries(opts: ResolveEntriesOptions): Promise<Entry[]>` — Fetch a list of populated Entries from a collection (or singleton with multiple instances).
282
282
  - `interface ResolveEntriesOptions`
@@ -387,7 +387,7 @@ Tags:
387
387
  ### `includio-cms/files-local`
388
388
 
389
389
  - `const fullDir: <inferred>`
390
- - `local(config?: LocalFilesConfig): FilesAdapter` — Local-disk files adapter. Stores uploads under `./static/uploads` (dev) or `/data/uploads` (prod).
390
+ - `local(config?: LocalFilesConfig): FilesAdapter` — Local-disk files adapter. Stores uploads under `./static/uploads` (dev) or
391
391
  - `interface LocalFilesConfig`
392
392
 
393
393
  ### `includio-cms/email-nodemailer`
package/CHANGELOG.md CHANGED
@@ -3,6 +3,117 @@
3
3
  All notable changes to includio-cms are documented here.
4
4
  Generated from `src/lib/updates/` — do not edit manually.
5
5
 
6
+ ## 0.23.0 — 2026-04-30
7
+
8
+ Faza 10 — Documentation Pass. DOCS.md uzupełniony (REST cURL + error codes, Entries error handling + transaction patterns, Admin UI a11y guide, Adapter Contracts z interfaces + peer deps + lazy import, Shop retry-payment lifecycle, edge cases dla number/boolean/date/datetime). Nowe sekcje: Stability Promise (semver, @public/@experimental/@internal, deprecation timeline) i Security Model (CSRF, CSP, rate-limit, API keys, link do KNOWN-RISKS.md). Migration Guide rozszerzony o master cheatsheet 0.x → 1.0 (agregat 0.16-0.22). ROADMAP cleanup: pre-v1.0 historia → ROADMAP-ARCHIVE.md.
9
+
10
+ ### Added
11
+ - `docs/stability-promise/` — nowa strona: SemVer 2.0, JSDoc tagi (@public semver-protected, @experimental opt-in to change, @internal poza kontraktem), deprecation timeline (1 minor cycle z @deprecated → remove w MAJOR), reference do `API.md` jako single source of truth public surface.
12
+ - `docs/security/` — nowa strona: threat model in/out of scope, CSRF (Origin/Referer guard na `/admin/api/*`), CSP (`default-src self`, `unsafe-inline` na script/style + uzasadnienie TipTap/Paraglide), rate limiting (200/60s admin, 5/h forms, env override), API keys (opt-in `expiresAt`, audit `rotatedAt`, `generateApiKey()`), Sharp 30s timeout, link do `KNOWN-RISKS.md` (5 zaakceptowanych ryzyk).
13
+ - `docs/migration/` — sekcja "Migrating from 0.x to 1.0 — master cheatsheet": global find-replace (getEntry → resolveEntry, language → locale), per-version blocks dla 0.16.0, 0.18.0, 0.19.0, 0.20.0, 0.21.0, 0.22.0 z migration steps + code examples, suggested upgrade path (pnpm + check + db:push + test).
14
+ - `docs/adapters/` — sekcja "Adapter contracts": tabela 4 interfaces (DatabaseAdapter 38 metod, FilesAdapter 5+3 optional, EmailAdapter 1+config, AIAdapter 1) z source paths, peer deps required vs optional, lazy import pattern (przykład `email-nodemailer`), error contracts, best practices (timeouts, retry, partial state).
15
+ - `docs/api/` — REST cURL examples (GET/POST/PUT/DELETE, upload), tabela error responses (HTTP × `CmsError.code`: UNAUTHORIZED, ENTRY_NOT_FOUND, INVALID_DATA, MISSING_REQUIRED_PARAM, RATE_LIMITED, etc.), authentication (Bearer header), opt-in `expiresAt` w API keys. Remote Functions section zaktualizowana na `resolveEntry/resolveEntries/countEntries`.
16
+ - `docs/entries/` — sekcja "Error handling" (CmsError instanceof + stable codes), sekcja "Transaction patterns" (last-write-wins versioning, custom Drizzle tx z `cms.db.driver`, plugin hooks vs partial failure). Querying przepisany na `resolveEntry/resolveEntries/countEntries` (status enum: published/draft/scheduled, archived = ops nie status).
17
+ - `docs/admin-ui/` — sekcja "Accessibility": WCAG 2.1 AA targets per surface (color contrast, keyboard nav, focus management, skip-link, heading hierarchy, ARIA roles, reduced motion), pattern dla custom plugin panels.
18
+ - `docs/shop/retry-payment/` — pełen lifecycle (5 kroków + ASCII diagram), server endpoint scaffold, headless SDK + `createOrderState`, error responses (400/401/404/409/429/502 z `CmsError.code`), constraints (same totals, token-gated, rate-limited, idempotent gateway, no auto-retry), admin override.
19
+ - `docs/fields/{number,boolean,date,datetime}/` — sekcje "Edge cases": number (NaN/Infinity rejection, floating-point precision, integer-only via step:1, parseFloat guards), boolean (null vs false, no string coercion, defaultValue vs runtime backfill), date (no timezone, ISO-8601 calendar string, null handling, edge years), datetime (UTC storage + local render, DST traps, ISO datetime validation).
20
+ - `ROADMAP-ARCHIVE.md` (root) — pełna historia 0.0.69 → 0.16.0 wycięta z `ROADMAP.md`. `ROADMAP.md` zawiera od teraz wyłącznie v1.0+ (header + legenda + v1.0 + v1.x + Security + Backlog), z linkiem do archive.
21
+ - `_config/nav.ts` + `scripts/compile-docs.ts` — zsynchronizowane: dodane "Stability Promise" w Guides, "Security Model" w "Authentication & Security" (renamed z "Authentication"). Brakujący "InPost Carrier" w nav.ts dodany dla parity z compile-docs.
22
+
23
+ ### Notes
24
+
25
+ Brak code changes — only docs + ROADMAP cleanup. DOCS.md regeneruje się przez `pnpm docs:compile` (część `prepublishOnly`). Po publikacji pełen TOC widoczny w DOCS.md z 10 zaktualizowanymi/nowymi sekcjami. Dla user-facing changes — żadnych. Dla devów customizujących admin UI lub piszących adaptery — pełny stable contract w jednym miejscu.
26
+
27
+ ## 0.22.0 — 2026-04-30
28
+
29
+ Faza 9 — DX & config validation pass. `defineConfig()` waliduje config strict Zodem z czytelnymi błędami (path + hint), resolvery / operacje throwują typowane `CmsError` z `code` + `context`, CLI ma `--help` per subcommand i `--version`, README przepisany pod nowych userów (system requirements + 5-min quickstart), `.env.example` rozszerzony o wszystkie `INCLUDIO_*` envy, JSDoc na każdym `@public` symbolu (opis + `@param` + `@returns` + `@example`).
30
+
31
+ ### Added
32
+ - `defineConfig()` (`includio-cms/sveltekit`) — runtime Zod validation z agregacją wszystkich błędów. Invalid config → `ConfigValidationError` (extends `CmsError`) z `issues[]` (path + message + hint), bullet-list message ready-to-paste do PR. `superRefine`: unique slugs (collections/singles/forms), default locale ≤ 1, relation targets w deklarowanych kolekcjach, `apiKeys[].permissions` referuje istniejące collection slugs.
33
+ - `CmsError` + `ConfigValidationError` (`includio-cms` → `core/errors`) — bazowa klasa z `code` (SCREAMING_SNAKE_CASE), `context: Record<string, unknown>`, `cause?`. Stabilne kody: `ENTRY_NOT_FOUND`, `ENTRY_VERSION_NOT_FOUND`, `INVALID_DATA`, `MISSING_REQUIRED_PARAM`, `CONFIG_VALIDATION_FAILED`. `toString()` = `[CODE] message (k=v, k=v)`.
34
+ - `formatZodDataIssues(error)` helper — render Zod errora z entry/form data jako lista `path: message`. Używany w `createEntryVersion`, `updateEntryVersion`, `createFormSubmission`.
35
+ - CLI: `includio --help`, `includio scaffold admin --help`, `includio install-peers --help`, `includio create-user --help` — exit 0 + Usage/Options/Example block. `includio --version` / `-v` z `package.json`. Unknown command → exit 1 + top-level help.
36
+ - `.env.example` rozszerzony — 11 envów z komentarzami i sekcjami (Required / Media & Uploads / Security & Rate Limits). Demo vars usunięte (były tylko dla `src/lib/demo/` skasowanego w Fazie 1).
37
+ - README rebuild: TOC, sekcja **System requirements** (Node 18+, PG 14+, ffmpeg optional), 5-step **Quick start** (install → .env → config → scaffold → create-user → dev), poprawiony link do `DOCS.md`, dodana tabelka adapterów, sekcja CLI z subcommandami.
38
+ - JSDoc bodies (opis + `@param` + `@returns` + `@example`) na każdym `@public` symbolu — `defineConfig`, `defineCollection`, `defineSingle`, `defineForm`, `defineObject`, `getCMS`, `resolveEntry`, `resolveEntries`, `countEntries`, `createFormSubmission`, `parseFormDataForSubmission`, `createConsentLog`, `resolveMediaWithStyles`, `createEntityAPI`, `createRestApiHandler`, `generateApiKey`, `getAuth`, `includioCMS`, `getPreviewEntry`, `cmsLayoutLoad`, factory adapterów (`pg`, `local`, `nodemailerAdapter`, `openAIAdapter`, `claudeAdapter`).
39
+
40
+ ### Fixed
41
+ - `MISSING_REQUIRED_PARAM` zamiast `throw new Error('... is required')` w `resolveEntry` / `resolveEntries` / `countEntries`. Context zawiera `op` + `missing`.
42
+ - `INVALID_DATA` zamiast `throw Error('Invalid data: ' + JSON.stringify(parsedData.error.flatten()))` w `createEntryVersion` / `updateEntryVersion` / `createFormSubmission`. Context zawiera `collection`/`entryId`/`lang` (entries) lub `formSlug` (forms). Body errora to czytelna lista `field.path: message`.
43
+ - `ENTRY_NOT_FOUND` z `{ collection, id }` w `_getDbEntryOrThrow` / `_getRawEntryOrThrow`; `ENTRY_VERSION_NOT_FOUND` z `{ versionId, entryId, lang }` w `_getDbEntryVersionOrThrow`.
44
+
45
+ ### Breaking
46
+ - **Strict config validation w `defineConfig`** — invalid configs które wcześniej "działały" w runtime (np. duplicate slug, brak default locale, relation do nieistniejącej kolekcji, brak metody w adapterze) **teraz throwują `ConfigValidationError` na starcie**. Najczęstsze przypadki + fix:
47
+ - **Duplicate slug**: dwie kolekcje/singles/forms z tym samym `slug` → unique slug per kategoria.
48
+ - **Invalid language code**: `code: 'ENGLISH'` → `code: 'en'` (ISO-639-1, opcjonalnie z regionem `'pl-PL'`).
49
+ - **Multiple default locales**: dwa `{ default: true }` → tylko jeden.
50
+ - **Missing adapter method**: stub adaptera bez `getEntries` etc. → zaimportuj pełen `pg()` / `local()` lub doimplementuj brakujące metody.
51
+ - **Invalid relation target**: `{ type: 'relation', collection: 'authors' }` przy braku kolekcji `authors` → dodaj kolekcję lub popraw target.
52
+ - **Resolver / operation error format** — błędy z `resolveEntry` / `resolveEntries` / `countEntries` / `createEntryVersion` / `updateEntryVersion` / `createFormSubmission` rzucają teraz `CmsError` (extends `Error`). `error.message` zachowuje stary opis (przy `toString()` poprzedzony `[CODE]`) — string-matching `error.message === 'Entry not found'` może się rozjechać. **Migracja:**
53
+ ```ts
54
+ import { CmsError } from 'includio-cms';
55
+
56
+ try { await resolveEntry({ id }); }
57
+ catch (e) {
58
+ if (e instanceof CmsError && e.code === 'ENTRY_NOT_FOUND') { ... }
59
+ }
60
+ ```
61
+ - **`.env.example` reformatted** — `DEMO_USER_EMAIL`, `DEMO_USER_PASSWORD`, `DEMO_RESET_KEY` usunięte (były tylko dla wewnętrznego demo skasowanego w Fazie 1). Jeśli polegałeś na nich → trzymaj w lokalnym `.env`, nie w `.env.example`.
62
+
63
+ ### Notes
64
+
65
+ ## Czytelność błędów config
66
+
67
+ Po update — invalid config wyrzuci na starcie:
68
+
69
+ ```
70
+ ConfigValidationError: CMSConfig validation failed (2 issues):
71
+ - languages[0]: must be a 2-letter ISO code (e.g. 'en' or 'pl-PL')
72
+ - collections[1].slug: duplicate collection slug 'posts' — Hint: each collection/single/form must have a unique `slug`
73
+ ```
74
+
75
+ Każdy issue ma `path` (JS-notation: `collections[1].slug`, `apiKeys[0].permissions[2]`) i `message`. Tam gdzie da się rozsądnie zgadnąć, dochodzi `Hint:` z fix-suggestion.
76
+
77
+ ## Pattern: branchowanie po error code
78
+
79
+ Stary kod string-matchujący po `error.message` musi się przepisać:
80
+
81
+ ```ts
82
+ // PRZED
83
+ catch (e) {
84
+ if ((e as Error).message === 'Entry not found') { /* 404 */ }
85
+ }
86
+
87
+ // PO
88
+ import { CmsError } from 'includio-cms';
89
+ catch (e) {
90
+ if (e instanceof CmsError && e.code === 'ENTRY_NOT_FOUND') { /* 404 */ }
91
+ }
92
+ ```
93
+
94
+ Dostępne kody w v0.22.0: `ENTRY_NOT_FOUND`, `ENTRY_VERSION_NOT_FOUND`, `INVALID_DATA`, `MISSING_REQUIRED_PARAM`, `CONFIG_VALIDATION_FAILED`.
95
+
96
+ ## Nowe envy (opt-in)
97
+
98
+ Skopiuj `node_modules/includio-cms/.env.example` do swojego `.env` — domyślne wartości działają OOTB:
99
+
100
+ - `INCLUDIO_SHARP_TIMEOUT_MS` (default 30000)
101
+ - `INCLUDIO_RATE_LIMIT_MAX` / `INCLUDIO_RATE_LIMIT_WINDOW_MS` (default 200/60000)
102
+ - `INCLUDIO_FORM_RATE_LIMIT_MAX` / `INCLUDIO_FORM_RATE_LIMIT_WINDOW_MS` (default 5/3600000)
103
+ - `INCLUDIO_CSRF_ALLOWED_ORIGINS` (default: same-origin only)
104
+
105
+ ## CLI helpy
106
+
107
+ ```bash
108
+ includio --help
109
+ includio scaffold admin --help
110
+ includio install-peers --help
111
+ includio create-user --help
112
+ includio --version
113
+ ```
114
+
115
+ Brak SQL migration.
116
+
6
117
  ## 0.21.0 — 2026-04-30
7
118
 
8
119
  Faza 5 część 2 — security finish: form rate-limit DRY refactor, API keys `expiresAt` / `rotatedAt`, sharp timeout 30s, `{@html}` audit close. `KNOWN-RISKS.md` w root jako single source of truth dla zaakceptowanych ryzyk v1.0. Plus: faza 6 setup — vitest coverage (info-only), docker test profile, integration test scaffolding (`tests/`).