@manta-eu/horns-kit 0.1.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/LICENSE +21 -0
- package/dist/catalog/manta-react.json +914 -0
- package/dist/catalog.d.ts +21 -0
- package/dist/catalog.js +7 -0
- package/dist/embed/client.d.ts +15 -0
- package/dist/embed/client.js +45 -0
- package/dist/embed/horn-snapshot-view.d.ts +64 -0
- package/dist/embed/horn-snapshot-view.js +142 -0
- package/dist/embed/plan-strip.d.ts +49 -0
- package/dist/embed/plan-strip.js +141 -0
- package/dist/embed/server.d.ts +10 -0
- package/dist/embed/server.js +17 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -0
- package/dist/look/chrome.d.ts +11 -0
- package/dist/look/chrome.js +7 -0
- package/dist/look/format.d.ts +15 -0
- package/dist/look/format.js +44 -0
- package/dist/look/index.d.ts +4 -0
- package/dist/look/index.js +5 -0
- package/dist/look/palette.d.ts +21 -0
- package/dist/look/palette.js +46 -0
- package/dist/look/types.d.ts +7 -0
- package/dist/look/types.js +1 -0
- package/dist/shape-views/attio.json +21 -0
- package/dist/shape-views/coresignal.json +28 -0
- package/dist/shape-views/generated.json +3535 -0
- package/dist/shape-views/google.json +22 -0
- package/dist/shape-views/index.d.ts +2 -0
- package/dist/shape-views/index.js +13 -0
- package/dist/shape-views/linkedin.json +23 -0
- package/dist/shape-views/meta.json +19 -0
- package/dist/shape-views/slack.json +12 -0
- package/dist/written/index.d.ts +2 -0
- package/dist/written/index.js +4 -0
- package/dist/written/runtime.d.ts +43 -0
- package/dist/written/runtime.js +83 -0
- package/dist/written/written-view.d.ts +23 -0
- package/dist/written/written-view.js +47 -0
- package/package.json +72 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"schema": "GoogleCampaignSchema",
|
|
4
|
+
"classCurie": "google:Campaign",
|
|
5
|
+
"status": "curated",
|
|
6
|
+
"fields": [
|
|
7
|
+
{ "name": "campaignName", "path": "google:campaignName", "type": "string" },
|
|
8
|
+
{ "name": "campaignAdvertisingChannelType", "path": "google:campaignAdvertisingChannelType", "type": "string" },
|
|
9
|
+
{ "name": "campaignStatus", "path": "google:campaignStatus", "type": "string" },
|
|
10
|
+
{ "name": "campaignBiddingStrategyType", "path": "google:campaignBiddingStrategyType", "type": "string" },
|
|
11
|
+
{ "name": "campaignStartDate", "path": "google:campaignStartDate", "type": "date" },
|
|
12
|
+
{ "name": "campaignOptimizationScore", "path": "google:campaignOptimizationScore", "type": "number" }
|
|
13
|
+
],
|
|
14
|
+
"record": {
|
|
15
|
+
"type": "record",
|
|
16
|
+
"title": "campaignName",
|
|
17
|
+
"subtitle": "campaignAdvertisingChannelType",
|
|
18
|
+
"fields": ["campaignBiddingStrategyType", "campaignStartDate", "campaignOptimizationScore"],
|
|
19
|
+
"badges": ["campaignStatus"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { shapeViewSpecSchema } from "@manta-eu/horns/shapes";
|
|
2
|
+
import attio from "./attio.json" with { type: "json" };
|
|
3
|
+
import coresignal from "./coresignal.json" with { type: "json" };
|
|
4
|
+
import generated from "./generated.json" with { type: "json" };
|
|
5
|
+
import google from "./google.json" with { type: "json" };
|
|
6
|
+
import linkedin from "./linkedin.json" with { type: "json" };
|
|
7
|
+
import meta from "./meta.json" with { type: "json" };
|
|
8
|
+
import slack from "./slack.json" with { type: "json" };
|
|
9
|
+
// The HornViews the kit ships for LDKit shapes, one file per namespace. Coverage work adds to these, and
|
|
10
|
+
// `apps/web` checks every one against the SDK's live shapes.
|
|
11
|
+
export const shapeViewSpecs = shapeViewSpecSchema
|
|
12
|
+
.array()
|
|
13
|
+
.parse([...attio, ...coresignal, ...generated, ...google, ...linkedin, ...meta, ...slack]);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"schema": "LinkedinAdAccountSchema",
|
|
4
|
+
"classCurie": "linkedin:AdAccount",
|
|
5
|
+
"status": "drafted",
|
|
6
|
+
"fields": [
|
|
7
|
+
{ "name": "name", "path": "schema:name", "type": "string" },
|
|
8
|
+
{ "name": "type", "path": "linkedin:type", "type": "string" },
|
|
9
|
+
{ "name": "status", "path": "linkedin:status", "type": "string" },
|
|
10
|
+
{ "name": "currency", "path": "schema:currency", "type": "string" },
|
|
11
|
+
{ "name": "totalBudgetAmount", "path": "linkedin:totalBudgetAmount", "type": "number" },
|
|
12
|
+
{ "name": "dateCreated", "path": "schema:dateCreated", "type": "date" },
|
|
13
|
+
{ "name": "test", "path": "linkedin:test", "type": "boolean" }
|
|
14
|
+
],
|
|
15
|
+
"record": {
|
|
16
|
+
"type": "record",
|
|
17
|
+
"title": "name",
|
|
18
|
+
"subtitle": "type",
|
|
19
|
+
"fields": ["currency", "totalBudgetAmount", "dateCreated", "test"],
|
|
20
|
+
"badges": ["status"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"schema": "MetaAdSchema",
|
|
4
|
+
"classCurie": "meta:Ad",
|
|
5
|
+
"status": "curated",
|
|
6
|
+
"fields": [
|
|
7
|
+
{ "name": "label", "path": "rdfs:label", "type": "string" },
|
|
8
|
+
{ "name": "effectiveStatus", "path": "meta:effectiveStatus", "type": "string" },
|
|
9
|
+
{ "name": "identifier", "path": "schema:identifier", "type": "string" },
|
|
10
|
+
{ "name": "dateCreated", "path": "schema:dateCreated", "type": "date" }
|
|
11
|
+
],
|
|
12
|
+
"record": {
|
|
13
|
+
"type": "record",
|
|
14
|
+
"title": "label",
|
|
15
|
+
"fields": ["dateCreated", "identifier"],
|
|
16
|
+
"badges": ["effectiveStatus"]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"schema": "SlackWorkspaceSchema",
|
|
4
|
+
"classCurie": "slack:Workspace",
|
|
5
|
+
"status": "curated",
|
|
6
|
+
"fields": [
|
|
7
|
+
{ "name": "name", "path": "schema:name", "type": "string" },
|
|
8
|
+
{ "name": "identifier", "path": "schema:identifier", "type": "string" }
|
|
9
|
+
],
|
|
10
|
+
"record": { "type": "record", "title": "name", "fields": ["identifier"] }
|
|
11
|
+
}
|
|
12
|
+
]
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { compileWritten, createSurfaceLoader, evaluateWritten, transpileWritten, WrittenViewError, type CompileWrittenOptions, type WrittenComponent, type WrittenComponentProps, type WrittenLink, type WrittenSurface, } from "./runtime.ts";
|
|
2
|
+
export { WrittenView, type WrittenViewProps } from "./written-view.tsx";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Off the package barrel on purpose: the only part of the kit carrying a transpiler, so a host that shows no
|
|
2
|
+
// written view never loads it.
|
|
3
|
+
export { compileWritten, createSurfaceLoader, evaluateWritten, transpileWritten, WrittenViewError, } from "./runtime.js";
|
|
4
|
+
export { WrittenView } from "./written-view.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/** A module the host binds by specifier: `{ "@manta-eu/react": mod, "@manta-eu/react/chart": mod }`. */
|
|
3
|
+
export type WrittenSurface = Readonly<Record<string, Readonly<Record<string, unknown>>>>;
|
|
4
|
+
export declare class WrittenViewError extends Error {
|
|
5
|
+
constructor(message: string, options?: {
|
|
6
|
+
cause?: unknown;
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
/** Serves the surface and nothing else, narrowed to the declared exports so a host cannot widen it. */
|
|
10
|
+
export declare function createSurfaceLoader(surface: WrittenSurface, hooks: Readonly<Record<string, unknown>>): (specifier: string) => Readonly<Record<string, unknown>>;
|
|
11
|
+
/** TSX to CommonJS. Loaded on first use: a Horn with no written view must not pay for the transpiler. */
|
|
12
|
+
export declare function transpileWritten(source: string): Promise<string>;
|
|
13
|
+
/** Where an IRI opens, and what the link says. The host builds the href; a view never composes one. */
|
|
14
|
+
export type WrittenLink = {
|
|
15
|
+
href: string;
|
|
16
|
+
label: string;
|
|
17
|
+
};
|
|
18
|
+
export type WrittenComponentProps = {
|
|
19
|
+
rows: readonly Readonly<Record<string, unknown>>[];
|
|
20
|
+
columns: readonly string[];
|
|
21
|
+
/** The display name of every IRI in the rows, so a view shows a thing rather than an address. */
|
|
22
|
+
labels: Readonly<Record<string, string>>;
|
|
23
|
+
/** Where each IRI opens, for the ones that have a page. Absent means there is nothing to link to. */
|
|
24
|
+
links: Readonly<Record<string, WrittenLink>>;
|
|
25
|
+
};
|
|
26
|
+
export type WrittenComponent = (props: WrittenComponentProps) => ReactNode;
|
|
27
|
+
/** `new Function` rather than an import: by now the source is CommonJS, and its only way out is `require`. */
|
|
28
|
+
export declare function evaluateWritten(code: string, load: (specifier: string) => Readonly<Record<string, unknown>>): WrittenComponent;
|
|
29
|
+
export type CompileWrittenOptions = {
|
|
30
|
+
source: string;
|
|
31
|
+
/**
|
|
32
|
+
* Fetches the host's surface, on demand.
|
|
33
|
+
*
|
|
34
|
+
* A function rather than the modules themselves so that binding the whole design system costs nothing on a
|
|
35
|
+
* page with no written view — which is every page, most of the time. The host's loader is where the dynamic
|
|
36
|
+
* import lives, so the bundler can split it out.
|
|
37
|
+
*/
|
|
38
|
+
loadSurface: () => Promise<WrittenSurface>;
|
|
39
|
+
/** React's own hooks, from the host's React, so a view's state lives in the same reconciler as the page. */
|
|
40
|
+
hooks: Readonly<Record<string, unknown>>;
|
|
41
|
+
};
|
|
42
|
+
/** Source to a component, ready to render in the host's own tree. */
|
|
43
|
+
export declare function compileWritten(options: CompileWrittenOptions): Promise<WrittenComponent>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createElement, Fragment } from "react";
|
|
2
|
+
import { allowedReactHooks, isSurfaceModule, surfaceExports } from "@manta-eu/horns/render";
|
|
3
|
+
export class WrittenViewError extends Error {
|
|
4
|
+
constructor(message, options) {
|
|
5
|
+
super(message, options);
|
|
6
|
+
this.name = "WrittenViewError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
// The JSX the transpiler emits calls `React.createElement`, and the classic runtime needs `Fragment` for
|
|
10
|
+
// `<>`. Neither is importable — `allowedReactHooks` is what the model may name — so they are injected rather
|
|
11
|
+
// than served, and a source that imports them is refused upstream.
|
|
12
|
+
const reactModule = {
|
|
13
|
+
createElement,
|
|
14
|
+
Fragment,
|
|
15
|
+
};
|
|
16
|
+
/** Serves the surface and nothing else, narrowed to the declared exports so a host cannot widen it. */
|
|
17
|
+
export function createSurfaceLoader(surface, hooks) {
|
|
18
|
+
const bound = new Map();
|
|
19
|
+
for (const [specifier, module] of Object.entries(surface)) {
|
|
20
|
+
const allowed = surfaceExports(specifier);
|
|
21
|
+
if (allowed === undefined)
|
|
22
|
+
continue;
|
|
23
|
+
bound.set(specifier, Object.fromEntries([...allowed].flatMap((name) => (name in module ? [[name, module[name]]] : []))));
|
|
24
|
+
}
|
|
25
|
+
bound.set("react", {
|
|
26
|
+
...reactModule,
|
|
27
|
+
...Object.fromEntries(allowedReactHooks.flatMap((name) => (name in hooks ? [[name, hooks[name]]] : []))),
|
|
28
|
+
});
|
|
29
|
+
return (specifier) => {
|
|
30
|
+
const module = bound.get(specifier);
|
|
31
|
+
if (module === undefined) {
|
|
32
|
+
throw new WrittenViewError(isSurfaceModule(specifier)
|
|
33
|
+
? `The host did not bind "${specifier}", which this view imports.`
|
|
34
|
+
: `"${specifier}" is not on the view surface.`);
|
|
35
|
+
}
|
|
36
|
+
return module;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
let transpiler;
|
|
40
|
+
/** TSX to CommonJS. Loaded on first use: a Horn with no written view must not pay for the transpiler. */
|
|
41
|
+
export async function transpileWritten(source) {
|
|
42
|
+
transpiler ??= (await import("sucrase")).transform;
|
|
43
|
+
try {
|
|
44
|
+
return transpiler(source, {
|
|
45
|
+
transforms: ["typescript", "jsx", "imports"],
|
|
46
|
+
jsxRuntime: "classic",
|
|
47
|
+
production: true,
|
|
48
|
+
}).code;
|
|
49
|
+
}
|
|
50
|
+
catch (cause) {
|
|
51
|
+
throw new WrittenViewError(`This view does not compile: ${cause instanceof Error ? cause.message : "unknown"}`, {
|
|
52
|
+
cause,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function isCallable(value) {
|
|
57
|
+
return typeof value === "function";
|
|
58
|
+
}
|
|
59
|
+
/** `new Function` rather than an import: by now the source is CommonJS, and its only way out is `require`. */
|
|
60
|
+
export function evaluateWritten(code, load) {
|
|
61
|
+
const moduleRecord = { exports: {} };
|
|
62
|
+
try {
|
|
63
|
+
const factory = new Function("require", "exports", "module", "React", code);
|
|
64
|
+
factory(load, moduleRecord.exports, moduleRecord, reactModule);
|
|
65
|
+
}
|
|
66
|
+
catch (cause) {
|
|
67
|
+
if (cause instanceof WrittenViewError)
|
|
68
|
+
throw cause;
|
|
69
|
+
throw new WrittenViewError(`This view failed while loading: ${cause instanceof Error ? cause.message : "unknown"}`, {
|
|
70
|
+
cause,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const component = moduleRecord.exports["default"];
|
|
74
|
+
if (!isCallable(component)) {
|
|
75
|
+
throw new WrittenViewError("This view exports no component. A written view is one `export default`.");
|
|
76
|
+
}
|
|
77
|
+
return component;
|
|
78
|
+
}
|
|
79
|
+
/** Source to a component, ready to render in the host's own tree. */
|
|
80
|
+
export async function compileWritten(options) {
|
|
81
|
+
const [code, surface] = await Promise.all([transpileWritten(options.source), options.loadSurface()]);
|
|
82
|
+
return evaluateWritten(code, createSurfaceLoader(surface, options.hooks));
|
|
83
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type WrittenLink, type WrittenSurface } from "./runtime.ts";
|
|
3
|
+
export type WrittenViewProps = {
|
|
4
|
+
/** The TSX the Studio wrote. Refused by `tsxViolations` long before it reaches here. */
|
|
5
|
+
source: string;
|
|
6
|
+
rows: readonly Readonly<Record<string, unknown>>[];
|
|
7
|
+
columns: readonly string[];
|
|
8
|
+
/** The snapshot's names by IRI, so a view can show the thing an IRI points at. */
|
|
9
|
+
labels: Readonly<Record<string, string>>;
|
|
10
|
+
/** Where each IRI opens, for the ones with a page. The host composes the href; the view never does. */
|
|
11
|
+
links: Readonly<Record<string, WrittenLink>>;
|
|
12
|
+
/**
|
|
13
|
+
* Fetches the host's own modules, by specifier, narrowed to the declared surface before the view sees
|
|
14
|
+
* them. Hold this at module scope: a fresh function every render recompiles the view every render.
|
|
15
|
+
*/
|
|
16
|
+
loadSurface: () => Promise<WrittenSurface>;
|
|
17
|
+
/** The host's React hooks, so a view's state lives in the same reconciler as the page. Also stable. */
|
|
18
|
+
hooks: Readonly<Record<string, unknown>>;
|
|
19
|
+
/** Drawn while the transpiler loads. */
|
|
20
|
+
fallback?: ReactNode;
|
|
21
|
+
renderError?: (message: string) => ReactNode;
|
|
22
|
+
};
|
|
23
|
+
export declare function WrittenView(props: WrittenViewProps): ReactNode;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Component, useEffect, useState } from "react";
|
|
3
|
+
import { compileWritten, WrittenViewError, } from "./runtime.js";
|
|
4
|
+
// Keyed on the source, so fixing a view brings it back without a reload.
|
|
5
|
+
class WrittenBoundary extends Component {
|
|
6
|
+
state = {};
|
|
7
|
+
static getDerivedStateFromError(error) {
|
|
8
|
+
return { message: error instanceof Error ? error.message : "unknown error" };
|
|
9
|
+
}
|
|
10
|
+
render() {
|
|
11
|
+
const { message } = this.state;
|
|
12
|
+
return message === undefined ? this.props.children : this.props.render(message);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const defaultError = (message) => (_jsx("p", { role: "alert", style: { margin: 0, fontSize: 14 }, children: message }));
|
|
16
|
+
export function WrittenView(props) {
|
|
17
|
+
const { source, rows, columns, labels, links, loadSurface, hooks, fallback, renderError = defaultError } = props;
|
|
18
|
+
const [state, setState] = useState({});
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
let live = true;
|
|
21
|
+
setState({});
|
|
22
|
+
compileWritten({ source, loadSurface, hooks })
|
|
23
|
+
.then((component) => {
|
|
24
|
+
if (live)
|
|
25
|
+
setState({ component });
|
|
26
|
+
})
|
|
27
|
+
.catch((cause) => {
|
|
28
|
+
if (!live)
|
|
29
|
+
return;
|
|
30
|
+
// A WrittenViewError already says what a person can act on; anything else is a bug in the runtime.
|
|
31
|
+
setState({
|
|
32
|
+
error: cause instanceof WrittenViewError
|
|
33
|
+
? cause.message
|
|
34
|
+
: `This view could not be prepared: ${cause instanceof Error ? cause.message : "unknown"}`,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
return () => {
|
|
38
|
+
live = false;
|
|
39
|
+
};
|
|
40
|
+
}, [source, loadSurface, hooks]);
|
|
41
|
+
if (state.error !== undefined)
|
|
42
|
+
return renderError(state.error);
|
|
43
|
+
if (state.component === undefined)
|
|
44
|
+
return fallback ?? null;
|
|
45
|
+
const View = state.component;
|
|
46
|
+
return (_jsx(WrittenBoundary, { render: (message) => renderError(`This view stopped while drawing: ${message}`), children: _jsx(View, { rows: rows, columns: columns, labels: labels, links: links }) }, source));
|
|
47
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@manta-eu/horns-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Manta Horns component kit: charts and snapshot views that render on a server and hydrate in any React host, and the components the HornView sandbox runs.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/manta-eu/manta-horns.git",
|
|
9
|
+
"directory": "packages/horns-kit"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./server": {
|
|
23
|
+
"types": "./dist/embed/server.d.ts",
|
|
24
|
+
"default": "./dist/embed/server.js"
|
|
25
|
+
},
|
|
26
|
+
"./client": {
|
|
27
|
+
"types": "./dist/embed/client.d.ts",
|
|
28
|
+
"default": "./dist/embed/client.js"
|
|
29
|
+
},
|
|
30
|
+
"./catalog": {
|
|
31
|
+
"types": "./dist/catalog.d.ts",
|
|
32
|
+
"default": "./dist/catalog.js"
|
|
33
|
+
},
|
|
34
|
+
"./shape-views": {
|
|
35
|
+
"types": "./dist/shape-views/index.d.ts",
|
|
36
|
+
"default": "./dist/shape-views/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./written": {
|
|
39
|
+
"types": "./dist/written/index.d.ts",
|
|
40
|
+
"default": "./dist/written/index.js"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"registry": "https://registry.npmjs.org",
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"sucrase": "^3.35.1",
|
|
49
|
+
"ts-pattern": "^5.9.0",
|
|
50
|
+
"@manta-eu/horns": "0.1.0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"react": ">=18",
|
|
54
|
+
"react-dom": ">=18"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^24",
|
|
58
|
+
"@types/react": "^19.2.18",
|
|
59
|
+
"@types/react-dom": "^19.2.7",
|
|
60
|
+
"react": "19.2.4",
|
|
61
|
+
"react-dom": "19.2.4",
|
|
62
|
+
"rimraf": "^6.1.3",
|
|
63
|
+
"typescript": "^5.9.0",
|
|
64
|
+
"vitest": "^3.2.0"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "rimraf dist && tsc -p tsconfig.build.json",
|
|
68
|
+
"types": "tsc --noEmit && tsc -p tsconfig.build.json --noEmit",
|
|
69
|
+
"test": "vitest run",
|
|
70
|
+
"catalog:snapshot": "node scripts/snapshot-react-catalog.ts"
|
|
71
|
+
}
|
|
72
|
+
}
|