@cancia/astro 0.7.0 → 0.9.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.
@@ -3,9 +3,11 @@ import {
3
3
  PT_LIST_ITEMS,
4
4
  PT_STYLES,
5
5
  isSafeHref,
6
+ parseRichValue,
6
7
  portableTextSubsetSchema,
7
- ptBlockSchema
8
- } from "../chunk-BOIQNZAO.js";
8
+ ptBlockSchema,
9
+ serializeRichValue
10
+ } from "../chunk-KHCFVVYV.js";
9
11
 
10
12
  // src/richtext/markdown.ts
11
13
  function keyGen(prefix) {
@@ -134,9 +136,11 @@ export {
134
136
  PT_STYLES,
135
137
  blockToRow,
136
138
  isSafeHref,
139
+ parseRichValue,
137
140
  portableTextSubsetSchema,
138
141
  portableTextToRows,
139
142
  ptBlockSchema,
140
143
  rowToBlock,
141
- rowsToPortableText
144
+ rowsToPortableText,
145
+ serializeRichValue
142
146
  };
package/dist/runtime.js CHANGED
@@ -3,11 +3,11 @@ import {
3
3
  getCanciaRuntime,
4
4
  setBakedConfig,
5
5
  setCanciaRuntime
6
- } from "./chunk-AGNPUTKS.js";
6
+ } from "./chunk-LJSSPOSW.js";
7
7
  import "./chunk-5IPHDIC6.js";
8
- import "./chunk-GNWD7EL2.js";
8
+ import "./chunk-MXVOJRAM.js";
9
9
  import "./chunk-U7V53JX7.js";
10
- import "./chunk-L2VKQJPY.js";
10
+ import "./chunk-2NVZWZPE.js";
11
11
  import "./chunk-7IA5B5CF.js";
12
12
  export {
13
13
  __resetRuntimeForTests,
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  export { z } from 'zod';
3
- export { P as PT_DECORATORS, a as PT_LIST_ITEMS, b as PT_STYLES, c as PortableTextValue, d as PtBlock, e as PtDecorator, f as PtLinkMarkDef, g as PtListItem, h as PtSpan, i as PtStyle, j as isSafeHref, p as portableTextSubsetSchema, k as ptBlockSchema } from '../portable-text-BikSqS9T.js';
3
+ export { P as PT_DECORATORS, a as PT_LIST_ITEMS, b as PT_STYLES, c as PortableTextValue, d as PtBlock, e as PtDecorator, f as PtLinkMarkDef, g as PtListItem, h as PtSpan, i as PtStyle, j as isSafeHref, p as parseRichValue, k as portableTextSubsetSchema, l as ptBlockSchema, s as serializeRichValue } from '../portable-text-D74aIuHn.js';
4
4
 
5
5
  /**
6
6
  * Widget hint the modal form uses to pick an input element. The Zod type
@@ -82,6 +82,21 @@ interface ListSchemaOptions<TFields extends Record<string, z.ZodTypeAny>> {
82
82
  * Defaults to the entry ID. The server validates slug uniqueness on save.
83
83
  */
84
84
  slugField?: keyof TFields & string;
85
+ /**
86
+ * Field name holding the entry's draft flag. When set, `canciaLoader`
87
+ * omits entries whose value is truthy from the content collection, so a
88
+ * draft never reaches the built site.
89
+ *
90
+ * The field MUST be a boolean with a default (`defineField.draft()` gives
91
+ * you exactly that) — an `undefined` draft flag reads as published, which
92
+ * is the safe direction for the pre-existing entries of a list that adds
93
+ * `draftField` later.
94
+ *
95
+ * Draft is deliberately per-list opt-in rather than an implicit field on
96
+ * every list: a list of office locations or nav links has no meaningful
97
+ * draft state, and a phantom "Draft" checkbox on every form is noise.
98
+ */
99
+ draftField?: keyof TFields & string;
85
100
  /** Field definitions. */
86
101
  fields: TFields;
87
102
  }
@@ -91,10 +106,26 @@ interface ListSchema<TFields extends Record<string, z.ZodTypeAny> = Record<strin
91
106
  titleField: string;
92
107
  bodyField: string | undefined;
93
108
  slugField: string | undefined;
109
+ draftField: string | undefined;
94
110
  fields: TFields;
95
111
  /** Zod object schema combining all fields, for one-shot validation. */
96
112
  validator: z.ZodObject<TFields>;
97
113
  }
