@persona/layout-editor-remote-module 0.0.0-bootstrap.0 → 0.5.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 +147 -0
- package/dist/bridge-frame.d.mts +45 -0
- package/dist/bridge-frame.mjs +350 -0
- package/dist/bridge-host.d.mts +61 -0
- package/dist/bridge-host.mjs +217 -0
- package/dist/define-Dt8sbrVO.d.mts +236 -0
- package/dist/index.d.mts +98 -0
- package/dist/index.mjs +58 -0
- package/dist/protocol-DMsysRFd.mjs +211 -0
- package/dist/protocol-edoRdXpF.d.mts +30 -0
- package/dist/schema-BeI8GdXS.mjs +105 -0
- package/dist/vite-plugin.d.mts +43 -0
- package/dist/vite-plugin.mjs +435 -0
- package/package.json +117 -4
- package/skills/getting-started/SKILL.md +371 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/bridge/origin.ts
|
|
4
|
+
const dashboardHostOriginPattern = /^https:\/\/([a-z0-9-]+\.)*withpersona(-staging)?\.com$/;
|
|
5
|
+
const pagesHostOriginPattern = /^https:\/\/[a-z0-9-]+\.persona-web\.pages\.dev$/;
|
|
6
|
+
const coderHostOriginPattern = /^https:\/\/[a-z0-9-]+\.coder\.development\.personerds\.com$/;
|
|
7
|
+
const localHostOriginPattern = /^http:\/\/(?:localhost|127\.0\.0\.1):\d+$/;
|
|
8
|
+
function personaDashboardHostOrigins(origin) {
|
|
9
|
+
return dashboardHostOriginPattern.test(origin) || pagesHostOriginPattern.test(origin) || coderHostOriginPattern.test(origin) || localHostOriginPattern.test(origin);
|
|
10
|
+
}
|
|
11
|
+
function resolveAllowedHostOrigins(allowedHostOrigins) {
|
|
12
|
+
if (allowedHostOrigins === void 0) return personaDashboardHostOrigins;
|
|
13
|
+
if (typeof allowedHostOrigins === "function") return allowedHostOrigins;
|
|
14
|
+
return (origin) => allowedHostOrigins.some((allowedOrigin) => typeof allowedOrigin === "string" ? allowedOrigin === origin : allowedOrigin.test(origin));
|
|
15
|
+
}
|
|
16
|
+
function candidateParentOrigin() {
|
|
17
|
+
if (typeof window === "undefined") return;
|
|
18
|
+
try {
|
|
19
|
+
const ancestorOrigin = window.location.ancestorOrigins?.[0];
|
|
20
|
+
if (ancestorOrigin) return ancestorOrigin;
|
|
21
|
+
} catch {}
|
|
22
|
+
try {
|
|
23
|
+
return document.referrer ? new URL(document.referrer).origin : void 0;
|
|
24
|
+
} catch {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function assertNotSelfOrigin(moduleOrigin) {
|
|
29
|
+
if (typeof window !== "undefined" && moduleOrigin === window.location.origin) throw new Error("Remote module origin must not match the host origin");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/schema.ts
|
|
34
|
+
/**
|
|
35
|
+
* Mirrors persona-web's `LAYOUT_COLUMN_TOTAL`
|
|
36
|
+
* (front-end/dashboard/modules/lib/constants.ts). The enum schemas below
|
|
37
|
+
* mirror persona-web's corresponding enum values and are kept in sync by hand;
|
|
38
|
+
* this package has no dependency on persona-web.
|
|
39
|
+
*/
|
|
40
|
+
const MAX_GRID_COLUMNS = 12;
|
|
41
|
+
const layoutTypeSchema = z.enum([
|
|
42
|
+
"account",
|
|
43
|
+
"case",
|
|
44
|
+
"transaction"
|
|
45
|
+
]);
|
|
46
|
+
const moduleCategorySchema = z.enum([
|
|
47
|
+
"build_your_own",
|
|
48
|
+
"components",
|
|
49
|
+
"management",
|
|
50
|
+
"related_records"
|
|
51
|
+
]);
|
|
52
|
+
const moduleBadgeSchema = z.enum([
|
|
53
|
+
"beta",
|
|
54
|
+
"deprecated",
|
|
55
|
+
"improved",
|
|
56
|
+
"new"
|
|
57
|
+
]);
|
|
58
|
+
/**
|
|
59
|
+
* A manifest `key` is embedded verbatim into a persisted module identity
|
|
60
|
+
* string (`${sourceId}/${key}`) and used in DOM ids and analytics — restrict it
|
|
61
|
+
* to a safe, stable charset up front rather than discovering the hard way that
|
|
62
|
+
* some producer emitted spaces or slashes.
|
|
63
|
+
*/
|
|
64
|
+
const moduleKeySchema = z.string().min(1).regex(/^[a-z0-9_]+$/, "key must be lowercase alphanumeric with underscores only");
|
|
65
|
+
const gridSizeSchema = z.object({
|
|
66
|
+
height: z.number().int().min(1),
|
|
67
|
+
width: z.number().int().min(1).max(MAX_GRID_COLUMNS)
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* `code` (a chunk URL, direct-`import()`ed) and `document` (a page URL, host
|
|
71
|
+
* iframes it instead) are mutually exclusive — a delivery is one or the
|
|
72
|
+
* other, never both, never neither.
|
|
73
|
+
*/
|
|
74
|
+
const remoteDeliverySchema = z.union([z.object({ code: z.string().min(1) }), z.object({ document: z.string().min(1) })]);
|
|
75
|
+
const remoteEntrySchema = z.object({
|
|
76
|
+
css: z.array(z.string()).optional(),
|
|
77
|
+
render: remoteDeliverySchema
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* Loose check shared by `configSchema` and `uiConfigSchema` — this validates
|
|
81
|
+
* the manifest envelope, not the arbitrary object either one carries. Both
|
|
82
|
+
* are trusted structurally (an object) and used for their stated purpose
|
|
83
|
+
* (JSON Schema validation, RJSF ui hints) by the consumer, not re-validated
|
|
84
|
+
* here.
|
|
85
|
+
*/
|
|
86
|
+
const looseObjectSchema = z.record(z.string(), z.unknown());
|
|
87
|
+
const remoteModuleRegistrationManifestV1Schema = z.object({
|
|
88
|
+
allowAddingToLayout: z.boolean(),
|
|
89
|
+
allowDynamicHeight: z.boolean().optional(),
|
|
90
|
+
badge: moduleBadgeSchema.optional(),
|
|
91
|
+
category: moduleCategorySchema.optional(),
|
|
92
|
+
configSchema: looseObjectSchema.optional(),
|
|
93
|
+
defaultSize: z.partialRecord(layoutTypeSchema, gridSizeSchema),
|
|
94
|
+
descriptionShort: z.string().min(1),
|
|
95
|
+
displayName: z.string().min(1),
|
|
96
|
+
icon: z.string().min(1).optional(),
|
|
97
|
+
internalUsersOnly: z.boolean().optional(),
|
|
98
|
+
key: moduleKeySchema,
|
|
99
|
+
layouts: z.array(layoutTypeSchema).default([]),
|
|
100
|
+
manifestVersion: z.literal("v1"),
|
|
101
|
+
remote: remoteEntrySchema,
|
|
102
|
+
uiConfigSchema: looseObjectSchema.optional()
|
|
103
|
+
}).refine((manifest) => manifest.layouts.every((layout) => manifest.defaultSize[layout]), {
|
|
104
|
+
message: "defaultSize must have an entry for every layout in `layouts`",
|
|
105
|
+
path: ["defaultSize"]
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/bridge/protocol.ts
|
|
110
|
+
const SOURCE = "persona-layout-module";
|
|
111
|
+
const PROTOCOL_VERSION = 1;
|
|
112
|
+
const jsonSchema = z.lazy(() => z.union([
|
|
113
|
+
z.boolean(),
|
|
114
|
+
z.null(),
|
|
115
|
+
z.number(),
|
|
116
|
+
z.string(),
|
|
117
|
+
z.array(jsonSchema),
|
|
118
|
+
z.record(z.string(), jsonSchema)
|
|
119
|
+
]));
|
|
120
|
+
const envelopeSchema = {
|
|
121
|
+
source: z.literal(SOURCE),
|
|
122
|
+
protocolVersion: z.literal(PROTOCOL_VERSION)
|
|
123
|
+
};
|
|
124
|
+
const requestIdSchema = z.string().min(1);
|
|
125
|
+
const variableMapSchema = z.record(z.string(), z.union([z.string(), z.number()]));
|
|
126
|
+
const readySchema = z.object({
|
|
127
|
+
...envelopeSchema,
|
|
128
|
+
type: z.literal("ready")
|
|
129
|
+
}).strict();
|
|
130
|
+
const requestDataSchema = z.object({
|
|
131
|
+
...envelopeSchema,
|
|
132
|
+
type: z.literal("request-data"),
|
|
133
|
+
requestId: requestIdSchema
|
|
134
|
+
}).strict();
|
|
135
|
+
const setHeightSchema = z.object({
|
|
136
|
+
...envelopeSchema,
|
|
137
|
+
type: z.literal("set-height"),
|
|
138
|
+
height: z.number()
|
|
139
|
+
}).strict();
|
|
140
|
+
const renderErrorSchema = z.object({
|
|
141
|
+
...envelopeSchema,
|
|
142
|
+
type: z.literal("render-error"),
|
|
143
|
+
message: z.string()
|
|
144
|
+
}).strict();
|
|
145
|
+
const resolveDataPathSchema = z.object({
|
|
146
|
+
...envelopeSchema,
|
|
147
|
+
type: z.literal("resolve-data-path"),
|
|
148
|
+
requestId: requestIdSchema,
|
|
149
|
+
dataPath: z.string(),
|
|
150
|
+
variableMap: variableMapSchema.optional()
|
|
151
|
+
}).strict();
|
|
152
|
+
/**
|
|
153
|
+
* Runtime facts about where the module is rendered, owned by the host and not
|
|
154
|
+
* derivable by the module itself. Distinct from `data`, which is the module's
|
|
155
|
+
* persisted config.
|
|
156
|
+
*/
|
|
157
|
+
const remoteModuleContextSchema = z.object({
|
|
158
|
+
layoutType: layoutTypeSchema,
|
|
159
|
+
layoutObjectId: z.string().nullable(),
|
|
160
|
+
isReadOnly: z.boolean(),
|
|
161
|
+
isInEditor: z.boolean(),
|
|
162
|
+
isUsingStubData: z.boolean()
|
|
163
|
+
}).strict();
|
|
164
|
+
const moduleToHostMessageSchema = z.discriminatedUnion("type", [
|
|
165
|
+
readySchema,
|
|
166
|
+
requestDataSchema,
|
|
167
|
+
setHeightSchema,
|
|
168
|
+
renderErrorSchema,
|
|
169
|
+
resolveDataPathSchema
|
|
170
|
+
]);
|
|
171
|
+
const initSchema = z.object({
|
|
172
|
+
...envelopeSchema,
|
|
173
|
+
type: z.literal("init"),
|
|
174
|
+
data: jsonSchema,
|
|
175
|
+
context: remoteModuleContextSchema
|
|
176
|
+
}).strict();
|
|
177
|
+
const dataSchema = z.object({
|
|
178
|
+
...envelopeSchema,
|
|
179
|
+
type: z.literal("data"),
|
|
180
|
+
requestId: requestIdSchema.optional(),
|
|
181
|
+
data: jsonSchema
|
|
182
|
+
}).strict();
|
|
183
|
+
const contextSchema = z.object({
|
|
184
|
+
...envelopeSchema,
|
|
185
|
+
type: z.literal("context"),
|
|
186
|
+
context: remoteModuleContextSchema
|
|
187
|
+
}).strict();
|
|
188
|
+
const dataPathResultSchema = z.object({
|
|
189
|
+
...envelopeSchema,
|
|
190
|
+
type: z.literal("data-path-result"),
|
|
191
|
+
requestId: requestIdSchema,
|
|
192
|
+
result: jsonSchema.optional(),
|
|
193
|
+
error: z.string().optional()
|
|
194
|
+
}).strict().refine(({ result, error }) => result === void 0 !== (error === void 0));
|
|
195
|
+
const hostToModuleMessageSchema = z.discriminatedUnion("type", [
|
|
196
|
+
initSchema,
|
|
197
|
+
dataSchema,
|
|
198
|
+
contextSchema,
|
|
199
|
+
dataPathResultSchema
|
|
200
|
+
]);
|
|
201
|
+
function parseModuleToHostMessage(data) {
|
|
202
|
+
const parsed = moduleToHostMessageSchema.safeParse(data);
|
|
203
|
+
return parsed.success ? parsed.data : null;
|
|
204
|
+
}
|
|
205
|
+
function parseHostToModuleMessage(data) {
|
|
206
|
+
const parsed = hostToModuleMessageSchema.safeParse(data);
|
|
207
|
+
return parsed.success ? parsed.data : null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
//#endregion
|
|
211
|
+
export { assertNotSelfOrigin as a, resolveAllowedHostOrigins as c, parseModuleToHostMessage as i, SOURCE as n, candidateParentOrigin as o, parseHostToModuleMessage as r, personaDashboardHostOrigins as s, PROTOCOL_VERSION as t };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
|
|
5
|
+
type Json = boolean | JsonObject | JsonValue[] | null | number | string;
|
|
6
|
+
type JsonObject = {
|
|
7
|
+
[key: string]: Json;
|
|
8
|
+
};
|
|
9
|
+
type JsonValue = Json;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/bridge/protocol.d.ts
|
|
12
|
+
/**
|
|
13
|
+
* Runtime facts about where the module is rendered, owned by the host and not
|
|
14
|
+
* derivable by the module itself. Distinct from `data`, which is the module's
|
|
15
|
+
* persisted config.
|
|
16
|
+
*/
|
|
17
|
+
declare const remoteModuleContextSchema: z.ZodObject<{
|
|
18
|
+
layoutType: z.ZodEnum<{
|
|
19
|
+
account: "account";
|
|
20
|
+
case: "case";
|
|
21
|
+
transaction: "transaction";
|
|
22
|
+
}>;
|
|
23
|
+
layoutObjectId: z.ZodNullable<z.ZodString>;
|
|
24
|
+
isReadOnly: z.ZodBoolean;
|
|
25
|
+
isInEditor: z.ZodBoolean;
|
|
26
|
+
isUsingStubData: z.ZodBoolean;
|
|
27
|
+
}, z.core.$strict>;
|
|
28
|
+
type RemoteModuleContext = z.infer<typeof remoteModuleContextSchema>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { Json as n, RemoteModuleContext as t };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/define.ts
|
|
4
|
+
/**
|
|
5
|
+
* Identity function at runtime — it exists to give authors a typed,
|
|
6
|
+
* discoverable way to build a `personaLayoutModules({ modules: [...] })`
|
|
7
|
+
* entry, nothing more. All real work (path resolution, build-graph
|
|
8
|
+
* injection, schema conversion, manifest emission) happens in the Vite
|
|
9
|
+
* plugin, not here.
|
|
10
|
+
*/
|
|
11
|
+
function defineLayoutModule(input) {
|
|
12
|
+
return input;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/manifest-path.ts
|
|
17
|
+
/**
|
|
18
|
+
* Default path (site-root-relative) the manifest document is served from and
|
|
19
|
+
* written to, when `PersonaLayoutModulesOptions.manifestPath` isn't
|
|
20
|
+
* overridden. A standalone module (rather than living in vite-plugin.ts, the
|
|
21
|
+
* one place that actually uses it) so it can also be re-exported from the
|
|
22
|
+
* runtime-safe `.` entry — a consumer wiring up something like CORS for the
|
|
23
|
+
* manifest route in its own server, outside of vite.config.ts, needs this
|
|
24
|
+
* default without pulling in vite/esbuild.
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_MANIFEST_PATH = "/_layout_modules_manifest.json";
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/schema.ts
|
|
30
|
+
/**
|
|
31
|
+
* Mirrors persona-web's `LAYOUT_COLUMN_TOTAL`
|
|
32
|
+
* (front-end/dashboard/modules/lib/constants.ts). The enum schemas below
|
|
33
|
+
* mirror persona-web's corresponding enum values and are kept in sync by hand;
|
|
34
|
+
* this package has no dependency on persona-web.
|
|
35
|
+
*/
|
|
36
|
+
const MAX_GRID_COLUMNS = 12;
|
|
37
|
+
const layoutTypeSchema = z.enum([
|
|
38
|
+
"account",
|
|
39
|
+
"case",
|
|
40
|
+
"transaction"
|
|
41
|
+
]);
|
|
42
|
+
const moduleCategorySchema = z.enum([
|
|
43
|
+
"build_your_own",
|
|
44
|
+
"components",
|
|
45
|
+
"management",
|
|
46
|
+
"related_records"
|
|
47
|
+
]);
|
|
48
|
+
const moduleBadgeSchema = z.enum([
|
|
49
|
+
"beta",
|
|
50
|
+
"deprecated",
|
|
51
|
+
"improved",
|
|
52
|
+
"new"
|
|
53
|
+
]);
|
|
54
|
+
/**
|
|
55
|
+
* A manifest `key` is embedded verbatim into a persisted module identity
|
|
56
|
+
* string (`${sourceId}/${key}`) and used in DOM ids and analytics — restrict it
|
|
57
|
+
* to a safe, stable charset up front rather than discovering the hard way that
|
|
58
|
+
* some producer emitted spaces or slashes.
|
|
59
|
+
*/
|
|
60
|
+
const moduleKeySchema = z.string().min(1).regex(/^[a-z0-9_]+$/, "key must be lowercase alphanumeric with underscores only");
|
|
61
|
+
const gridSizeSchema = z.object({
|
|
62
|
+
height: z.number().int().min(1),
|
|
63
|
+
width: z.number().int().min(1).max(MAX_GRID_COLUMNS)
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* `code` (a chunk URL, direct-`import()`ed) and `document` (a page URL, host
|
|
67
|
+
* iframes it instead) are mutually exclusive — a delivery is one or the
|
|
68
|
+
* other, never both, never neither.
|
|
69
|
+
*/
|
|
70
|
+
const remoteDeliverySchema = z.union([z.object({ code: z.string().min(1) }), z.object({ document: z.string().min(1) })]);
|
|
71
|
+
const remoteEntrySchema = z.object({
|
|
72
|
+
css: z.array(z.string()).optional(),
|
|
73
|
+
render: remoteDeliverySchema
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* Loose check shared by `configSchema` and `uiConfigSchema` — this validates
|
|
77
|
+
* the manifest envelope, not the arbitrary object either one carries. Both
|
|
78
|
+
* are trusted structurally (an object) and used for their stated purpose
|
|
79
|
+
* (JSON Schema validation, RJSF ui hints) by the consumer, not re-validated
|
|
80
|
+
* here.
|
|
81
|
+
*/
|
|
82
|
+
const looseObjectSchema = z.record(z.string(), z.unknown());
|
|
83
|
+
const remoteModuleRegistrationManifestV1Schema = z.object({
|
|
84
|
+
allowAddingToLayout: z.boolean(),
|
|
85
|
+
allowDynamicHeight: z.boolean().optional(),
|
|
86
|
+
badge: moduleBadgeSchema.optional(),
|
|
87
|
+
category: moduleCategorySchema.optional(),
|
|
88
|
+
configSchema: looseObjectSchema.optional(),
|
|
89
|
+
defaultSize: z.partialRecord(layoutTypeSchema, gridSizeSchema),
|
|
90
|
+
descriptionShort: z.string().min(1),
|
|
91
|
+
displayName: z.string().min(1),
|
|
92
|
+
icon: z.string().min(1).optional(),
|
|
93
|
+
internalUsersOnly: z.boolean().optional(),
|
|
94
|
+
key: moduleKeySchema,
|
|
95
|
+
layouts: z.array(layoutTypeSchema).default([]),
|
|
96
|
+
manifestVersion: z.literal("v1"),
|
|
97
|
+
remote: remoteEntrySchema,
|
|
98
|
+
uiConfigSchema: looseObjectSchema.optional()
|
|
99
|
+
}).refine((manifest) => manifest.layouts.every((layout) => manifest.defaultSize[layout]), {
|
|
100
|
+
message: "defaultSize must have an entry for every layout in `layouts`",
|
|
101
|
+
path: ["defaultSize"]
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
export { DEFAULT_MANIFEST_PATH as n, defineLayoutModule as r, remoteModuleRegistrationManifestV1Schema as t };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { n as LayoutModuleEntry, r as defineLayoutModule, t as LayoutModuleDefinitionInput } from "./define-Dt8sbrVO.mjs";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
|
|
4
|
+
//#region src/vite-plugin.d.ts
|
|
5
|
+
|
|
6
|
+
interface PersonaLayoutModulesOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Where the manifest document is emitted, relative to the site root — must
|
|
9
|
+
* include the full JSON file name (e.g. `/manifests/my-app.json`), not just
|
|
10
|
+
* a directory. Defaults to `DEFAULT_MANIFEST_PATH` (exported from the
|
|
11
|
+
* package's `.` entry). A leading `/` is optional and stripped if present;
|
|
12
|
+
* either form resolves to the same path.
|
|
13
|
+
*/
|
|
14
|
+
manifestPath?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Plugins the production build of `code`-delivered layout-module entries
|
|
17
|
+
* needs (e.g. `react()`, `tailwindcss()`) — called once. These entries are
|
|
18
|
+
* built via a SEPARATE, isolated `vite.build()` call (see the
|
|
19
|
+
* `closeBundle` hook), deliberately not part of the app's own build graph
|
|
20
|
+
* — see its doc comment for why — so the app's own plugin list isn't
|
|
21
|
+
* inherited automatically. Omit if your modules only need plain TS/JSX
|
|
22
|
+
* (Vite's built-in esbuild transform already handles that with no plugin).
|
|
23
|
+
* `document` (`.html`) entries never need this — they run through the
|
|
24
|
+
* app's own build graph and its own configured plugins directly.
|
|
25
|
+
*/
|
|
26
|
+
modulePlugins?: () => Plugin[];
|
|
27
|
+
/** Every module this app registers — passed directly, not discovered. */
|
|
28
|
+
modules: LayoutModuleDefinitionInput[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Vite plugin that takes a statically-declared list of layout modules
|
|
32
|
+
* (`options.modules`, authored via `defineLayoutModule` — see ./define.ts),
|
|
33
|
+
* wires every `code`-delivered entry into the build as an addressable ESM
|
|
34
|
+
* chunk, ensures every `document`-delivered (`.html`) entry is actually
|
|
35
|
+
* built/served, and emits a `RemoteModuleRegistrationManifestV1[]` document
|
|
36
|
+
* persona-web can intake.
|
|
37
|
+
*
|
|
38
|
+
* Modules are configured directly here, not discovered by globbing the
|
|
39
|
+
* source tree — a module IS whatever's in `options.modules`, full stop.
|
|
40
|
+
*/
|
|
41
|
+
declare function personaLayoutModules(options: PersonaLayoutModulesOptions): Plugin;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { type LayoutModuleDefinitionInput, type LayoutModuleEntry, PersonaLayoutModulesOptions, defineLayoutModule, personaLayoutModules };
|