includio-cms 0.18.0 → 0.19.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 (35) hide show
  1. package/CHANGELOG.md +43 -1
  2. package/DOCS.md +1 -1
  3. package/README.md +62 -0
  4. package/dist/ai-claude/index.d.ts +9 -0
  5. package/dist/ai-claude/index.js +23 -7
  6. package/dist/ai-openai/index.d.ts +9 -0
  7. package/dist/ai-openai/index.js +28 -9
  8. package/dist/db-postgres/index.d.ts +4 -0
  9. package/dist/db-postgres/index.js +4 -0
  10. package/dist/email-nodemailer/index.d.ts +9 -0
  11. package/dist/email-nodemailer/index.js +28 -6
  12. package/dist/files-local/index.d.ts +4 -0
  13. package/dist/files-local/index.js +4 -0
  14. package/dist/paraglide/messages/_index.d.ts +3 -36
  15. package/dist/paraglide/messages/_index.js +3 -71
  16. package/dist/paraglide/messages/hello_world.d.ts +5 -0
  17. package/dist/paraglide/messages/hello_world.js +33 -0
  18. package/dist/paraglide/messages/login_hello.d.ts +16 -0
  19. package/dist/paraglide/messages/login_hello.js +34 -0
  20. package/dist/paraglide/messages/login_please_login.d.ts +16 -0
  21. package/dist/paraglide/messages/login_please_login.js +34 -0
  22. package/dist/types/adapters/ai.d.ts +8 -0
  23. package/dist/types/adapters/db.d.ts +9 -0
  24. package/dist/types/adapters/email.d.ts +6 -0
  25. package/dist/types/adapters/files.d.ts +5 -0
  26. package/dist/updates/{0.17.0 → 0.18.0}/index.js +1 -1
  27. package/dist/updates/0.19.0/index.d.ts +2 -0
  28. package/dist/updates/0.19.0/index.js +40 -0
  29. package/dist/updates/index.js +3 -2
  30. package/package.json +14 -5
  31. package/dist/paraglide/messages/en.d.ts +0 -5
  32. package/dist/paraglide/messages/en.js +0 -14
  33. package/dist/paraglide/messages/pl.d.ts +0 -5
  34. package/dist/paraglide/messages/pl.js +0 -14
  35. /package/dist/updates/{0.17.0 → 0.18.0}/index.d.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -3,7 +3,49 @@
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.17.0 — 2026-04-29
6
+ ## 0.19.0 — 2026-04-29
7
+
8
+ Adapter contracts final + 3rd-party SDKs (`@anthropic-ai/sdk`, `openai`, `nodemailer`) przeniesione do `peerDependenciesMeta` jako optional. Adapter typy + factory oznaczone `@public` JSDoc. README sekcja "Writing your own adapter".
9
+
10
+ ### Added
11
+ - Adapter typy (`DatabaseAdapter`, `FilesAdapter`, `EmailAdapter`, `AIAdapter`) finalne, oznaczone `@public` JSDoc — stabilna powierzchnia kontraktu, TypeScript egzekwuje surface.
12
+ - Factory funkcje adapterów (`pg`, `local`, `nodemailerAdapter`, `openAIAdapter`, `claudeAdapter`) oznaczone `@public`.
13
+ - README sekcja "Writing your own adapter" + przykład bazujący na `db-postgres` + tabela optional peer dependencies.
14
+ - Lazy import 3 SDK (`@anthropic-ai/sdk`, `openai`, `nodemailer`) w factory adapterach — SDK nie ładuje się dopóki adapter nie jest faktycznie użyty.
15
+
16
+ ### Fixed
17
+ - Bundle slim — instalacja `includio-cms` w czystym projekcie nie ciąga już ~7-9MB SDK (anthropic + openai + nodemailer). Zostają w peer optional, doinstalowane tylko gdy faktycznie potrzebne.
18
+
19
+ ### Breaking
20
+ - **`@anthropic-ai/sdk`, `openai`, `nodemailer` przeniesione z `dependencies` do `peerDependenciesMeta` jako optional**. Userland używający `email-nodemailer`/`ai-openai`/`ai-claude` musi sam doinstalować odpowiedni SDK: `pnpm add nodemailer`, `pnpm add openai`, `pnpm add @anthropic-ai/sdk`. Brak peer = throw przy pierwszym użyciu adaptera (`generateAltText`/`sendMail`) z czytelnym komunikatem co doinstalować.
21
+ - **`runed` przeniesione z `peerDependenciesMeta.optional` do required peer**. `runed` jest hard-importowane w admin UI (PersistedState), więc opcjonalność była fikcyjna — userland uruchamiający admin BEZ `runed` dostawał crash przy bootcie. Teraz peer wymaga jawnej instalacji (lub pozostaje pulled przez SvelteKit projektu).
22
+
23
+ ### Notes
24
+
25
+ Migracja:
26
+
27
+ 1. Dodaj wymagane peer SDK do swojego `package.json`:
28
+
29
+ ```bash
30
+ # Jeśli używasz nodemailerAdapter:
31
+ pnpm add nodemailer
32
+
33
+ # Jeśli używasz openAIAdapter:
34
+ pnpm add openai
35
+
36
+ # Jeśli używasz claudeAdapter:
37
+ pnpm add @anthropic-ai/sdk
38
+ ```
39
+
40
+ 2. `runed` był już peer wcześniej, ale teraz nie jest optional — upewnij się że jest zainstalowane (zwykle pulled przez SvelteKit). Jeśli `pnpm install` zgłasza missing peer, dodaj jawnie: `pnpm add runed`.
41
+
42
+ Brak SQL migration. Zmiana czysto package-level.
43
+
44
+ Pisanie własnych adapterów:
45
+
46
+ Wszystkie 4 typy adapterów (`DatabaseAdapter`, `FilesAdapter`, `EmailAdapter`, `AIAdapter`) mają teraz `@public` kontrakty. Patrz README sekcja "Writing your own adapter" + przykład bazujący na `db-postgres`.
47
+
48
+ ## 0.18.0 — 2026-04-29
7
49
 