114
+ /**
115
+ * True when `entry.data` is a draft under `schema.draftField`.
116
+ *
117
+ * The single source of truth for "is this entry a draft" — the loader, the
118
+ * toolbar preview rows and any user-side filter all call THIS, so a draft is
119
+ * decided identically everywhere. Vite-free and dependency-free by design.
120
+ *
121
+ * Reads as published (`false`) when the list declares no draftField, when the
122
+ * field is absent, or when it is `undefined` — every ambiguous case resolves
123
+ * to "published", matching the field's own default and keeping entries that
124
+ * predate the draftField visible.
125
+ */
126
+ declare function isDraft(schema: {
127
+ draftField?: string;
128
+ }, data: Record<string, unknown>): boolean;
98
129
  declare function defineList<TFields extends Record<string, z.ZodTypeAny>>(opts: ListSchemaOptions<TFields>): ListSchema<TFields>;
99
130
  /**
100
131
  * One field as seen by the modal form. Plain JSON, no Zod refs.
@@ -154,6 +185,15 @@ declare const defineField: {
154
185
  email: (o?: PlainFieldOptions) => z.ZodString;
155
186
  datetime: (o?: PlainFieldOptions) => z.ZodString;
156
187
  checkbox: (o?: PlainFieldOptions) => z.ZodBoolean;
188
+ /**
189
+ * The draft flag for a list's `draftField`. A checkbox that DEFAULTS to
190
+ * false, which is what makes it safe to add to an existing list: every
191
+ * stored entry that predates the field validates and reads as published
192
+ * rather than vanishing from the built site.
193
+ *
194
+ * Label defaults to "Draft" so the affordance reads the same on every list.
195
+ */
196
+ draft: (o?: PlainFieldOptions) => z.ZodDefault<z.ZodBoolean>;
157
197
  number: (o?: PlainFieldOptions & {
158
198
  min?: number;
159
199
  max?: number;
@@ -266,6 +306,11 @@ interface ListDescription {
266
306
  titleField: string;
267
307
  bodyField?: string;
268
308
  slugField?: string;
309
+ /**
310
+ * Field holding the draft flag, when the list opts in. The toolbar uses it
311
+ * to badge unpublished rows; the loader uses it to omit them from the build.
312
+ */
313
+ draftField?: string;
269
314
  fields: FieldDescription[];
270
315
  }
271
316
  /**
@@ -317,4 +362,4 @@ declare function isExternalHref(href: string): boolean;
317
362
  /** Map of list name → schema. What users export from src/cms/schemas.ts. */
318
363
  type SchemasModule = Record<string, ListSchema>;
319
364
 
320
- export { type FieldDescription, type FieldMeta, type FieldMetaBase, type FieldWidget, type LinkValue, type ListDescription, type ListSchema, type ListSchemaOptions, type SchemasModule, defineField, defineList, describeList, isExternalHref, parseLinkValue, serializeLinkValue, slugify };
365
+ export { type FieldDescription, type FieldMeta, type FieldMetaBase, type FieldWidget, type LinkValue, type ListDescription, type ListSchema, type ListSchemaOptions, type SchemasModule, defineField, defineList, describeList, isDraft, isExternalHref, parseLinkValue, serializeLinkValue, slugify };
@@ -2,20 +2,23 @@ import {
2
2
  defineField,
3
3
  defineList,
4
4
  describeList,
5
+ isDraft,
5
6
  isExternalHref,
6
7
  parseLinkValue,
7
8
  serializeLinkValue,
8
9
  slugify,
9
10
  z
10
- } from "../chunk-UMCBQXB6.js";
11
+ } from "../chunk-WVHTCFE6.js";
11
12
  import {
12
13
  PT_DECORATORS,
13
14
  PT_LIST_ITEMS,
14
15
  PT_STYLES,
15
16
  isSafeHref,
17
+ parseRichValue,
16
18
  portableTextSubsetSchema,
17
- ptBlockSchema
18
- } from "../chunk-BOIQNZAO.js";
19
+ ptBlockSchema,
20
+ serializeRichValue
21
+ } from "../chunk-KHCFVVYV.js";
19
22
  export {
20
23
  PT_DECORATORS,
21
24
  PT_LIST_ITEMS,
@@ -23,12 +26,15 @@ export {
23
26
  defineField,
24
27
  defineList,
25
28
  describeList,
29
+ isDraft,
26
30
  isExternalHref,
27
31
  isSafeHref,
28
32
  parseLinkValue,
33
+ parseRichValue,
29
34
  portableTextSubsetSchema,
30
35
  ptBlockSchema,
31
36
  serializeLinkValue,
37
+ serializeRichValue,
32
38
  slugify,
33
39
  z
34
40
  };
@@ -0,0 +1,23 @@
1
+ import { ListSchema, SchemasModule } from './index.js';
2
+ import 'zod';
3
+ import '../portable-text-D74aIuHn.js';
4
+
5
+ /**
6
+ * Resolve the absolute path to the user's schemas.ts. Returns null if no
7
+ * file exists at the expected location.
8
+ */
9
+ declare function resolveSchemasPath(projectRoot: string, overridePath?: string): string | null;
10
+ /**
11
+ * Load (and cache) the user's schemas module. Returns an empty map if no
12
+ * schemas.ts exists — the inline editor still works for KV edits without
13
+ * any lists defined.
14
+ */
15
+ declare function loadSchemas(projectRoot: string, overridePath?: string): Promise<SchemasModule>;
16
+ /**
17
+ * Get a single list schema, or null if it doesn't exist.
18
+ */
19
+ declare function loadListSchema(projectRoot: string, listName: string, overridePath?: string): Promise<ListSchema | null>;
20
+ /** For tests — drop the in-memory cache. */
21
+ declare function clearSchemaCache(): void;
22
+
23
+ export { clearSchemaCache, loadListSchema, loadSchemas, resolveSchemasPath };
@@ -0,0 +1,12 @@
1
+ import {
2
+ clearSchemaCache,
3
+ loadListSchema,
4
+ loadSchemas,
5
+ resolveSchemasPath
6
+ } from "../chunk-VL6FO446.js";
7
+ export {
8
+ clearSchemaCache,
9
+ loadListSchema,
10
+ loadSchemas,
11
+ resolveSchemasPath
12
+ };
@@ -6,7 +6,7 @@ import {
6
6
  closeSqliteAdapterV2,
7
7
  createGitBackedAdapter,
8
8
  createSqliteAdapterV2
9
- } from "../chunk-GNWD7EL2.js";
9
+ } from "../chunk-MXVOJRAM.js";
10
10
  import {
11
11
  createGitHubClient
12
12
  } from "../chunk-U7V53JX7.js";
