canopycms 0.0.25 → 0.0.27
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.
- package/dist/ai/generate.d.ts +3 -0
- package/dist/ai/generate.d.ts.map +1 -1
- package/dist/ai/generate.js +17 -6
- package/dist/ai/generate.js.map +1 -1
- package/dist/ai/handler.d.ts.map +1 -1
- package/dist/ai/handler.js +1 -0
- package/dist/ai/handler.js.map +1 -1
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/json-to-markdown.d.ts.map +1 -1
- package/dist/ai/json-to-markdown.js +10 -2
- package/dist/ai/json-to-markdown.js.map +1 -1
- package/dist/ai/transform-components.d.ts +27 -0
- package/dist/ai/transform-components.d.ts.map +1 -0
- package/dist/ai/transform-components.js +168 -0
- package/dist/ai/transform-components.js.map +1 -0
- package/dist/ai/types.d.ts +50 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/api/content.d.ts +6 -0
- package/dist/api/content.d.ts.map +1 -1
- package/dist/api/content.js +18 -1
- package/dist/api/content.js.map +1 -1
- package/dist/api/schema.d.ts +20 -20
- package/dist/build/generate-ai-content.d.ts.map +1 -1
- package/dist/build/generate-ai-content.js +1 -0
- package/dist/build/generate-ai-content.js.map +1 -1
- package/dist/cli/generate-ai-content.js +383 -124
- package/dist/cli/init.js +2 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -0
- package/dist/client.js.map +1 -1
- package/dist/config/helpers.d.ts.map +1 -1
- package/dist/config/helpers.js +2 -1
- package/dist/config/helpers.js.map +1 -1
- package/dist/config/schemas/collection.d.ts +6 -6
- package/dist/config/schemas/config.d.ts +10 -6
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/config.js +1 -0
- package/dist/config/schemas/config.js.map +1 -1
- package/dist/config/types.d.ts +6 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/content-reader.d.ts +2 -0
- package/dist/content-reader.d.ts.map +1 -1
- package/dist/content-reader.js +13 -4
- package/dist/content-reader.js.map +1 -1
- package/dist/editor/CanopyEditor.d.ts.map +1 -1
- package/dist/editor/CanopyEditor.js +1 -1
- package/dist/editor/CanopyEditor.js.map +1 -1
- package/dist/editor/Editor.d.ts +1 -0
- package/dist/editor/Editor.d.ts.map +1 -1
- package/dist/editor/Editor.js +32 -9
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/fields/MarkdownField.d.ts.map +1 -1
- package/dist/editor/fields/MarkdownField.js +8 -2
- package/dist/editor/fields/MarkdownField.js.map +1 -1
- package/dist/editor/fields/entry-link/EntryLinkContext.d.ts +20 -0
- package/dist/editor/fields/entry-link/EntryLinkContext.d.ts.map +1 -0
- package/dist/editor/fields/entry-link/EntryLinkContext.js +12 -0
- package/dist/editor/fields/entry-link/EntryLinkContext.js.map +1 -0
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +16 -0
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts.map +1 -0
- package/dist/editor/fields/entry-link/InsertEntryLink.js +62 -0
- package/dist/editor/fields/entry-link/InsertEntryLink.js.map +1 -0
- package/dist/editor/fields/entry-link/index.d.ts +3 -0
- package/dist/editor/fields/entry-link/index.d.ts.map +1 -0
- package/dist/editor/fields/entry-link/index.js +3 -0
- package/dist/editor/fields/entry-link/index.js.map +1 -0
- package/dist/editor/hooks/useEntryLinkResolution.d.ts +26 -0
- package/dist/editor/hooks/useEntryLinkResolution.d.ts.map +1 -0
- package/dist/editor/hooks/useEntryLinkResolution.js +96 -0
- package/dist/editor/hooks/useEntryLinkResolution.js.map +1 -0
- package/dist/entry-link-resolver.d.ts +67 -0
- package/dist/entry-link-resolver.d.ts.map +1 -0
- package/dist/entry-link-resolver.js +226 -0
- package/dist/entry-link-resolver.js.map +1 -0
- package/dist/schema/schema-store.d.ts +10 -10
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/dist/utils/entry-url.d.ts +21 -0
- package/dist/utils/entry-url.d.ts.map +1 -0
- package/dist/utils/entry-url.js +41 -0
- package/dist/utils/entry-url.js.map +1 -0
- package/dist/validation/entry-link-validator.d.ts +27 -0
- package/dist/validation/entry-link-validator.d.ts.map +1 -0
- package/dist/validation/entry-link-validator.js +49 -0
- package/dist/validation/entry-link-validator.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry link resolution for body content.
|
|
3
|
+
*
|
|
4
|
+
* Resolves `entry:CONTENT_ID` patterns in markdown/MDX body text to actual URL paths.
|
|
5
|
+
* This extends the reference-by-ID pattern (already used for structured reference fields)
|
|
6
|
+
* to inline links in content bodies.
|
|
7
|
+
*
|
|
8
|
+
* Syntax:
|
|
9
|
+
* [Link text](entry:vh2WdhwAFiSL)
|
|
10
|
+
* [Link text](entry:vh2WdhwAFiSL#section-heading)
|
|
11
|
+
*
|
|
12
|
+
* Resolution skips fenced code blocks and inline code spans to avoid
|
|
13
|
+
* corrupting code examples.
|
|
14
|
+
*/
|
|
15
|
+
import { createDebugLogger } from './utils/debug.js';
|
|
16
|
+
import { computeEntryUrl } from './utils/entry-url.js';
|
|
17
|
+
const log = createDebugLogger({ prefix: 'EntryLinks' });
|
|
18
|
+
/**
|
|
19
|
+
* Base58 alphabet pattern (matches content IDs).
|
|
20
|
+
* Excludes ambiguous characters: 0, O, I, l
|
|
21
|
+
*/
|
|
22
|
+
/** Base58 alphabet character class (excludes ambiguous: 0, O, I, l). */
|
|
23
|
+
export const BASE58_CHAR = '[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]';
|
|
24
|
+
/**
|
|
25
|
+
* Pattern matching `entry:CONTENT_ID` with optional anchor fragment.
|
|
26
|
+
* Uses the `g` flag — safe to share when used only with `.replace()`.
|
|
27
|
+
*/
|
|
28
|
+
export const ENTRY_LINK_PATTERN = new RegExp(`entry:(${BASE58_CHAR}{12})(#[^\\s)>"']*)?`, 'g');
|
|
29
|
+
/**
|
|
30
|
+
* Compute a URL path from an entry's location in the content tree.
|
|
31
|
+
* Delegates to the shared `computeEntryUrl` utility.
|
|
32
|
+
*/
|
|
33
|
+
export function resolveEntryUrl(location, contentRoot) {
|
|
34
|
+
return computeEntryUrl(location.collection ?? '', location.slug ?? '', contentRoot);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Replace `entry:CONTENT_ID` patterns in text with resolved URL paths.
|
|
38
|
+
*
|
|
39
|
+
* Skips code blocks (fenced ``` and inline `code`) to avoid corrupting
|
|
40
|
+
* code examples that mention the entry: syntax.
|
|
41
|
+
*
|
|
42
|
+
* Missing IDs are replaced with "#" (dead link) and logged as warnings.
|
|
43
|
+
* Anchor fragments are preserved: entry:ID#heading => /path#heading
|
|
44
|
+
*/
|
|
45
|
+
export function resolveEntryLinksInText(text, idIndex, contentRoot, customResolver) {
|
|
46
|
+
// Split text into protected regions (code blocks/spans) and resolvable regions
|
|
47
|
+
const parts = splitByCodeRegions(text);
|
|
48
|
+
return parts
|
|
49
|
+
.map((part) => {
|
|
50
|
+
if (part.isCode)
|
|
51
|
+
return part.text;
|
|
52
|
+
return part.text.replace(ENTRY_LINK_PATTERN, (_match, id, anchor) => {
|
|
53
|
+
const location = idIndex.findById(id);
|
|
54
|
+
if (!location || location.type !== 'entry' || !location.collection || !location.slug) {
|
|
55
|
+
log.warn('resolve', `Entry link target not found: entry:${id}`);
|
|
56
|
+
return anchor ?? '#';
|
|
57
|
+
}
|
|
58
|
+
let url;
|
|
59
|
+
if (customResolver) {
|
|
60
|
+
url = customResolver({
|
|
61
|
+
collection: location.collection,
|
|
62
|
+
slug: location.slug,
|
|
63
|
+
id,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
url = resolveEntryUrl(location, contentRoot);
|
|
68
|
+
}
|
|
69
|
+
return `${url}${anchor ?? ''}`;
|
|
70
|
+
});
|
|
71
|
+
})
|
|
72
|
+
.join('');
|
|
73
|
+
}
|
|
74
|
+
/** Quick-check pattern for early bail-out (no `g` flag, safe for `.test()`). */
|
|
75
|
+
export const ENTRY_LINK_QUICK_CHECK = /entry:[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{12}/;
|
|
76
|
+
/**
|
|
77
|
+
* Recursively resolve entry:ID patterns in all string values of a data object.
|
|
78
|
+
*
|
|
79
|
+
* This handles nested objects, arrays, and mixed structures — important for
|
|
80
|
+
* JSON entries where markdown fields live inside nested objects (e.g., hero.body).
|
|
81
|
+
*
|
|
82
|
+
* Returns the same object reference if nothing changed (structural sharing).
|
|
83
|
+
*/
|
|
84
|
+
export function resolveEntryLinksInData(data, idIndex, contentRoot, customResolver) {
|
|
85
|
+
if (typeof data === 'string') {
|
|
86
|
+
if (!ENTRY_LINK_QUICK_CHECK.test(data))
|
|
87
|
+
return data;
|
|
88
|
+
return resolveEntryLinksInText(data, idIndex, contentRoot, customResolver);
|
|
89
|
+
}
|
|
90
|
+
if (Array.isArray(data)) {
|
|
91
|
+
let changed = false;
|
|
92
|
+
const result = data.map((item) => {
|
|
93
|
+
const resolved = resolveEntryLinksInData(item, idIndex, contentRoot, customResolver);
|
|
94
|
+
if (resolved !== item)
|
|
95
|
+
changed = true;
|
|
96
|
+
return resolved;
|
|
97
|
+
});
|
|
98
|
+
return changed ? result : data;
|
|
99
|
+
}
|
|
100
|
+
if (data != null && typeof data === 'object') {
|
|
101
|
+
let changed = false;
|
|
102
|
+
const result = {};
|
|
103
|
+
for (const [key, value] of Object.entries(data)) {
|
|
104
|
+
const resolved = resolveEntryLinksInData(value, idIndex, contentRoot, customResolver);
|
|
105
|
+
result[key] = resolved;
|
|
106
|
+
if (resolved !== value)
|
|
107
|
+
changed = true;
|
|
108
|
+
}
|
|
109
|
+
return changed ? result : data;
|
|
110
|
+
}
|
|
111
|
+
return data;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Extract all entry link IDs from text (for validation, not resolution).
|
|
115
|
+
* Returns IDs found in entry:ID patterns, skipping code blocks.
|
|
116
|
+
*/
|
|
117
|
+
export function extractEntryLinkIds(text) {
|
|
118
|
+
const parts = splitByCodeRegions(text);
|
|
119
|
+
const results = [];
|
|
120
|
+
for (const part of parts) {
|
|
121
|
+
if (part.isCode)
|
|
122
|
+
continue;
|
|
123
|
+
const regex = new RegExp(ENTRY_LINK_PATTERN.source, 'g');
|
|
124
|
+
let match;
|
|
125
|
+
while ((match = regex.exec(part.text)) !== null) {
|
|
126
|
+
results.push({
|
|
127
|
+
id: match[1],
|
|
128
|
+
anchor: match[2] || undefined,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return results;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Split text into alternating code/non-code regions.
|
|
136
|
+
*
|
|
137
|
+
* Handles:
|
|
138
|
+
* - Fenced code blocks (``` or ~~~), including with language tags
|
|
139
|
+
* - Inline code spans (`code` and ``code``)
|
|
140
|
+
*
|
|
141
|
+
* This ensures entry:ID inside code is never resolved.
|
|
142
|
+
*/
|
|
143
|
+
function splitByCodeRegions(text) {
|
|
144
|
+
const parts = [];
|
|
145
|
+
let current = '';
|
|
146
|
+
let i = 0;
|
|
147
|
+
while (i < text.length) {
|
|
148
|
+
// Check for fenced code block (``` or ~~~)
|
|
149
|
+
if ((text[i] === '`' || text[i] === '~') &&
|
|
150
|
+
i + 2 < text.length &&
|
|
151
|
+
text[i + 1] === text[i] &&
|
|
152
|
+
text[i + 2] === text[i]) {
|
|
153
|
+
const fence = text[i];
|
|
154
|
+
// Count fence length (could be ``` or ```` etc.)
|
|
155
|
+
let fenceLen = 0;
|
|
156
|
+
while (i + fenceLen < text.length && text[i + fenceLen] === fence)
|
|
157
|
+
fenceLen++;
|
|
158
|
+
// Find end of opening fence line
|
|
159
|
+
const lineEnd = text.indexOf('\n', i + fenceLen);
|
|
160
|
+
if (lineEnd === -1) {
|
|
161
|
+
// No newline — rest of text is code block
|
|
162
|
+
if (current)
|
|
163
|
+
parts.push({ text: current, isCode: false });
|
|
164
|
+
parts.push({ text: text.slice(i), isCode: true });
|
|
165
|
+
return parts;
|
|
166
|
+
}
|
|
167
|
+
// Find closing fence
|
|
168
|
+
const closingPattern = fence.repeat(fenceLen);
|
|
169
|
+
let closeStart = lineEnd + 1;
|
|
170
|
+
let found = false;
|
|
171
|
+
while (closeStart < text.length) {
|
|
172
|
+
const nextNewline = text.indexOf('\n', closeStart);
|
|
173
|
+
const lineContent = nextNewline === -1 ? text.slice(closeStart) : text.slice(closeStart, nextNewline);
|
|
174
|
+
if (lineContent.trim().startsWith(closingPattern)) {
|
|
175
|
+
const endPos = nextNewline === -1 ? text.length : nextNewline + 1;
|
|
176
|
+
if (current)
|
|
177
|
+
parts.push({ text: current, isCode: false });
|
|
178
|
+
current = '';
|
|
179
|
+
parts.push({ text: text.slice(i, endPos), isCode: true });
|
|
180
|
+
i = endPos;
|
|
181
|
+
found = true;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
if (nextNewline === -1)
|
|
185
|
+
break;
|
|
186
|
+
closeStart = nextNewline + 1;
|
|
187
|
+
}
|
|
188
|
+
if (!found) {
|
|
189
|
+
// Unclosed code block — treat rest as code
|
|
190
|
+
if (current)
|
|
191
|
+
parts.push({ text: current, isCode: false });
|
|
192
|
+
parts.push({ text: text.slice(i), isCode: true });
|
|
193
|
+
return parts;
|
|
194
|
+
}
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
// Check for inline code span (` or ``)
|
|
198
|
+
if (text[i] === '`') {
|
|
199
|
+
// Count opening backticks
|
|
200
|
+
let ticks = 0;
|
|
201
|
+
while (i + ticks < text.length && text[i + ticks] === '`')
|
|
202
|
+
ticks++;
|
|
203
|
+
// Find matching closing backticks
|
|
204
|
+
const closer = '`'.repeat(ticks);
|
|
205
|
+
const closeIdx = text.indexOf(closer, i + ticks);
|
|
206
|
+
if (closeIdx !== -1) {
|
|
207
|
+
if (current)
|
|
208
|
+
parts.push({ text: current, isCode: false });
|
|
209
|
+
current = '';
|
|
210
|
+
parts.push({ text: text.slice(i, closeIdx + ticks), isCode: true });
|
|
211
|
+
i = closeIdx + ticks;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
// No closing backticks — treat as regular text
|
|
215
|
+
current += text.slice(i, i + ticks);
|
|
216
|
+
i += ticks;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
current += text[i];
|
|
220
|
+
i++;
|
|
221
|
+
}
|
|
222
|
+
if (current)
|
|
223
|
+
parts.push({ text: current, isCode: false });
|
|
224
|
+
return parts;
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=entry-link-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-link-resolver.js","sourceRoot":"","sources":["../src/entry-link-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,15 +57,15 @@ declare const entryTypeInputSchema: z.ZodObject<{
|
|
|
57
57
|
name: string;
|
|
58
58
|
format: "mdx" | "md" | "json";
|
|
59
59
|
schema: string;
|
|
60
|
-
label?: string | undefined;
|
|
61
60
|
default?: boolean | undefined;
|
|
61
|
+
label?: string | undefined;
|
|
62
62
|
maxItems?: number | undefined;
|
|
63
63
|
}, {
|
|
64
64
|
name: string;
|
|
65
65
|
format: "mdx" | "md" | "json";
|
|
66
66
|
schema: string;
|
|
67
|
-
label?: string | undefined;
|
|
68
67
|
default?: boolean | undefined;
|
|
68
|
+
label?: string | undefined;
|
|
69
69
|
maxItems?: number | undefined;
|
|
70
70
|
}>;
|
|
71
71
|
declare const createCollectionInputSchema: z.ZodObject<{
|
|
@@ -83,15 +83,15 @@ declare const createCollectionInputSchema: z.ZodObject<{
|
|
|
83
83
|
name: string;
|
|
84
84
|
format: "mdx" | "md" | "json";
|
|
85
85
|
schema: string;
|
|
86
|
-
label?: string | undefined;
|
|
87
86
|
default?: boolean | undefined;
|
|
87
|
+
label?: string | undefined;
|
|
88
88
|
maxItems?: number | undefined;
|
|
89
89
|
}, {
|
|
90
90
|
name: string;
|
|
91
91
|
format: "mdx" | "md" | "json";
|
|
92
92
|
schema: string;
|
|
93
|
-
label?: string | undefined;
|
|
94
93
|
default?: boolean | undefined;
|
|
94
|
+
label?: string | undefined;
|
|
95
95
|
maxItems?: number | undefined;
|
|
96
96
|
}>, "many">;
|
|
97
97
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -99,8 +99,8 @@ declare const createCollectionInputSchema: z.ZodObject<{
|
|
|
99
99
|
name: string;
|
|
100
100
|
format: "mdx" | "md" | "json";
|
|
101
101
|
schema: string;
|
|
102
|
-
label?: string | undefined;
|
|
103
102
|
default?: boolean | undefined;
|
|
103
|
+
label?: string | undefined;
|
|
104
104
|
maxItems?: number | undefined;
|
|
105
105
|
}[];
|
|
106
106
|
name: string;
|
|
@@ -111,8 +111,8 @@ declare const createCollectionInputSchema: z.ZodObject<{
|
|
|
111
111
|
name: string;
|
|
112
112
|
format: "mdx" | "md" | "json";
|
|
113
113
|
schema: string;
|
|
114
|
-
label?: string | undefined;
|
|
115
114
|
default?: boolean | undefined;
|
|
115
|
+
label?: string | undefined;
|
|
116
116
|
maxItems?: number | undefined;
|
|
117
117
|
}[];
|
|
118
118
|
name: string;
|
|
@@ -126,14 +126,14 @@ declare const updateCollectionInputSchema: z.ZodObject<{
|
|
|
126
126
|
order: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
127
127
|
}, "strip", z.ZodTypeAny, {
|
|
128
128
|
name?: string | undefined;
|
|
129
|
+
slug?: string | undefined;
|
|
129
130
|
label?: string | undefined;
|
|
130
131
|
order?: string[] | undefined;
|
|
131
|
-
slug?: string | undefined;
|
|
132
132
|
}, {
|
|
133
133
|
name?: string | undefined;
|
|
134
|
+
slug?: string | undefined;
|
|
134
135
|
label?: string | undefined;
|
|
135
136
|
order?: string[] | undefined;
|
|
136
|
-
slug?: string | undefined;
|
|
137
137
|
}>;
|
|
138
138
|
declare const updateEntryTypeInputSchema: z.ZodObject<{
|
|
139
139
|
label: z.ZodOptional<z.ZodString>;
|
|
@@ -142,16 +142,16 @@ declare const updateEntryTypeInputSchema: z.ZodObject<{
|
|
|
142
142
|
default: z.ZodOptional<z.ZodBoolean>;
|
|
143
143
|
maxItems: z.ZodOptional<z.ZodNumber>;
|
|
144
144
|
}, "strip", z.ZodTypeAny, {
|
|
145
|
+
default?: boolean | undefined;
|
|
145
146
|
label?: string | undefined;
|
|
146
147
|
format?: "mdx" | "md" | "json" | undefined;
|
|
147
148
|
schema?: string | undefined;
|
|
148
|
-
default?: boolean | undefined;
|
|
149
149
|
maxItems?: number | undefined;
|
|
150
150
|
}, {
|
|
151
|
+
default?: boolean | undefined;
|
|
151
152
|
label?: string | undefined;
|
|
152
153
|
format?: "mdx" | "md" | "json" | undefined;
|
|
153
154
|
schema?: string | undefined;
|
|
154
|
-
default?: boolean | undefined;
|
|
155
155
|
maxItems?: number | undefined;
|
|
156
156
|
}>;
|
|
157
157
|
export declare class SchemaOps {
|
package/dist/server.d.ts
CHANGED
|
@@ -14,4 +14,7 @@ export { buildContentTree } from './content-tree';
|
|
|
14
14
|
export type { ContentTreeNode, BuildContentTreeOptions, ContentTreeExtractMeta, } from './content-tree';
|
|
15
15
|
export { listEntries } from './content-listing';
|
|
16
16
|
export type { ListEntriesItem, ListEntriesOptions } from './content-listing';
|
|
17
|
+
export { resolveEntryUrl, resolveEntryLinksInText, resolveEntryLinksInData, extractEntryLinkIds, } from './entry-link-resolver';
|
|
18
|
+
export type { EntryLinkUrlResolver } from './entry-link-resolver';
|
|
19
|
+
export { computeEntryUrl } from './utils/entry-url';
|
|
17
20
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,wBAAwB,EACxB,aAAa,GACd,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAClE,OAAO,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAChG,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,wBAAwB,EACxB,aAAa,GACd,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAClE,OAAO,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAChG,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC5E,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/server.js
CHANGED
|
@@ -11,4 +11,6 @@ export { createEntrySchemaRegistry, validateEntrySchemaRegistry } from './entry-
|
|
|
11
11
|
export { generateId, isValidId } from './id.js';
|
|
12
12
|
export { buildContentTree } from './content-tree.js';
|
|
13
13
|
export { listEntries } from './content-listing.js';
|
|
14
|
+
export { resolveEntryUrl, resolveEntryLinksInText, resolveEntryLinksInData, extractEntryLinkIds, } from './entry-link-resolver.js';
|
|
15
|
+
export { computeEntryUrl } from './utils/entry-url.js';
|
|
14
16
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,wBAAwB,EACxB,aAAa,GACd,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAChG,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAMjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,wBAAwB,EACxB,aAAa,GACd,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAChG,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAMjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared entry URL computation — used by both server and client code.
|
|
3
|
+
*
|
|
4
|
+
* This module has NO server-only dependencies (no node:fs, etc.)
|
|
5
|
+
* so it can be safely imported into browser bundles.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Compute a URL path from an entry's collection path and slug.
|
|
9
|
+
*
|
|
10
|
+
* Logic:
|
|
11
|
+
* - Strip the contentRoot prefix (e.g., "content/") from the collection path
|
|
12
|
+
* - Append the slug (unless it's "index", which collapses to the parent path)
|
|
13
|
+
* - Always returns a path starting with "/"
|
|
14
|
+
*
|
|
15
|
+
* Examples:
|
|
16
|
+
* ("content/posts", "hello-world", "content") => "/posts/hello-world"
|
|
17
|
+
* ("content/docs/api", "index", "content") => "/docs/api"
|
|
18
|
+
* ("content", "index", "content") => "/"
|
|
19
|
+
*/
|
|
20
|
+
export declare function computeEntryUrl(collection: string, slug: string, contentRoot: string): string;
|
|
21
|
+
//# sourceMappingURL=entry-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-url.d.ts","sourceRoot":"","sources":["../../src/utils/entry-url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAsB7F"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared entry URL computation — used by both server and client code.
|
|
3
|
+
*
|
|
4
|
+
* This module has NO server-only dependencies (no node:fs, etc.)
|
|
5
|
+
* so it can be safely imported into browser bundles.
|
|
6
|
+
*/
|
|
7
|
+
import { trimSlashes } from '../paths/normalize.js';
|
|
8
|
+
/**
|
|
9
|
+
* Compute a URL path from an entry's collection path and slug.
|
|
10
|
+
*
|
|
11
|
+
* Logic:
|
|
12
|
+
* - Strip the contentRoot prefix (e.g., "content/") from the collection path
|
|
13
|
+
* - Append the slug (unless it's "index", which collapses to the parent path)
|
|
14
|
+
* - Always returns a path starting with "/"
|
|
15
|
+
*
|
|
16
|
+
* Examples:
|
|
17
|
+
* ("content/posts", "hello-world", "content") => "/posts/hello-world"
|
|
18
|
+
* ("content/docs/api", "index", "content") => "/docs/api"
|
|
19
|
+
* ("content", "index", "content") => "/"
|
|
20
|
+
*/
|
|
21
|
+
export function computeEntryUrl(collection, slug, contentRoot) {
|
|
22
|
+
const root = trimSlashes(contentRoot);
|
|
23
|
+
// Strip contentRoot prefix
|
|
24
|
+
let stripped = collection;
|
|
25
|
+
if (root && collection.startsWith(`${root}/`)) {
|
|
26
|
+
stripped = collection.slice(root.length + 1);
|
|
27
|
+
}
|
|
28
|
+
else if (collection === root) {
|
|
29
|
+
stripped = '';
|
|
30
|
+
}
|
|
31
|
+
// Build URL segments
|
|
32
|
+
const segments = stripped.split('/').filter(Boolean);
|
|
33
|
+
// Append slug unless it's "index" (index entries collapse to parent)
|
|
34
|
+
if (slug && slug !== 'index') {
|
|
35
|
+
segments.push(slug);
|
|
36
|
+
}
|
|
37
|
+
const path = segments.length > 0 ? `/${segments.join('/')}` : '/';
|
|
38
|
+
// Lowercase to match content-listing.ts and content-tree.ts URL conventions
|
|
39
|
+
return path.toLowerCase();
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=entry-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-url.js","sourceRoot":"","sources":["../../src/utils/entry-url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB,EAAE,IAAY,EAAE,WAAmB;IACnF,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IAErC,2BAA2B;IAC3B,IAAI,QAAQ,GAAG,UAAU,CAAA;IACzB,IAAI,IAAI,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC;QAC9C,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC9C,CAAC;SAAM,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QAC/B,QAAQ,GAAG,EAAE,CAAA;IACf,CAAC;IAED,qBAAqB;IACrB,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAEpD,qEAAqE;IACrE,IAAI,IAAI,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrB,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA;IACjE,4EAA4E;IAC5E,OAAO,IAAI,CAAC,WAAW,EAAE,CAAA;AAC3B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EntryLinkValidator validates that entry:ID patterns in body/markdown fields
|
|
3
|
+
* reference existing entries.
|
|
4
|
+
*
|
|
5
|
+
* Returns warnings (not errors) — saves are never blocked by broken entry links.
|
|
6
|
+
* This parallels ReferenceValidator but operates on inline links in text content
|
|
7
|
+
* rather than structured reference fields.
|
|
8
|
+
*/
|
|
9
|
+
import type { ContentIdIndex } from '../content-id-index';
|
|
10
|
+
import type { FieldConfig } from '../config';
|
|
11
|
+
export interface EntryLinkWarning {
|
|
12
|
+
field: string;
|
|
13
|
+
fieldPath: string;
|
|
14
|
+
id: string;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
export interface EntryLinkValidationResult {
|
|
18
|
+
warnings: EntryLinkWarning[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Validate entry links in body/markdown/mdx fields of the provided data.
|
|
22
|
+
*
|
|
23
|
+
* Scans all markdown, mdx, and rich-text fields for entry:ID patterns
|
|
24
|
+
* and checks that each referenced ID exists in the content index.
|
|
25
|
+
*/
|
|
26
|
+
export declare function validateEntryLinks(data: Record<string, unknown>, schema: readonly FieldConfig[], idIndex: ContentIdIndex, bodyContent?: string): EntryLinkValidationResult;
|
|
27
|
+
//# sourceMappingURL=entry-link-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-link-validator.d.ts","sourceRoot":"","sources":["../../src/validation/entry-link-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAI5C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,OAAO,EAAE,cAAc,EACvB,WAAW,CAAC,EAAE,MAAM,GACnB,yBAAyB,CAoB3B"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EntryLinkValidator validates that entry:ID patterns in body/markdown fields
|
|
3
|
+
* reference existing entries.
|
|
4
|
+
*
|
|
5
|
+
* Returns warnings (not errors) — saves are never blocked by broken entry links.
|
|
6
|
+
* This parallels ReferenceValidator but operates on inline links in text content
|
|
7
|
+
* rather than structured reference fields.
|
|
8
|
+
*/
|
|
9
|
+
import { extractEntryLinkIds } from '../entry-link-resolver.js';
|
|
10
|
+
import { findFieldsByType } from './field-traversal.js';
|
|
11
|
+
/**
|
|
12
|
+
* Validate entry links in body/markdown/mdx fields of the provided data.
|
|
13
|
+
*
|
|
14
|
+
* Scans all markdown, mdx, and rich-text fields for entry:ID patterns
|
|
15
|
+
* and checks that each referenced ID exists in the content index.
|
|
16
|
+
*/
|
|
17
|
+
export function validateEntryLinks(data, schema, idIndex, bodyContent) {
|
|
18
|
+
const warnings = [];
|
|
19
|
+
// Check body content (for md/mdx entries, body is separate from data)
|
|
20
|
+
if (bodyContent) {
|
|
21
|
+
checkText(bodyContent, 'body', 'body', idIndex, warnings);
|
|
22
|
+
}
|
|
23
|
+
// Check markdown/mdx/rich-text fields in structured data
|
|
24
|
+
const markdownTypes = ['markdown', 'mdx', 'rich-text'];
|
|
25
|
+
for (const fieldType of markdownTypes) {
|
|
26
|
+
const contexts = findFieldsByType(schema, data, fieldType);
|
|
27
|
+
for (const ctx of contexts) {
|
|
28
|
+
if (typeof ctx.value === 'string' && ctx.value) {
|
|
29
|
+
checkText(ctx.value, ctx.field.name, ctx.path, idIndex, warnings);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { warnings };
|
|
34
|
+
}
|
|
35
|
+
function checkText(text, fieldName, fieldPath, idIndex, warnings) {
|
|
36
|
+
const links = extractEntryLinkIds(text);
|
|
37
|
+
for (const link of links) {
|
|
38
|
+
const location = idIndex.findById(link.id);
|
|
39
|
+
if (!location || location.type !== 'entry') {
|
|
40
|
+
warnings.push({
|
|
41
|
+
field: fieldName,
|
|
42
|
+
fieldPath,
|
|
43
|
+
id: link.id,
|
|
44
|
+
message: `Entry link target not found: entry:${link.id}`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=entry-link-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-link-validator.js","sourceRoot":"","sources":["../../src/validation/entry-link-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAapD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAA6B,EAC7B,MAA8B,EAC9B,OAAuB,EACvB,WAAoB;IAEpB,MAAM,QAAQ,GAAuB,EAAE,CAAA;IAEvC,sEAAsE;IACtE,IAAI,WAAW,EAAE,CAAC;QAChB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC3D,CAAC;IAED,yDAAyD;IACzD,MAAM,aAAa,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,CAAU,CAAA;IAC/D,KAAK,MAAM,SAAS,IAAI,aAAa,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;QAC1D,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC/C,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,CAAA;AACrB,CAAC;AAED,SAAS,SAAS,CAChB,IAAY,EACZ,SAAiB,EACjB,SAAiB,EACjB,OAAuB,EACvB,QAA4B;IAE5B,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAEvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC1C,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,SAAS;gBAChB,SAAS;gBACT,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,OAAO,EAAE,sCAAsC,IAAI,CAAC,EAAE,EAAE;aACzD,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "@codemirror/language, @lezer/highlight: workaround — @mdxeditor/editor uses cm6-theme-basic-light which peer-requires these but mdxeditor doesn't declare them as dependencies",
|
|
3
3
|
"name": "canopycms",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.27",
|
|
5
5
|
"description": "CanopyCMS core package: schema-driven content, branch-aware editing, and editor UI for Next.js.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|