@replohq/sdk 0.13.0 → 0.15.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.
- package/_vendor/replo-utils/lib/json.mjs +2 -42
- package/_vendor/replo-utils/lib/misc.mjs +3 -0
- package/_vendor/schemas/contentCollection.d.ts +231 -0
- package/_vendor/schemas/contentCollection.mjs +2 -0
- package/_vendor/schemas/contentEntry.d.ts +53 -0
- package/_vendor/schemas/contentEntry.mjs +3 -0
- package/_vendor/schemas/contentFrontmatter.d.ts +18 -0
- package/_vendor/schemas/contentManifest.d.ts +44 -0
- package/_vendor/schemas/contentManifest.mjs +197 -0
- package/_vendor/schemas/money.mjs +2 -0
- package/_vendor/schemas/routing/locale.mjs +2 -0
- package/_vendor/schemas/routing/rules.mjs +2 -0
- package/cart/cart-provider.d.ts +1 -2
- package/cart/cart-provider.js +1 -12
- package/cart/cart-provider.js.map +2 -2
- package/cart/hooks/use-buy-now.js +2 -1
- package/cart/hooks/use-buy-now.js.map +2 -2
- package/chunk-AL3F36PH.mjs +1514 -0
- package/chunk-GV5FY7ZZ.mjs +89 -0
- package/chunk-I23U2PUI.mjs +151 -0
- package/chunk-IQ5GRTXO.mjs +182 -0
- package/chunk-VKO7P3ED.mjs +41 -0
- package/content.d.ts +126 -0
- package/content.js +594 -0
- package/content.js.map +7 -0
- package/lib/buildMetadata.js +3 -3
- package/lib/external-navigation.d.ts +16 -0
- package/lib/external-navigation.js +13 -0
- package/lib/external-navigation.js.map +7 -0
- package/package.json +12 -4
|
@@ -1,43 +1,3 @@
|
|
|
1
|
+
export { jsonStringifyOrNull, omitJsonObjectFieldsOrNull, parseJsonOrNull } from '../../../chunk-VKO7P3ED.mjs';
|
|
2
|
+
import '../../../chunk-GV5FY7ZZ.mjs';
|
|
1
3
|
import '../../../chunk-UJCSKKID.mjs';
|
|
2
|
-
|
|
3
|
-
// ../replo-utils/lib/object.ts
|
|
4
|
-
function omit(obj, keysToOmit) {
|
|
5
|
-
const result = { ...obj };
|
|
6
|
-
for (const key of keysToOmit) {
|
|
7
|
-
delete result[key];
|
|
8
|
-
}
|
|
9
|
-
return result;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// ../replo-utils/lib/json.ts
|
|
13
|
-
function parseJsonOrNull(json) {
|
|
14
|
-
try {
|
|
15
|
-
return JSON.parse(json);
|
|
16
|
-
} catch {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function omitJsonObjectFieldsOrNull({
|
|
21
|
-
json,
|
|
22
|
-
fields
|
|
23
|
-
}) {
|
|
24
|
-
const parsedJson = parseJsonOrNull(json);
|
|
25
|
-
if (typeof parsedJson !== "object" || parsedJson === null || Array.isArray(parsedJson)) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
return jsonStringifyOrNull(
|
|
29
|
-
omit(Object.fromEntries(Object.entries(parsedJson)), fields)
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
function jsonStringifyOrNull(value) {
|
|
33
|
-
if (value === null || value === void 0) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
return JSON.stringify(value);
|
|
38
|
-
} catch {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export { jsonStringifyOrNull, omitJsonObjectFieldsOrNull, parseJsonOrNull };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { coerceNumberToString, deepCloneAndMergeReplacingArrays, errorMessage, exhaustiveSwitch, formatFileSize, getFromRecordOrNull, hasOwnProperty, invariant, isEmpty, isFunction_default as isFunction, isNotNullish, isNullish, isPrimitive, mergeReplacingArrays, mergeReplacingObjects, noop, preventDefault, sleep, warning } from '../../../chunk-AL3F36PH.mjs';
|
|
2
|
+
export { isNumber_default as isNumber, isString_default as isString } from '../../../chunk-GV5FY7ZZ.mjs';
|
|
3
|
+
import '../../../chunk-UJCSKKID.mjs';
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* The shared app-root manifest that bundles `content/**` for production
|
|
4
|
+
* builds (published Workers have no filesystem). Scaffolded as a placeholder
|
|
5
|
+
* by the coordinator, imported by the generated templates, and populated by
|
|
6
|
+
* the harness publish tool before `next build` — one constant so those three
|
|
7
|
+
* can never drift.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CONTENT_MANIFEST_FILENAME = "content-manifest.generated.json";
|
|
10
|
+
/** Site-relative directory that holds all content. */
|
|
11
|
+
export declare const CONTENT_DIRNAME = "content";
|
|
12
|
+
/** Per-collection schema file inside `content/<collection>/`. */
|
|
13
|
+
export declare const CONTENT_COLLECTION_SCHEMA_FILENAME = "_collection.json";
|
|
14
|
+
/** Extension of entry files inside `content/<collection>/`. */
|
|
15
|
+
export declare const CONTENT_ENTRY_FILE_EXTENSION = ".mdx";
|
|
16
|
+
/**
|
|
17
|
+
* Frontmatter key that stores the `relatedContent` field's value (an array of
|
|
18
|
+
* `<collection>/<entry>` paths). The storage key predates the field id; both
|
|
19
|
+
* the editor's serializer and the SDK renderer map between them through this
|
|
20
|
+
* constant.
|
|
21
|
+
*/
|
|
22
|
+
export declare const CONTENT_RELATED_VALUE_STORAGE_KEY = "related";
|
|
23
|
+
/**
|
|
24
|
+
* One slug contract for collection and entry slugs: they become directory
|
|
25
|
+
* names, file names, and public URL segments in every consumer. The pattern
|
|
26
|
+
* is ASCII-only, so the length cap counts bytes and characters identically.
|
|
27
|
+
*/
|
|
28
|
+
export declare const CONTENT_SLUG_PATTERN: RegExp;
|
|
29
|
+
export declare const CONTENT_MAX_SLUG_LENGTH = 100;
|
|
30
|
+
export declare const contentSlugSchema: z.ZodString;
|
|
31
|
+
export declare function isValidContentSlug(slug: string): boolean;
|
|
32
|
+
export declare const CONTENT_ENTRY_STATUSES: readonly ["draft", "published", "archived"];
|
|
33
|
+
export type ContentEntryStatus = (typeof CONTENT_ENTRY_STATUSES)[number];
|
|
34
|
+
export declare const contentEntryStatusSchema: z.ZodEnum<{
|
|
35
|
+
draft: "draft";
|
|
36
|
+
published: "published";
|
|
37
|
+
archived: "archived";
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* The one public-visibility rule: only published, non-archived entries render
|
|
41
|
+
* on the published site. The sandbox preview (`next dev`) and the website
|
|
42
|
+
* builder pass `allowDrafts: true` so drafts are previewable before publish.
|
|
43
|
+
*/
|
|
44
|
+
export declare function isContentEntryPubliclyVisible({ status, archivedAt, allowDrafts, }: {
|
|
45
|
+
status: ContentEntryStatus;
|
|
46
|
+
archivedAt: unknown;
|
|
47
|
+
allowDrafts: boolean;
|
|
48
|
+
}): boolean;
|
|
49
|
+
export declare const contentCollectionFieldTypeSchema: z.ZodEnum<{
|
|
50
|
+
boolean: "boolean";
|
|
51
|
+
status: "status";
|
|
52
|
+
image: "image";
|
|
53
|
+
url: "url";
|
|
54
|
+
date: "date";
|
|
55
|
+
tags: "tags";
|
|
56
|
+
related: "related";
|
|
57
|
+
"short-text": "short-text";
|
|
58
|
+
"long-text": "long-text";
|
|
59
|
+
"rich-text": "rich-text";
|
|
60
|
+
}>;
|
|
61
|
+
export type ContentCollectionFieldType = z.infer<typeof contentCollectionFieldTypeSchema>;
|
|
62
|
+
export declare const contentCollectionColorSchema: z.ZodEnum<{
|
|
63
|
+
seashell: "seashell";
|
|
64
|
+
yellow: "yellow";
|
|
65
|
+
lightGreen: "lightGreen";
|
|
66
|
+
darkGreen: "darkGreen";
|
|
67
|
+
lightPink: "lightPink";
|
|
68
|
+
magenta: "magenta";
|
|
69
|
+
purple: "purple";
|
|
70
|
+
blue: "blue";
|
|
71
|
+
}>;
|
|
72
|
+
export declare const contentCollectionFieldSchema: z.ZodObject<{
|
|
73
|
+
id: z.ZodString;
|
|
74
|
+
label: z.ZodString;
|
|
75
|
+
type: z.ZodEnum<{
|
|
76
|
+
boolean: "boolean";
|
|
77
|
+
status: "status";
|
|
78
|
+
image: "image";
|
|
79
|
+
url: "url";
|
|
80
|
+
date: "date";
|
|
81
|
+
tags: "tags";
|
|
82
|
+
related: "related";
|
|
83
|
+
"short-text": "short-text";
|
|
84
|
+
"long-text": "long-text";
|
|
85
|
+
"rich-text": "rich-text";
|
|
86
|
+
}>;
|
|
87
|
+
required: z.ZodBoolean;
|
|
88
|
+
enabled: z.ZodBoolean;
|
|
89
|
+
helpText: z.ZodOptional<z.ZodString>;
|
|
90
|
+
builtin: z.ZodBoolean;
|
|
91
|
+
}, z.core.$strip>;
|
|
92
|
+
export type ContentCollectionField = z.infer<typeof contentCollectionFieldSchema>;
|
|
93
|
+
/**
|
|
94
|
+
* The `_collection.json` file contract. `passthrough` keeps unknown keys so
|
|
95
|
+
* editor round-trips never drop data another writer added.
|
|
96
|
+
*/
|
|
97
|
+
export declare const contentCollectionFileSchema: z.ZodObject<{
|
|
98
|
+
name: z.ZodString;
|
|
99
|
+
description: z.ZodString;
|
|
100
|
+
icon: z.ZodString;
|
|
101
|
+
color: z.ZodEnum<{
|
|
102
|
+
seashell: "seashell";
|
|
103
|
+
yellow: "yellow";
|
|
104
|
+
lightGreen: "lightGreen";
|
|
105
|
+
darkGreen: "darkGreen";
|
|
106
|
+
lightPink: "lightPink";
|
|
107
|
+
magenta: "magenta";
|
|
108
|
+
purple: "purple";
|
|
109
|
+
blue: "blue";
|
|
110
|
+
}>;
|
|
111
|
+
tags: z.ZodArray<z.ZodString>;
|
|
112
|
+
fields: z.ZodArray<z.ZodObject<{
|
|
113
|
+
id: z.ZodString;
|
|
114
|
+
label: z.ZodString;
|
|
115
|
+
type: z.ZodEnum<{
|
|
116
|
+
boolean: "boolean";
|
|
117
|
+
status: "status";
|
|
118
|
+
image: "image";
|
|
119
|
+
url: "url";
|
|
120
|
+
date: "date";
|
|
121
|
+
tags: "tags";
|
|
122
|
+
related: "related";
|
|
123
|
+
"short-text": "short-text";
|
|
124
|
+
"long-text": "long-text";
|
|
125
|
+
"rich-text": "rich-text";
|
|
126
|
+
}>;
|
|
127
|
+
required: z.ZodBoolean;
|
|
128
|
+
enabled: z.ZodBoolean;
|
|
129
|
+
helpText: z.ZodOptional<z.ZodString>;
|
|
130
|
+
builtin: z.ZodBoolean;
|
|
131
|
+
}, z.core.$strip>>;
|
|
132
|
+
archivedAt: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
|
|
133
|
+
hasListingPage: z.ZodOptional<z.ZodBoolean>;
|
|
134
|
+
}, z.core.$loose>;
|
|
135
|
+
/**
|
|
136
|
+
* Whether a URL is renderable on a published page. Relative URLs resolve
|
|
137
|
+
* against a dummy base so path-only values pass; only http(s) may be an
|
|
138
|
+
* image source, while links additionally allow mailto/tel.
|
|
139
|
+
*/
|
|
140
|
+
export declare function isSafeContentUrl(value: string, { image }: {
|
|
141
|
+
image: boolean;
|
|
142
|
+
}): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Validity of a present (non-empty) value for a field type. This decides both
|
|
145
|
+
* editor-side validation errors and whether the SDK renders the entry at all,
|
|
146
|
+
* so the two can never disagree about what a valid value is.
|
|
147
|
+
*/
|
|
148
|
+
export declare function getContentFieldValueSchema(fieldType: ContentCollectionFieldType): z.ZodType;
|
|
149
|
+
/**
|
|
150
|
+
* Slugs a collection may never claim even when the segment doesn't exist yet:
|
|
151
|
+
* conventional Next.js route namespaces every site is expected to grow into.
|
|
152
|
+
* Segments the site already owns are rejected separately at scaffold time.
|
|
153
|
+
*/
|
|
154
|
+
export declare const CONTENT_RESERVED_COLLECTION_SLUGS: readonly ["api", "new"];
|
|
155
|
+
export declare const CONTENT_RESERVED_ENTRY_SLUGS: readonly ["new"];
|
|
156
|
+
export declare function isContentReservedEntrySlug(slug: string): boolean;
|
|
157
|
+
/**
|
|
158
|
+
* - `content`: rendered on the published page and ordered by collection
|
|
159
|
+
* settings (all custom fields are content).
|
|
160
|
+
* - `publishing`: publish controls (never rendered as page content).
|
|
161
|
+
* - `seo`: head metadata, not body content.
|
|
162
|
+
* - `private`: never leaves the editor.
|
|
163
|
+
*/
|
|
164
|
+
export type ContentFieldRole = "content" | "publishing" | "seo" | "private";
|
|
165
|
+
/**
|
|
166
|
+
* Role of every builtin collection field. `satisfies` makes adding a builtin
|
|
167
|
+
* without classifying it a compile error wherever field ids are typed as
|
|
168
|
+
* `ContentBuiltinFieldId`.
|
|
169
|
+
*/
|
|
170
|
+
export declare const CONTENT_BUILTIN_FIELD_ROLES: {
|
|
171
|
+
readonly title: "content";
|
|
172
|
+
readonly author: "content";
|
|
173
|
+
readonly excerpt: "content";
|
|
174
|
+
readonly coverImage: "content";
|
|
175
|
+
readonly body: "content";
|
|
176
|
+
readonly tags: "content";
|
|
177
|
+
readonly relatedContent: "content";
|
|
178
|
+
readonly slug: "publishing";
|
|
179
|
+
readonly status: "publishing";
|
|
180
|
+
readonly publishedAt: "publishing";
|
|
181
|
+
};
|
|
182
|
+
export type ContentBuiltinFieldId = keyof typeof CONTENT_BUILTIN_FIELD_ROLES;
|
|
183
|
+
/** Entry-level frontmatter keys that are head metadata, not collection fields. */
|
|
184
|
+
export declare const CONTENT_SEO_VALUE_KEYS: readonly ["seoTitle", "seoDescription"];
|
|
185
|
+
/** Entry-level frontmatter keys that must never be publicly rendered. */
|
|
186
|
+
export declare const CONTENT_PRIVATE_VALUE_KEYS: readonly ["scratchpad", "backlinks"];
|
|
187
|
+
/**
|
|
188
|
+
* Values that render and edit with a parent content field instead of owning
|
|
189
|
+
* an ordered slot of their own.
|
|
190
|
+
*/
|
|
191
|
+
export declare const CONTENT_COUPLED_VALUE_PARENTS: {
|
|
192
|
+
readonly coverImageAlt: "coverImage";
|
|
193
|
+
readonly authorInitials: "author";
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* A related-content reference as stored in `related` frontmatter:
|
|
197
|
+
* `<collectionSlug>/<entrySlug>`. Producer and consumer share this pair so
|
|
198
|
+
* the written form and the published renderer can't drift apart.
|
|
199
|
+
*/
|
|
200
|
+
export declare function formatContentEntryRef({ collectionSlug, entrySlug, }: {
|
|
201
|
+
collectionSlug: string;
|
|
202
|
+
entrySlug: string;
|
|
203
|
+
}): string;
|
|
204
|
+
/** Null when the ref isn't a `<collectionSlug>/<entrySlug>` pair. */
|
|
205
|
+
export declare function parseContentEntryRef(ref: string): {
|
|
206
|
+
collectionSlug: string;
|
|
207
|
+
entrySlug: string;
|
|
208
|
+
} | null;
|
|
209
|
+
export declare function isContentPrivateValueKey(key: string): boolean;
|
|
210
|
+
export declare function isContentSeoValueKey(key: string): boolean;
|
|
211
|
+
export declare function isContentReservedCollectionSlug(slug: string): boolean;
|
|
212
|
+
/** Custom (non-builtin) collection fields are always content. */
|
|
213
|
+
export declare function getContentFieldRole(fieldId: string): ContentFieldRole;
|
|
214
|
+
/**
|
|
215
|
+
* Enabled fields in collection-settings order, for the published page. The
|
|
216
|
+
* "Visible" toggle is authoritative here — including lifecycle fields like
|
|
217
|
+
* status and the slug, which the entry editor renders as dedicated controls
|
|
218
|
+
* rather than ordered fields. Private keys never publish.
|
|
219
|
+
*/
|
|
220
|
+
export declare function getPublishedContentFields<Field extends {
|
|
221
|
+
id: string;
|
|
222
|
+
enabled: boolean;
|
|
223
|
+
}>(fields: Field[]): Field[];
|
|
224
|
+
/**
|
|
225
|
+
* Enabled content-role fields in collection-settings order — what the entry
|
|
226
|
+
* editor renders as the ordered field list.
|
|
227
|
+
*/
|
|
228
|
+
export declare function getOrderedContentFields<Field extends {
|
|
229
|
+
id: string;
|
|
230
|
+
enabled: boolean;
|
|
231
|
+
}>(fields: Field[]): Field[];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { CONTENT_BUILTIN_FIELD_ROLES, CONTENT_COLLECTION_SCHEMA_FILENAME, CONTENT_COUPLED_VALUE_PARENTS, CONTENT_DIRNAME, CONTENT_ENTRY_FILE_EXTENSION, CONTENT_ENTRY_STATUSES, CONTENT_MANIFEST_FILENAME, CONTENT_MAX_SLUG_LENGTH, CONTENT_PRIVATE_VALUE_KEYS, CONTENT_RELATED_VALUE_STORAGE_KEY, CONTENT_RESERVED_COLLECTION_SLUGS, CONTENT_RESERVED_ENTRY_SLUGS, CONTENT_SEO_VALUE_KEYS, CONTENT_SLUG_PATTERN, contentCollectionColorSchema, contentCollectionFieldSchema, contentCollectionFieldTypeSchema, contentCollectionFileSchema, contentEntryStatusSchema, contentSlugSchema, formatContentEntryRef, getContentFieldRole, getContentFieldValueSchema, getOrderedContentFields, getPublishedContentFields, isContentEntryPubliclyVisible, isContentPrivateValueKey, isContentReservedCollectionSlug, isContentReservedEntrySlug, isContentSeoValueKey, isSafeContentUrl, isValidContentSlug, parseContentEntryRef } from '../../chunk-IQ5GRTXO.mjs';
|
|
2
|
+
import '../../chunk-UJCSKKID.mjs';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { contentCollectionFieldSchema } from "./contentCollection";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export declare const CONTENT_MANAGED_ENTRY_VALUE_KEYS: readonly ["slug", "title", "status", "author", "authorInitials", "excerpt", "coverImage", "coverImageAlt", "tags", "updatedAt", "publishedAt", "archivedAt", "seoTitle", "seoDescription", "related", "scratchpad", "backlinks"];
|
|
4
|
+
export declare const contentEntryFrontmatterSchema: z.ZodObject<{
|
|
5
|
+
slug: z.ZodOptional<z.ZodUnknown>;
|
|
6
|
+
title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
7
|
+
status: z.ZodEnum<{
|
|
8
|
+
draft: "draft";
|
|
9
|
+
published: "published";
|
|
10
|
+
archived: "archived";
|
|
11
|
+
}>;
|
|
12
|
+
author: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
13
|
+
authorInitials: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
14
|
+
excerpt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15
|
+
coverImage: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
16
|
+
coverImageAlt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
17
|
+
tags: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
18
|
+
updatedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
19
|
+
publishedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
20
|
+
archivedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
21
|
+
seoTitle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
22
|
+
seoDescription: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
23
|
+
related: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
|
|
24
|
+
scratchpad: z.ZodOptional<z.ZodUnknown>;
|
|
25
|
+
backlinks: z.ZodOptional<z.ZodUnknown>;
|
|
26
|
+
}, z.core.$loose>;
|
|
27
|
+
export type ContentEntryFrontmatter = z.infer<typeof contentEntryFrontmatterSchema>;
|
|
28
|
+
export interface ContentEntryDocument {
|
|
29
|
+
values: ContentEntryFrontmatter;
|
|
30
|
+
body: string;
|
|
31
|
+
}
|
|
32
|
+
export type ParsedContentEntryDocument = {
|
|
33
|
+
status: "ready";
|
|
34
|
+
document: ContentEntryDocument;
|
|
35
|
+
} | {
|
|
36
|
+
status: "invalid";
|
|
37
|
+
message: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function parseContentEntryDocument(raw: string): ParsedContentEntryDocument;
|
|
40
|
+
export declare function serializeContentEntryDocument({ values, body, }: ContentEntryDocument): string;
|
|
41
|
+
export declare function getContentRenderableEntryValues({ document, slug, }: {
|
|
42
|
+
document: ContentEntryDocument;
|
|
43
|
+
slug: string;
|
|
44
|
+
}): Record<string, unknown>;
|
|
45
|
+
export interface ContentEntryFieldValidationIssue {
|
|
46
|
+
fieldId: string;
|
|
47
|
+
message: string;
|
|
48
|
+
}
|
|
49
|
+
export declare function getContentEntryFieldValidationIssues({ fields, values, requireRequiredFields, }: {
|
|
50
|
+
fields: z.infer<typeof contentCollectionFieldSchema>[];
|
|
51
|
+
values: Record<string, unknown>;
|
|
52
|
+
requireRequiredFields: boolean;
|
|
53
|
+
}): ContentEntryFieldValidationIssue[];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { CONTENT_MANAGED_ENTRY_VALUE_KEYS, contentEntryFrontmatterSchema, getContentEntryFieldValidationIssues, getContentRenderableEntryValues, parseContentEntryDocument, serializeContentEntryDocument } from '../../chunk-I23U2PUI.mjs';
|
|
2
|
+
import '../../chunk-IQ5GRTXO.mjs';
|
|
3
|
+
import '../../chunk-UJCSKKID.mjs';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Matches a leading `---` frontmatter block, tolerating CRLF and EOF. */
|
|
2
|
+
export declare const CONTENT_FRONTMATTER_PATTERN: RegExp;
|
|
3
|
+
/**
|
|
4
|
+
* Strictly parse a frontmatter YAML block into a plain object, or null when
|
|
5
|
+
* it isn't valid. Strictness (unique keys, no merge, bounded aliases) is part
|
|
6
|
+
* of the format contract: a file the published runtime would reject must be
|
|
7
|
+
* rejected by every editor surface too.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseContentFrontmatterYaml(yamlText: string): Record<string, unknown> | null;
|
|
10
|
+
/**
|
|
11
|
+
* Parse a full entry file that must start with a frontmatter block. Returns
|
|
12
|
+
* null when the block is missing or invalid; the remainder of the file is the
|
|
13
|
+
* markdown body.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseContentFrontmatter(raw: string): {
|
|
16
|
+
values: Record<string, unknown>;
|
|
17
|
+
body: string;
|
|
18
|
+
} | null;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const contentManifestSchema: z.ZodObject<{
|
|
3
|
+
files: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
4
|
+
}, z.core.$strip>;
|
|
5
|
+
export type ContentManifest = z.infer<typeof contentManifestSchema>;
|
|
6
|
+
export type ContentFilePath = {
|
|
7
|
+
type: "collection";
|
|
8
|
+
collection: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: "entry";
|
|
11
|
+
collection: string;
|
|
12
|
+
entry: string;
|
|
13
|
+
};
|
|
14
|
+
export interface ContentValidationIssue {
|
|
15
|
+
path: string;
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ContentIndexEntry {
|
|
19
|
+
slug: string;
|
|
20
|
+
title: string;
|
|
21
|
+
status: "draft" | "published";
|
|
22
|
+
}
|
|
23
|
+
export interface ContentIndexCollection {
|
|
24
|
+
slug: string;
|
|
25
|
+
name: string;
|
|
26
|
+
entries: ContentIndexEntry[];
|
|
27
|
+
}
|
|
28
|
+
export declare function createContentManifest({ files, }: {
|
|
29
|
+
files: {
|
|
30
|
+
path: string;
|
|
31
|
+
content: string;
|
|
32
|
+
}[];
|
|
33
|
+
}): ContentManifest;
|
|
34
|
+
export declare function getContentFilePath(filePath: string): ContentFilePath | null;
|
|
35
|
+
export declare function getContentManifestCollectionSlugs(contentManifest: ContentManifest): string[];
|
|
36
|
+
export declare function getContentManifestEntrySlugs({ collection, contentManifest, }: {
|
|
37
|
+
collection: string;
|
|
38
|
+
contentManifest: ContentManifest;
|
|
39
|
+
}): string[];
|
|
40
|
+
export declare function getContentIndex({ files, allowDrafts, }: {
|
|
41
|
+
files: Record<string, string | null>;
|
|
42
|
+
allowDrafts: boolean;
|
|
43
|
+
}): ContentIndexCollection[];
|
|
44
|
+
export declare function validateContentManifest(contentManifest: ContentManifest): ContentValidationIssue[];
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { parseContentEntryDocument, getContentRenderableEntryValues, getContentEntryFieldValidationIssues } from '../../chunk-I23U2PUI.mjs';
|
|
2
|
+
import { isValidContentSlug, CONTENT_COLLECTION_SCHEMA_FILENAME, CONTENT_ENTRY_FILE_EXTENSION, contentCollectionFileSchema, isContentEntryPubliclyVisible } from '../../chunk-IQ5GRTXO.mjs';
|
|
3
|
+
import { parseJsonOrNull } from '../../chunk-VKO7P3ED.mjs';
|
|
4
|
+
import '../../chunk-GV5FY7ZZ.mjs';
|
|
5
|
+
import '../../chunk-UJCSKKID.mjs';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
var contentManifestSchema = z.object({
|
|
9
|
+
files: z.record(z.string(), z.string())
|
|
10
|
+
});
|
|
11
|
+
function createContentManifest({
|
|
12
|
+
files
|
|
13
|
+
}) {
|
|
14
|
+
const sortedFiles = [...files].sort((left, right) => {
|
|
15
|
+
return left.path.localeCompare(right.path);
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
files: Object.fromEntries(
|
|
19
|
+
sortedFiles.map((file) => [file.path, file.content])
|
|
20
|
+
)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function getContentFilePath(filePath) {
|
|
24
|
+
const segments = filePath.split("/").filter(Boolean);
|
|
25
|
+
const filename = segments.at(-1);
|
|
26
|
+
const collection = segments.at(-2);
|
|
27
|
+
if (!filename || !collection || !isValidContentSlug(collection)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (filename === CONTENT_COLLECTION_SCHEMA_FILENAME) {
|
|
31
|
+
return { type: "collection", collection };
|
|
32
|
+
}
|
|
33
|
+
if (!filename.endsWith(CONTENT_ENTRY_FILE_EXTENSION)) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const entry = filename.slice(0, -CONTENT_ENTRY_FILE_EXTENSION.length);
|
|
37
|
+
return isValidContentSlug(entry) ? { type: "entry", collection, entry } : null;
|
|
38
|
+
}
|
|
39
|
+
function getContentManifestCollectionSlugs(contentManifest) {
|
|
40
|
+
return Object.keys(contentManifest.files).flatMap((relativePath) => {
|
|
41
|
+
const parsedPath = getContentManifestFilePath(relativePath);
|
|
42
|
+
return parsedPath?.type === "collection" ? [parsedPath.collection] : [];
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function getContentManifestEntrySlugs({
|
|
46
|
+
collection,
|
|
47
|
+
contentManifest
|
|
48
|
+
}) {
|
|
49
|
+
return Object.keys(contentManifest.files).flatMap((relativePath) => {
|
|
50
|
+
const parsedPath = getContentManifestFilePath(relativePath);
|
|
51
|
+
return parsedPath?.type === "entry" && parsedPath.collection === collection ? [parsedPath.entry] : [];
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function getContentIndex({
|
|
55
|
+
files,
|
|
56
|
+
allowDrafts
|
|
57
|
+
}) {
|
|
58
|
+
const collectionsBySlug = /* @__PURE__ */ new Map();
|
|
59
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
60
|
+
const parsedPath = getContentFilePath(filePath);
|
|
61
|
+
if (parsedPath?.type !== "collection" || content === null) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const parsedCollection = contentCollectionFileSchema.safeParse(
|
|
65
|
+
parseJsonOrNull(content)
|
|
66
|
+
);
|
|
67
|
+
if (!parsedCollection.success || parsedCollection.data.archivedAt) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
collectionsBySlug.set(parsedPath.collection, {
|
|
71
|
+
schema: parsedCollection.data,
|
|
72
|
+
collection: {
|
|
73
|
+
slug: parsedPath.collection,
|
|
74
|
+
name: parsedCollection.data.name,
|
|
75
|
+
entries: []
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
80
|
+
const parsedPath = getContentFilePath(filePath);
|
|
81
|
+
if (parsedPath?.type !== "entry" || content === null) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const collection = collectionsBySlug.get(parsedPath.collection);
|
|
85
|
+
if (!collection) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const parsedDocument = parseContentEntryDocument(content);
|
|
89
|
+
if (parsedDocument.status === "invalid") {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const document = parsedDocument.document;
|
|
93
|
+
const status = document.values.status;
|
|
94
|
+
if (status === "archived" || !isContentEntryPubliclyVisible({
|
|
95
|
+
status,
|
|
96
|
+
archivedAt: document.values.archivedAt,
|
|
97
|
+
allowDrafts
|
|
98
|
+
})) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const values = getContentRenderableEntryValues({
|
|
102
|
+
document,
|
|
103
|
+
slug: parsedPath.entry
|
|
104
|
+
});
|
|
105
|
+
const validationIssues = getContentEntryFieldValidationIssues({
|
|
106
|
+
fields: collection.schema.fields,
|
|
107
|
+
values,
|
|
108
|
+
requireRequiredFields: document.values.status === "published"
|
|
109
|
+
});
|
|
110
|
+
if (validationIssues.length > 0) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const trimmedTitle = document.values.title?.trim();
|
|
114
|
+
collection.collection.entries.push({
|
|
115
|
+
slug: parsedPath.entry,
|
|
116
|
+
title: trimmedTitle && trimmedTitle.length > 0 ? trimmedTitle : parsedPath.entry,
|
|
117
|
+
status
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const collections = [...collectionsBySlug.values()].map(({ collection }) => {
|
|
121
|
+
collection.entries.sort((left, right) => {
|
|
122
|
+
return left.title.localeCompare(right.title);
|
|
123
|
+
});
|
|
124
|
+
return collection;
|
|
125
|
+
});
|
|
126
|
+
return collections.sort((left, right) => {
|
|
127
|
+
return left.name.localeCompare(right.name);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function validateContentManifest(contentManifest) {
|
|
131
|
+
const collectionSchemas = /* @__PURE__ */ new Map();
|
|
132
|
+
const issues = [];
|
|
133
|
+
for (const [relativePath, content] of Object.entries(contentManifest.files)) {
|
|
134
|
+
const parsedPath = getContentManifestFilePath(relativePath);
|
|
135
|
+
if (!parsedPath) {
|
|
136
|
+
issues.push({
|
|
137
|
+
path: relativePath,
|
|
138
|
+
message: "The collection or entry slug is not valid."
|
|
139
|
+
});
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (parsedPath.type !== "collection") {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const parsedCollection = contentCollectionFileSchema.safeParse(
|
|
146
|
+
parseJsonOrNull(content)
|
|
147
|
+
);
|
|
148
|
+
if (!parsedCollection.success) {
|
|
149
|
+
issues.push({
|
|
150
|
+
path: relativePath,
|
|
151
|
+
message: parsedCollection.error.issues[0]?.message ?? "The collection settings are invalid."
|
|
152
|
+
});
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
collectionSchemas.set(parsedPath.collection, parsedCollection.data);
|
|
156
|
+
}
|
|
157
|
+
for (const [relativePath, content] of Object.entries(contentManifest.files)) {
|
|
158
|
+
const parsedPath = getContentManifestFilePath(relativePath);
|
|
159
|
+
if (parsedPath?.type !== "entry") {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const collectionSchema = collectionSchemas.get(parsedPath.collection);
|
|
163
|
+
if (!collectionSchema) {
|
|
164
|
+
issues.push({
|
|
165
|
+
path: relativePath,
|
|
166
|
+
message: `Collection "${parsedPath.collection}" has no valid ${CONTENT_COLLECTION_SCHEMA_FILENAME}.`
|
|
167
|
+
});
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const parsedDocument = parseContentEntryDocument(content);
|
|
171
|
+
if (parsedDocument.status === "invalid") {
|
|
172
|
+
issues.push({ path: relativePath, message: parsedDocument.message });
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const document = parsedDocument.document;
|
|
176
|
+
const fieldIssues = getContentEntryFieldValidationIssues({
|
|
177
|
+
fields: collectionSchema.fields,
|
|
178
|
+
values: getContentRenderableEntryValues({
|
|
179
|
+
document,
|
|
180
|
+
slug: parsedPath.entry
|
|
181
|
+
}),
|
|
182
|
+
requireRequiredFields: document.values.status === "published"
|
|
183
|
+
});
|
|
184
|
+
issues.push(
|
|
185
|
+
...fieldIssues.map((issue) => ({
|
|
186
|
+
path: relativePath,
|
|
187
|
+
message: `${issue.fieldId}: ${issue.message}`
|
|
188
|
+
}))
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
return issues;
|
|
192
|
+
}
|
|
193
|
+
function getContentManifestFilePath(relativePath) {
|
|
194
|
+
return relativePath.split("/").length === 2 ? getContentFilePath(relativePath) : null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export { contentManifestSchema, createContentManifest, getContentFilePath, getContentIndex, getContentManifestCollectionSlugs, getContentManifestEntrySlugs, validateContentManifest };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getParamSegment, getRouteParams, hasRouteParam, matchSource } from '../../../chunk-VPEVERWE.mjs';
|
|
2
2
|
import { ReploError } from '../../../chunk-5M7VU32I.mjs';
|
|
3
|
+
import '../../../chunk-AL3F36PH.mjs';
|
|
4
|
+
import '../../../chunk-GV5FY7ZZ.mjs';
|
|
3
5
|
import '../../../chunk-UJCSKKID.mjs';
|
|
4
6
|
import { z } from 'zod';
|
|
5
7
|
|
package/cart/cart-provider.d.ts
CHANGED
|
@@ -53,8 +53,7 @@ export interface CartContextType {
|
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
55
|
* Provider component that manages global cart state and operations. Handles both
|
|
56
|
-
* server-side cart synchronization and client-side optimistic updates.
|
|
57
|
-
* editor mode for preview environments.
|
|
56
|
+
* server-side cart synchronization and client-side optimistic updates.
|
|
58
57
|
*
|
|
59
58
|
* @returns A context provider wrapping the children with cart functionality
|
|
60
59
|
*/
|
package/cart/cart-provider.js
CHANGED
|
@@ -17,12 +17,6 @@ import { recalculateCartCost } from "./utils/cart-utils";
|
|
|
17
17
|
import { createOptimisticSellingPlanAllocation } from "./utils/variant-to-cart-line";
|
|
18
18
|
class CartContextError extends CanopyError {
|
|
19
19
|
}
|
|
20
|
-
const isEditorMode = () => {
|
|
21
|
-
if (typeof window === "undefined") {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
return window.parent !== window;
|
|
25
|
-
};
|
|
26
20
|
let cartCreationPromise = null;
|
|
27
21
|
function addLineToCart(cart, line) {
|
|
28
22
|
const existingLineIndex = cart.lines.findIndex((existingLine) => {
|
|
@@ -312,12 +306,7 @@ function CartProvider({
|
|
|
312
306
|
return null;
|
|
313
307
|
}
|
|
314
308
|
};
|
|
315
|
-
const checkoutUrl =
|
|
316
|
-
if (isEditorMode()) {
|
|
317
|
-
return "/";
|
|
318
|
-
}
|
|
319
|
-
return cartData?.checkoutUrl ?? "/";
|
|
320
|
-
})();
|
|
309
|
+
const checkoutUrl = cartData?.checkoutUrl ?? "/";
|
|
321
310
|
return /* @__PURE__ */ jsx(
|
|
322
311
|
CartContext.Provider,
|
|
323
312
|
{
|