@@ -15,7 +15,7 @@ import {
15
15
  createJsonFileAdapter,
16
16
  createJsonFileAdapterV2,
17
17
  hashRev
18
- } from "../chunk-L2VKQJPY.js";
18
+ } from "../chunk-2NVZWZPE.js";
19
19
  import {
20
20
  RevConflictError
21
21
  } from "../chunk-7IA5B5CF.js";
@@ -0,0 +1,47 @@
1
+ import { ContentMap } from '../content.js';
2
+
3
+ /** Test/dev hook — a content change must not be served from a stale cache. */
4
+ declare function clearTextCache(): void;
5
+ interface TextHelperConfig {
6
+ site: string;
7
+ lang: string;
8
+ /** Reads the whole content map. Injected so this module imports no adapter. */
9
+ read: () => Promise<ContentMap>;
10
+ }
11
+ declare function configureTextHelper(next: TextHelperConfig): void;
12
+ /**
13
+ * Load the content map. Awaited once per page, in frontmatter.
14
+ *
15
+ * NEVER throws or rejects. A content read must not break a build — the same rule
16
+ * createContentReader holds — so every failure resolves to an empty map, and
17
+ * every call site then falls back to the text authored in the page. A site whose
18
+ * database is unreachable renders exactly as its source says.
19
+ */
20
+ declare function __canciaContent(): Promise<ContentMap>;
21
+ /**
22
+ * Resolve one annotated element's text.
23
+ *
24
+ * `??` is load-bearing, not style: a stored "" means DELIBERATELY EMPTY (the
25
+ * client removed this text on purpose) and must NOT fall through to the authored
26
+ * fallback, or deleted content reappears on every build.
27
+ */
28
+ declare function __canciaText(cms: ContentMap, key: string, fallback: string): string;
29
+ interface LinkValue {
30
+ label: string;
31
+ href: string;
32
+ }
33
+ /**
34
+ * Resolve a link field — label AND href from one stored value.
35
+ *
36
+ * A link stores `{label, href}` as JSON so a new label can never be saved
37
+ * against a stale href. Both halves have an authored fallback (the text, and the
38
+ * `href=` already in the markup), which is why a link needs no t() call either.
39
+ *
40
+ * An unsafe href is DROPPED on read, falling back to the authored one — the same
41
+ * rule parseLinkValue holds, and for the same reason: validation guards the
42
+ * write path, but a value can reach a renderer from an older row or a
43
+ * hand-edited DB, so the read is where the guarantee has to hold.
44
+ */
45
+ declare function __canciaLink(cms: ContentMap, key: string, labelFallback: string, hrefFallback: string): LinkValue;
46
+
47
+ export { type LinkValue, type TextHelperConfig, __canciaContent, __canciaLink, __canciaText, clearTextCache, configureTextHelper };
@@ -0,0 +1,64 @@
1
+ // src/transform/text-helper.ts
2
+ var contentPromise = null;
3
+ function clearTextCache() {
4
+ contentPromise = null;
5
+ }
6
+ var config = null;
7
+ function configureTextHelper(next) {
8
+ config = next;
9
+ contentPromise = null;
10
+ }
11
+ async function __canciaContent() {
12
+ if (!config) return {};
13
+ try {
14
+ if (!contentPromise) contentPromise = config.read();
15
+ return await contentPromise;
16
+ } catch {
17
+ contentPromise = null;
18
+ return {};
19
+ }
20
+ }
21
+ function lang() {
22
+ return config?.lang ?? "en";
23
+ }
24
+ function __canciaText(cms, key, fallback) {
25
+ return cms[`${key}.${lang()}`] ?? fallback;
26
+ }
27
+ function isSafeHref(href) {
28
+ const trimmed = href.trim();
29
+ if (trimmed === "") return true;
30
+ if (/^(https?:|mailto:|tel:)/i.test(trimmed)) return true;
31
+ const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);
32
+ if (scheme) {
33
+ const firstSep = trimmed.search(/[/?#]/);
34
+ if (firstSep === -1 || scheme[1].length < firstSep) return false;
35
+ }
36
+ return true;
37
+ }
38
+ function __canciaLink(cms, key, labelFallback, hrefFallback) {
39
+ const fallback = { label: labelFallback, href: hrefFallback };
40
+ const raw = cms[`${key}.${lang()}`];
41
+ if (raw === void 0) return fallback;
42
+ if (raw === "") return { label: "", href: "" };
43
+ const trimmed = raw.trim();
44
+ if (trimmed.startsWith("{")) {
45
+ try {
46
+ const parsed = JSON.parse(trimmed);
47
+ const href = String(parsed.href ?? "");
48
+ return {
49
+ label: String(parsed.label ?? "") || labelFallback,
50
+ href: href && isSafeHref(href) ? href : hrefFallback
51
+ };
52
+ } catch {
53
+ return fallback;
54
+ }
55
+ }
56
+ return { label: raw, href: hrefFallback };
57
+ }
58
+ export {
59
+ __canciaContent,
60
+ __canciaLink,
61
+ __canciaText,
62
+ clearTextCache,
63
+ configureTextHelper
64
+ };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@cancia/astro",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Astro integration for Cancia CMS — inline editing with zero separate server",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/ninuzdellalb/cancia",
8
+ "url": "git+https://github.com/ninuzdellalb/cancia.git",
9
9
  "directory": "packages/astro"
10
10
  },
