@wordrhyme/plugin 0.1.0-alpha.10
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/admin/index.d.ts +19 -0
- package/dist/admin/index.js +42 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/artifact.d.ts +17 -0
- package/dist/artifact.js +97 -0
- package/dist/artifact.js.map +1 -0
- package/dist/chunk-3IM3FPTJ.js +1470 -0
- package/dist/chunk-3IM3FPTJ.js.map +1 -0
- package/dist/chunk-6GDCFR67.js +218 -0
- package/dist/chunk-6GDCFR67.js.map +1 -0
- package/dist/chunk-7EM22QYB.js +333 -0
- package/dist/chunk-7EM22QYB.js.map +1 -0
- package/dist/chunk-BI7E5CVM.js +26 -0
- package/dist/chunk-BI7E5CVM.js.map +1 -0
- package/dist/chunk-BVOTSKM2.js +254 -0
- package/dist/chunk-BVOTSKM2.js.map +1 -0
- package/dist/chunk-DY44Q4CK.js +188 -0
- package/dist/chunk-DY44Q4CK.js.map +1 -0
- package/dist/chunk-MZOLSLJ7.js +65 -0
- package/dist/chunk-MZOLSLJ7.js.map +1 -0
- package/dist/chunk-O4AYK3YP.js +156 -0
- package/dist/chunk-O4AYK3YP.js.map +1 -0
- package/dist/chunk-UGMYO6AU.js +37 -0
- package/dist/chunk-UGMYO6AU.js.map +1 -0
- package/dist/client-poND5ovI.d.ts +679 -0
- package/dist/client.d.ts +9 -0
- package/dist/client.js +68 -0
- package/dist/client.js.map +1 -0
- package/dist/dev-utils.d.ts +105 -0
- package/dist/dev-utils.js +35 -0
- package/dist/dev-utils.js.map +1 -0
- package/dist/entity-extensions-CnhKoT4k.d.ts +56 -0
- package/dist/globalization.d.ts +85 -0
- package/dist/globalization.js +53 -0
- package/dist/globalization.js.map +1 -0
- package/dist/index.d.ts +724 -0
- package/dist/index.js +931 -0
- package/dist/index.js.map +1 -0
- package/dist/locale.d.ts +15 -0
- package/dist/locale.js +13 -0
- package/dist/locale.js.map +1 -0
- package/dist/manifest-CTFX-h0w.d.ts +2053 -0
- package/dist/react.d.ts +227 -0
- package/dist/react.js +226 -0
- package/dist/react.js.map +1 -0
- package/dist/release-BDJeO54k.d.ts +230 -0
- package/dist/server.d.ts +115 -0
- package/dist/server.js +194 -0
- package/dist/server.js.map +1 -0
- package/dist/time.d.ts +34 -0
- package/dist/time.js +31 -0
- package/dist/time.js.map +1 -0
- package/dist/trpc.d.ts +44 -0
- package/dist/trpc.js +11 -0
- package/dist/trpc.js.map +1 -0
- package/dist/types-BJo3_91V.d.ts +1997 -0
- package/package.json +92 -0
|
@@ -0,0 +1,1470 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canonicalizeLocale
|
|
3
|
+
} from "./chunk-BI7E5CVM.js";
|
|
4
|
+
|
|
5
|
+
// src/presentation.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var presentationIdPattern = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
8
|
+
var pluginIdPattern = /^[a-z0-9-]+(\.[a-z0-9-]+)+$/;
|
|
9
|
+
var contractVersionPattern = /^\d+(?:\.\d+){0,2}(?:-[0-9A-Za-z.-]+)?$/;
|
|
10
|
+
var contractRangePattern = /^(?:\^|~|>=|<=|>|<)?\d+(?:\.\d+){0,2}(?:-[0-9A-Za-z.-]+)?$|^\d+(?:\.\d+)?\.(?:x|\*)$|^\d+\.(?:x|\*)$/;
|
|
11
|
+
var presentationIdSchema = z.string().min(1).max(160).regex(presentationIdPattern, "presentation id must be URL-safe");
|
|
12
|
+
var presentationPluginIdSchema = z.string().regex(pluginIdPattern, "pluginId must be reverse-domain format");
|
|
13
|
+
var presentationContractVersionSchema = z.string().regex(contractVersionPattern, "contract version must contain one to three numeric semver components");
|
|
14
|
+
var presentationContractRangeSchema = z.string().regex(contractRangePattern, "contract range must be an exact, comparator, caret, tilde, or wildcard range");
|
|
15
|
+
var presentationSchemaRefSchema = z.union([z.string().min(1), z.record(z.string(), z.json())]);
|
|
16
|
+
var presentationModelSchema = z.json();
|
|
17
|
+
var presentationRenderModeSchema = z.enum(["ssr", "react", "island"]);
|
|
18
|
+
var presentationRegionSchema = z.object({
|
|
19
|
+
id: presentationIdSchema,
|
|
20
|
+
label: z.string().min(1).optional(),
|
|
21
|
+
required: z.boolean().optional(),
|
|
22
|
+
accepts: z.array(presentationIdSchema).optional(),
|
|
23
|
+
contextSchema: presentationSchemaRefSchema.optional(),
|
|
24
|
+
min: z.number().int().nonnegative().optional(),
|
|
25
|
+
max: z.number().int().positive().optional(),
|
|
26
|
+
order: z.number().optional()
|
|
27
|
+
}).superRefine((region, ctx) => {
|
|
28
|
+
if (region.min !== void 0 && region.max !== void 0 && region.min > region.max) {
|
|
29
|
+
ctx.addIssue({
|
|
30
|
+
code: "custom",
|
|
31
|
+
path: ["min"],
|
|
32
|
+
message: "presentation region min must not exceed max"
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
var presentationActionSchema = z.object({
|
|
37
|
+
id: presentationIdSchema,
|
|
38
|
+
inputSchema: presentationSchemaRefSchema.optional(),
|
|
39
|
+
outputSchema: presentationSchemaRefSchema.optional(),
|
|
40
|
+
permission: z.string().min(1).optional()
|
|
41
|
+
}).passthrough();
|
|
42
|
+
var presentationSurfaceSchema = z.object({
|
|
43
|
+
id: presentationIdSchema,
|
|
44
|
+
contractVersion: presentationContractVersionSchema,
|
|
45
|
+
modelSchema: presentationSchemaRefSchema,
|
|
46
|
+
defaultRenderer: z.string().min(1),
|
|
47
|
+
clientComponent: z.string().min(1).optional(),
|
|
48
|
+
renderModes: z.array(presentationRenderModeSchema).min(1),
|
|
49
|
+
actions: z.array(presentationActionSchema).optional(),
|
|
50
|
+
regions: z.array(presentationRegionSchema).optional()
|
|
51
|
+
}).superRefine((surface, ctx) => {
|
|
52
|
+
addDuplicateIdIssues(surface.actions, ["actions"], ctx);
|
|
53
|
+
addDuplicateIdIssues(surface.regions, ["regions"], ctx);
|
|
54
|
+
});
|
|
55
|
+
var presentationAdapterSchema = z.object({
|
|
56
|
+
id: presentationIdSchema.optional(),
|
|
57
|
+
label: z.string().min(1).optional(),
|
|
58
|
+
labelKey: z.string().min(1).optional(),
|
|
59
|
+
ownerPluginId: presentationPluginIdSchema,
|
|
60
|
+
surfaceId: presentationIdSchema,
|
|
61
|
+
accepts: presentationContractRangeSchema,
|
|
62
|
+
serverRenderer: z.string().min(1).optional(),
|
|
63
|
+
clientComponent: z.string().min(1).optional(),
|
|
64
|
+
expose: z.string().min(1).optional(),
|
|
65
|
+
required: z.boolean().optional(),
|
|
66
|
+
regions: z.array(presentationIdSchema).optional()
|
|
67
|
+
}).superRefine((adapter, ctx) => {
|
|
68
|
+
if (!adapter.serverRenderer && !adapter.clientComponent) {
|
|
69
|
+
ctx.addIssue({
|
|
70
|
+
code: "custom",
|
|
71
|
+
path: ["serverRenderer"],
|
|
72
|
+
message: "presentation adapter requires serverRenderer or clientComponent"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
var themeAssetPathSchema = z.string().min(1).max(512).refine((value) => !value.startsWith("/") && !value.includes("\\"), {
|
|
77
|
+
message: "theme asset paths must be relative POSIX paths"
|
|
78
|
+
}).refine((value) => value.split("/").every((segment) => segment !== "" && segment !== "." && segment !== ".."), {
|
|
79
|
+
message: "theme asset paths must not contain empty, dot, or parent segments"
|
|
80
|
+
});
|
|
81
|
+
var themeAssetSchema = z.object({
|
|
82
|
+
path: themeAssetPathSchema,
|
|
83
|
+
kind: z.enum(["stylesheet", "script", "font", "image", "other"]),
|
|
84
|
+
integrity: z.string().min(1).optional(),
|
|
85
|
+
media: z.string().min(1).optional(),
|
|
86
|
+
preload: z.boolean().optional(),
|
|
87
|
+
order: z.number().optional()
|
|
88
|
+
}).passthrough();
|
|
89
|
+
var themeHeadSchema = z.object({
|
|
90
|
+
title: z.string().min(1).max(300).optional(),
|
|
91
|
+
description: z.string().max(1e3).optional(),
|
|
92
|
+
meta: z.record(z.string().min(1).max(120), z.string().max(2048)).optional(),
|
|
93
|
+
links: z.array(z.object({
|
|
94
|
+
rel: z.string().min(1).max(80),
|
|
95
|
+
href: z.string().min(1).max(2048),
|
|
96
|
+
as: z.string().min(1).max(80).optional(),
|
|
97
|
+
type: z.string().min(1).max(160).optional()
|
|
98
|
+
})).optional()
|
|
99
|
+
});
|
|
100
|
+
var themeTokenTypeSchema = z.enum(["color", "length", "font-family", "number", "shadow", "enum", "image"]);
|
|
101
|
+
var themeTokenSchema = z.object({
|
|
102
|
+
id: presentationIdSchema,
|
|
103
|
+
cssVariable: z.string().regex(/^--[a-z0-9][a-z0-9-]*$/, "theme token cssVariable must be a CSS custom property"),
|
|
104
|
+
type: themeTokenTypeSchema,
|
|
105
|
+
default: z.json(),
|
|
106
|
+
enumValues: z.array(z.string().min(1)).optional(),
|
|
107
|
+
label: z.string().min(1).optional(),
|
|
108
|
+
labelKey: z.string().min(1).optional(),
|
|
109
|
+
description: z.string().optional(),
|
|
110
|
+
descriptionKey: z.string().min(1).optional()
|
|
111
|
+
}).superRefine((token, ctx) => {
|
|
112
|
+
if (token.type === "enum" && !token.enumValues?.length) {
|
|
113
|
+
ctx.addIssue({
|
|
114
|
+
code: "custom",
|
|
115
|
+
path: ["enumValues"],
|
|
116
|
+
message: "enum theme tokens require enumValues"
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
var themeTokenPresetSchema = z.object({
|
|
121
|
+
id: presentationIdSchema,
|
|
122
|
+
label: z.string().min(1).optional(),
|
|
123
|
+
labelKey: z.string().min(1).optional(),
|
|
124
|
+
description: z.string().optional(),
|
|
125
|
+
descriptionKey: z.string().min(1).optional(),
|
|
126
|
+
extends: presentationIdSchema.optional(),
|
|
127
|
+
values: z.record(presentationIdSchema, z.json())
|
|
128
|
+
});
|
|
129
|
+
var themeSiteShellSchema = z.union([
|
|
130
|
+
z.string().min(1),
|
|
131
|
+
z.object({
|
|
132
|
+
serverRenderer: z.string().min(1),
|
|
133
|
+
clientComponent: z.string().min(1).optional(),
|
|
134
|
+
expose: z.string().min(1).optional()
|
|
135
|
+
})
|
|
136
|
+
]);
|
|
137
|
+
var themeHomeTargetSchema = z.discriminatedUnion("type", [
|
|
138
|
+
z.object({
|
|
139
|
+
type: z.literal("theme-route"),
|
|
140
|
+
routeId: presentationIdSchema
|
|
141
|
+
}),
|
|
142
|
+
z.object({
|
|
143
|
+
type: z.literal("plugin-route"),
|
|
144
|
+
pluginId: presentationPluginIdSchema,
|
|
145
|
+
routeId: presentationIdSchema
|
|
146
|
+
}),
|
|
147
|
+
z.object({
|
|
148
|
+
type: z.literal("designer-page"),
|
|
149
|
+
pageId: z.string().min(1).max(160)
|
|
150
|
+
}),
|
|
151
|
+
z.object({
|
|
152
|
+
type: z.literal("default")
|
|
153
|
+
})
|
|
154
|
+
]);
|
|
155
|
+
var themeIntegrationSchema = z.object({
|
|
156
|
+
pluginId: presentationPluginIdSchema,
|
|
157
|
+
required: z.boolean().optional(),
|
|
158
|
+
surfaces: z.array(
|
|
159
|
+
z.object({
|
|
160
|
+
id: presentationIdSchema,
|
|
161
|
+
accepts: presentationContractRangeSchema,
|
|
162
|
+
required: z.boolean().optional()
|
|
163
|
+
})
|
|
164
|
+
).optional(),
|
|
165
|
+
storefrontApis: z.array(
|
|
166
|
+
z.object({
|
|
167
|
+
id: presentationIdSchema,
|
|
168
|
+
accepts: presentationContractRangeSchema,
|
|
169
|
+
required: z.boolean().optional()
|
|
170
|
+
})
|
|
171
|
+
).optional()
|
|
172
|
+
});
|
|
173
|
+
var webPresentationSchema = z.object({
|
|
174
|
+
contractVersion: z.literal(1),
|
|
175
|
+
shell: themeSiteShellSchema.optional(),
|
|
176
|
+
defaultHomeRouteId: presentationIdSchema.optional(),
|
|
177
|
+
head: themeHeadSchema.optional(),
|
|
178
|
+
assets: z.array(themeAssetSchema).optional(),
|
|
179
|
+
tokens: z.array(themeTokenSchema).optional(),
|
|
180
|
+
presets: z.array(themeTokenPresetSchema).optional(),
|
|
181
|
+
settingsSchema: themeAssetPathSchema.optional(),
|
|
182
|
+
settingsVersion: z.number().int().positive().optional(),
|
|
183
|
+
adapters: z.array(presentationAdapterSchema).optional(),
|
|
184
|
+
integrations: z.array(themeIntegrationSchema).optional()
|
|
185
|
+
}).superRefine((presentation, ctx) => {
|
|
186
|
+
const hasDeclaration = Boolean(
|
|
187
|
+
presentation.shell || presentation.defaultHomeRouteId || presentation.head || presentation.assets?.length || presentation.tokens?.length || presentation.presets?.length || presentation.settingsSchema || presentation.adapters?.length || presentation.integrations?.length
|
|
188
|
+
);
|
|
189
|
+
if (!hasDeclaration) {
|
|
190
|
+
ctx.addIssue({
|
|
191
|
+
code: "custom",
|
|
192
|
+
path: [],
|
|
193
|
+
message: "web.presentation must declare at least one presentation resource"
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
addDuplicateIdIssues(presentation.tokens, ["tokens"], ctx);
|
|
197
|
+
addDuplicateIdIssues(presentation.presets, ["presets"], ctx);
|
|
198
|
+
const adapterKeys = /* @__PURE__ */ new Set();
|
|
199
|
+
for (const [index, adapter] of (presentation.adapters ?? []).entries()) {
|
|
200
|
+
const key = `${adapter.ownerPluginId}:${adapter.surfaceId}`;
|
|
201
|
+
if (adapterKeys.has(key)) {
|
|
202
|
+
ctx.addIssue({
|
|
203
|
+
code: "custom",
|
|
204
|
+
path: ["adapters", index, "surfaceId"],
|
|
205
|
+
message: `duplicate presentation adapter target: ${key}`
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
adapterKeys.add(key);
|
|
209
|
+
}
|
|
210
|
+
validatePresetGraph(presentation.presets ?? [], ctx);
|
|
211
|
+
});
|
|
212
|
+
var presentationDiagnosticSeveritySchema = z.enum(["info", "warning", "error"]);
|
|
213
|
+
var presentationCompatibilityStatusSchema = z.enum(["compatible", "incompatible", "missing"]);
|
|
214
|
+
var presentationDiagnosticSchema = z.object({
|
|
215
|
+
code: z.string().min(1),
|
|
216
|
+
severity: presentationDiagnosticSeveritySchema,
|
|
217
|
+
ownerPluginId: presentationPluginIdSchema,
|
|
218
|
+
contractId: presentationIdSchema,
|
|
219
|
+
expectedRange: presentationContractRangeSchema.optional(),
|
|
220
|
+
actualVersion: presentationContractVersionSchema.optional(),
|
|
221
|
+
required: z.boolean(),
|
|
222
|
+
remediation: z.enum(["install", "enable", "upgrade-owner", "upgrade-theme", "disable-integration", "fallback"]),
|
|
223
|
+
message: z.string().min(1)
|
|
224
|
+
});
|
|
225
|
+
var presentationCompatibilityResultSchema = z.object({
|
|
226
|
+
status: presentationCompatibilityStatusSchema,
|
|
227
|
+
diagnostic: presentationDiagnosticSchema.optional()
|
|
228
|
+
});
|
|
229
|
+
var PRESENTATION_OBSERVABILITY = {
|
|
230
|
+
spans: {
|
|
231
|
+
resolve: "site.presentation.resolve",
|
|
232
|
+
shell: "site.presentation.shell.render",
|
|
233
|
+
adapter: "site.presentation.adapter.render",
|
|
234
|
+
storefront: "site.presentation.storefront.call",
|
|
235
|
+
designNode: "site.presentation.design-node.render",
|
|
236
|
+
embed: "site.presentation.embed.load"
|
|
237
|
+
},
|
|
238
|
+
metrics: {
|
|
239
|
+
resolution: "site_presentation_resolution_total",
|
|
240
|
+
fallback: "site_presentation_fallback_total",
|
|
241
|
+
renderDuration: "site_presentation_render_duration_ms",
|
|
242
|
+
compatibility: "site_presentation_compatibility_total"
|
|
243
|
+
},
|
|
244
|
+
auditEvents: {
|
|
245
|
+
previewIssued: "site.theme.preview.issued",
|
|
246
|
+
published: "site.theme.published",
|
|
247
|
+
rolledBack: "site.theme.rolled_back",
|
|
248
|
+
safeModeEntered: "site.theme.safe_mode.entered",
|
|
249
|
+
safeModeRecovered: "site.theme.safe_mode.recovered"
|
|
250
|
+
},
|
|
251
|
+
fields: [
|
|
252
|
+
"organizationId",
|
|
253
|
+
"themePluginId",
|
|
254
|
+
"themeVersion",
|
|
255
|
+
"revisionId",
|
|
256
|
+
"presentationMode",
|
|
257
|
+
"routeId",
|
|
258
|
+
"surfaceId",
|
|
259
|
+
"contractVersion",
|
|
260
|
+
"fallbackReason",
|
|
261
|
+
"pluginLoadGeneration"
|
|
262
|
+
]
|
|
263
|
+
};
|
|
264
|
+
function defineWebPresentation(presentation) {
|
|
265
|
+
return presentation;
|
|
266
|
+
}
|
|
267
|
+
function defineThemeHomeTarget(target) {
|
|
268
|
+
return target;
|
|
269
|
+
}
|
|
270
|
+
function definePresentationSurface(surface) {
|
|
271
|
+
return surface;
|
|
272
|
+
}
|
|
273
|
+
function definePresentationAdapter(adapter) {
|
|
274
|
+
return adapter;
|
|
275
|
+
}
|
|
276
|
+
function parsePresentationModel(value) {
|
|
277
|
+
return presentationModelSchema.parse(value);
|
|
278
|
+
}
|
|
279
|
+
function evaluatePresentationCompatibility(check) {
|
|
280
|
+
if (!check.actualVersion) {
|
|
281
|
+
return {
|
|
282
|
+
status: "missing",
|
|
283
|
+
diagnostic: {
|
|
284
|
+
code: `presentation.${check.kind ?? "surface"}.missing`,
|
|
285
|
+
severity: check.required ? "error" : "warning",
|
|
286
|
+
ownerPluginId: check.ownerPluginId,
|
|
287
|
+
contractId: check.contractId,
|
|
288
|
+
expectedRange: check.expectedRange,
|
|
289
|
+
required: check.required,
|
|
290
|
+
remediation: "install",
|
|
291
|
+
message: `Missing ${check.ownerPluginId}:${check.contractId} ${check.expectedRange}`
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (satisfiesPresentationRange(check.actualVersion, check.expectedRange)) {
|
|
296
|
+
return { status: "compatible" };
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
status: "incompatible",
|
|
300
|
+
diagnostic: {
|
|
301
|
+
code: `presentation.${check.kind ?? "surface"}.version_mismatch`,
|
|
302
|
+
severity: check.required ? "error" : "warning",
|
|
303
|
+
ownerPluginId: check.ownerPluginId,
|
|
304
|
+
contractId: check.contractId,
|
|
305
|
+
expectedRange: check.expectedRange,
|
|
306
|
+
actualVersion: check.actualVersion,
|
|
307
|
+
required: check.required,
|
|
308
|
+
remediation: check.required ? "upgrade-theme" : "fallback",
|
|
309
|
+
message: `Expected ${check.expectedRange}, received ${check.actualVersion}`
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
function satisfiesPresentationRange(version, range) {
|
|
314
|
+
const parsedVersion = parseVersion(version);
|
|
315
|
+
if (!parsedVersion) return false;
|
|
316
|
+
if (range.endsWith(".x") || range.endsWith(".*")) {
|
|
317
|
+
const prefix = range.slice(0, -2).split(".").map(Number);
|
|
318
|
+
if (prefix.some(Number.isNaN)) return false;
|
|
319
|
+
return prefix.every((part, index) => parsedVersion[index] === part);
|
|
320
|
+
}
|
|
321
|
+
const comparator = range.match(/^(\^|~|>=|<=|>|<)?(.+)$/);
|
|
322
|
+
if (!comparator) return false;
|
|
323
|
+
const operator = comparator[1] ?? "=";
|
|
324
|
+
const base = parseVersion(comparator[2] ?? "");
|
|
325
|
+
if (!base) return false;
|
|
326
|
+
const comparison = compareVersion(parsedVersion, base);
|
|
327
|
+
if (operator === "=") return comparison === 0;
|
|
328
|
+
if (operator === ">=") return comparison >= 0;
|
|
329
|
+
if (operator === "<=") return comparison <= 0;
|
|
330
|
+
if (operator === ">") return comparison > 0;
|
|
331
|
+
if (operator === "<") return comparison < 0;
|
|
332
|
+
if (comparison < 0) return false;
|
|
333
|
+
if (operator === "~") {
|
|
334
|
+
return parsedVersion[0] === base[0] && parsedVersion[1] === base[1];
|
|
335
|
+
}
|
|
336
|
+
if (base[0] > 0) return parsedVersion[0] === base[0];
|
|
337
|
+
if (base[1] > 0) return parsedVersion[0] === 0 && parsedVersion[1] === base[1];
|
|
338
|
+
return parsedVersion[0] === 0 && parsedVersion[1] === 0 && parsedVersion[2] === base[2];
|
|
339
|
+
}
|
|
340
|
+
function addDuplicateIdIssues(values, path, ctx) {
|
|
341
|
+
const ids = /* @__PURE__ */ new Set();
|
|
342
|
+
for (const [index, value] of (values ?? []).entries()) {
|
|
343
|
+
if (ids.has(value.id)) {
|
|
344
|
+
ctx.addIssue({
|
|
345
|
+
code: "custom",
|
|
346
|
+
path: [...path, index, "id"],
|
|
347
|
+
message: `duplicate presentation id: ${value.id}`
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
ids.add(value.id);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function validatePresetGraph(presets, ctx) {
|
|
354
|
+
const byId = new Map(presets.map((preset) => [preset.id, preset]));
|
|
355
|
+
for (const [index, preset] of presets.entries()) {
|
|
356
|
+
if (preset.extends && !byId.has(preset.extends)) {
|
|
357
|
+
ctx.addIssue({
|
|
358
|
+
code: "custom",
|
|
359
|
+
path: ["presets", index, "extends"],
|
|
360
|
+
message: `unknown theme token preset: ${preset.extends}`
|
|
361
|
+
});
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const visited = /* @__PURE__ */ new Set();
|
|
365
|
+
let current = preset;
|
|
366
|
+
while (current?.extends) {
|
|
367
|
+
if (visited.has(current.id)) {
|
|
368
|
+
ctx.addIssue({
|
|
369
|
+
code: "custom",
|
|
370
|
+
path: ["presets", index, "extends"],
|
|
371
|
+
message: `cyclic theme token preset inheritance: ${preset.id}`
|
|
372
|
+
});
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
visited.add(current.id);
|
|
376
|
+
current = byId.get(current.extends);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function parseVersion(value) {
|
|
381
|
+
const core = value.split("-")[0];
|
|
382
|
+
if (!core) return null;
|
|
383
|
+
const parts = core.split(".");
|
|
384
|
+
if (parts.length < 1 || parts.length > 3) return null;
|
|
385
|
+
const numbers = parts.map(Number);
|
|
386
|
+
if (numbers.some((part) => !Number.isInteger(part) || part < 0)) return null;
|
|
387
|
+
return [numbers[0] ?? 0, numbers[1] ?? 0, numbers[2] ?? 0];
|
|
388
|
+
}
|
|
389
|
+
function compareVersion(left, right) {
|
|
390
|
+
for (let index = 0; index < 3; index += 1) {
|
|
391
|
+
const difference = (left[index] ?? 0) - (right[index] ?? 0);
|
|
392
|
+
if (difference !== 0) return difference;
|
|
393
|
+
}
|
|
394
|
+
return 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/storefront.ts
|
|
398
|
+
import { z as z2 } from "zod";
|
|
399
|
+
var storefrontOperationKindSchema = z2.enum(["query", "command"]);
|
|
400
|
+
var storefrontOperationSchema = z2.object({
|
|
401
|
+
id: presentationIdSchema,
|
|
402
|
+
kind: storefrontOperationKindSchema,
|
|
403
|
+
inputSchema: presentationSchemaRefSchema,
|
|
404
|
+
outputSchema: presentationSchemaRefSchema,
|
|
405
|
+
anonymous: z2.boolean().optional(),
|
|
406
|
+
permission: z2.string().min(1).optional()
|
|
407
|
+
}).passthrough();
|
|
408
|
+
var storefrontApiSchema = z2.object({
|
|
409
|
+
id: presentationIdSchema,
|
|
410
|
+
version: presentationContractVersionSchema,
|
|
411
|
+
serverExport: z2.string().min(1),
|
|
412
|
+
browserExport: z2.string().min(1).optional(),
|
|
413
|
+
operations: z2.array(storefrontOperationSchema).min(1),
|
|
414
|
+
openapi: z2.object({
|
|
415
|
+
basePath: z2.string().regex(/^\/v\d+(?:\/[a-z0-9-]+)*$/),
|
|
416
|
+
cors: z2.enum(["site-origin", "allowlist", "disabled"]).optional()
|
|
417
|
+
}).optional()
|
|
418
|
+
}).superRefine((api, ctx) => {
|
|
419
|
+
const ids = /* @__PURE__ */ new Set();
|
|
420
|
+
for (const [index, operation] of api.operations.entries()) {
|
|
421
|
+
if (ids.has(operation.id)) {
|
|
422
|
+
ctx.addIssue({
|
|
423
|
+
code: "custom",
|
|
424
|
+
path: ["operations", index, "id"],
|
|
425
|
+
message: `duplicate Storefront operation: ${operation.id}`
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
ids.add(operation.id);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
function defineStorefrontApi(api) {
|
|
432
|
+
return api;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/web-design.ts
|
|
436
|
+
import { z as z3 } from "zod";
|
|
437
|
+
var webDesignNodeKindSchema = z3.enum(["content", "container", "app-block"]);
|
|
438
|
+
var webDesignRegionSchema = z3.object({
|
|
439
|
+
id: presentationIdSchema,
|
|
440
|
+
label: z3.string().min(1).optional(),
|
|
441
|
+
accepts: z3.array(presentationIdSchema).optional(),
|
|
442
|
+
min: z3.number().int().nonnegative().optional(),
|
|
443
|
+
max: z3.number().int().positive().optional(),
|
|
444
|
+
required: z3.boolean().optional()
|
|
445
|
+
}).superRefine((region, ctx) => {
|
|
446
|
+
if (region.min !== void 0 && region.max !== void 0 && region.min > region.max) {
|
|
447
|
+
ctx.addIssue({
|
|
448
|
+
code: "custom",
|
|
449
|
+
path: ["min"],
|
|
450
|
+
message: "Web Designer region min must not exceed max"
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
var webDesignBindingSchema = z3.object({
|
|
455
|
+
id: presentationIdSchema,
|
|
456
|
+
source: presentationIdSchema,
|
|
457
|
+
inputSchema: presentationSchemaRefSchema.optional(),
|
|
458
|
+
outputSchema: presentationSchemaRefSchema.optional()
|
|
459
|
+
});
|
|
460
|
+
var webDesignMigrationSchema = z3.object({
|
|
461
|
+
from: presentationContractVersionSchema,
|
|
462
|
+
to: presentationContractVersionSchema,
|
|
463
|
+
handler: z3.string().min(1)
|
|
464
|
+
});
|
|
465
|
+
var webDesignNodeDefinitionSchema = z3.object({
|
|
466
|
+
id: presentationIdSchema,
|
|
467
|
+
version: presentationContractVersionSchema,
|
|
468
|
+
kind: webDesignNodeKindSchema,
|
|
469
|
+
title: z3.string().min(1),
|
|
470
|
+
category: z3.string().min(1).optional(),
|
|
471
|
+
icon: z3.string().min(1).optional(),
|
|
472
|
+
settingsSchema: presentationSchemaRefSchema.optional(),
|
|
473
|
+
contextSchema: presentationSchemaRefSchema.optional(),
|
|
474
|
+
editorComponent: z3.string().min(1),
|
|
475
|
+
serverRenderer: z3.string().min(1),
|
|
476
|
+
clientComponent: z3.string().min(1).optional(),
|
|
477
|
+
regions: z3.array(webDesignRegionSchema).optional(),
|
|
478
|
+
bindings: z3.array(webDesignBindingSchema).optional(),
|
|
479
|
+
actions: z3.array(presentationIdSchema).optional(),
|
|
480
|
+
migrations: z3.array(webDesignMigrationSchema).optional()
|
|
481
|
+
}).superRefine((node, ctx) => {
|
|
482
|
+
if (node.kind === "container" && !node.regions?.length) {
|
|
483
|
+
ctx.addIssue({
|
|
484
|
+
code: "custom",
|
|
485
|
+
path: ["regions"],
|
|
486
|
+
message: "container Web Designer nodes require at least one region"
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
var webAppEmbedTargetSchema = z3.enum(["head", "body-start", "body-end", "floating-layer"]);
|
|
491
|
+
var webAppEmbedConsentSchema = z3.enum(["necessary", "functional", "analytics", "marketing"]);
|
|
492
|
+
var webAppEmbedSchema = z3.object({
|
|
493
|
+
id: presentationIdSchema,
|
|
494
|
+
version: presentationContractVersionSchema,
|
|
495
|
+
title: z3.string().min(1),
|
|
496
|
+
target: webAppEmbedTargetSchema,
|
|
497
|
+
clientComponent: z3.string().min(1),
|
|
498
|
+
settingsSchema: presentationSchemaRefSchema.optional(),
|
|
499
|
+
consent: webAppEmbedConsentSchema.optional(),
|
|
500
|
+
csp: z3.object({
|
|
501
|
+
scriptSrc: z3.array(z3.string().min(1)).optional(),
|
|
502
|
+
connectSrc: z3.array(z3.string().min(1)).optional(),
|
|
503
|
+
frameSrc: z3.array(z3.string().min(1)).optional(),
|
|
504
|
+
imgSrc: z3.array(z3.string().min(1)).optional()
|
|
505
|
+
}).optional(),
|
|
506
|
+
order: z3.number().optional()
|
|
507
|
+
});
|
|
508
|
+
function defineWebDesignNode(node) {
|
|
509
|
+
return node;
|
|
510
|
+
}
|
|
511
|
+
function defineAppEmbed(embed) {
|
|
512
|
+
return embed;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// src/manifest.ts
|
|
516
|
+
import { z as z4 } from "zod";
|
|
517
|
+
var aggregationStrategySchema = z4.enum(["none", "by_target", "by_actor", "by_type"]);
|
|
518
|
+
var notificationCategorySchema = z4.enum(["system", "collaboration", "social"]);
|
|
519
|
+
var notificationTypeSchema = z4.object({
|
|
520
|
+
id: z4.string().min(1).regex(/^[a-z0-9_]+$/, "type id must be lowercase alphanumeric with underscores"),
|
|
521
|
+
category: notificationCategorySchema,
|
|
522
|
+
aggregation: aggregationStrategySchema.default("none"),
|
|
523
|
+
i18n: z4.record(
|
|
524
|
+
z4.string(),
|
|
525
|
+
// locale key (e.g., 'en-US', 'zh-CN')
|
|
526
|
+
z4.object({
|
|
527
|
+
title: z4.string().min(1),
|
|
528
|
+
description: z4.string().optional()
|
|
529
|
+
})
|
|
530
|
+
)
|
|
531
|
+
});
|
|
532
|
+
var notificationWebhooksSchema = z4.object({
|
|
533
|
+
onClicked: z4.string().url().optional(),
|
|
534
|
+
onArchived: z4.string().url().optional()
|
|
535
|
+
}).optional();
|
|
536
|
+
var notificationRateLimitSchema = z4.object({
|
|
537
|
+
maxPerMinute: z4.number().int().positive().max(1e4).default(100),
|
|
538
|
+
maxPerHour: z4.number().int().positive().max(2e4).default(1e3),
|
|
539
|
+
maxPerDay: z4.number().int().positive().max(1e5).default(1e4)
|
|
540
|
+
}).partial();
|
|
541
|
+
var notificationPermissionSchema = z4.enum([
|
|
542
|
+
"notification:send",
|
|
543
|
+
"notification:send:batch",
|
|
544
|
+
"notification:read:own"
|
|
545
|
+
]);
|
|
546
|
+
var notificationsConfigSchema = z4.object({
|
|
547
|
+
types: z4.array(notificationTypeSchema).min(1),
|
|
548
|
+
permissions: z4.array(notificationPermissionSchema).optional(),
|
|
549
|
+
rateLimit: notificationRateLimitSchema.optional(),
|
|
550
|
+
webhooks: notificationWebhooksSchema
|
|
551
|
+
}).optional();
|
|
552
|
+
var permissionDeclarationSchema = z4.union([
|
|
553
|
+
z4.string().min(1),
|
|
554
|
+
z4.object({
|
|
555
|
+
action: z4.string().min(1),
|
|
556
|
+
subject: z4.string().min(1),
|
|
557
|
+
anonymous: z4.boolean().optional()
|
|
558
|
+
})
|
|
559
|
+
]);
|
|
560
|
+
var navTargetSchema = z4.object({
|
|
561
|
+
slot: z4.literal("nav.sidebar"),
|
|
562
|
+
path: z4.string(),
|
|
563
|
+
icon: z4.string().optional(),
|
|
564
|
+
order: z4.number().optional(),
|
|
565
|
+
permission: permissionDeclarationSchema.optional(),
|
|
566
|
+
/** @deprecated Use permission instead. */
|
|
567
|
+
requiredPermission: z4.string().optional(),
|
|
568
|
+
parent: z4.string().optional()
|
|
569
|
+
});
|
|
570
|
+
var navGroupTargetSchema = z4.object({
|
|
571
|
+
slot: z4.literal("nav.sidebar.group"),
|
|
572
|
+
path: z4.string().optional(),
|
|
573
|
+
icon: z4.string().optional(),
|
|
574
|
+
order: z4.number().optional()
|
|
575
|
+
});
|
|
576
|
+
var routeTargetSchema = z4.object({
|
|
577
|
+
slot: z4.literal("plugin.route"),
|
|
578
|
+
path: z4.string(),
|
|
579
|
+
order: z4.number().optional(),
|
|
580
|
+
params: z4.record(z4.string(), z4.string()).optional()
|
|
581
|
+
});
|
|
582
|
+
var marketplaceTabTargetSchema = z4.object({
|
|
583
|
+
slot: z4.literal("marketplace.tabs"),
|
|
584
|
+
value: z4.string().min(1).regex(/^[a-z0-9][a-z0-9._-]*$/, "marketplace tab value must be URL-safe"),
|
|
585
|
+
order: z4.number().optional(),
|
|
586
|
+
visibility: z4.enum(["platform", "all"]).optional()
|
|
587
|
+
});
|
|
588
|
+
var settingsTargetSchema = z4.object({
|
|
589
|
+
slot: z4.literal("settings.plugin"),
|
|
590
|
+
category: z4.string().optional(),
|
|
591
|
+
order: z4.number().optional(),
|
|
592
|
+
visibility: z4.enum(["platform", "all"]).optional()
|
|
593
|
+
});
|
|
594
|
+
var dashboardTargetSchema = z4.object({
|
|
595
|
+
slot: z4.enum(["dashboard.widgets", "dashboard.overview"]),
|
|
596
|
+
order: z4.number().optional(),
|
|
597
|
+
colSpan: z4.union([z4.literal(1), z4.literal(2), z4.literal(3), z4.literal(4)]).optional()
|
|
598
|
+
});
|
|
599
|
+
var genericTargetSchema = z4.object({
|
|
600
|
+
slot: z4.string(),
|
|
601
|
+
order: z4.number().optional()
|
|
602
|
+
});
|
|
603
|
+
var targetSchema = z4.union([
|
|
604
|
+
navTargetSchema,
|
|
605
|
+
navGroupTargetSchema,
|
|
606
|
+
routeTargetSchema,
|
|
607
|
+
marketplaceTabTargetSchema,
|
|
608
|
+
settingsTargetSchema,
|
|
609
|
+
dashboardTargetSchema,
|
|
610
|
+
genericTargetSchema
|
|
611
|
+
]);
|
|
612
|
+
var adminExtensionSchema = z4.object({
|
|
613
|
+
id: z4.string().min(1),
|
|
614
|
+
label: z4.string().min(1),
|
|
615
|
+
icon: z4.string().optional(),
|
|
616
|
+
hidden: z4.boolean().optional(),
|
|
617
|
+
targets: z4.array(targetSchema).min(1)
|
|
618
|
+
});
|
|
619
|
+
var adminSlotPropSchema = z4.union([
|
|
620
|
+
z4.string().min(1),
|
|
621
|
+
z4.object({
|
|
622
|
+
name: z4.string().min(1),
|
|
623
|
+
type: z4.string().optional(),
|
|
624
|
+
required: z4.boolean().optional(),
|
|
625
|
+
description: z4.string().optional()
|
|
626
|
+
}).passthrough()
|
|
627
|
+
]);
|
|
628
|
+
var adminSlotSchema = z4.object({
|
|
629
|
+
slot: z4.string().min(1),
|
|
630
|
+
description: z4.string().optional(),
|
|
631
|
+
props: z4.array(adminSlotPropSchema).optional()
|
|
632
|
+
}).passthrough();
|
|
633
|
+
var adminTourPlacementSchema = z4.enum([
|
|
634
|
+
"top",
|
|
635
|
+
"top-start",
|
|
636
|
+
"top-end",
|
|
637
|
+
"bottom",
|
|
638
|
+
"bottom-start",
|
|
639
|
+
"bottom-end",
|
|
640
|
+
"left",
|
|
641
|
+
"left-start",
|
|
642
|
+
"left-end",
|
|
643
|
+
"right",
|
|
644
|
+
"right-start",
|
|
645
|
+
"right-end",
|
|
646
|
+
"auto",
|
|
647
|
+
"center"
|
|
648
|
+
]);
|
|
649
|
+
var adminTourStepSchema = z4.object({
|
|
650
|
+
target: z4.string().min(1),
|
|
651
|
+
title: z4.string().min(1).optional(),
|
|
652
|
+
titleKey: z4.string().min(1).optional(),
|
|
653
|
+
content: z4.string().min(1).optional(),
|
|
654
|
+
contentKey: z4.string().min(1).optional(),
|
|
655
|
+
placement: adminTourPlacementSchema.optional()
|
|
656
|
+
}).refine((step) => Boolean(step.content || step.contentKey), {
|
|
657
|
+
message: "admin tour step must define content or contentKey",
|
|
658
|
+
path: ["content"]
|
|
659
|
+
});
|
|
660
|
+
var adminTourSchema = z4.object({
|
|
661
|
+
id: z4.string().min(1),
|
|
662
|
+
label: z4.string().min(1).optional(),
|
|
663
|
+
labelKey: z4.string().min(1).optional(),
|
|
664
|
+
routePatterns: z4.array(z4.string().min(1)).optional(),
|
|
665
|
+
order: z4.number().optional(),
|
|
666
|
+
steps: z4.array(adminTourStepSchema).min(1)
|
|
667
|
+
});
|
|
668
|
+
var pluginTranslationRecordSchema = z4.record(z4.string().min(1), z4.string());
|
|
669
|
+
function normalizeLocaleRecord(value, ctx) {
|
|
670
|
+
const normalized = {};
|
|
671
|
+
for (const [rawLocale, message] of Object.entries(value)) {
|
|
672
|
+
const locale = canonicalizeLocale(rawLocale);
|
|
673
|
+
if (!locale) {
|
|
674
|
+
ctx.addIssue({
|
|
675
|
+
code: "custom",
|
|
676
|
+
path: [rawLocale],
|
|
677
|
+
message: `Invalid BCP 47 locale: ${rawLocale}`
|
|
678
|
+
});
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
if (locale in normalized && normalized[locale] !== message) {
|
|
682
|
+
ctx.addIssue({
|
|
683
|
+
code: "custom",
|
|
684
|
+
path: [rawLocale],
|
|
685
|
+
message: `Duplicate canonical locale: ${locale}`
|
|
686
|
+
});
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
normalized[locale] = message;
|
|
690
|
+
}
|
|
691
|
+
return normalized;
|
|
692
|
+
}
|
|
693
|
+
var pluginKeyFirstMessagesSchema = z4.record(
|
|
694
|
+
z4.string().min(1),
|
|
695
|
+
pluginTranslationRecordSchema.transform(normalizeLocaleRecord)
|
|
696
|
+
);
|
|
697
|
+
var pluginLocaleFirstMessagesSchema = z4.record(
|
|
698
|
+
z4.string(),
|
|
699
|
+
pluginTranslationRecordSchema
|
|
700
|
+
).transform((value, ctx) => {
|
|
701
|
+
const normalized = {};
|
|
702
|
+
for (const [rawLocale, messages] of Object.entries(value)) {
|
|
703
|
+
const locale = canonicalizeLocale(rawLocale);
|
|
704
|
+
if (!locale) {
|
|
705
|
+
ctx.addIssue({
|
|
706
|
+
code: "custom",
|
|
707
|
+
path: [rawLocale],
|
|
708
|
+
message: `Invalid BCP 47 locale: ${rawLocale}`
|
|
709
|
+
});
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
if (locale in normalized) {
|
|
713
|
+
ctx.addIssue({
|
|
714
|
+
code: "custom",
|
|
715
|
+
path: [rawLocale],
|
|
716
|
+
message: `Duplicate canonical locale: ${locale}`
|
|
717
|
+
});
|
|
718
|
+
continue;
|
|
719
|
+
}
|
|
720
|
+
normalized[locale] = messages;
|
|
721
|
+
}
|
|
722
|
+
return normalized;
|
|
723
|
+
});
|
|
724
|
+
var pluginI18nConfigSchema = z4.object({
|
|
725
|
+
namespace: z4.string().min(1).optional(),
|
|
726
|
+
messages: pluginKeyFirstMessagesSchema.optional(),
|
|
727
|
+
localesFile: z4.string().min(1).optional(),
|
|
728
|
+
onUninstall: z4.enum(["delete", "archive", "retain"]).optional()
|
|
729
|
+
}).strict();
|
|
730
|
+
var pluginI18nSchema = z4.union([
|
|
731
|
+
pluginLocaleFirstMessagesSchema,
|
|
732
|
+
pluginI18nConfigSchema
|
|
733
|
+
]);
|
|
734
|
+
var extensionTargetPluginIdSchema = z4.string().min(1).max(160).regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, "target pluginId must be reverse-domain format");
|
|
735
|
+
var crudIdSchema = z4.string().min(1).max(80).regex(/^[a-zA-Z][a-zA-Z0-9_-]*$/, "crud id must be an identifier");
|
|
736
|
+
var entityNameSchema = z4.string().min(1).max(160).regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, 'entity must be dot-separated (e.g., "shop.store")');
|
|
737
|
+
var extensionFieldNameSchema = z4.string().min(1).max(80).regex(/^[a-zA-Z][a-zA-Z0-9_]*$/, "field must be an identifier");
|
|
738
|
+
var entityExtensionFieldTypeSchema = z4.enum([
|
|
739
|
+
"text",
|
|
740
|
+
"number",
|
|
741
|
+
"boolean",
|
|
742
|
+
"date",
|
|
743
|
+
"datetime",
|
|
744
|
+
"select",
|
|
745
|
+
"ref",
|
|
746
|
+
"json"
|
|
747
|
+
]);
|
|
748
|
+
var entityExtensionRefSchema = z4.object({
|
|
749
|
+
entity: entityNameSchema,
|
|
750
|
+
display: z4.string().min(1).optional(),
|
|
751
|
+
changed: z4.string().min(1).optional()
|
|
752
|
+
}).passthrough();
|
|
753
|
+
var autoCrudFieldOptionSchema = z4.object({
|
|
754
|
+
label: z4.string().min(1),
|
|
755
|
+
value: z4.string().min(1),
|
|
756
|
+
searchText: z4.union([
|
|
757
|
+
z4.string().min(1),
|
|
758
|
+
z4.array(z4.string().min(1))
|
|
759
|
+
]).optional(),
|
|
760
|
+
count: z4.number().optional(),
|
|
761
|
+
disabled: z4.boolean().optional()
|
|
762
|
+
}).passthrough();
|
|
763
|
+
var autoCrudDataSourceSchema = z4.string().min(1);
|
|
764
|
+
var autoCrudFieldConfigSchema = z4.object({
|
|
765
|
+
label: z4.string().min(1).optional(),
|
|
766
|
+
enum: z4.array(autoCrudFieldOptionSchema).optional(),
|
|
767
|
+
dataSource: autoCrudDataSourceSchema.optional(),
|
|
768
|
+
hidden: z4.boolean().optional(),
|
|
769
|
+
table: z4.union([z4.literal(false), z4.record(z4.string(), z4.unknown())]).optional(),
|
|
770
|
+
filter: z4.union([z4.literal(false), z4.record(z4.string(), z4.unknown())]).optional(),
|
|
771
|
+
form: z4.union([z4.literal(false), z4.record(z4.string(), z4.unknown())]).optional(),
|
|
772
|
+
search: z4.boolean().optional()
|
|
773
|
+
}).passthrough();
|
|
774
|
+
var entityExtensionOwnedFieldSchema = autoCrudFieldConfigSchema.extend({
|
|
775
|
+
label: z4.string().min(1),
|
|
776
|
+
type: entityExtensionFieldTypeSchema,
|
|
777
|
+
ref: entityExtensionRefSchema.optional()
|
|
778
|
+
});
|
|
779
|
+
var entityExtensionFieldSchema = z4.union([
|
|
780
|
+
entityExtensionOwnedFieldSchema,
|
|
781
|
+
autoCrudFieldConfigSchema
|
|
782
|
+
]);
|
|
783
|
+
var autoCrudActionZoneSchema = z4.enum(["toolbar", "row", "batch"]);
|
|
784
|
+
var autoCrudActionSchema = z4.object({
|
|
785
|
+
type: z4.enum([
|
|
786
|
+
"create",
|
|
787
|
+
"import",
|
|
788
|
+
"export",
|
|
789
|
+
"view",
|
|
790
|
+
"edit",
|
|
791
|
+
"copy",
|
|
792
|
+
"delete",
|
|
793
|
+
"batchUpdate",
|
|
794
|
+
"custom"
|
|
795
|
+
]),
|
|
796
|
+
id: z4.string().min(1).optional(),
|
|
797
|
+
label: z4.string().min(1).optional(),
|
|
798
|
+
component: z4.string().min(1).optional(),
|
|
799
|
+
onClick: z4.string().min(1).optional(),
|
|
800
|
+
order: z4.number().optional(),
|
|
801
|
+
hidden: z4.boolean().optional(),
|
|
802
|
+
position: z4.enum(["start", "end"]).optional(),
|
|
803
|
+
variant: z4.enum(["default", "destructive"]).optional()
|
|
804
|
+
}).passthrough();
|
|
805
|
+
var autoCrudActionsSchema = z4.object({
|
|
806
|
+
toolbar: z4.array(autoCrudActionSchema).optional(),
|
|
807
|
+
row: z4.array(autoCrudActionSchema).optional(),
|
|
808
|
+
batch: z4.array(autoCrudActionSchema).optional()
|
|
809
|
+
}).passthrough();
|
|
810
|
+
var entityExtensionCrudConfigSchema = z4.object({
|
|
811
|
+
fields: z4.record(extensionFieldNameSchema, entityExtensionFieldSchema).optional(),
|
|
812
|
+
actions: autoCrudActionsSchema.optional()
|
|
813
|
+
}).passthrough();
|
|
814
|
+
var entityExtensionSlotSchema = z4.object({
|
|
815
|
+
slot: z4.string().min(1),
|
|
816
|
+
component: z4.string().min(1),
|
|
817
|
+
order: z4.number().optional(),
|
|
818
|
+
label: z4.string().optional()
|
|
819
|
+
}).passthrough();
|
|
820
|
+
var entityExtensionBaseSchema = z4.object({
|
|
821
|
+
fields: z4.record(
|
|
822
|
+
crudIdSchema,
|
|
823
|
+
z4.record(extensionFieldNameSchema, entityExtensionFieldSchema)
|
|
824
|
+
).optional(),
|
|
825
|
+
slots: z4.array(entityExtensionSlotSchema).optional(),
|
|
826
|
+
hide: z4.record(crudIdSchema, z4.array(extensionFieldNameSchema)).optional()
|
|
827
|
+
}).passthrough();
|
|
828
|
+
var entityExtensionSchema = entityExtensionBaseSchema.superRefine((extension, ctx) => {
|
|
829
|
+
const reservedKeys = /* @__PURE__ */ new Set(["fields", "slots", "hide"]);
|
|
830
|
+
for (const [key, value] of Object.entries(extension)) {
|
|
831
|
+
if (reservedKeys.has(key)) continue;
|
|
832
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) continue;
|
|
833
|
+
const record = value;
|
|
834
|
+
if (!("fields" in record) && !("actions" in record)) continue;
|
|
835
|
+
const parsed = entityExtensionCrudConfigSchema.safeParse(value);
|
|
836
|
+
if (!parsed.success) {
|
|
837
|
+
for (const issue of parsed.error.issues) {
|
|
838
|
+
ctx.addIssue({
|
|
839
|
+
...issue,
|
|
840
|
+
path: [key, ...issue.path]
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
var entityExtensionUseSchema = z4.object({
|
|
847
|
+
pluginId: z4.string().regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, "pluginId must be reverse-domain format"),
|
|
848
|
+
targetId: z4.string().min(1).max(240),
|
|
849
|
+
field: extensionFieldNameSchema,
|
|
850
|
+
required: z4.boolean().optional()
|
|
851
|
+
}).passthrough();
|
|
852
|
+
var pluginUsesSchema = z4.object({
|
|
853
|
+
extensions: z4.array(entityExtensionUseSchema).optional()
|
|
854
|
+
}).passthrough();
|
|
855
|
+
var webSsrContractVersionSchema = z4.union([z4.literal(1), z4.literal("1")]);
|
|
856
|
+
var webPluginRouteSchema = z4.object({
|
|
857
|
+
id: z4.string().min(1).optional(),
|
|
858
|
+
path: z4.string().min(1).regex(/^\//, "web route path must start with /"),
|
|
859
|
+
handler: z4.string().min(1).optional(),
|
|
860
|
+
component: z4.string().min(1),
|
|
861
|
+
permission: permissionDeclarationSchema.optional(),
|
|
862
|
+
order: z4.number().optional()
|
|
863
|
+
}).passthrough();
|
|
864
|
+
var webExtensionTargetSchema = z4.object({
|
|
865
|
+
pluginId: extensionTargetPluginIdSchema,
|
|
866
|
+
slot: z4.string().min(1),
|
|
867
|
+
permission: permissionDeclarationSchema.optional(),
|
|
868
|
+
order: z4.number().optional()
|
|
869
|
+
}).passthrough();
|
|
870
|
+
var webExtensionQuerySchema = z4.object({
|
|
871
|
+
id: z4.string().min(1),
|
|
872
|
+
procedure: z4.string().min(1),
|
|
873
|
+
inputFrom: z4.enum(["slotProps", "static"]).optional(),
|
|
874
|
+
staticInput: z4.record(z4.string(), z4.unknown()).optional()
|
|
875
|
+
}).passthrough();
|
|
876
|
+
var webExtensionSchema = z4.object({
|
|
877
|
+
id: z4.string().min(1),
|
|
878
|
+
label: z4.string().min(1).optional(),
|
|
879
|
+
component: z4.string().min(1),
|
|
880
|
+
expose: z4.string().min(1).optional(),
|
|
881
|
+
permission: permissionDeclarationSchema.optional(),
|
|
882
|
+
targets: z4.array(webExtensionTargetSchema).min(1),
|
|
883
|
+
queries: z4.array(webExtensionQuerySchema).optional()
|
|
884
|
+
}).passthrough();
|
|
885
|
+
var webDesignBlockSchema = z4.object({
|
|
886
|
+
id: z4.string().min(1),
|
|
887
|
+
component: z4.string().min(1),
|
|
888
|
+
title: z4.string().min(1).optional(),
|
|
889
|
+
/** @deprecated Use title instead. */
|
|
890
|
+
label: z4.string().min(1).optional(),
|
|
891
|
+
category: z4.string().min(1).optional(),
|
|
892
|
+
icon: z4.string().min(1).optional(),
|
|
893
|
+
defaultProps: z4.record(z4.string(), z4.unknown()).optional(),
|
|
894
|
+
previewProps: z4.record(z4.string(), z4.unknown()).optional(),
|
|
895
|
+
propsSchema: z4.record(z4.string(), z4.unknown()).optional(),
|
|
896
|
+
settingsSchema: z4.record(z4.string(), z4.unknown()).optional(),
|
|
897
|
+
designable: z4.object({
|
|
898
|
+
resource: z4.record(z4.string(), z4.unknown()).optional(),
|
|
899
|
+
behavior: z4.record(z4.string(), z4.unknown()).optional()
|
|
900
|
+
}).optional(),
|
|
901
|
+
previewImage: z4.string().min(1).optional(),
|
|
902
|
+
order: z4.number().optional()
|
|
903
|
+
}).passthrough().superRefine((block, ctx) => {
|
|
904
|
+
if ("schema" in block) {
|
|
905
|
+
ctx.addIssue({
|
|
906
|
+
code: "custom",
|
|
907
|
+
path: ["schema"],
|
|
908
|
+
message: "web.design.blocks[] must not declare platform schema; use propsSchema/settingsSchema for configuration metadata"
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
if (!block.title && !block.label) {
|
|
912
|
+
ctx.addIssue({
|
|
913
|
+
code: "custom",
|
|
914
|
+
path: ["title"],
|
|
915
|
+
message: "web.design.blocks[] must define title or label"
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
var webDesignSlotSchema = z4.object({
|
|
920
|
+
id: z4.string().min(1),
|
|
921
|
+
label: z4.string().min(1).optional(),
|
|
922
|
+
renderMode: z4.enum(["island", "react"]).optional(),
|
|
923
|
+
scope: z4.enum(["site", "route", "template", "entity"]).optional(),
|
|
924
|
+
routeId: z4.string().min(1).optional(),
|
|
925
|
+
templateId: z4.string().min(1).optional(),
|
|
926
|
+
acceptedBlocks: z4.array(z4.string().min(1)).optional(),
|
|
927
|
+
order: z4.number().optional()
|
|
928
|
+
}).passthrough();
|
|
929
|
+
var webDesignTemplateSchema = z4.object({
|
|
930
|
+
id: z4.string().min(1),
|
|
931
|
+
label: z4.string().min(1).optional(),
|
|
932
|
+
routeId: z4.string().min(1).optional(),
|
|
933
|
+
entityType: z4.string().min(1).optional(),
|
|
934
|
+
component: z4.string().min(1),
|
|
935
|
+
slots: z4.array(z4.string().min(1)).optional(),
|
|
936
|
+
order: z4.number().optional()
|
|
937
|
+
}).passthrough();
|
|
938
|
+
var webDesignDataSourceSchema = z4.object({
|
|
939
|
+
id: z4.string().min(1),
|
|
940
|
+
title: z4.string().min(1).optional(),
|
|
941
|
+
/** @deprecated Use title instead. */
|
|
942
|
+
label: z4.string().min(1).optional(),
|
|
943
|
+
permission: permissionDeclarationSchema.optional(),
|
|
944
|
+
inputSchema: z4.record(z4.string(), z4.unknown()).optional(),
|
|
945
|
+
outputSchema: z4.record(z4.string(), z4.unknown()).optional(),
|
|
946
|
+
order: z4.number().optional()
|
|
947
|
+
}).passthrough().superRefine((dataSource, ctx) => {
|
|
948
|
+
if (!dataSource.title && !dataSource.label) {
|
|
949
|
+
ctx.addIssue({
|
|
950
|
+
code: "custom",
|
|
951
|
+
path: ["title"],
|
|
952
|
+
message: "web.design.dataSources[] must define title or label"
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
var webDesignActionSchema = z4.object({
|
|
957
|
+
id: z4.string().min(1),
|
|
958
|
+
title: z4.string().min(1).optional(),
|
|
959
|
+
/** @deprecated Use title instead. */
|
|
960
|
+
label: z4.string().min(1).optional(),
|
|
961
|
+
permission: permissionDeclarationSchema.optional(),
|
|
962
|
+
inputSchema: z4.record(z4.string(), z4.unknown()).optional(),
|
|
963
|
+
order: z4.number().optional()
|
|
964
|
+
}).passthrough().superRefine((action, ctx) => {
|
|
965
|
+
if (!action.title && !action.label) {
|
|
966
|
+
ctx.addIssue({
|
|
967
|
+
code: "custom",
|
|
968
|
+
path: ["title"],
|
|
969
|
+
message: "web.design.actions[] must define title or label"
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
});
|
|
973
|
+
var webDesignSurfaceSchema = z4.object({
|
|
974
|
+
editorEntry: z4.string().min(1).optional(),
|
|
975
|
+
previewEntry: z4.string().min(1).optional(),
|
|
976
|
+
blocks: z4.array(webDesignBlockSchema).optional(),
|
|
977
|
+
nodes: z4.array(webDesignNodeDefinitionSchema).optional(),
|
|
978
|
+
slots: z4.array(webDesignSlotSchema).optional(),
|
|
979
|
+
templates: z4.array(webDesignTemplateSchema).optional(),
|
|
980
|
+
dataSources: z4.array(webDesignDataSourceSchema).optional(),
|
|
981
|
+
actions: z4.array(webDesignActionSchema).optional(),
|
|
982
|
+
embeds: z4.array(webAppEmbedSchema).optional()
|
|
983
|
+
}).superRefine((design, ctx) => {
|
|
984
|
+
const hasDesignSurface = Boolean(
|
|
985
|
+
design.blocks?.length || design.nodes?.length || design.slots?.length || design.templates?.length || design.dataSources?.length || design.actions?.length || design.embeds?.length
|
|
986
|
+
);
|
|
987
|
+
if (!hasDesignSurface) {
|
|
988
|
+
ctx.addIssue({
|
|
989
|
+
code: "custom",
|
|
990
|
+
path: [],
|
|
991
|
+
message: "web.design must declare at least one block, slot, template, dataSource, or action"
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
for (const [field, values] of [
|
|
995
|
+
["blocks", design.blocks],
|
|
996
|
+
["nodes", design.nodes],
|
|
997
|
+
["slots", design.slots],
|
|
998
|
+
["templates", design.templates],
|
|
999
|
+
["dataSources", design.dataSources],
|
|
1000
|
+
["actions", design.actions],
|
|
1001
|
+
["embeds", design.embeds]
|
|
1002
|
+
]) {
|
|
1003
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1004
|
+
for (const [index, value] of (values ?? []).entries()) {
|
|
1005
|
+
if (ids.has(value.id)) {
|
|
1006
|
+
ctx.addIssue({
|
|
1007
|
+
code: "custom",
|
|
1008
|
+
path: [field, index, "id"],
|
|
1009
|
+
message: `duplicate web.design.${field} id: ${value.id}`
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
ids.add(value.id);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
var webSurfaceSchema = z4.object({
|
|
1017
|
+
ssrContractVersion: webSsrContractVersionSchema.optional(),
|
|
1018
|
+
serverEntry: z4.string().min(1).optional(),
|
|
1019
|
+
clientEntry: z4.string().min(1).optional(),
|
|
1020
|
+
remoteEntry: z4.string().min(1).optional(),
|
|
1021
|
+
devRemoteEntry: z4.string().min(1).optional(),
|
|
1022
|
+
moduleName: z4.string().min(1).optional(),
|
|
1023
|
+
exposes: z4.record(z4.string(), z4.string()).optional(),
|
|
1024
|
+
routes: z4.array(webPluginRouteSchema).optional(),
|
|
1025
|
+
fills: z4.never().optional(),
|
|
1026
|
+
extensions: z4.array(webExtensionSchema).optional(),
|
|
1027
|
+
design: webDesignSurfaceSchema.optional(),
|
|
1028
|
+
/** Standalone feature presentation adapters supplied by a Presentation Pack. */
|
|
1029
|
+
adapters: z4.array(presentationAdapterSchema).optional(),
|
|
1030
|
+
surfaces: z4.array(presentationSurfaceSchema).optional(),
|
|
1031
|
+
storefrontApis: z4.array(storefrontApiSchema).optional(),
|
|
1032
|
+
presentation: webPresentationSchema.optional(),
|
|
1033
|
+
/** @deprecated Use serverEntry/clientEntry plus routes[].handler/component. */
|
|
1034
|
+
entry: z4.string().optional(),
|
|
1035
|
+
/** @deprecated Use routes[].component. */
|
|
1036
|
+
components: z4.array(z4.string()).optional()
|
|
1037
|
+
}).superRefine((web, ctx) => {
|
|
1038
|
+
const hasRoutes = Boolean(web.routes?.length);
|
|
1039
|
+
const hasExtensions = Boolean(web.extensions?.length);
|
|
1040
|
+
const hasSurfaceServerRenderers = Boolean(web.surfaces?.some((surface) => surface.defaultRenderer));
|
|
1041
|
+
const hasStorefrontServerExports = Boolean(web.storefrontApis?.some((api) => api.serverExport));
|
|
1042
|
+
const hasPresentationServerRenderers = Boolean(
|
|
1043
|
+
typeof web.presentation?.shell === "string" || web.presentation?.shell?.serverRenderer || web.presentation?.adapters?.some((adapter) => adapter.serverRenderer) || web.adapters?.some((adapter) => adapter.serverRenderer)
|
|
1044
|
+
);
|
|
1045
|
+
const hasPresentationClientComponents = Boolean(
|
|
1046
|
+
typeof web.presentation?.shell === "object" && web.presentation.shell.clientComponent || web.presentation?.adapters?.some((adapter) => adapter.clientComponent) || web.adapters?.some((adapter) => adapter.clientComponent)
|
|
1047
|
+
);
|
|
1048
|
+
const usesSsrSurface = Boolean(
|
|
1049
|
+
web.ssrContractVersion || web.serverEntry || web.clientEntry || hasRoutes || hasSurfaceServerRenderers || hasStorefrontServerExports || hasPresentationServerRenderers
|
|
1050
|
+
);
|
|
1051
|
+
const usesRemoteSurface = Boolean(
|
|
1052
|
+
web.remoteEntry || web.devRemoteEntry || web.moduleName || web.exposes || hasExtensions || hasPresentationClientComponents || web.storefrontApis?.some((api) => api.browserExport)
|
|
1053
|
+
);
|
|
1054
|
+
if (!usesSsrSurface && !usesRemoteSurface) return;
|
|
1055
|
+
if (hasRoutes && !web.ssrContractVersion) {
|
|
1056
|
+
ctx.addIssue({
|
|
1057
|
+
code: "custom",
|
|
1058
|
+
path: ["ssrContractVersion"],
|
|
1059
|
+
message: "web.ssrContractVersion is required for SSR web surface"
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
if ((hasRoutes || hasSurfaceServerRenderers || hasStorefrontServerExports || hasPresentationServerRenderers) && !web.serverEntry) {
|
|
1063
|
+
ctx.addIssue({
|
|
1064
|
+
code: "custom",
|
|
1065
|
+
path: ["serverEntry"],
|
|
1066
|
+
message: "web.serverEntry is required for server-rendered web declarations"
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
if ((hasExtensions || hasPresentationClientComponents || web.storefrontApis?.some((api) => api.browserExport)) && !web.remoteEntry) {
|
|
1070
|
+
ctx.addIssue({
|
|
1071
|
+
code: "custom",
|
|
1072
|
+
path: ["remoteEntry"],
|
|
1073
|
+
message: "web.remoteEntry is required for public Web remote components or clients"
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
for (const [index, route] of (web.routes ?? []).entries()) {
|
|
1077
|
+
if (!route.id) {
|
|
1078
|
+
ctx.addIssue({
|
|
1079
|
+
code: "custom",
|
|
1080
|
+
path: ["routes", index, "id"],
|
|
1081
|
+
message: "web.routes[].id is required for SSR web surface"
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
if (!route.handler) {
|
|
1085
|
+
ctx.addIssue({
|
|
1086
|
+
code: "custom",
|
|
1087
|
+
path: ["routes", index, "handler"],
|
|
1088
|
+
message: "web.routes[].handler is required for SSR web surface"
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
if (!route.permission) {
|
|
1092
|
+
ctx.addIssue({
|
|
1093
|
+
code: "custom",
|
|
1094
|
+
path: ["routes", index, "permission"],
|
|
1095
|
+
message: "web.routes[].permission is required for SSR web surface"
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
for (const [field, values] of [
|
|
1100
|
+
["adapters", web.adapters],
|
|
1101
|
+
["surfaces", web.surfaces],
|
|
1102
|
+
["storefrontApis", web.storefrontApis]
|
|
1103
|
+
]) {
|
|
1104
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1105
|
+
for (const [index, value] of (values ?? []).entries()) {
|
|
1106
|
+
const id = value.id;
|
|
1107
|
+
if (!id) continue;
|
|
1108
|
+
if (ids.has(id)) {
|
|
1109
|
+
ctx.addIssue({
|
|
1110
|
+
code: "custom",
|
|
1111
|
+
path: [field, index, "id"],
|
|
1112
|
+
message: `duplicate web.${field} id: ${id}`
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
ids.add(id);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
const adapterTargets = /* @__PURE__ */ new Set();
|
|
1119
|
+
for (const [field, adapters] of [
|
|
1120
|
+
["presentation.adapters", web.presentation?.adapters],
|
|
1121
|
+
["adapters", web.adapters]
|
|
1122
|
+
]) {
|
|
1123
|
+
for (const [index, adapter] of (adapters ?? []).entries()) {
|
|
1124
|
+
const key = `${adapter.ownerPluginId}:${adapter.surfaceId}`;
|
|
1125
|
+
if (adapterTargets.has(key)) {
|
|
1126
|
+
ctx.addIssue({
|
|
1127
|
+
code: "custom",
|
|
1128
|
+
path: [field, index, "surfaceId"],
|
|
1129
|
+
message: `duplicate presentation adapter target across theme and pack declarations: ${key}`
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
adapterTargets.add(key);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
var pluginManifestSchema = z4.object({
|
|
1137
|
+
// === Identity ===
|
|
1138
|
+
pluginId: z4.string().regex(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/, "pluginId must be reverse-domain format (e.g., com.vendor.plugin-name)"),
|
|
1139
|
+
version: z4.string().regex(/^\d+\.\d+\.\d+/, "version must be semver format"),
|
|
1140
|
+
name: z4.string().min(1).max(100),
|
|
1141
|
+
description: z4.string().max(500).optional(),
|
|
1142
|
+
vendor: z4.string().min(1).max(100),
|
|
1143
|
+
private: z4.boolean().optional(),
|
|
1144
|
+
type: z4.enum(["backend", "frontend", "full", "extension", "integration", "feature"]).optional(),
|
|
1145
|
+
// === UI Translations ===
|
|
1146
|
+
// Locale -> { key: translated text }. Stored under namespace `plugin.{pluginId}`.
|
|
1147
|
+
i18n: pluginI18nSchema.optional(),
|
|
1148
|
+
// === Runtime ===
|
|
1149
|
+
runtime: z4.enum(["node"]).default("node"),
|
|
1150
|
+
// Note: surfaces is auto-generated from server/admin/web presence
|
|
1151
|
+
// Used by plugin marketplace for filtering
|
|
1152
|
+
// === Compatibility ===
|
|
1153
|
+
engines: z4.object({
|
|
1154
|
+
wordrhyme: z4.string(),
|
|
1155
|
+
// semver range, e.g., "^0.1.0"
|
|
1156
|
+
node: z4.string().optional()
|
|
1157
|
+
// e.g., ">=20.0.0"
|
|
1158
|
+
}),
|
|
1159
|
+
// === Capabilities Declared ===
|
|
1160
|
+
capabilities: z4.object({
|
|
1161
|
+
ui: z4.object({
|
|
1162
|
+
adminPage: z4.boolean().optional(),
|
|
1163
|
+
webPage: z4.boolean().optional(),
|
|
1164
|
+
webTheme: z4.boolean().optional(),
|
|
1165
|
+
webPresentationPack: z4.boolean().optional(),
|
|
1166
|
+
webDesigner: z4.boolean().optional(),
|
|
1167
|
+
settingsTab: z4.boolean().optional()
|
|
1168
|
+
}).optional(),
|
|
1169
|
+
storage: z4.object({
|
|
1170
|
+
provider: z4.boolean().optional()
|
|
1171
|
+
}).optional(),
|
|
1172
|
+
artifacts: z4.object({
|
|
1173
|
+
write: z4.boolean().optional()
|
|
1174
|
+
}).optional(),
|
|
1175
|
+
/**
|
|
1176
|
+
* Agent capability (AI Action Gateway, Phase 0 spike).
|
|
1177
|
+
* Static whitelist declarations reconciled by the Host at load time:
|
|
1178
|
+
* - `runtime: true` — this plugin hosts the agent runtime and may read
|
|
1179
|
+
* the Core agent tool registry (gated capability injection).
|
|
1180
|
+
* - `tools` — tools this plugin contributes to the AI Tool Catalog.
|
|
1181
|
+
* Declaration only; undeclared tools never become visible.
|
|
1182
|
+
*/
|
|
1183
|
+
agent: z4.object({
|
|
1184
|
+
runtime: z4.boolean().optional(),
|
|
1185
|
+
/** Governed action invoker access (ActionInvokerCapability, ctx.actions). */
|
|
1186
|
+
invoker: z4.boolean().optional(),
|
|
1187
|
+
tools: z4.array(z4.object({
|
|
1188
|
+
id: z4.string().min(1).regex(
|
|
1189
|
+
/^[a-z0-9-]+(\.[a-z0-9-]+)*$/,
|
|
1190
|
+
'tool id must be lowercase dot-separated (e.g., "canvas.add-node")'
|
|
1191
|
+
),
|
|
1192
|
+
title: z4.string().min(1),
|
|
1193
|
+
summary: z4.string().optional()
|
|
1194
|
+
})).optional()
|
|
1195
|
+
}).optional(),
|
|
1196
|
+
/** Governed AI generation metadata and the reserved official Runtime boundary. */
|
|
1197
|
+
ai: z4.object({
|
|
1198
|
+
aliases: z4.array(z4.object({
|
|
1199
|
+
id: z4.string().min(1).max(80).regex(
|
|
1200
|
+
/^[a-z0-9][a-z0-9._-]{0,79}$/,
|
|
1201
|
+
"AI alias must be lowercase and may contain dots, underscores, or hyphens"
|
|
1202
|
+
),
|
|
1203
|
+
name: z4.string().min(1).max(80),
|
|
1204
|
+
description: z4.string().max(240).optional()
|
|
1205
|
+
})).superRefine((aliases, ctx) => {
|
|
1206
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1207
|
+
for (const [index, alias] of aliases.entries()) {
|
|
1208
|
+
if (seen.has(alias.id)) {
|
|
1209
|
+
ctx.addIssue({
|
|
1210
|
+
code: "custom",
|
|
1211
|
+
message: `duplicate AI alias: ${alias.id}`,
|
|
1212
|
+
path: [index, "id"]
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
seen.add(alias.id);
|
|
1216
|
+
}
|
|
1217
|
+
}).optional(),
|
|
1218
|
+
provider: z4.boolean().optional()
|
|
1219
|
+
}).optional(),
|
|
1220
|
+
provides: z4.array(z4.string()).optional(),
|
|
1221
|
+
// e.g., ["logger-adapter", "cache-adapter"]
|
|
1222
|
+
billing: z4.object({
|
|
1223
|
+
subjects: z4.array(z4.object({
|
|
1224
|
+
subject: z4.string().min(1).regex(
|
|
1225
|
+
/^[a-z0-9-]+(\.[a-z0-9-]+)+\.[a-zA-Z0-9_]+$/,
|
|
1226
|
+
'subject must be dot-separated (e.g., "com.vendor.plugin.apiCalls")'
|
|
1227
|
+
),
|
|
1228
|
+
type: z4.enum(["boolean", "metered"]),
|
|
1229
|
+
unit: z4.string().optional(),
|
|
1230
|
+
description: z4.string().optional()
|
|
1231
|
+
})).optional(),
|
|
1232
|
+
procedures: z4.record(z4.string(), z4.string()).optional()
|
|
1233
|
+
}).optional()
|
|
1234
|
+
}).optional(),
|
|
1235
|
+
// === Exports ===
|
|
1236
|
+
exports: z4.object({
|
|
1237
|
+
loggerAdapter: z4.string().optional(),
|
|
1238
|
+
// e.g., "./dist/logger-adapter.js"
|
|
1239
|
+
cacheAdapter: z4.string().optional()
|
|
1240
|
+
}).optional(),
|
|
1241
|
+
// === Permissions Defined ===
|
|
1242
|
+
permissions: z4.object({
|
|
1243
|
+
definitions: z4.array(z4.object({
|
|
1244
|
+
key: z4.string().regex(/^[a-z0-9_.]+$/, "Permission key must be lowercase with dots/underscores"),
|
|
1245
|
+
description: z4.string().optional()
|
|
1246
|
+
})).optional(),
|
|
1247
|
+
required: z4.array(z4.string()).optional(),
|
|
1248
|
+
/**
|
|
1249
|
+
* Quick-select action groups for the permission configuration UI.
|
|
1250
|
+
* Keyed by CASL subject name. Each subject can have multiple groups,
|
|
1251
|
+
* and groups may overlap (same action in multiple groups).
|
|
1252
|
+
*
|
|
1253
|
+
* @example
|
|
1254
|
+
* ```json
|
|
1255
|
+
* {
|
|
1256
|
+
* "Article": [
|
|
1257
|
+
* { "key": "editor", "label": "Editor", "actions": ["create", "update"] },
|
|
1258
|
+
* { "key": "full", "label": "Full Access", "actions": ["create", "update", "delete", "publish"] }
|
|
1259
|
+
* ]
|
|
1260
|
+
* }
|
|
1261
|
+
* ```
|
|
1262
|
+
*/
|
|
1263
|
+
actionGroups: z4.record(
|
|
1264
|
+
z4.string(),
|
|
1265
|
+
// subject name
|
|
1266
|
+
z4.array(z4.object({
|
|
1267
|
+
key: z4.string().min(1),
|
|
1268
|
+
label: z4.string().min(1),
|
|
1269
|
+
actions: z4.array(z4.string().min(1)).min(1)
|
|
1270
|
+
}))
|
|
1271
|
+
).optional()
|
|
1272
|
+
}).optional(),
|
|
1273
|
+
// === Server Entry ===
|
|
1274
|
+
server: z4.object({
|
|
1275
|
+
entry: z4.string(),
|
|
1276
|
+
// e.g., "./dist/server/index.js"
|
|
1277
|
+
router: z4.boolean().optional(),
|
|
1278
|
+
// Exports tRPC router
|
|
1279
|
+
nestModule: z4.string().optional(),
|
|
1280
|
+
// NestJS module for advanced plugins, e.g., "./dist/server/hello.module.js"
|
|
1281
|
+
fastifyRoutes: z4.string().optional(),
|
|
1282
|
+
// Fastify route registrar, e.g., "./dist/server/http/routes.js"
|
|
1283
|
+
publicServices: z4.array(z4.object({
|
|
1284
|
+
name: z4.string().min(1).max(80).regex(/^[a-z0-9-]+$/),
|
|
1285
|
+
mountPath: z4.string().regex(/^\/api\/[a-z0-9/-]+$/),
|
|
1286
|
+
methods: z4.array(z4.enum(["GET", "POST", "PUT", "PATCH", "DELETE"])).min(1),
|
|
1287
|
+
auth: z4.enum(["public", "bearer", "session", "user"]).default("public"),
|
|
1288
|
+
maxBodyBytes: z4.number().int().positive().max(100 * 1024 * 1024).default(1024 * 1024)
|
|
1289
|
+
})).optional(),
|
|
1290
|
+
trustedApiTokenProxy: z4.object({
|
|
1291
|
+
invoker: z4.string().min(1),
|
|
1292
|
+
paths: z4.array(z4.string().min(1)).min(1)
|
|
1293
|
+
}).optional(),
|
|
1294
|
+
hooks: z4.array(z4.enum(["onInstall", "onEnable", "onDisable", "onUninstall"])).optional()
|
|
1295
|
+
}).optional(),
|
|
1296
|
+
// === Admin UI Entry ===
|
|
1297
|
+
admin: z4.object({
|
|
1298
|
+
remoteEntry: z4.string(),
|
|
1299
|
+
// e.g., "./dist/admin/remoteEntry.js"
|
|
1300
|
+
devRemoteEntry: z4.string().optional(),
|
|
1301
|
+
// Dev mode: e.g., "http://localhost:3010/remoteEntry.js"
|
|
1302
|
+
moduleName: z4.string().optional(),
|
|
1303
|
+
// MF2.0 module name
|
|
1304
|
+
exposes: z4.record(z4.string(), z4.string()).optional(),
|
|
1305
|
+
extensions: z4.array(adminExtensionSchema).optional(),
|
|
1306
|
+
slots: z4.array(adminSlotSchema).optional(),
|
|
1307
|
+
tours: z4.array(adminTourSchema).optional(),
|
|
1308
|
+
/** @deprecated Use slots instead. */
|
|
1309
|
+
extensionSlots: z4.array(adminSlotSchema).optional(),
|
|
1310
|
+
/** @deprecated Use extensions[] instead */
|
|
1311
|
+
menus: z4.array(z4.object({
|
|
1312
|
+
label: z4.string(),
|
|
1313
|
+
icon: z4.string().optional(),
|
|
1314
|
+
path: z4.string(),
|
|
1315
|
+
order: z4.number().optional(),
|
|
1316
|
+
parentId: z4.string().optional(),
|
|
1317
|
+
permission: permissionDeclarationSchema.optional(),
|
|
1318
|
+
/** @deprecated Use permission instead. */
|
|
1319
|
+
requiredPermission: z4.string().optional(),
|
|
1320
|
+
metadata: z4.record(z4.string(), z4.unknown()).optional()
|
|
1321
|
+
})).optional()
|
|
1322
|
+
}).optional(),
|
|
1323
|
+
// === Web UI Entry ===
|
|
1324
|
+
web: webSurfaceSchema.optional(),
|
|
1325
|
+
// === Dependencies ===
|
|
1326
|
+
dependencies: z4.array(z4.string()).optional(),
|
|
1327
|
+
// Other plugin IDs
|
|
1328
|
+
conflicts: z4.array(z4.string()).optional(),
|
|
1329
|
+
// Conflicting plugin IDs
|
|
1330
|
+
peerDependencies: z4.record(z4.string(), z4.string()).optional(),
|
|
1331
|
+
// e.g., { react: "^18.0.0" }
|
|
1332
|
+
compatibilityMode: z4.enum(["strict", "lenient", "fallback"]).optional(),
|
|
1333
|
+
// === Entity Extensions ===
|
|
1334
|
+
extends: z4.record(extensionTargetPluginIdSchema, entityExtensionSchema).optional(),
|
|
1335
|
+
uses: pluginUsesSchema.optional(),
|
|
1336
|
+
// === Data Retention ===
|
|
1337
|
+
dataRetention: z4.object({
|
|
1338
|
+
onDisable: z4.enum(["retain"]).optional(),
|
|
1339
|
+
onUninstall: z4.enum(["delete", "archive", "retain"]).optional(),
|
|
1340
|
+
tables: z4.array(z4.string()).optional()
|
|
1341
|
+
}).optional(),
|
|
1342
|
+
// === Infrastructure (Tenant Config Delegation) ===
|
|
1343
|
+
infrastructure: z4.object({
|
|
1344
|
+
tenantOverride: z4.boolean(),
|
|
1345
|
+
riskLevel: z4.enum(["high", "medium", "low"]),
|
|
1346
|
+
sensitiveFields: z4.array(z4.string()).default([])
|
|
1347
|
+
}).optional(),
|
|
1348
|
+
// === Notifications ===
|
|
1349
|
+
notifications: notificationsConfigSchema
|
|
1350
|
+
}).superRefine((manifest, ctx) => {
|
|
1351
|
+
const declaresThemeCapability = manifest.capabilities?.ui?.webTheme === true;
|
|
1352
|
+
const hasPresentation = manifest.web?.presentation !== void 0;
|
|
1353
|
+
if (declaresThemeCapability && !hasPresentation) {
|
|
1354
|
+
ctx.addIssue({
|
|
1355
|
+
code: "custom",
|
|
1356
|
+
path: ["web", "presentation"],
|
|
1357
|
+
message: "capabilities.ui.webTheme requires web.presentation"
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
if (hasPresentation && !declaresThemeCapability) {
|
|
1361
|
+
ctx.addIssue({
|
|
1362
|
+
code: "custom",
|
|
1363
|
+
path: ["capabilities", "ui", "webTheme"],
|
|
1364
|
+
message: "web.presentation requires capabilities.ui.webTheme = true"
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
const declaresPresentationPack = manifest.capabilities?.ui?.webPresentationPack === true;
|
|
1368
|
+
const hasStandaloneAdapters = (manifest.web?.adapters?.length ?? 0) > 0;
|
|
1369
|
+
if (declaresPresentationPack && !hasStandaloneAdapters) {
|
|
1370
|
+
ctx.addIssue({
|
|
1371
|
+
code: "custom",
|
|
1372
|
+
path: ["web", "adapters"],
|
|
1373
|
+
message: "capabilities.ui.webPresentationPack requires web.adapters"
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
if (hasStandaloneAdapters && !declaresPresentationPack) {
|
|
1377
|
+
ctx.addIssue({
|
|
1378
|
+
code: "custom",
|
|
1379
|
+
path: ["capabilities", "ui", "webPresentationPack"],
|
|
1380
|
+
message: "web.adapters requires capabilities.ui.webPresentationPack = true"
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
});
|
|
1384
|
+
|
|
1385
|
+
export {
|
|
1386
|
+
presentationIdSchema,
|
|
1387
|
+
presentationPluginIdSchema,
|
|
1388
|
+
presentationContractVersionSchema,
|
|
1389
|
+
presentationContractRangeSchema,
|
|
1390
|
+
presentationSchemaRefSchema,
|
|
1391
|
+
presentationModelSchema,
|
|
1392
|
+
presentationRenderModeSchema,
|
|
1393
|
+
presentationRegionSchema,
|
|
1394
|
+
presentationActionSchema,
|
|
1395
|
+
presentationSurfaceSchema,
|
|
1396
|
+
presentationAdapterSchema,
|
|
1397
|
+
themeAssetPathSchema,
|
|
1398
|
+
themeAssetSchema,
|
|
1399
|
+
themeHeadSchema,
|
|
1400
|
+
themeTokenTypeSchema,
|
|
1401
|
+
themeTokenSchema,
|
|
1402
|
+
themeTokenPresetSchema,
|
|
1403
|
+
themeSiteShellSchema,
|
|
1404
|
+
themeHomeTargetSchema,
|
|
1405
|
+
themeIntegrationSchema,
|
|
1406
|
+
webPresentationSchema,
|
|
1407
|
+
presentationDiagnosticSeveritySchema,
|
|
1408
|
+
presentationCompatibilityStatusSchema,
|
|
1409
|
+
presentationDiagnosticSchema,
|
|
1410
|
+
presentationCompatibilityResultSchema,
|
|
1411
|
+
PRESENTATION_OBSERVABILITY,
|
|
1412
|
+
defineWebPresentation,
|
|
1413
|
+
defineThemeHomeTarget,
|
|
1414
|
+
definePresentationSurface,
|
|
1415
|
+
definePresentationAdapter,
|
|
1416
|
+
parsePresentationModel,
|
|
1417
|
+
evaluatePresentationCompatibility,
|
|
1418
|
+
satisfiesPresentationRange,
|
|
1419
|
+
storefrontOperationKindSchema,
|
|
1420
|
+
storefrontOperationSchema,
|
|
1421
|
+
storefrontApiSchema,
|
|
1422
|
+
defineStorefrontApi,
|
|
1423
|
+
webDesignNodeKindSchema,
|
|
1424
|
+
webDesignRegionSchema,
|
|
1425
|
+
webDesignBindingSchema,
|
|
1426
|
+
webDesignMigrationSchema,
|
|
1427
|
+
webDesignNodeDefinitionSchema,
|
|
1428
|
+
webAppEmbedTargetSchema,
|
|
1429
|
+
webAppEmbedConsentSchema,
|
|
1430
|
+
webAppEmbedSchema,
|
|
1431
|
+
defineWebDesignNode,
|
|
1432
|
+
defineAppEmbed,
|
|
1433
|
+
navTargetSchema,
|
|
1434
|
+
navGroupTargetSchema,
|
|
1435
|
+
routeTargetSchema,
|
|
1436
|
+
settingsTargetSchema,
|
|
1437
|
+
dashboardTargetSchema,
|
|
1438
|
+
targetSchema,
|
|
1439
|
+
adminExtensionSchema,
|
|
1440
|
+
adminTourPlacementSchema,
|
|
1441
|
+
adminTourStepSchema,
|
|
1442
|
+
adminTourSchema,
|
|
1443
|
+
pluginI18nSchema,
|
|
1444
|
+
autoCrudFieldOptionSchema,
|
|
1445
|
+
autoCrudDataSourceSchema,
|
|
1446
|
+
autoCrudFieldConfigSchema,
|
|
1447
|
+
entityExtensionFieldSchema,
|
|
1448
|
+
autoCrudActionZoneSchema,
|
|
1449
|
+
autoCrudActionSchema,
|
|
1450
|
+
autoCrudActionsSchema,
|
|
1451
|
+
entityExtensionCrudConfigSchema,
|
|
1452
|
+
entityExtensionSlotSchema,
|
|
1453
|
+
entityExtensionSchema,
|
|
1454
|
+
entityExtensionUseSchema,
|
|
1455
|
+
pluginUsesSchema,
|
|
1456
|
+
webSsrContractVersionSchema,
|
|
1457
|
+
webPluginRouteSchema,
|
|
1458
|
+
webExtensionTargetSchema,
|
|
1459
|
+
webExtensionQuerySchema,
|
|
1460
|
+
webExtensionSchema,
|
|
1461
|
+
webDesignBlockSchema,
|
|
1462
|
+
webDesignSlotSchema,
|
|
1463
|
+
webDesignTemplateSchema,
|
|
1464
|
+
webDesignDataSourceSchema,
|
|
1465
|
+
webDesignActionSchema,
|
|
1466
|
+
webDesignSurfaceSchema,
|
|
1467
|
+
webSurfaceSchema,
|
|
1468
|
+
pluginManifestSchema
|
|
1469
|
+
};
|
|
1470
|
+
//# sourceMappingURL=chunk-3IM3FPTJ.js.map
|