@avocadostudio-ai/shared 0.1.0 → 0.2.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/contract/operation.schema.json +3 -0
- package/dist/block-manifest.d.ts +443 -0
- package/dist/block-manifest.js +306 -22
- package/dist/blocks/_registry.d.ts +58 -0
- package/dist/blocks/_registry.js +66 -0
- package/dist/blocks/footer.js +20 -1
- package/dist/blocks/index.d.ts +16 -0
- package/dist/blocks/index.js +18 -0
- package/dist/blocks/quote.js +1 -1
- package/dist/chat-events.d.ts +3 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +13 -2
- package/dist/ops/builders.d.ts +8 -3
- package/dist/ops/builders.js +11 -6
- package/dist/schemas.d.ts +5 -2
- package/dist/schemas.js +46 -2
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
export { EDITOR_PROTOCOL_VERSION } from "./protocol.js";
|
|
2
2
|
export { getConfiguredDraftSecret, getSafeInternalRedirectPath, validateDraftSecret } from "./draft-mode.js";
|
|
3
3
|
export { isImagePath, toAltPath, setPropAtPath } from "./editable-path.js";
|
|
4
|
-
|
|
4
|
+
/*
|
|
5
|
+
* The rich-text grammar lives in `@avocadostudio-ai/richtext`, which owns the
|
|
6
|
+
* parser and every CMS converter and has no dependencies of its own. It is
|
|
7
|
+
* re-exported here because the renderers, the overlay and the Puck adapter all
|
|
8
|
+
* already import it from `shared` — moving the source should not move every
|
|
9
|
+
* call site. New code that only needs the grammar should depend on the
|
|
10
|
+
* richtext package directly.
|
|
11
|
+
*/
|
|
12
|
+
export { parseInline, parseRichText, parseRichTextBlocks, normalizeRichTextBody, resolveRichTextHeadingLevel, clampMarkdownHeadings, unescapeMarkdownText, isRichTextDoc, fromMarkdown, toMarkdown, mergeRichTextDoc, NODE, MARK } from "@avocadostudio-ai/richtext";
|
|
13
|
+
export { blockDefinitionSchema, blockManifestSchema, buildBlockManifest, jsonSchemaLikeSchema, validateByJsonSchemaLike, findManifestSchemaIssue, validateManifestDefaultProps, deriveFieldMetaFromSchema, resolveManifestFieldMeta, isProseMirrorDocSchema } from "./block-manifest.js";
|
|
5
14
|
export {
|
|
6
15
|
// Constants & helpers
|
|
7
16
|
IMAGE_PLACEHOLDER, isImagePlaceholder,
|
|
@@ -9,11 +18,13 @@ IMAGE_PLACEHOLDER, isImagePlaceholder,
|
|
|
9
18
|
registerBlock, getBlockMeta, getAllBlockMeta, getImageFields, getListImageFields, isFieldInlineEditable, getImageSpec, isChrome, getChromeTypes,
|
|
10
19
|
// Backwards-compatible exports
|
|
11
20
|
blockSchemas, allowedBlockTypes,
|
|
21
|
+
// The catalogue a site actually renders — see `declareBlockCatalogue`
|
|
22
|
+
declareBlockCatalogue, getBlockCatalogue, isInBlockCatalogue, catalogueBlockTypes, undeclaredBlockTypes,
|
|
12
23
|
// Utility functions
|
|
13
24
|
getPropDisplayName, defaultListItemForBlock,
|
|
14
25
|
// Schemas & validation
|
|
15
26
|
blockInstanceSchema, blockInstanceSchemaLenient, validateBlockProps, getBlockJsonSchema, } from "./blocks/_registry.js";
|
|
16
|
-
export { defaultPropsForType, resolveHeadingTag, resolveItemHeadingTag, DEFAULT_HEADING_LEVELS, } from "./blocks/index.js";
|
|
27
|
+
export { defaultPropsForType, declaredDefaultPropsForType, resolveHeadingTag, resolveItemHeadingTag, DEFAULT_HEADING_LEVELS, } from "./blocks/index.js";
|
|
17
28
|
export { blockTypeToCamel, camelToBlockType, blockTypeToLower, lowerToBlockType, } from "./block-names.js";
|
|
18
29
|
export { makeAddBlock, generateBlockId, makeAddItem, generateItemId, ensureItemIds, } from "./ops/builders.js";
|
|
19
30
|
export { THEME_TOKEN_TO_CSS_VARS, themeTokenKeys, semanticThemeTokensSchema, mapSemanticThemeTokens, } from "./ops/theme-tokens.js";
|
package/dist/ops/builders.d.ts
CHANGED
|
@@ -12,9 +12,14 @@ export type MakeAddBlockOptions = {
|
|
|
12
12
|
/**
|
|
13
13
|
* Build a canonical `add_block` op from a block type and partial props.
|
|
14
14
|
*
|
|
15
|
-
* The returned op's `block` merges
|
|
16
|
-
* (partial wins) and carries a generated id, so it is valid
|
|
17
|
-
* operation schema and ready to send to the orchestrator.
|
|
15
|
+
* The returned op's `block` merges the type's declared defaults with
|
|
16
|
+
* `partialProps` (partial wins) and carries a generated id, so it is valid
|
|
17
|
+
* against the strict operation schema and ready to send to the orchestrator.
|
|
18
|
+
*
|
|
19
|
+
* A type that declares no defaults — every block a site registers itself —
|
|
20
|
+
* contributes nothing, so the op carries exactly the props the caller passed.
|
|
21
|
+
* The alternative is worse than empty: the generic fallback would add a
|
|
22
|
+
* `title`, `description` and CTA the site's block has no field for.
|
|
18
23
|
*
|
|
19
24
|
* @example
|
|
20
25
|
* makeAddBlock("/", "Hero", { heading: "Welcome" })
|
package/dist/ops/builders.js
CHANGED
|
@@ -8,20 +8,25 @@
|
|
|
8
8
|
// must mint an id and supply a full prop set.
|
|
9
9
|
//
|
|
10
10
|
// `makeAddBlock` closes that gap without denormalizing the op: it generates a
|
|
11
|
-
// collision-resistant id and fills
|
|
11
|
+
// collision-resistant id and fills the type's declared defaults under any
|
|
12
12
|
// partial props you pass, returning a canonical, schema-valid `add_block`.
|
|
13
13
|
//
|
|
14
14
|
// External integrators: prefer this over hand-constructing the op (and never
|
|
15
15
|
// hand-write the `Operation` union — import it from this package, or validate
|
|
16
16
|
// against `contract/operation.schema.json`).
|
|
17
17
|
import { getBlockMeta } from "./../blocks/_registry.js";
|
|
18
|
-
import {
|
|
18
|
+
import { declaredDefaultPropsForType } from "../blocks/index.js";
|
|
19
19
|
/**
|
|
20
20
|
* Build a canonical `add_block` op from a block type and partial props.
|
|
21
21
|
*
|
|
22
|
-
* The returned op's `block` merges
|
|
23
|
-
* (partial wins) and carries a generated id, so it is valid
|
|
24
|
-
* operation schema and ready to send to the orchestrator.
|
|
22
|
+
* The returned op's `block` merges the type's declared defaults with
|
|
23
|
+
* `partialProps` (partial wins) and carries a generated id, so it is valid
|
|
24
|
+
* against the strict operation schema and ready to send to the orchestrator.
|
|
25
|
+
*
|
|
26
|
+
* A type that declares no defaults — every block a site registers itself —
|
|
27
|
+
* contributes nothing, so the op carries exactly the props the caller passed.
|
|
28
|
+
* The alternative is worse than empty: the generic fallback would add a
|
|
29
|
+
* `title`, `description` and CTA the site's block has no field for.
|
|
25
30
|
*
|
|
26
31
|
* @example
|
|
27
32
|
* makeAddBlock("/", "Hero", { heading: "Welcome" })
|
|
@@ -31,7 +36,7 @@ export function makeAddBlock(pageSlug, type, partialProps = {}, options = {}) {
|
|
|
31
36
|
const block = {
|
|
32
37
|
id: options.id ?? generateBlockId(type),
|
|
33
38
|
type,
|
|
34
|
-
props: { ...
|
|
39
|
+
props: { ...declaredDefaultPropsForType(type), ...partialProps },
|
|
35
40
|
};
|
|
36
41
|
return options.afterBlockId
|
|
37
42
|
? { op: "add_block", pageSlug, afterBlockId: options.afterBlockId, block }
|
package/dist/schemas.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export type PageMeta = {
|
|
|
15
15
|
title?: string;
|
|
16
16
|
description?: string;
|
|
17
17
|
ogImage?: string;
|
|
18
|
+
/** The public URL path, when it differs from the slug. See `pageMetaSchema`. */
|
|
19
|
+
path?: string;
|
|
18
20
|
};
|
|
19
21
|
export type PageDoc = {
|
|
20
22
|
id: string;
|
|
@@ -28,6 +30,7 @@ export declare const pageMetaSchema: z.ZodObject<{
|
|
|
28
30
|
title: z.ZodOptional<z.ZodString>;
|
|
29
31
|
description: z.ZodOptional<z.ZodString>;
|
|
30
32
|
ogImage: z.ZodOptional<z.ZodString>;
|
|
33
|
+
path: z.ZodOptional<z.ZodString>;
|
|
31
34
|
}, z.core.$strip>;
|
|
32
35
|
/** Lenient — accepts any block type (for ingesting content from sites with custom blocks). */
|
|
33
36
|
export declare const pageDocSchemaLenient: z.ZodType<PageDoc>;
|
|
@@ -133,7 +136,7 @@ export declare const operationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
133
136
|
title: z.ZodOptional<z.ZodString>;
|
|
134
137
|
description: z.ZodOptional<z.ZodString>;
|
|
135
138
|
ogImage: z.ZodOptional<z.ZodString>;
|
|
136
|
-
}, z.core.$
|
|
139
|
+
}, z.core.$strict>;
|
|
137
140
|
}, z.core.$strip>, z.ZodObject<{
|
|
138
141
|
op: z.ZodLiteral<"update_site_config">;
|
|
139
142
|
patch: z.ZodObject<{
|
|
@@ -267,7 +270,7 @@ export declare const editPlanSchema: z.ZodObject<{
|
|
|
267
270
|
title: z.ZodOptional<z.ZodString>;
|
|
268
271
|
description: z.ZodOptional<z.ZodString>;
|
|
269
272
|
ogImage: z.ZodOptional<z.ZodString>;
|
|
270
|
-
}, z.core.$
|
|
273
|
+
}, z.core.$strict>;
|
|
271
274
|
}, z.core.$strip>, z.ZodObject<{
|
|
272
275
|
op: z.ZodLiteral<"update_site_config">;
|
|
273
276
|
patch: z.ZodObject<{
|
package/dist/schemas.js
CHANGED
|
@@ -18,7 +18,22 @@ export const siteConfigSchema = z.object({
|
|
|
18
18
|
export const pageMetaSchema = z.object({
|
|
19
19
|
title: z.string().optional(),
|
|
20
20
|
description: z.string().optional(),
|
|
21
|
-
ogImage: z.string().optional()
|
|
21
|
+
ogImage: z.string().optional(),
|
|
22
|
+
/*
|
|
23
|
+
* The public path this page is served at, when that differs from its slug.
|
|
24
|
+
*
|
|
25
|
+
* Avocado has always treated the slug as the URL, which holds only while a
|
|
26
|
+
* site's routing is Avocado's. It is not for anything with a locale prefix,
|
|
27
|
+
* a basePath, or a CMS that owns its own routes: Paintball Arena Bern keeps
|
|
28
|
+
* one editable page per (document x language), so `/de/events` is a page
|
|
29
|
+
* identity, while the site serves German at the root and answers 404 for
|
|
30
|
+
* that path. An agent given the slug and told to open it goes to a 404 and
|
|
31
|
+
* has no way to know it was handed an id rather than a URL.
|
|
32
|
+
*
|
|
33
|
+
* Optional, and absent means "the slug is the path" — which stays true for
|
|
34
|
+
* every site whose routing Avocado does own.
|
|
35
|
+
*/
|
|
36
|
+
path: z.string().optional()
|
|
22
37
|
});
|
|
23
38
|
const pageDocFields = {
|
|
24
39
|
id: z.string().min(1),
|
|
@@ -165,13 +180,42 @@ const duplicatePageSchema = z.object({
|
|
|
165
180
|
newTitle: z.string().min(1).optional(),
|
|
166
181
|
afterPageSlug: z.string().min(1).optional()
|
|
167
182
|
});
|
|
183
|
+
const UPDATE_PAGE_META_KEYS = ["title", "description", "ogImage"];
|
|
184
|
+
// The patch is strict, and carries its own wording, because stripping is what
|
|
185
|
+
// made this unreadable. An agent that sent `path` here had the key dropped by
|
|
186
|
+
// Zod before validation returned; the engine then reported a patch with no
|
|
187
|
+
// defined keys and listed the three fields the caller had *not* sent, so the
|
|
188
|
+
// only conclusion available was "path is unsettable for some other reason".
|
|
189
|
+
//
|
|
190
|
+
// `path` stays unsettable on purpose — it is the adapter's report of where the
|
|
191
|
+
// site already serves a page, and Avocado cannot move a route it does not own
|
|
192
|
+
// (see docs/ideas/page-identity-punch-list.md, PI-03/PI-07). What changes here
|
|
193
|
+
// is that the refusal says so.
|
|
194
|
+
//
|
|
195
|
+
// The message must keep the word "invalid" and must avoid "not found",
|
|
196
|
+
// "ambiguous", "unclear" and "no effective … change": classifyGuardrailError
|
|
197
|
+
// (ops-engine.ts) matches on those keywords, and Zod's own "Unrecognized key"
|
|
198
|
+
// text classifies as internal_error, which the planner's repair pass does not
|
|
199
|
+
// retry. Only unrecognized keys are reworded — every other issue keeps Zod's
|
|
200
|
+
// default, so a non-object patch still reads as a type error.
|
|
168
201
|
const updatePageMetaSchema = z.object({
|
|
169
202
|
op: z.literal("update_page_meta"),
|
|
170
203
|
pageSlug: z.string().min(1),
|
|
171
|
-
patch: z.
|
|
204
|
+
patch: z.strictObject({
|
|
172
205
|
title: z.string().optional(),
|
|
173
206
|
description: z.string().optional(),
|
|
174
207
|
ogImage: z.string().optional()
|
|
208
|
+
}, {
|
|
209
|
+
error: (issue) => {
|
|
210
|
+
if (issue.code !== "unrecognized_keys")
|
|
211
|
+
return undefined;
|
|
212
|
+
const keys = issue.keys;
|
|
213
|
+
const named = keys.map((key) => `\`${key}\``).join(", ");
|
|
214
|
+
const why = keys.includes("path")
|
|
215
|
+
? " `path` reports where the site already serves this page and is supplied by the site's adapter, so Avocado cannot reassign it here."
|
|
216
|
+
: "";
|
|
217
|
+
return `Invalid update_page_meta patch: unrecognized key ${named}. This patch accepts ${UPDATE_PAGE_META_KEYS.join(", ")}.${why}`;
|
|
218
|
+
}
|
|
175
219
|
})
|
|
176
220
|
});
|
|
177
221
|
const updateSiteConfigSchema = z.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avocadostudio-ai/shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"contract"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"zod": "^4.3.6"
|
|
21
|
+
"zod": "^4.3.6",
|
|
22
|
+
"@avocadostudio-ai/richtext": "0.2.0"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
25
|
"tsx": "^4.21.0",
|
|
@@ -33,7 +34,8 @@
|
|
|
33
34
|
"exports": {
|
|
34
35
|
".": {
|
|
35
36
|
"types": "./dist/index.d.ts",
|
|
36
|
-
"import": "./dist/index.js"
|
|
37
|
+
"import": "./dist/index.js",
|
|
38
|
+
"default": "./dist/index.js"
|
|
37
39
|
},
|
|
38
40
|
"./contract/*": "./contract/*",
|
|
39
41
|
"./package.json": "./package.json"
|
|
@@ -41,7 +43,7 @@
|
|
|
41
43
|
"scripts": {
|
|
42
44
|
"build": "tsc -p tsconfig.build.json",
|
|
43
45
|
"typecheck": "tsc --noEmit",
|
|
44
|
-
"test": "NODE_ENV=test
|
|
46
|
+
"test": "NODE_ENV=test node ../../scripts/run-tests.mjs",
|
|
45
47
|
"gen:contract": "tsx scripts/gen-contract.ts",
|
|
46
48
|
"gen:contract:check": "tsx scripts/gen-contract.ts --check"
|
|
47
49
|
}
|