11
11
  "type": "module",
@@ -20,6 +20,10 @@
20
20
  "types": "./dist/schema/index.d.ts",
21
21
  "import": "./dist/schema/index.js"
22
22
  },
23
+ "./schema-loader": {
24
+ "types": "./dist/schema/loader.d.ts",
25
+ "import": "./dist/schema/loader.js"
26
+ },
23
27
  "./loader": {
24
28
  "types": "./dist/loader/index.d.ts",
25
29
  "import": "./dist/loader/index.js"
@@ -40,7 +44,8 @@
40
44
  "types": "./dist/richtext/index.d.ts",
41
45
  "import": "./dist/richtext/index.js"
42
46
  },
43
- "./richtext/CanciaRichText.astro": "./dist/richtext/CanciaRichText.astro"
47
+ "./richtext/CanciaRichText.astro": "./dist/richtext/CanciaRichText.astro",
48
+ "./richtext/CanciaRichRegion.astro": "./dist/richtext/CanciaRichRegion.astro"
44
49
  },
45
50
  "files": [
46
51
  "dist"
@@ -68,7 +73,8 @@
68
73
  },
69
74
  "dependencies": {
70
75
  "astro-portabletext": "^0.13.0",
71
- "zod": "^4.4.3"
76
+ "zod": "^4.4.3",
77
+ "@astrojs/compiler": "^2.10.0"
72
78
  },
73
79
  "scripts": {
74
80
  "build": "tsup",