@avocadostudio-ai/site-sdk 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/README.md +212 -2
- package/dist/create-site-page.d.ts +38 -8
- package/dist/create-site-page.js +59 -8
- package/dist/draft-common.d.ts +32 -0
- package/dist/draft-common.js +58 -0
- package/dist/draft-context-core.js +39 -6
- package/dist/draft-context-core.test.d.ts +10 -0
- package/dist/draft-context-core.test.js +146 -0
- package/dist/editor-cors.d.ts +12 -0
- package/dist/editor-cors.js +31 -6
- package/dist/editor-cors.test.d.ts +1 -0
- package/dist/editor-cors.test.js +66 -0
- package/dist/editor-manifest.d.ts +2 -3
- package/dist/editor-manifest.js +12 -64
- package/dist/editor-matcher.d.ts +27 -0
- package/dist/editor-matcher.js +34 -0
- package/dist/editor-query.js +7 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/integration-check.js +11 -1
- package/dist/manifest-utils.d.ts +13 -0
- package/dist/manifest-utils.js +30 -3
- package/dist/manifest-utils.test.d.ts +1 -0
- package/dist/manifest-utils.test.js +72 -0
- package/dist/middleware.d.ts +21 -19
- package/dist/middleware.js +19 -22
- package/dist/next-config.test.d.ts +1 -0
- package/dist/next-config.test.js +253 -0
- package/dist/page-metadata.d.ts +66 -0
- package/dist/page-metadata.js +110 -0
- package/dist/page-metadata.test.d.ts +1 -0
- package/dist/page-metadata.test.js +105 -0
- package/dist/proxy.d.ts +58 -0
- package/dist/proxy.js +50 -0
- package/dist/proxy.test.d.ts +1 -0
- package/dist/proxy.test.js +72 -0
- package/dist/publish/field-diff.d.ts +191 -0
- package/dist/publish/field-diff.js +252 -0
- package/dist/publish/field-diff.test.d.ts +1 -0
- package/dist/publish/field-diff.test.js +286 -0
- package/dist/server/orchestrator.d.ts +1 -117
- package/dist/server/orchestrator.js +14 -733
- package/next-config.d.ts +68 -0
- package/next-config.mjs +358 -0
- package/package.json +63 -19
package/next-config.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for `next-config.mjs`.
|
|
3
|
+
*
|
|
4
|
+
* The implementation is plain ESM on purpose — it is imported by `next.config`,
|
|
5
|
+
* before any of Next's loaders exist — so its types cannot be inferred and have
|
|
6
|
+
* to be declared here. A `next.config.ts` under `noImplicitAny` fails without
|
|
7
|
+
* this file.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** The linked Avocado packages that still ship TypeScript entry points. */
|
|
11
|
+
export function linkedAvocadoPackages(from?: string): string[]
|
|
12
|
+
|
|
13
|
+
/** A `next/image` remote pattern, structurally matching Next's own type. */
|
|
14
|
+
export type AvocadoImagePattern = {
|
|
15
|
+
protocol: "http" | "https"
|
|
16
|
+
hostname: string
|
|
17
|
+
port?: string
|
|
18
|
+
pathname?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The image hosts Avocado itself can produce URLs for — stock search, the image
|
|
23
|
+
* models' blob storage, and the placeholder host. `withAvocado` merges these
|
|
24
|
+
* into `images.remotePatterns`; exported so an app that opts out with
|
|
25
|
+
* `{ images: false }` can still reference the list.
|
|
26
|
+
*/
|
|
27
|
+
export const AVOCADO_IMAGE_HOSTS: AvocadoImagePattern[]
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The packages that must stay external to the server build — native binaries
|
|
31
|
+
* (`better-sqlite3`, `sharp`) and the provider SDKs `orchestrator-core` reaches
|
|
32
|
+
* through `await import(...)`. `withAvocado` applies these; exported so an app
|
|
33
|
+
* that opts out with `{ serverExternals: false }` can still reference the list.
|
|
34
|
+
*/
|
|
35
|
+
export const AVOCADO_SERVER_EXTERNALS: string[]
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Wrap a Next config so `transpilePackages` covers every linked Avocado package,
|
|
39
|
+
* `images.remotePatterns` covers every host Avocado can serve an image from, and
|
|
40
|
+
* Avocado's native and provider dependencies stay external to the server build.
|
|
41
|
+
* Additive, and never throws.
|
|
42
|
+
*/
|
|
43
|
+
export function withAvocado<
|
|
44
|
+
T extends {
|
|
45
|
+
transpilePackages?: string[]
|
|
46
|
+
images?: { remotePatterns?: unknown[] }
|
|
47
|
+
serverExternalPackages?: string[]
|
|
48
|
+
/** `null` is in Next's own type for this field, so the constraint admits it. */
|
|
49
|
+
webpack?: ((config: any, context: any) => any) | null
|
|
50
|
+
}
|
|
51
|
+
>(
|
|
52
|
+
config?: T,
|
|
53
|
+
options?: {
|
|
54
|
+
cwd?: string
|
|
55
|
+
silent?: boolean
|
|
56
|
+
/** Set false to manage `images.remotePatterns` yourself. Defaults to true. */
|
|
57
|
+
images?: boolean
|
|
58
|
+
/**
|
|
59
|
+
* Set false to manage `serverExternalPackages` and the server `externals`
|
|
60
|
+
* yourself. Defaults to true.
|
|
61
|
+
*/
|
|
62
|
+
serverExternals?: boolean
|
|
63
|
+
/** Environment to read the orchestrator origin from. Defaults to `process.env`. */
|
|
64
|
+
env?: Record<string, string | undefined>
|
|
65
|
+
}
|
|
66
|
+
): T
|
|
67
|
+
|
|
68
|
+
export default withAvocado
|
package/next-config.mjs
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Next.js config helper.
|
|
3
|
+
*
|
|
4
|
+
* Plain ESM, deliberately: it is imported *by* `next.config`, which Next loads
|
|
5
|
+
* before any of its own loaders exist. Everything else in this package ships
|
|
6
|
+
* TypeScript source in a workspace checkout, and a config that imported that
|
|
7
|
+
* would fail to parse — which is the very failure this file exists to prevent.
|
|
8
|
+
*
|
|
9
|
+
* ## What it prevents
|
|
10
|
+
*
|
|
11
|
+
* Avocado's packages point `main` at `src/index.ts` so a monorepo checkout
|
|
12
|
+
* needs no build step. Webpack has no idea what to do with that, so every
|
|
13
|
+
* linked package must be named in `transpilePackages` — and when one is
|
|
14
|
+
* missing, the error names a file inside `node_modules` and says nothing about
|
|
15
|
+
* the config the integrator has to change:
|
|
16
|
+
*
|
|
17
|
+
* Module parse failed: Unexpected token (27:7)
|
|
18
|
+
* > type InlineToken,
|
|
19
|
+
*
|
|
20
|
+
* Nothing catches it earlier. A type-check does not compile a Next app, and a
|
|
21
|
+
* test suite does not boot one, so the app is green everywhere except in a
|
|
22
|
+
* browser. It also breaks *retroactively*: adding a package to Avocado, or
|
|
23
|
+
* re-exporting one from another, silently breaks every consumer that pinned the
|
|
24
|
+
* old list by hand.
|
|
25
|
+
*
|
|
26
|
+
* So the list is not maintained by hand. This reads what is actually linked and
|
|
27
|
+
* adds whatever ships TypeScript, keeping anything the app already declared.
|
|
28
|
+
*
|
|
29
|
+
* ## What else it prevents
|
|
30
|
+
*
|
|
31
|
+
* Avocado writes image URLs its host never chose. A generated image comes back
|
|
32
|
+
* from Unsplash or from an image model's blob storage, and `next/image` refuses
|
|
33
|
+
* any host not listed in `images.remotePatterns` — so the first image a user
|
|
34
|
+
* generates 500s, on a config line nothing in the integration docs mentioned.
|
|
35
|
+
* Four apps in this repo carried the same hand-copied host list to work around
|
|
36
|
+
* that. It belongs here, next to the other thing an integrator cannot be
|
|
37
|
+
* expected to know.
|
|
38
|
+
*
|
|
39
|
+
* ## And the third thing
|
|
40
|
+
*
|
|
41
|
+
* `orchestrator-core` reaches native binaries (`better-sqlite3`, `sharp`) and
|
|
42
|
+
* heavyweight provider SDKs, some of them through `await import(...)` because
|
|
43
|
+
* they are optional peers. A bundler must be told to leave all of them alone:
|
|
44
|
+
*
|
|
45
|
+
* - A native `.node` binary that gets bundled crashes when it is loaded, not
|
|
46
|
+
* when it is built, so the failure surfaces on the first request.
|
|
47
|
+
* - Turbopack statically resolves dynamic imports, so an optional peer that is
|
|
48
|
+
* *deliberately absent* fails the build with `Module not found`. "An optional
|
|
49
|
+
* peer is genuinely skipped" holds at install time; it does not hold at bundle
|
|
50
|
+
* time.
|
|
51
|
+
*
|
|
52
|
+
* `serverExternalPackages` alone is not enough, and this is the part nobody
|
|
53
|
+
* guesses: `transpilePackages` overrides server externals for a transitive
|
|
54
|
+
* dependency, so `sharp` reached through the transpiled `orchestrator-core` got
|
|
55
|
+
* bundled anyway. The two options interact, this helper sets both, and it is the
|
|
56
|
+
* only place that knows it has to.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs"
|
|
60
|
+
import { dirname, join, resolve } from "node:path"
|
|
61
|
+
|
|
62
|
+
/** Scopes whose packages may ship TypeScript source in a linked checkout. */
|
|
63
|
+
const SCOPES = ["@avocadostudio-ai", "@ai-site-editor"]
|
|
64
|
+
|
|
65
|
+
function readJson(file) {
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(readFileSync(file, "utf8"))
|
|
68
|
+
} catch {
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Does any entry point in this manifest resolve to TypeScript? */
|
|
74
|
+
function shipsTypeScript(pkg) {
|
|
75
|
+
const seen = []
|
|
76
|
+
const walk = (value) => {
|
|
77
|
+
if (typeof value === "string") seen.push(value)
|
|
78
|
+
else if (value && typeof value === "object") Object.values(value).forEach(walk)
|
|
79
|
+
}
|
|
80
|
+
walk(pkg.main)
|
|
81
|
+
walk(pkg.types)
|
|
82
|
+
walk(pkg.exports)
|
|
83
|
+
return seen.some((entry) => /\.tsx?$/.test(entry))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Every `node_modules` directory from `start` up to the filesystem root. */
|
|
87
|
+
function nodeModulesDirs(start) {
|
|
88
|
+
const dirs = []
|
|
89
|
+
let current = resolve(start)
|
|
90
|
+
for (;;) {
|
|
91
|
+
const candidate = join(current, "node_modules")
|
|
92
|
+
if (existsSync(candidate)) dirs.push(candidate)
|
|
93
|
+
const parent = dirname(current)
|
|
94
|
+
if (parent === current) return dirs
|
|
95
|
+
current = parent
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The linked Avocado packages that have to be transpiled with the app.
|
|
101
|
+
*
|
|
102
|
+
* Resolved from what is on disk rather than from a list in this file, so a
|
|
103
|
+
* package added to Avocado tomorrow is picked up without anyone editing a
|
|
104
|
+
* config. A package installed from a registry resolves to built JavaScript and
|
|
105
|
+
* is correctly left out.
|
|
106
|
+
*/
|
|
107
|
+
export function linkedAvocadoPackages(from = process.cwd()) {
|
|
108
|
+
const found = new Set()
|
|
109
|
+
for (const nodeModules of nodeModulesDirs(from)) {
|
|
110
|
+
for (const scope of SCOPES) {
|
|
111
|
+
const scopeDir = join(nodeModules, scope)
|
|
112
|
+
if (!existsSync(scopeDir)) continue
|
|
113
|
+
let entries
|
|
114
|
+
try {
|
|
115
|
+
entries = readdirSync(scopeDir)
|
|
116
|
+
} catch {
|
|
117
|
+
continue
|
|
118
|
+
}
|
|
119
|
+
for (const name of entries) {
|
|
120
|
+
const full = `${scope}/${name}`
|
|
121
|
+
if (found.has(full)) continue
|
|
122
|
+
const pkg = readJson(join(scopeDir, name, "package.json"))
|
|
123
|
+
if (pkg && shipsTypeScript(pkg)) found.add(full)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return [...found].sort()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Hosts Avocado itself can put in an image URL.
|
|
132
|
+
*
|
|
133
|
+
* Unsplash for stock search, the image models' own blob storage for generated
|
|
134
|
+
* images, `placehold.co` for the placeholder a block renders before an image is
|
|
135
|
+
* chosen. A host the *site's own CMS* serves from (`cdn.sanity.io`,
|
|
136
|
+
* `images.ctfassets.net`, …) is not here — that is the app's to declare,
|
|
137
|
+
* because only the app knows which CMS it uses.
|
|
138
|
+
*/
|
|
139
|
+
export const AVOCADO_IMAGE_HOSTS = [
|
|
140
|
+
{ protocol: "https", hostname: "images.unsplash.com" },
|
|
141
|
+
{ protocol: "https", hostname: "plus.unsplash.com" },
|
|
142
|
+
{ protocol: "https", hostname: "oaidalleapiprodscus.blob.core.windows.net" },
|
|
143
|
+
{ protocol: "https", hostname: "generativelanguage.googleapis.com" },
|
|
144
|
+
{ protocol: "https", hostname: "placehold.co" },
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
/** `{protocol}://{hostname}` — the identity two patterns are deduped on. */
|
|
148
|
+
function patternKey(pattern) {
|
|
149
|
+
return `${pattern.protocol ?? "https"}://${pattern.hostname}${pattern.port ? `:${pattern.port}` : ""}${pattern.pathname ?? ""}`
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The orchestrator's own origin, when it is somewhere `next/image` would need
|
|
154
|
+
* permission to reach.
|
|
155
|
+
*
|
|
156
|
+
* Uploaded and locally-cached images are served by the orchestrator, so its
|
|
157
|
+
* host has to be allowed too — and unlike the list above it is per-deployment,
|
|
158
|
+
* which is exactly why hand-maintained config kept getting it wrong.
|
|
159
|
+
*/
|
|
160
|
+
function orchestratorImagePattern(env) {
|
|
161
|
+
const configured = (env.NEXT_PUBLIC_ORCHESTRATOR_URL ?? env.ORCHESTRATOR_URL ?? "").trim()
|
|
162
|
+
/*
|
|
163
|
+
* The same default `draft-fetch.ts` uses — but only outside production. A
|
|
164
|
+
* build that never names its orchestrator is a local one, and allowing
|
|
165
|
+
* `localhost` through the image optimizer of a deployed site is a wider hole
|
|
166
|
+
* than the convenience is worth.
|
|
167
|
+
*/
|
|
168
|
+
const raw = configured || (env.NODE_ENV === "production" ? "" : "http://localhost:4200")
|
|
169
|
+
if (!raw) return null
|
|
170
|
+
try {
|
|
171
|
+
const url = new URL(raw)
|
|
172
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null
|
|
173
|
+
return {
|
|
174
|
+
protocol: url.protocol.replace(":", ""),
|
|
175
|
+
hostname: url.hostname,
|
|
176
|
+
...(url.port ? { port: url.port } : {}),
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
return null
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Merge Avocado's image hosts into a Next config's `images.remotePatterns`.
|
|
185
|
+
*
|
|
186
|
+
* Additive, like the transpile list: whatever the app declared stays, in its
|
|
187
|
+
* own order, and a host it already covers is not duplicated.
|
|
188
|
+
*/
|
|
189
|
+
function withAvocadoImages(config, env) {
|
|
190
|
+
const images = config.images ?? {}
|
|
191
|
+
const declared = Array.isArray(images.remotePatterns) ? images.remotePatterns : []
|
|
192
|
+
const seen = new Set(declared.map(patternKey))
|
|
193
|
+
|
|
194
|
+
const additions = []
|
|
195
|
+
for (const pattern of [...AVOCADO_IMAGE_HOSTS, orchestratorImagePattern(env)]) {
|
|
196
|
+
if (!pattern) continue
|
|
197
|
+
const key = patternKey(pattern)
|
|
198
|
+
if (seen.has(key)) continue
|
|
199
|
+
seen.add(key)
|
|
200
|
+
additions.push(pattern)
|
|
201
|
+
}
|
|
202
|
+
if (additions.length === 0) return config
|
|
203
|
+
|
|
204
|
+
return { ...config, images: { ...images, remotePatterns: [...declared, ...additions] } }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Packages a bundler must not bundle into the server build.
|
|
209
|
+
*
|
|
210
|
+
* Two kinds, and they fail differently:
|
|
211
|
+
*
|
|
212
|
+
* - **Native binaries** — `better-sqlite3` (the orchestrator's state) and
|
|
213
|
+
* `sharp` (image processing). Bundling one produces a build that succeeds and
|
|
214
|
+
* a server that dies loading the `.node` file.
|
|
215
|
+
* - **Provider SDKs** — reached from `orchestrator-core`, several of them via
|
|
216
|
+
* `await import(...)` so that a site which does not use a provider need not
|
|
217
|
+
* install it. Turbopack resolves those statically and fails the build over a
|
|
218
|
+
* package that was never meant to be there.
|
|
219
|
+
*
|
|
220
|
+
* Naming a package that is not installed is a no-op, which is what makes one
|
|
221
|
+
* list correct for every consumer: a site with no Gemini key still lists
|
|
222
|
+
* `@google/genai`, and nothing looks for it.
|
|
223
|
+
*/
|
|
224
|
+
export const AVOCADO_SERVER_EXTERNALS = [
|
|
225
|
+
"better-sqlite3",
|
|
226
|
+
"sharp",
|
|
227
|
+
"@anthropic-ai/sdk",
|
|
228
|
+
"@anthropic-ai/claude-agent-sdk",
|
|
229
|
+
"openai",
|
|
230
|
+
"@google/genai",
|
|
231
|
+
"googleapis",
|
|
232
|
+
"@modelcontextprotocol/sdk",
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Mark every entry in `AVOCADO_SERVER_EXTERNALS` external to the server build,
|
|
237
|
+
* both ways it has to be said.
|
|
238
|
+
*
|
|
239
|
+
* `serverExternalPackages` is the documented knob and is not sufficient on its
|
|
240
|
+
* own: `transpilePackages` — which the same helper is busy populating — takes
|
|
241
|
+
* precedence for a *transitive* dependency, so a native binary imported by a
|
|
242
|
+
* transpiled Avocado package is bundled despite being listed. The webpack
|
|
243
|
+
* `externals` entry is what actually holds, and it is scoped to `isServer` so a
|
|
244
|
+
* client bundle is untouched.
|
|
245
|
+
*
|
|
246
|
+
* Both halves are additive: an app's own externals and its own `webpack` hook
|
|
247
|
+
* run first and keep whatever they did.
|
|
248
|
+
*
|
|
249
|
+
* The hook is attached even for an app that had none, which has one cosmetic
|
|
250
|
+
* cost: Next warns "Webpack is configured while Turbopack is not" for a
|
|
251
|
+
* Turbopack app that declares no `turbopack` key of its own. Under Turbopack the
|
|
252
|
+
* hook is never called and `serverExternalPackages` is what carries the fix, so
|
|
253
|
+
* the warning is about an inert function. An app that would rather not see it
|
|
254
|
+
* can declare `turbopack: {}` or opt out with `{ serverExternals: false }`.
|
|
255
|
+
*/
|
|
256
|
+
function withAvocadoServerExternals(config) {
|
|
257
|
+
const declared = Array.isArray(config.serverExternalPackages) ? config.serverExternalPackages : []
|
|
258
|
+
const missing = AVOCADO_SERVER_EXTERNALS.filter((name) => !declared.includes(name))
|
|
259
|
+
|
|
260
|
+
const appWebpack = typeof config.webpack === "function" ? config.webpack : null
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
...config,
|
|
264
|
+
...(missing.length > 0 ? { serverExternalPackages: [...declared, ...missing] } : {}),
|
|
265
|
+
webpack(webpackConfig, context) {
|
|
266
|
+
const result = appWebpack ? appWebpack(webpackConfig, context) : webpackConfig
|
|
267
|
+
if (!context?.isServer) return result
|
|
268
|
+
|
|
269
|
+
const existing = result.externals ?? []
|
|
270
|
+
result.externals = [
|
|
271
|
+
...(Array.isArray(existing) ? existing : [existing]),
|
|
272
|
+
/*
|
|
273
|
+
* A function rather than a name list so that a deep import
|
|
274
|
+
* (`sharp/lib/...`) is externalised along with the package root.
|
|
275
|
+
* Calling back with no arguments means "not external" and hands the
|
|
276
|
+
* request to the next resolver, which is why this composes.
|
|
277
|
+
*/
|
|
278
|
+
({ request }, callback) => {
|
|
279
|
+
if (!request) return callback()
|
|
280
|
+
for (const name of AVOCADO_SERVER_EXTERNALS) {
|
|
281
|
+
if (request === name || request.startsWith(`${name}/`)) {
|
|
282
|
+
return callback(null, `commonjs ${request}`)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
callback()
|
|
286
|
+
},
|
|
287
|
+
]
|
|
288
|
+
return result
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Wrap a Next config so its `transpilePackages` covers every linked Avocado
|
|
295
|
+
* package.
|
|
296
|
+
*
|
|
297
|
+
* Also merges Avocado's own image hosts into `images.remotePatterns`, since a
|
|
298
|
+
* generated image comes from a host the site never chose, and marks Avocado's
|
|
299
|
+
* native and provider dependencies external to the server build, since neither
|
|
300
|
+
* survives being bundled. Pass `{ images: false }` or
|
|
301
|
+
* `{ serverExternals: false }` to manage either list yourself.
|
|
302
|
+
*
|
|
303
|
+
* Additive and total: whatever the app already listed is kept in the order it
|
|
304
|
+
* wrote it, unrelated entries included, its own `webpack` hook still runs and
|
|
305
|
+
* still wins, and any failure to read the filesystem leaves the config exactly
|
|
306
|
+
* as it was. Never throws — a helper that can break `next.config` is worse than
|
|
307
|
+
* the bug it fixes.
|
|
308
|
+
*/
|
|
309
|
+
export function withAvocado(config = {}, options = {}) {
|
|
310
|
+
const {
|
|
311
|
+
cwd = process.cwd(),
|
|
312
|
+
silent = false,
|
|
313
|
+
images = true,
|
|
314
|
+
serverExternals = true,
|
|
315
|
+
env = process.env,
|
|
316
|
+
} = options
|
|
317
|
+
|
|
318
|
+
/*
|
|
319
|
+
* Applied before the `transpilePackages` derivation below, which has two
|
|
320
|
+
* early returns of its own — a config that already lists every linked package
|
|
321
|
+
* still needs its externals.
|
|
322
|
+
*/
|
|
323
|
+
const withImages = images ? withAvocadoImages(config, env) : config
|
|
324
|
+
const result = serverExternals ? withAvocadoServerExternals(withImages) : withImages
|
|
325
|
+
|
|
326
|
+
let linked
|
|
327
|
+
try {
|
|
328
|
+
linked = linkedAvocadoPackages(cwd)
|
|
329
|
+
} catch {
|
|
330
|
+
return result
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const declared = Array.isArray(result.transpilePackages) ? result.transpilePackages : []
|
|
334
|
+
const missing = linked.filter((name) => !declared.includes(name))
|
|
335
|
+
if (missing.length === 0) return result
|
|
336
|
+
|
|
337
|
+
if (!silent) {
|
|
338
|
+
/*
|
|
339
|
+
* Best-effort only. Next runs `next.config` inside its own reporter, and on
|
|
340
|
+
* Next 16 neither stdout nor stderr written during that window reaches the
|
|
341
|
+
* terminal (measured, not assumed). So this is not the mechanism that keeps
|
|
342
|
+
* an integrator informed — the auto-fix is, and the comment they write next
|
|
343
|
+
* to their own `withAvocado(...)` call is. It stays because it does surface
|
|
344
|
+
* on hosts that do not capture the config run, and it costs nothing.
|
|
345
|
+
*/
|
|
346
|
+
try {
|
|
347
|
+
process.stderr.write(
|
|
348
|
+
`[avocado] transpilePackages: added ${missing.join(", ")} — linked from source, so webpack has to compile them.\n`
|
|
349
|
+
)
|
|
350
|
+
} catch {
|
|
351
|
+
// A host with no writable stderr is not a reason to fail the build.
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return { ...result, transpilePackages: [...declared, ...missing] }
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export default withAvocado
|
package/package.json
CHANGED
|
@@ -1,58 +1,94 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avocadostudio-ai/site-sdk",
|
|
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",
|
|
7
7
|
"exports": {
|
|
8
8
|
"./package.json": "./package.json",
|
|
9
9
|
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
10
11
|
"import": "./dist/index.js",
|
|
11
|
-
"
|
|
12
|
+
"default": "./dist/index.js"
|
|
12
13
|
},
|
|
13
14
|
"./draft": {
|
|
15
|
+
"types": "./dist/draft.d.ts",
|
|
14
16
|
"import": "./dist/draft.js",
|
|
15
|
-
"
|
|
17
|
+
"default": "./dist/draft.js"
|
|
16
18
|
},
|
|
17
19
|
"./editor": {
|
|
20
|
+
"types": "./dist/editor.d.ts",
|
|
18
21
|
"import": "./dist/editor.js",
|
|
19
|
-
"
|
|
22
|
+
"default": "./dist/editor.js"
|
|
20
23
|
},
|
|
21
24
|
"./routes": {
|
|
25
|
+
"types": "./dist/routes.d.ts",
|
|
22
26
|
"import": "./dist/routes.js",
|
|
23
|
-
"
|
|
27
|
+
"default": "./dist/routes.js"
|
|
24
28
|
},
|
|
25
29
|
"./editor-manifest": {
|
|
30
|
+
"types": "./dist/editor-manifest.d.ts",
|
|
26
31
|
"import": "./dist/editor-manifest.js",
|
|
27
|
-
"
|
|
32
|
+
"default": "./dist/editor-manifest.js"
|
|
28
33
|
},
|
|
29
34
|
"./draft/core": {
|
|
35
|
+
"types": "./dist/draft-context-core.d.ts",
|
|
30
36
|
"import": "./dist/draft-context-core.js",
|
|
31
|
-
"
|
|
37
|
+
"default": "./dist/draft-context-core.js"
|
|
32
38
|
},
|
|
33
39
|
"./routes/core": {
|
|
40
|
+
"types": "./dist/draft-routes-core.d.ts",
|
|
34
41
|
"import": "./dist/draft-routes-core.js",
|
|
35
|
-
"
|
|
42
|
+
"default": "./dist/draft-routes-core.js"
|
|
36
43
|
},
|
|
37
44
|
"./publish-handlers/json-file": {
|
|
45
|
+
"types": "./dist/publish-handlers/json-file.d.ts",
|
|
38
46
|
"import": "./dist/publish-handlers/json-file.js",
|
|
39
|
-
"
|
|
47
|
+
"default": "./dist/publish-handlers/json-file.js"
|
|
48
|
+
},
|
|
49
|
+
"./publish": {
|
|
50
|
+
"types": "./dist/publish/field-diff.d.ts",
|
|
51
|
+
"import": "./dist/publish/field-diff.js",
|
|
52
|
+
"default": "./dist/publish/field-diff.js"
|
|
40
53
|
},
|
|
41
54
|
"./middleware": {
|
|
55
|
+
"types": "./dist/middleware.d.ts",
|
|
42
56
|
"import": "./dist/middleware.js",
|
|
43
|
-
"
|
|
57
|
+
"default": "./dist/middleware.js"
|
|
58
|
+
},
|
|
59
|
+
"./proxy": {
|
|
60
|
+
"types": "./dist/proxy.d.ts",
|
|
61
|
+
"import": "./dist/proxy.js",
|
|
62
|
+
"default": "./dist/proxy.js"
|
|
63
|
+
},
|
|
64
|
+
"./matcher": {
|
|
65
|
+
"types": "./dist/editor-matcher.d.ts",
|
|
66
|
+
"import": "./dist/editor-matcher.js",
|
|
67
|
+
"default": "./dist/editor-matcher.js"
|
|
44
68
|
},
|
|
45
69
|
"./navigation": {
|
|
70
|
+
"types": "./dist/navigation.d.ts",
|
|
46
71
|
"import": "./dist/navigation.js",
|
|
47
|
-
"
|
|
72
|
+
"default": "./dist/navigation.js"
|
|
48
73
|
},
|
|
49
74
|
"./page": {
|
|
75
|
+
"types": "./dist/create-site-page.d.ts",
|
|
50
76
|
"import": "./dist/create-site-page.js",
|
|
51
|
-
"
|
|
77
|
+
"default": "./dist/create-site-page.js"
|
|
78
|
+
},
|
|
79
|
+
"./seo": {
|
|
80
|
+
"types": "./dist/page-metadata.d.ts",
|
|
81
|
+
"import": "./dist/page-metadata.js",
|
|
82
|
+
"default": "./dist/page-metadata.js"
|
|
52
83
|
},
|
|
53
84
|
"./server": {
|
|
85
|
+
"types": "./dist/server/orchestrator.d.ts",
|
|
54
86
|
"import": "./dist/server/orchestrator.js",
|
|
55
|
-
"
|
|
87
|
+
"default": "./dist/server/orchestrator.js"
|
|
88
|
+
},
|
|
89
|
+
"./next-config": {
|
|
90
|
+
"types": "./next-config.d.ts",
|
|
91
|
+
"default": "./next-config.mjs"
|
|
56
92
|
}
|
|
57
93
|
},
|
|
58
94
|
"repository": {
|
|
@@ -65,27 +101,34 @@
|
|
|
65
101
|
"access": "public"
|
|
66
102
|
},
|
|
67
103
|
"files": [
|
|
68
|
-
"dist"
|
|
104
|
+
"dist",
|
|
105
|
+
"next-config.d.ts",
|
|
106
|
+
"next-config.mjs"
|
|
69
107
|
],
|
|
70
108
|
"dependencies": {
|
|
71
109
|
"zod": "^4.3.6",
|
|
72
|
-
"@avocadostudio-ai/blocks": "0.
|
|
73
|
-
"@avocadostudio-ai/preview-adapter": "0.
|
|
74
|
-
"@avocadostudio-ai/shared": "0.
|
|
110
|
+
"@avocadostudio-ai/blocks": "0.2.0",
|
|
111
|
+
"@avocadostudio-ai/preview-adapter": "0.2.0",
|
|
112
|
+
"@avocadostudio-ai/shared": "0.2.0"
|
|
75
113
|
},
|
|
76
114
|
"peerDependencies": {
|
|
77
115
|
"next": ">=15.0.0",
|
|
78
116
|
"react": ">=19.0.0",
|
|
79
117
|
"react-dom": ">=19.0.0",
|
|
80
|
-
"
|
|
118
|
+
"better-sqlite3": ">=12.0.0",
|
|
119
|
+
"@avocadostudio-ai/orchestrator-core": "^0.2.0"
|
|
81
120
|
},
|
|
82
121
|
"peerDependenciesMeta": {
|
|
83
122
|
"@avocadostudio-ai/orchestrator-core": {
|
|
84
123
|
"optional": true
|
|
124
|
+
},
|
|
125
|
+
"better-sqlite3": {
|
|
126
|
+
"optional": true
|
|
85
127
|
}
|
|
86
128
|
},
|
|
87
129
|
"devDependencies": {
|
|
88
130
|
"@types/react": "^19.0.10",
|
|
131
|
+
"tsx": "^4.21.0",
|
|
89
132
|
"typescript": "^5.7.3"
|
|
90
133
|
},
|
|
91
134
|
"description": "SDK for adding Avocado Studio AI editing and live preview to a Next.js site",
|
|
@@ -96,7 +139,8 @@
|
|
|
96
139
|
},
|
|
97
140
|
"scripts": {
|
|
98
141
|
"build": "tsc -p tsconfig.build.json",
|
|
99
|
-
"typecheck": "tsc --noEmit"
|
|
142
|
+
"typecheck": "tsc --noEmit",
|
|
143
|
+
"test": "NODE_ENV=test node ../../scripts/run-tests.mjs"
|
|
100
144
|
},
|
|
101
145
|
"bin": {
|
|
102
146
|
"avocado-register": "./dist/cli/register.js"
|