8
50
  Konsolidacja entry resolverów — kanoniczny `resolveEntry()` / `resolveEntries()` / `countEntries()` w jednym public API. Locale strict, cycle detection, populate config per-field opt-out + maxDepth. Hard remove starych funkcji (getEntry, getEntries, getRawEntry/ies, getDbEntry/ies, populateEntryData) z public surface — przeniesione do internal lub całkowicie usunięte.
9
51
 
package/DOCS.md CHANGED
@@ -1,4 +1,4 @@
1
- # Includio CMS Documentation (v0.18.0)
1
+ # Includio CMS Documentation (v0.19.0)
2
2
 
3
3
  > This file is auto-generated from the docs site. For the latest version, update the package.
4
4
 
package/README.md CHANGED
@@ -38,6 +38,68 @@ export default defineConfig({
38
38
 
39
39
  See the [full documentation](/docs) for installation, configuration, and usage.
40
40
 
41
+ ## Writing your own adapter
42
+
43
+ `includio-cms` ships with default adapters (`db-postgres`, `files-local`, `email-nodemailer`, `ai-openai`, `ai-claude`). Each is a factory returning an object that implements a `@public` contract from `includio-cms/types`. Build your own by implementing the same interface — TypeScript will enforce the surface.
44
+
45
+ Four adapter contracts:
46
+
47
+ - `DatabaseAdapter` — entries, versions, media, tags, form submissions, consent logs.
48
+ - `FilesAdapter` — file upload/download/list, optional private files (e.g. shop receipts).
49
+ - `EmailAdapter` — `sendMail`, default from address/name.
50
+ - `AIAdapter` — currently `generateAltText(fileId)`.
51
+
52
+ Source of truth: [`src/lib/types/adapters/`](src/lib/types/adapters/).
53
+
54
+ ### Minimal custom DB adapter (sketch)
55
+
56
+ ```ts
57
+ import type { DatabaseAdapter } from 'includio-cms/types';
58
+
59
+ export function myDbAdapter(config: { connection: string }): DatabaseAdapter {
60
+ // ...connect, prepare your client...
61
+ return {
62
+ createEntry: async (data) => { /* ... */ },
63
+ getEntries: async (opts) => { /* ... */ },
64
+ countEntries: async (opts) => { /* ... */ },
65
+ updateEntry: async (data) => { /* ... */ },
66
+ archiveEntry: async (data) => { /* ... */ },
67
+ deleteEntry: async (data) => { /* ... */ },
68
+ createEntryVersion: async (data) => { /* ... */ },
69
+ updateEntryVersion: async (data) => { /* ... */ },
70
+ getEntryVersions: async (data) => { /* ... */ },
71
+ deleteEntryVersion: async (data) => { /* ... */ },
72
+ // ...form submissions, media files, image/video styles, tags, consent logs...
73
+ };
74
+ }
75
+ ```
76
+
77
+ Wire it in `cms.config.ts`:
78
+
79
+ ```ts
80
+ import { defineConfig } from 'includio-cms/sveltekit';
81
+ import { myDbAdapter } from './my-adapter.js';
82
+
83
+ export default defineConfig({
84
+ db: myDbAdapter({ connection: process.env.MY_DB_URL! }),
85
+ // ...
86
+ });
87
+ ```
88
+
89
+ Reference implementation: [`src/lib/db-postgres/index.ts`](src/lib/db-postgres/index.ts) (drizzle + `postgres`).
90
+
91
+ ### Optional peer dependencies
92
+
93
+ The default email + AI adapters depend on third-party SDKs that **are not installed by default**. If you use them, install the peer:
94
+
95
+ | Adapter | Required peer | Install |
96
+ | ------------------------- | ------------------------ | -------------------------------------- |
97
+ | `email-nodemailer` | `nodemailer` | `pnpm add nodemailer` |
98
+ | `ai-openai` | `openai` | `pnpm add openai` |
99
+ | `ai-claude` | `@anthropic-ai/sdk` | `pnpm add @anthropic-ai/sdk` |
100
+
101
+ Each SDK is loaded lazily on first call. Missing peer throws a clear error at runtime — install it and the adapter wakes up.
102
+
41
103
  ## Links
42
104
 
43
105
  - [Full Documentation](DOCS.md)
@@ -1,2 +1,11 @@
1
1
  import type { AIAdapter, AIConfig } from '../types/adapters/ai.js';
2
+ /**
3
+ * Anthropic Claude AI adapter for `generateAltText`.
4
+ *
5
+ * `@anthropic-ai/sdk` is an **optional peer dependency** — install it in your
6
+ * project (`pnpm add @anthropic-ai/sdk`) when using this adapter. SDK loads
7
+ * lazily on first call; missing peer throws a clear error.
8
+ *
9
+ * @public
10
+ */
2
11
  export declare function claudeAdapter(config: AIConfig): AIAdapter;
@@ -1,14 +1,29 @@
1
1
  import { getCMS } from '../core/cms.js';
2
- import Anthropic from '@anthropic-ai/sdk';
3
2
  import sharp from 'sharp';
3
+ /**
4
+ * Anthropic Claude AI adapter for `generateAltText`.
5
+ *
6
+ * `@anthropic-ai/sdk` is an **optional peer dependency** — install it in your
7
+ * project (`pnpm add @anthropic-ai/sdk`) when using this adapter. SDK loads
8
+ * lazily on first call; missing peer throws a clear error.
9
+ *
10
+ * @public
11
+ */
4
12
  export function claudeAdapter(config) {
5
13
  let client = null;
6
- function getClient() {
7
- if (!client) {
8
- if (!config.apiKey)
9
- throw new Error('AI_CLAUDE_API_KEY is not set');
10
- client = new Anthropic({ apiKey: config.apiKey });
14
+ async function getClient() {
15
+ if (client)
16
+ return client;
17
+ if (!config.apiKey)
18
+ throw new Error('AI_CLAUDE_API_KEY is not set');
19
+ let Anthropic;
20
+ try {
21
+ Anthropic = (await import('@anthropic-ai/sdk')).default;
11
22
  }
23
+ catch {
24
+ throw new Error('@anthropic-ai/sdk is required for claudeAdapter — install it with `pnpm add @anthropic-ai/sdk`');
25
+ }
26
+ client = new Anthropic({ apiKey: config.apiKey });
12
27
  return client;
13
28
  }
14
29
  return {
@@ -29,7 +44,8 @@ export function claudeAdapter(config) {
29
44
  const pngBuffer = await sharp(fileBuffer).png().toBuffer();
30
45
  const imageBase64 = pngBuffer.toString('base64');
31
46
  const prompt = `Generate a concise and descriptive alt text for the following image file in polish language. The alt text should accurately describe the content and context of the image, be no longer than 125 characters, and avoid using phrases like "image of" or "picture of". Return only the alt text, nothing else.`;
32
- const message = await getClient().messages.create({
47
+ const anthropic = await getClient();
48
+ const message = await anthropic.messages.create({
33
49
  model: 'claude-haiku-4-5-20251001',
34
50
  max_tokens: 256,
35
51
  messages: [
@@ -1,2 +1,11 @@
1
1
  import type { AIAdapter, AIConfig } from '../types/adapters/ai.js';
2
+ /**
3
+ * OpenAI AI adapter for `generateAltText`.
4
+ *
5
+ * `openai` is an **optional peer dependency** — install it in your project
6
+ * (`pnpm add openai`) when using this adapter. SDK loads lazily on first call;
7
+ * missing peer throws a clear error.
8
+ *
9
+ * @public
10
+ */
2
11
  export declare function openAIAdapter(config: AIConfig): AIAdapter;
@@ -1,12 +1,32 @@
1
1
  import { getCMS } from '../core/cms.js';
2
- import OpenAI from 'openai';
3
- import { zodResponseFormat } from 'openai/helpers/zod.mjs';
4
2
  import z from 'zod';
5
3
  import sharp from 'sharp';
4
+ /**
5
+ * OpenAI AI adapter for `generateAltText`.
6
+ *
7
+ * `openai` is an **optional peer dependency** — install it in your project
8
+ * (`pnpm add openai`) when using this adapter. SDK loads lazily on first call;
9
+ * missing peer throws a clear error.
10
+ *
11
+ * @public
12
+ */
6
13
  export function openAIAdapter(config) {
7
- const openai = new OpenAI({
8
- apiKey: config.apiKey
9
- });
14
+ let openai = null;
15
+ let zodResponseFormat = null;
16
+ async function getClient() {
17
+ if (openai && zodResponseFormat)
18
+ return { client: openai, zodResponseFormat };
19
+ let OpenAI;
20
+ try {
21
+ OpenAI = (await import('openai')).default;
22
+ zodResponseFormat = (await import('openai/helpers/zod.mjs')).zodResponseFormat;
23
+ }
24
+ catch {
25
+ throw new Error('openai is required for openAIAdapter — install it with `pnpm add openai`');
26
+ }
27
+ openai = new OpenAI({ apiKey: config.apiKey });
28
+ return { client: openai, zodResponseFormat };
29
+ }
10
30
  return {
11
31
  generateAltText: async (fileId) => {
12
32
  const altTextSchema = z.object({
@@ -24,13 +44,12 @@ export function openAIAdapter(config) {
24
44
  if (!file) {
25
45
  throw new Error('File not found');
26
46
  }
27
- // Konwertuj plik na PNG używając Sharp i przekonwertuj na base64
28
47
  const fileBuffer = Buffer.from(await file.arrayBuffer());
29
48
  const pngBuffer = await sharp(fileBuffer).png().toBuffer();
30
49
  const imageBase64 = pngBuffer.toString('base64');
31
50
  const prompt = `Generate a concise and descriptive alt text for the following image file in polish language. The alt text should accurately describe the content and context of the image, be no longer than 125 characters, and avoid using phrases like "image of" or "picture of".`;
32
- const completion = await openai.chat.completions.parse({
33
- // model: 'gpt-4.1-nano',
51
+ const { client, zodResponseFormat: zrf } = await getClient();
52
+ const completion = await client.chat.completions.parse({
34
53
  model: 'gpt-4o',
35
54
  messages: [
36
55
  {
@@ -49,7 +68,7 @@ export function openAIAdapter(config) {
49
68
  ]
50
69
  }
51
70
  ],
52
- response_format: zodResponseFormat(altTextSchema, 'response')
71
+ response_format: zrf(altTextSchema, 'response')
53
72
  });
54
73
  const response = completion.choices[0].message;
55
74
  if (!response.parsed) {
@@ -5,4 +5,8 @@ import type { DatabaseAdapter } from '../types/adapters/db.js';
5
5
  export type DatabaseAdapterWithDrizzle = DatabaseAdapter & {
6
6
  _drizzle: ReturnType<typeof drizzle<typeof schema>>;
7
7
  };
8
+ /**
9
+ * Postgres database adapter (drizzle + `postgres`).
10
+ * @public
11
+ */
8
12
  export declare function pg(config: Config): DatabaseAdapterWithDrizzle;
@@ -262,6 +262,10 @@ function buildMediaFileConditions(db, options) {
262
262
  }
263
263
  return conditions;
264
264
  }
265
+ /**
266
+ * Postgres database adapter (drizzle + `postgres`).
267
+ * @public
268
+ */
265
269
  export function pg(config) {
266
270
  const client = postgres(config.databaseUrl);
267
271
  const db = drizzle(client, { schema });
@@ -5,5 +5,14 @@ interface Options {
5
5
  defaultFromName: string;
6
6
  transportOptions: SMTPTransport.Options;
7
7
  }
8
+ /**
9
+ * SMTP email adapter built on `nodemailer`.
10
+ *
11
+ * `nodemailer` is an **optional peer dependency** — install it in your project
12
+ * (`pnpm add nodemailer`) when using this adapter. The SDK loads lazily on first
13
+ * `sendMail()`; missing peer throws a clear error.
14
+ *
15
+ * @public
16
+ */
8
17
  export declare function nodemailerAdapter(options: Options): EmailAdapter;
9
18
  export {};
@@ -1,14 +1,36 @@
1
- import { createTransport } from 'nodemailer';
1
+ /**
2
+ * SMTP email adapter built on `nodemailer`.
3
+ *
4
+ * `nodemailer` is an **optional peer dependency** — install it in your project
5
+ * (`pnpm add nodemailer`) when using this adapter. The SDK loads lazily on first
6
+ * `sendMail()`; missing peer throws a clear error.
7
+ *
8
+ * @public
9
+ */
2
10
  export function nodemailerAdapter(options) {
3
- const transporter = createTransport({
4
- ...options.transportOptions,
5
- from: `"${options.defaultFromName}" <${options.defaultFromAddress}>`
6
- });
11
+ let transporter = null;
12
+ async function getTransporter() {
13
+ if (transporter)
14
+ return transporter;
15
+ let createTransport;
16
+ try {
17
+ ({ createTransport } = await import('nodemailer'));
18
+ }
19
+ catch {
20
+ throw new Error('nodemailer is required for nodemailerAdapter — install it with `pnpm add nodemailer`');
21
+ }
22
+ transporter = createTransport({
23
+ ...options.transportOptions,
24
+ from: `"${options.defaultFromName}" <${options.defaultFromAddress}>`
25
+ });
26
+ return transporter;
27
+ }
7
28
  return {
8
29
  defaultFromAddress: options.defaultFromAddress,
9
30
  defaultFromName: options.defaultFromName,
10
31
  sendMail: async (sendMailOptions) => {
11
- await transporter.sendMail({
32
+ const t = await getTransporter();
33
+ await t.sendMail({
12
34
  ...sendMailOptions,
13
35
  from: `"${options.defaultFromName}" <${options.defaultFromAddress}>`
14
36
  });
@@ -4,4 +4,8 @@ export interface LocalFilesConfig {
4
4
  ffmpegPath?: string;
5
5
  ffprobePath?: string;
6
6
  }
7
+ /**
8
+ * Local-disk files adapter. Stores uploads under `./static/uploads` (dev) or `/data/uploads` (prod).
9
+ * @public
10
+ */
7
11
  export declare function local(config?: LocalFilesConfig): FilesAdapter;
@@ -19,6 +19,10 @@ async function ensureDir(dir) {
19
19
  // Already exists
20
20
  }
21
21
  }
22
+ /**
23
+ * Local-disk files adapter. Stores uploads under `./static/uploads` (dev) or `/data/uploads` (prod).
24
+ * @public
25
+ */
22
26
  export function local(config) {
23
27
  if (config?.ffmpegPath || config?.ffprobePath) {
24
28
  setFfmpegPaths(config.ffmpegPath, config.ffprobePath);
@@ -1,36 +1,3 @@
1
- export function hello_world(inputs: {
2
- name: NonNullable<unknown>;
3
- }, options?: {
4
- locale?: "en" | "pl";
5
- }): string;
6
- /**
7
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
8
- *
9
- * - Changing this function will be over-written by the next build.
10
- *
11
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
12
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
13
- *
14
- * @param {{}} inputs
15
- * @param {{ locale?: "en" | "pl" }} options
16
- * @returns {string}
17
- */
18
- declare function login_hello(inputs?: {}, options?: {
19
- locale?: "en" | "pl";
20
- }): string;
21
- /**
22
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
23
- *
24
- * - Changing this function will be over-written by the next build.
25
- *
26
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
27
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
28
- *
29
- * @param {{}} inputs
30
- * @param {{ locale?: "en" | "pl" }} options
31
- * @returns {string}
32
- */
33
- declare function login_please_login(inputs?: {}, options?: {
34
- locale?: "en" | "pl";
35
- }): string;
36
- export { login_hello as login.hello, login_please_login as login.please_login };
1
+ export * from "./hello_world.js";
2
+ export * from "./login_hello.js";
3
+ export * from "./login_please_login.js";
@@ -1,72 +1,4 @@
1
1
  /* eslint-disable */
2
- import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from "../runtime.js"
3
- import * as en from "./en.js"
4
- import * as pl from "./pl.js"
5
- /**
6
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
7
- *
8
- * - Changing this function will be over-written by the next build.
9
- *
10
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
11
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
12
- *
13
- * @param {{ name: NonNullable<unknown> }} inputs
14
- * @param {{ locale?: "en" | "pl" }} options
15
- * @returns {string}
16
- */
17
- /* @__NO_SIDE_EFFECTS__ */
18
- export const hello_world = (inputs, options = {}) => {
19
- if (experimentalMiddlewareLocaleSplitting && isServer === false) {
20
- return /** @type {any} */ (globalThis).__paraglide_ssr.hello_world(inputs)
21
- }
22
- const locale = options.locale ?? getLocale()
23
- trackMessageCall("hello_world", locale)
24
- if (locale === "en") return en.hello_world(inputs)
25
- return pl.hello_world(inputs)
26
- };
27
- /**
28
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
29
- *
30
- * - Changing this function will be over-written by the next build.
31
- *
32
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
33
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
34
- *
35
- * @param {{}} inputs
36
- * @param {{ locale?: "en" | "pl" }} options
37
- * @returns {string}
38
- */
39
- /* @__NO_SIDE_EFFECTS__ */
40
- const login_hello = (inputs = {}, options = {}) => {
41
- if (experimentalMiddlewareLocaleSplitting && isServer === false) {
42
- return /** @type {any} */ (globalThis).__paraglide_ssr.login_hello(inputs)
43
- }
44
- const locale = options.locale ?? getLocale()
45
- trackMessageCall("login_hello", locale)
46
- if (locale === "en") return en.login_hello(inputs)
47
- return pl.login_hello(inputs)
48
- };
49
- export { login_hello as "login.hello" }
50
- /**
51
- * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
52
- *
53
- * - Changing this function will be over-written by the next build.
54
- *
55
- * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
56
- * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
57
- *
58
- * @param {{}} inputs
59
- * @param {{ locale?: "en" | "pl" }} options
60
- * @returns {string}
61
- */
62
- /* @__NO_SIDE_EFFECTS__ */
63
- const login_please_login = (inputs = {}, options = {}) => {
64
- if (experimentalMiddlewareLocaleSplitting && isServer === false) {
65
- return /** @type {any} */ (globalThis).__paraglide_ssr.login_please_login(inputs)
66
- }
67
- const locale = options.locale ?? getLocale()
68
- trackMessageCall("login_please_login", locale)
69
- if (locale === "en") return en.login_please_login(inputs)
70
- return pl.login_please_login(inputs)
71
- };
72
- export { login_please_login as "login.please_login" }
2
+ export * from './hello_world.js'
3
+ export * from './login_hello.js'
4
+ export * from './login_please_login.js'
@@ -0,0 +1,5 @@
1
+ export function hello_world(inputs: {
2
+ name: NonNullable<unknown>;
3
+ }, options?: {
4
+ locale?: "en" | "pl";
5
+ }): string;
@@ -0,0 +1,33 @@
1
+ /* eslint-disable */
2
+ import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from '../runtime.js';
3
+
4
+ const en_hello_world = /** @type {(inputs: { name: NonNullable<unknown> }) => string} */ (i) => {
5
+ return `Hello, ${i.name} from en!`
6
+ };
7
+
8
+ const pl_hello_world = /** @type {(inputs: { name: NonNullable<unknown> }) => string} */ (i) => {
9
+ return `Hello, ${i.name} from pl!`
10
+ };
11
+
12
+ /**
13
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
14
+ *
15
+ * - Changing this function will be over-written by the next build.
16
+ *
17
+ * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
18
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
19
+ *
20
+ * @param {{ name: NonNullable<unknown> }} inputs
21
+ * @param {{ locale?: "en" | "pl" }} options
22
+ * @returns {string}
23
+ */
24
+ /* @__NO_SIDE_EFFECTS__ */
25
+ export const hello_world = (inputs, options = {}) => {
26
+ if (experimentalMiddlewareLocaleSplitting && isServer === false) {
27
+ return /** @type {any} */ (globalThis).__paraglide_ssr.hello_world(inputs)
28
+ }
29
+ const locale = options.locale ?? getLocale()
30
+ trackMessageCall("hello_world", locale)
31
+ if (locale === "en") return en_hello_world(inputs)
32
+ return pl_hello_world(inputs)
33
+ };
@@ -0,0 +1,16 @@
1
+ export { login_hello as login.hello };
2
+ /**
3
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
4
+ *
5
+ * - Changing this function will be over-written by the next build.
6
+ *
7
+ * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
8
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
9
+ *
10
+ * @param {{}} inputs
11
+ * @param {{ locale?: "en" | "pl" }} options
12
+ * @returns {string}
13
+ */
14
+ declare function login_hello(inputs?: {}, options?: {
15
+ locale?: "en" | "pl";
16
+ }): string;
@@ -0,0 +1,34 @@
1
+ /* eslint-disable */
2
+ import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from '../runtime.js';
3
+
4
+ const en_login_hello = /** @type {(inputs: {}) => string} */ () => {
5
+ return `Welcome back`
6
+ };
7
+
8
+ const pl_login_hello = /** @type {(inputs: {}) => string} */ () => {
9
+ return `Witaj ponownie`
10
+ };
11
+
12
+ /**
13
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
14
+ *
15
+ * - Changing this function will be over-written by the next build.
16
+ *
17
+ * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
18
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
19
+ *
20
+ * @param {{}} inputs
21
+ * @param {{ locale?: "en" | "pl" }} options
22
+ * @returns {string}
23
+ */
24
+ /* @__NO_SIDE_EFFECTS__ */
25
+ const login_hello = (inputs = {}, options = {}) => {
26
+ if (experimentalMiddlewareLocaleSplitting && isServer === false) {
27
+ return /** @type {any} */ (globalThis).__paraglide_ssr.login_hello(inputs)
28
+ }
29
+ const locale = options.locale ?? getLocale()
30
+ trackMessageCall("login_hello", locale)
31
+ if (locale === "en") return en_login_hello(inputs)
32
+ return pl_login_hello(inputs)
33
+ };
34
+ export { login_hello as "login.hello" }
@@ -0,0 +1,16 @@
1
+ export { login_please_login as login.please_login };
2
+ /**
3
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
4
+ *
5
+ * - Changing this function will be over-written by the next build.
6
+ *
7
+ * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
8
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
9
+ *
10
+ * @param {{}} inputs
11
+ * @param {{ locale?: "en" | "pl" }} options
12
+ * @returns {string}
13
+ */
14
+ declare function login_please_login(inputs?: {}, options?: {
15
+ locale?: "en" | "pl";
16
+ }): string;
@@ -0,0 +1,34 @@
1
+ /* eslint-disable */
2
+ import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from '../runtime.js';
3
+
4
+ const en_login_please_login = /** @type {(inputs: {}) => string} */ () => {
5
+ return `Login to your account`
6
+ };
7
+
8
+ const pl_login_please_login = /** @type {(inputs: {}) => string} */ () => {
9
+ return `Zaloguj się na swoje konto`
10
+ };
11
+
12
+ /**
13
+ * This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
14
+ *
15
+ * - Changing this function will be over-written by the next build.
16
+ *
17
+ * - If you want to change the translations, you can either edit the source files e.g. `en.json`, or
18
+ * use another inlang app like [Fink](https://inlang.com/m/tdozzpar) or the [VSCode extension Sherlock](https://inlang.com/m/r7kp499g).
19
+ *
20
+ * @param {{}} inputs
21
+ * @param {{ locale?: "en" | "pl" }} options
22
+ * @returns {string}
23
+ */
24
+ /* @__NO_SIDE_EFFECTS__ */
25
+ const login_please_login = (inputs = {}, options = {}) => {
26
+ if (experimentalMiddlewareLocaleSplitting && isServer === false) {
27
+ return /** @type {any} */ (globalThis).__paraglide_ssr.login_please_login(inputs)
28
+ }
29
+ const locale = options.locale ?? getLocale()
30
+ trackMessageCall("login_please_login", locale)
31
+ if (locale === "en") return en_login_please_login(inputs)
32
+ return pl_login_please_login(inputs)
33
+ };
34
+ export { login_please_login as "login.please_login" }
@@ -1,11 +1,19 @@
1
+ /** @public */
1
2
  export interface AIConfig {
2
3
  apiKey: string;
3
4
  }
5
+ /** @public */
4
6
  export type AIAdapterConfig = {
5
7
  config: AIConfig;
6
8
  adapter: (config: AIConfig, db: AIAdapter) => AIAdapter;
7
9
  };
10
+ /**
11
+ * Contract for AI adapters. Currently powers `generateAltText` (admin media UI).
12
+ * Default implementations: `includio-cms/ai-openai`, `includio-cms/ai-claude`.
13
+ * @public
14
+ */
8
15
  export interface AIAdapter {
9
16
  generateAltText: GenerateAltText;
10
17
  }
18
+ /** @public */
11
19
  export type GenerateAltText = (fileId: string) => Promise<string>;
@@ -4,6 +4,15 @@ import type { ImageFieldStyle } from '../fields.js';
4
4
  import type { FormSubmission } from '../forms.js';
5
5
  import type { ImageStyle, MediaFile, MediaTag, UploadedMediaFile, VideoStyle, VideoStyleStatus } from '../media.js';
6
6
  export type { FilesAdapter } from './files.js';
7
+ /**
8
+ * Contract for database adapters. Drives entries, versions, media, tags, form submissions,
9
+ * consent logs, and image/video styles. Default implementation: `includio-cms/db-postgres`.
10
+ *
11
+ * To build a custom adapter, implement every required method (optionals are marked `?`).
12
+ * See README — "Writing your own adapter".
13
+ *
14
+ * @public
15
+ */
7
16
  export interface DatabaseAdapter {
8
17
  createEntry: CreateEntry;
9
18
  getEntries: GetEntries;
@@ -1,4 +1,10 @@
1
+ /** @public */
1
2
  export type EmailAdapterFactory = () => EmailAdapter;
3
+ /**
4
+ * Contract for email adapters. Used by `better-auth` reset-password flow and form submission
5
+ * notifications. Default implementation: `includio-cms/email-nodemailer`.
6
+ * @public
7
+ */
2
8
  export interface EmailAdapter {
3
9
  sendMail: SendMail;
4
10
  defaultFromAddress: string;
@@ -1,4 +1,9 @@
1
1
  import type { UploadedMediaFile } from '../media.js';
2
+ /**
3
+ * Contract for file storage adapters. Used by media upload pipeline + private file flow
4
+ * (e.g. shop receipts). Default implementation: `includio-cms/files-local`.
5
+ * @public
6
+ */
2
7
  export interface FilesAdapter {
3
8
  downloadFile: DownloadFile;
4
9
  uploadFile: UploadFile;
@@ -1,5 +1,5 @@
1
1
  export const update = {
2
- version: '0.17.0',
2
+ version: '0.18.0',
3
3
  date: '2026-04-29',
4
4
  description: 'Konsolidacja entry resolverów — kanoniczny `resolveEntry()` / `resolveEntries()` / `countEntries()` w jednym public API. Locale strict, cycle detection, populate config per-field opt-out + maxDepth. Hard remove starych funkcji (getEntry, getEntries, getRawEntry/ies, getDbEntry/ies, populateEntryData) z public surface — przeniesione do internal lub całkowicie usunięte.',
5
5
  features: [
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,40 @@
1
+ export const update = {
2
+ version: '0.19.0',
3
+ date: '2026-04-29',
4
+ description: 'Adapter contracts final + 3rd-party SDKs (`@anthropic-ai/sdk`, `openai`, `nodemailer`) przeniesione do `peerDependenciesMeta` jako optional. Adapter typy + factory oznaczone `@public` JSDoc. README sekcja "Writing your own adapter".',
5
+ features: [
6
+ 'Adapter typy (`DatabaseAdapter`, `FilesAdapter`, `EmailAdapter`, `AIAdapter`) finalne, oznaczone `@public` JSDoc — stabilna powierzchnia kontraktu, TypeScript egzekwuje surface.',
7
+ 'Factory funkcje adapterów (`pg`, `local`, `nodemailerAdapter`, `openAIAdapter`, `claudeAdapter`) oznaczone `@public`.',
8
+ 'README sekcja "Writing your own adapter" + przykład bazujący na `db-postgres` + tabela optional peer dependencies.',
9
+ 'Lazy import 3 SDK (`@anthropic-ai/sdk`, `openai`, `nodemailer`) w factory adapterach — SDK nie ładuje się dopóki adapter nie jest faktycznie użyty.'
10
+ ],
11
+ fixes: [
12
+ 'Bundle slim — instalacja `includio-cms` w czystym projekcie nie ciąga już ~7-9MB SDK (anthropic + openai + nodemailer). Zostają w peer optional, doinstalowane tylko gdy faktycznie potrzebne.'
13
+ ],
14
+ breakingChanges: [
15
+ '**`@anthropic-ai/sdk`, `openai`, `nodemailer` przeniesione z `dependencies` do `peerDependenciesMeta` jako optional**. Userland używający `email-nodemailer`/`ai-openai`/`ai-claude` musi sam doinstalować odpowiedni SDK: `pnpm add nodemailer`, `pnpm add openai`, `pnpm add @anthropic-ai/sdk`. Brak peer = throw przy pierwszym użyciu adaptera (`generateAltText`/`sendMail`) z czytelnym komunikatem co doinstalować.',
16
+ '**`runed` przeniesione z `peerDependenciesMeta.optional` do required peer**. `runed` jest hard-importowane w admin UI (PersistedState), więc opcjonalność była fikcyjna — userland uruchamiający admin BEZ `runed` dostawał crash przy bootcie. Teraz peer wymaga jawnej instalacji (lub pozostaje pulled przez SvelteKit projektu).'
17
+ ],
18
+ notes: `Migracja:
19
+
20
+ 1. Dodaj wymagane peer SDK do swojego \`package.json\`:
21
+
22
+ \`\`\`bash
23
+ # Jeśli używasz nodemailerAdapter:
24
+ pnpm add nodemailer
25
+
26
+ # Jeśli używasz openAIAdapter:
27
+ pnpm add openai
28
+
29
+ # Jeśli używasz claudeAdapter:
30
+ pnpm add @anthropic-ai/sdk
31
+ \`\`\`
32
+
33
+ 2. \`runed\` był już peer wcześniej, ale teraz nie jest optional — upewnij się że jest zainstalowane (zwykle pulled przez SvelteKit). Jeśli \`pnpm install\` zgłasza missing peer, dodaj jawnie: \`pnpm add runed\`.
34
+
35
+ Brak SQL migration. Zmiana czysto package-level.
36
+
37
+ Pisanie własnych adapterów:
38
+
39
+ Wszystkie 4 typy adapterów (\`DatabaseAdapter\`, \`FilesAdapter\`, \`EmailAdapter\`, \`AIAdapter\`) mają teraz \`@public\` kontrakty. Patrz README sekcja "Writing your own adapter" + przykład bazujący na \`db-postgres\`.`
40
+ };
@@ -51,8 +51,9 @@ import { update as update0153 } from './0.15.3/index.js';
51
51
  import { update as update0154 } from './0.15.4/index.js';
52
52
  import { update as update0155 } from './0.15.5/index.js';
53
53
  import { update as update0160 } from './0.16.0/index.js';
54
- import { update as update0170 } from './0.17.0/index.js';
55
- 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, update0131, update0132, update0133, update0134, update0140, update0141, update0142, update0143, update0144, update0145, update0146, update0150, update0151, update0152, update0153, update0154, update0155, update0160, update0170];
54
+ import { update as update0180 } from './0.18.0/index.js';
55
+ import { update as update0190 } from './0.19.0/index.js';
56
+ 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, update0131, update0132, update0133, update0134, update0140, update0141, update0142, update0143, update0144, update0145, update0146, update0150, update0151, update0152, update0153, update0154, update0155, update0160, update0180, update0190];
56
57
  export const getUpdatesFrom = (fromVersion) => {
57
58
  const fromParts = fromVersion.split('.').map(Number);
58
59
  return updates.filter((update) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "includio-cms",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",
@@ -177,6 +177,7 @@
177
177
  }
178
178
  },
179
179
  "peerDependencies": {
180
+ "@anthropic-ai/sdk": ">=0.39.0",
180
181
  "@sveltejs/kit": "^2.48.0",
181
182
  "@sveltejs/vite-plugin-svelte": "^6.2.1",
182
183
  "better-auth": "^1.3.34",
@@ -184,6 +185,8 @@
184
185
  "drizzle-orm": "^0.40.0",
185
186
  "embla-carousel-svelte": "^8.6.0",
186
187
  "formsnap": "^2.0.1",
188
+ "nodemailer": ">=7.0.0",
189
+ "openai": ">=6.0.0",
187
190
  "paneforge": "^1.0.2",
188
191
  "postgres": "^3.4.5",
189
192
  "runed": "^0.35.1",
@@ -198,7 +201,13 @@
198
201
  "zod": "^4.0.0"
199
202
  },
200
203
  "peerDependenciesMeta": {
201
- "runed": {
204
+ "@anthropic-ai/sdk": {
205
+ "optional": true
206
+ },
207
+ "nodemailer": {
208
+ "optional": true
209
+ },
210
+ "openai": {
202
211
  "optional": true
203
212
  },
204
213
  "svelte-tiptap": {
@@ -215,6 +224,7 @@
215
224
  }
216
225
  },
217
226
  "devDependencies": {
227
+ "@anthropic-ai/sdk": "^0.39.0",
218
228
  "@chromatic-com/storybook": "^5.0.1",
219
229
  "@eslint/compat": "^1.2.5",
220
230
  "@eslint/js": "^9.18.0",
@@ -237,6 +247,8 @@
237
247
  "@types/fluent-ffmpeg": "^2.1.27",
238
248
  "@types/node": "^22",
239
249
  "@types/nodemailer": "^7.0.4",
250
+ "nodemailer": "^7.0.11",
251
+ "openai": "^6.9.0",
240
252
  "better-auth": "^1.3.34",
241
253
  "bits-ui": "^2.11.5",
242
254
  "clsx": "^2.1.1",
@@ -283,7 +295,6 @@
283
295
  "svelte"
284
296
  ],
285
297
  "dependencies": {
286
- "@anthropic-ai/sdk": "^0.39.0",
287
298
  "@inlang/paraglide-js": "^2.0.0",
288
299
  "@internationalized/date": "^3.8.2",
289
300
  "@lucide/svelte": "^0.544.0",
@@ -316,8 +327,6 @@
316
327
  "isomorphic-dompurify": "3.0.0-rc.2",
317
328
  "lowlight": "^3.3.0",
318
329
  "mrmime": "^2.0.1",
319
- "nodemailer": "^7.0.11",
320
- "openai": "^6.9.0",
321
330
  "path-to-regexp": "^8.2.0",
322
331
  "readline": "^1.3.0",
323
332
  "slugify": "^1.6.6",
@@ -1,5 +0,0 @@
1
- export const hello_world: (inputs: {
2
- name: NonNullable<unknown>;
3
- }) => string;
4
- export const login_hello: (inputs: {}) => string;
5
- export const login_please_login: (inputs: {}) => string;
@@ -1,14 +0,0 @@
1
- /* eslint-disable */
2
-
3
-
4
- export const hello_world = /** @type {(inputs: { name: NonNullable<unknown> }) => string} */ (i) => {
5
- return `Hello, ${i.name} from en!`
6
- };
7
-
8
- export const login_hello = /** @type {(inputs: {}) => string} */ () => {
9
- return `Welcome back`
10
- };
11
-
12
- export const login_please_login = /** @type {(inputs: {}) => string} */ () => {
13
- return `Login to your account`
14
- };
@@ -1,5 +0,0 @@
1
- export const hello_world: (inputs: {
2
- name: NonNullable<unknown>;
3
- }) => string;
4
- export const login_hello: (inputs: {}) => string;
5
- export const login_please_login: (inputs: {}) => string;
@@ -1,14 +0,0 @@
1
- /* eslint-disable */
2
-
3
-
4
- export const hello_world = /** @type {(inputs: { name: NonNullable<unknown> }) => string} */ (i) => {
5
- return `Hello, ${i.name} from pl!`
6
- };
7
-
8
- export const login_hello = /** @type {(inputs: {}) => string} */ () => {
9
- return `Witaj ponownie`
10
- };
11
-
12
- export const login_please_login = /** @type {(inputs: {}) => string} */ () => {
13
- return `Zaloguj się na swoje konto`
14
- };
File without changes