@opencorestack/opengridx 3.4.0 → 3.5.1
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/CHANGELOG.md +45 -0
- package/README.md +10 -3
- package/dist/ai.cjs +2 -1
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.d.ts +203 -3
- package/dist/ai.es.js +2 -1
- package/dist/ai.es.js.map +1 -1
- package/dist/index.d.ts +248 -4
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7334 -5906
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +16 -16
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +88 -7
- package/docs/README.md +3 -1
- package/docs/architecture/datagrid-orchestration.md +11 -5
- package/docs/components/filter-panel.md +1 -0
- package/docs/components/header.md +4 -1
- package/docs/components/toolbar.md +7 -0
- package/docs/customization/theming.md +3 -1
- package/docs/features/ai-toolkit.md +99 -5
- package/docs/features/cell-selection.md +8 -2
- package/docs/features/fill-handle.md +125 -0
- package/docs/features/filtering.md +3 -0
- package/docs/features/header-filters.md +138 -0
- package/docs/features/keyboard-navigation.md +20 -2
- package/docs/features/virtualization.md +5 -5
- package/docs/performance.md +212 -1
- package/docs/roadmap.md +3 -4
- package/lib/ai/agentTools.ts +160 -0
- package/lib/ai/index.ts +19 -2
- package/lib/ai/promptHandler.ts +109 -0
- package/lib/ai/types.ts +89 -25
- package/lib/ai/validate.ts +10 -0
- package/lib/components/AiAssistant/GridAiAssistantArea.tsx +26 -0
- package/lib/components/AiAssistant/GridAiAssistantPanel.css +171 -0
- package/lib/components/AiAssistant/GridAiAssistantPanel.tsx +145 -0
- package/lib/components/AiAssistant/useSpeechInput.ts +74 -0
- package/lib/components/Cell/Cell.css +28 -0
- package/lib/components/Cell/Cell.tsx +6 -2
- package/lib/components/DataGrid/DataGrid.tsx +84 -4
- package/lib/components/DataGrid/GridLiveRegion.tsx +5 -2
- package/lib/components/DataGrid/GridPinnedRows.tsx +5 -1
- package/lib/components/DataGrid/GridVirtualRows.tsx +5 -1
- package/lib/components/FilterPanel/FilterPanel.tsx +2 -9
- package/lib/components/Header/Header.tsx +44 -23
- package/lib/components/Header/headerColumnStyle.ts +28 -0
- package/lib/components/HeaderFilter/HeaderFilter.css +160 -0
- package/lib/components/HeaderFilter/HeaderFilterCell.tsx +370 -0
- package/lib/components/HeaderFilter/HeaderFilterOperatorMenu.tsx +124 -0
- package/lib/components/HeaderFilter/HeaderFilterRow.tsx +157 -0
- package/lib/components/Toolbar/GridToolbar.tsx +51 -0
- package/lib/hooks/core/gridApiPlaceholder.ts +8 -0
- package/lib/hooks/core/gridToolbarHostContext.ts +5 -0
- package/lib/hooks/core/useGridApiMethods.ts +39 -0
- package/lib/hooks/core/useGridAriaRows.ts +5 -3
- package/lib/hooks/core/useGridCellSelection.ts +77 -11
- package/lib/hooks/core/useGridColumnsPanel.ts +24 -1
- package/lib/hooks/core/useGridControlledState.ts +27 -0
- package/lib/hooks/core/useGridDevWarnings.ts +21 -6
- package/lib/hooks/core/useGridFillHandle.ts +323 -0
- package/lib/hooks/core/useGridKeyboardNavigation.ts +29 -10
- package/lib/hooks/core/useGridMaxContentHeight.ts +16 -0
- package/lib/hooks/core/useGridToolbarProps.ts +19 -0
- package/lib/hooks/core/useGridVirtualization.ts +19 -0
- package/lib/hooks/features/useGridAiAssistant.ts +284 -0
- package/lib/hooks/features/useGridBatchEdit.ts +2 -2
- package/lib/index.ts +3 -0
- package/lib/styles/opengridx.css +2 -0
- package/lib/theme/DataGridThemeProvider.tsx +2 -0
- package/lib/theme/types.ts +2 -0
- package/lib/types/index.ts +219 -1
- package/lib/utils/aiAssistant.ts +205 -0
- package/lib/utils/aiBrand.ts +17 -0
- package/lib/utils/cellSelection.ts +25 -5
- package/lib/utils/editing/fill.ts +238 -0
- package/lib/utils/filtering/index.ts +14 -0
- package/lib/utils/focus/index.ts +9 -3
- package/lib/utils/headerFilters.ts +189 -0
- package/lib/utils/maxElementHeight.ts +53 -0
- package/llms.txt +44 -4
- package/package.json +3 -2
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenGridX — AI Agent Context
|
|
2
2
|
# Package: @opencorestack/opengridx
|
|
3
|
-
# Version: 3.
|
|
3
|
+
# Version: 3.5.1
|
|
4
4
|
# Docs: https://opencorestack.github.io/OpenGridX/
|
|
5
5
|
# This file is machine-readable. AI developers: start here.
|
|
6
6
|
|
|
@@ -103,6 +103,8 @@ export default function App() {
|
|
|
103
103
|
| disableRangeClear | boolean (3.4.0+) | With cellSelection, Delete/Backspace on a multi-cell range empties editable cells ('' strings, null otherwise) as one edit; true = off |
|
|
104
104
|
| undoRedo | boolean / { limit } (3.4.0+) | Undo/redo of edits, pastes, range clears (default off, 100 actions). Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, Ctrl+Y on a cell with no editor open. Recorded only after processRowUpdate succeeds; replayed through valueSetter + processRowUpdate; cells changed since are skipped ('changed', compared by value), removed rows ('missing') |
|
|
105
105
|
| onHistoryChange | ({ canUndo, canRedo, size }) => void | History change (size = undoable actions) |
|
|
106
|
+
| disableFillHandle | boolean (3.5.0+) | With cellSelection, the range's bottom-right cell has a fill handle: drag down/up/right/left (one direction; auto-scroll; touch) fills the new cells from the range — numbers and dates with an exactly equal step continue (2,4 → 6,8; 15 Jan,15 Feb → 15 Mar; 5 Oct,6 Oct → 7 Oct), anything else repeats, one cell copies; Alt at release copies; Escape cancels. Ctrl/Cmd+D fills down from the range's top row, Ctrl/Cmd+R right from its left column. valueSetter + processRowUpdate once per row, one undo step, non-editable/synthetic cells skipped ('notEditable'). true = no handle, keys left to the browser |
|
|
107
|
+
| onFill | (result) => void (3.5.0+) | After every fill: { updated, failed, skipped, direction: 'down'/'up'/'right'/'left' } |
|
|
106
108
|
|
|
107
109
|
### Sorting
|
|
108
110
|
| Prop | Type | Description |
|
|
@@ -118,6 +120,8 @@ export default function App() {
|
|
|
118
120
|
| filterModel | GridFilterModel | Controlled filter state (optional: the grid keeps its own filter model otherwise) |
|
|
119
121
|
| onFilterModelChange | (model: GridFilterModel) => void | Filter change callback |
|
|
120
122
|
| filterMode | 'client' / 'server' | 'server': rows are shown unfiltered as given |
|
|
123
|
+
| headerFilters | boolean (default false) | Filter row under the column headers (3.5.0+): Input for string/number/date, Any/Yes/No select for boolean, valueOptions select for singleSelect, operator menu, clear button; 300 ms debounce. Each cell owns the root filterModel item with id 'header:<field>'; root logicOperator 'or', the field inside a group or another root item on the field shows a read-only "Custom filter" (opens the GridToolbar filter panel). Not rendered in pivot mode |
|
|
124
|
+
| headerFilterHeight | number (default 40) | Height of the header filter row (--ogx-header-filter-height) |
|
|
121
125
|
|
|
122
126
|
### Pagination
|
|
123
127
|
| Prop | Type | Description |
|
|
@@ -169,7 +173,8 @@ export default function App() {
|
|
|
169
173
|
### Grouping & Aggregation
|
|
170
174
|
| Prop | Type | Description |
|
|
171
175
|
|------------------------|---------------------------|------------------------------------------|
|
|
172
|
-
| rowGroupingModel | string[] | Fields to group by (one nesting level per field). Disables pagination. groupable:false fields are skipped |
|
|
176
|
+
| rowGroupingModel | string[] | Fields to group by (one nesting level per field). Disables pagination. groupable:false fields are skipped. Passing it controls grouping; without it the grid keeps its own model (3.5.0+: apiRef.setRowGroupingModel, AI assistant) |
|
|
177
|
+
| onRowGroupingModelChange | (model: string[]) => void | Grouping changed through apiRef.setRowGroupingModel or the AI assistant (3.5.0+) |
|
|
173
178
|
| aggregationModel | GridAggregationModel | {field: 'sum'/'avg'/'min'/'max'/'count'/'unique'} |
|
|
174
179
|
| onAggregationModelChange | (model) => void | Aggregation model changed (toolbar Summaries panel) |
|
|
175
180
|
| groupingColDef | Partial<GridColDef<R>> | Adds a dedicated `__group__` column pinned left (rowGroupingModel or treeData); no `field` needed; never exported |
|
|
@@ -252,6 +257,7 @@ There are no getRowClassName / getCellClassName / theme props: use GridColDef.ce
|
|
|
252
257
|
| valueGetter | ({row, field, value}) => unknown | Computed value; used by sort, filter, quick search, aggregation, copy, export. Must be pure (quick filter caches per row object); a throw reads as undefined + dev warning |
|
|
253
258
|
| valueSetter | ({value, row, field}) => R | Write an edited value back onto the row (editable valueGetter columns) |
|
|
254
259
|
| valueParser | (text, { row, field, colDef }) => unknown | Paste parser for this column (3.4.0+), e.g. "1.234,5" → 1234.5. Throw/undefined skips the cell ('invalidValue'). Default by type: number "1,234.5"/"12%"/"$5"; date ISO or Date.parse (keeps the cell's kind); boolean true/false/yes/no/1/0; singleSelect value or label; empty → null ('' for strings) |
|
|
260
|
+
| fillValue | ({ value, sourceValues, index, direction, copy, row, id, field, colDef }) => unknown | Fill handle (3.5.0+): what a fill writes into this column's cell. value = the grid's choice (series / pattern / copy); return it to keep it. Throw skips the cell ('invalidValue') |
|
|
255
261
|
| valueFormatter | ({value, row, field}) => string | Format display value (value is `unknown`: cast before calling methods) |
|
|
256
262
|
| cellClassName | string / (params) => string | CSS class on cells |
|
|
257
263
|
| headerClassName | string | CSS class on header cell |
|
|
@@ -263,6 +269,8 @@ There are no getRowClassName / getCellClassName / theme props: use GridColDef.ce
|
|
|
263
269
|
| sortable | boolean (default true) | Enable sorting |
|
|
264
270
|
| sortComparator | (v1, v2, params1, params2) => number | Custom ascending comparator (3.1.0+). v1/v2 are valueGetter values incl. null/undefined; params { id, field, row, value }. Negated for desc; multi-sort tie-break chain; groups by grouping value; tree siblings; pivot row labels. Throw/NaN = 0. Ignored in server sortingMode |
|
|
265
271
|
| filterable | boolean (default true) | Enable filtering and quick search |
|
|
272
|
+
| headerFilter | boolean (default true) | false: empty cell in the header filter row (3.5.0+) |
|
|
273
|
+
| headerFilterOperator | GridFilterOperator | Starting header filter operator (default: contains / = / is by type) (3.5.0+) |
|
|
266
274
|
| resizable | boolean (default true) | Enable resize handle (mouse, touch, Alt+Arrow on header); double-click or Enter on the handle auto-sizes to content (3.1.0+) |
|
|
267
275
|
| hideable | boolean (default true) | Allow hiding via toolbar / column menu |
|
|
268
276
|
| pinnable | boolean (default true) | Allow pinning via column menu (does not affect drag-reorder) |
|
|
@@ -306,6 +314,15 @@ apiRef.current.getSortModel() // → GridSortItem[]
|
|
|
306
314
|
apiRef.current.setFilterModel(model)
|
|
307
315
|
apiRef.current.getFilterModel() // → GridFilterModel
|
|
308
316
|
|
|
317
|
+
// Model setters (3.5.0+): each fires its change callback, like the UI
|
|
318
|
+
apiRef.current.setSortModel(model)
|
|
319
|
+
apiRef.current.setRowGroupingModel(fields)
|
|
320
|
+
apiRef.current.setAggregationModel(model)
|
|
321
|
+
apiRef.current.setColumnVisibilityModel(model)
|
|
322
|
+
apiRef.current.setPivotModel(model)
|
|
323
|
+
apiRef.current.getGridAiState() // → { filterModel, sortModel, rowGroupingModel, aggregationModel, pivotModel, columnVisibilityModel }
|
|
324
|
+
apiRef.current.openAiAssistant() // opens the aiAssistant panel (no-op without aiAssistant); closeAiAssistant()
|
|
325
|
+
|
|
309
326
|
// Pagination
|
|
310
327
|
apiRef.current.setPage(page)
|
|
311
328
|
apiRef.current.setPageSize(size)
|
|
@@ -558,7 +575,7 @@ await printGrid(rows, columns, 'My Report Title');
|
|
|
558
575
|
|
|
559
576
|
## AI TOOLKIT (@opencorestack/opengridx/ai, 3.4.0+)
|
|
560
577
|
|
|
561
|
-
Separate entry point: no React, no dependencies, ~
|
|
578
|
+
Separate entry point: no React, no dependencies, ~6.7 kB gzip with the 3.5.0 additions; never loaded by the core import. OpenGridX calls no AI service: the app sends { prompt, schema, currentState } to its own model (structured output) and validates the reply.
|
|
562
579
|
|
|
563
580
|
```ts
|
|
564
581
|
import { getGridAiSchema, validateGridAiState } from '@opencorestack/opengridx/ai';
|
|
@@ -575,6 +592,27 @@ if (state.sortModel) setSortModel(state.sortModel);
|
|
|
575
592
|
- Privacy: no row data by default; `aiExamples` and `valueOptions` ARE sent; always apply `state`, never the raw reply.
|
|
576
593
|
- Types (from /ai): GridAiColumn, GridAiPart, GridAiSchema, GridAiSchemaOptions, GridAiState, GridAiValidateOptions, GridAiValidationError, GridAiValidationResult.
|
|
577
594
|
|
|
595
|
+
### AI toolkit part 2 (3.5.0+): Ask AI panel and agent tools
|
|
596
|
+
|
|
597
|
+
```tsx
|
|
598
|
+
import { createGridAiPromptHandler, createGridAgentTools } from '@opencorestack/opengridx/ai';
|
|
599
|
+
|
|
600
|
+
const onPrompt = createGridAiPromptHandler({
|
|
601
|
+
columns,
|
|
602
|
+
callModel: async (request, { signal }) => (await fetch('/api/grid-ai', { method: 'POST', body: JSON.stringify(request), signal })).json(),
|
|
603
|
+
});
|
|
604
|
+
<DataGrid columns={columns} rows={rows} slots={{ toolbar: GridToolbar }} aiAssistant={{ onPrompt, suggestions: ['Top 10 by revenue'] }} />
|
|
605
|
+
|
|
606
|
+
const tools = createGridAgentTools(apiRef, columns); // [{ name, description, inputSchema, execute }]
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
- `aiAssistant` prop: { onPrompt(prompt, { currentState, history, signal }) => Promise<{ state, errors, message? }>, placeholder?, suggestions?, voice? = true, parts? }. GridToolbar shows an "Ask AI" button (localeText.aiAssistantButton); apiRef.openAiAssistant() without a toolbar; slots.aiAssistantPanel replaces the panel (GridAiAssistantPanelProps). Events: onAiAssistantApply(result), onAiAssistantError(error).
|
|
610
|
+
- BRAND RULE: the grid applies a result only if `result.state` carries Symbol.for('opengridx.ai.validated'), set (non-enumerable) by validateGridAiState on the result and its state. Unbranded → not applied, "The reply was not validated" + dev warning. `{ ...result, message }` keeps the brand; `{ ...result.state }` loses it.
|
|
611
|
+
- Applying: immediately, one undoable step (Undo restores the models from before the reply; separate from the cell-edit undoRedo history). Each change is a removable chip; removing one re-applies the reply without it. Parts replace the grid's models, except columnVisibilityModel (merged). Parts outside `parts`, and parts the validator emptied (all entries dropped), are not applied. Voice: mic button only where SpeechRecognition / webkitSpeechRecognition exists; the microphone is requested only on click. Panel: role=dialog "Ask AI", Escape closes and returns focus, status in the grid's live region; Stop aborts `signal`.
|
|
612
|
+
- createGridAiPromptHandler({ columns, callModel, parts?, schemaOptions? }): schema built once; callModel({ prompt, schema, currentState, history }, { signal }); reply = state object | JSON string | text with a ```json fence (surrounding text / a `message` key → result.message; plain text → message only); validated + branded. callModel throw → { state: {}, errors: [{ path: '', message }] }; abort → rejects AbortError.
|
|
613
|
+
- createGridAgentTools(apiRef, columns, { allowRowAccess?, fields?, maxRows? = 20 }): get_grid_state, set_filter, set_sort, set_grouping, set_aggregation, set_column_visibility (merged), clear_filters, and get_row_summary ONLY with allowRowAccess: true (the one tool that sends rows). Inputs validated with validateGridAiState; any error → nothing applied, { ok: false, errors }. execute never throws. Works with the Vercel AI SDK, CopilotKit, OpenAI / Anthropic tool calling, WebMCP.
|
|
614
|
+
- More types (from /ai): GridAiPromptContext, GridAiPromptResult, GridAiHistoryEntry, GridAiAssistantOptions, GridAiAssistantPanelProps, GridAiChip, GridAiModelRequest, GridAiPromptHandlerOptions, GridAgentTool, GridAgentToolResult, GridAgentToolsOptions, GridAgentApi. /ai is ~6.7 kB gzip (budget 8 kB).
|
|
615
|
+
|
|
578
616
|
---
|
|
579
617
|
|
|
580
618
|
## CSS CUSTOMIZATION
|
|
@@ -598,7 +636,9 @@ Class names use the `ogx__` BEM prefix, e.g.:
|
|
|
598
636
|
- `ogx__row`, `ogx__row--selected`, `ogx__row--even`, `ogx__row--odd`
|
|
599
637
|
- `ogx__cell`, `ogx__cell--focused`, `ogx__cell--editing`
|
|
600
638
|
- Cell ranges (3.3.0+): `ogx__cell--range`, `ogx__cell--range-top|bottom|left|right` (inset box-shadow outline), `ogx--range-dragging` on the root during a drag; variables `--ogx-range-background`, `--ogx-range-border` (theme keys `grid.rangeBackground`, `grid.rangeBorder`)
|
|
639
|
+
- Fill handle (3.5.0+): `ogx__cell-fill-handle` (24px hit area in the corner cell, visible square is `::after`), variable `--ogx-fill-handle-color` (defaults to `--ogx-range-border`; theme key `grid.fillHandleColor`)
|
|
601
640
|
- `ogx__header-cell`, `ogx__header-cell--sorted`, `ogx__header-cell--wrap` (wrapHeaderText, 3.3.0+)
|
|
641
|
+
- Header filter row (3.5.0+): `ogx__header-filter-row`, `ogx__header-filter-cell` (`--focused`, `--active`, `--custom`, `--empty`, `--system`, `--pinned*`), `ogx__header-filter-operator`, `ogx__header-filter-menu`, `ogx__header-filter-input-wrapper` / `ogx__header-filter-input`, `ogx__header-filter-select`, `ogx__header-filter-clear`, `ogx__header-filter-custom`; height variable `--ogx-header-filter-height`
|
|
602
642
|
- Sticky wrappers: `ogx__sticky-top` (header + top-pinned rows), `ogx__sticky-bottom` (bottom-pinned rows + aggregation footer)
|
|
603
643
|
- Form controls (3.3.1+): the toolbar search, column-panel search, filter value box and text/number/date editors render through `Input`: the `<input>` keeps its class (`ogx-global-search__input`, `ogx-column-visibility-panel__search-input`, `ogx-filter__value-input`, `ogx__edit-input`) inside a `div.ogx-input-wrapper` (`ogx-input-wrapper--cell` for editors) — use descendant selectors (`.ogx-global-search input`), not `> input`. The boolean editor and list-view row checkbox are the shared `Checkbox` (`.ogx-checkbox__box`; hidden `<input>`)
|
|
604
644
|
|
|
@@ -660,7 +700,7 @@ interface GridGetRowsResponse<R = GridRowModel> {
|
|
|
660
700
|
|
|
661
701
|
## KEYBOARD
|
|
662
702
|
|
|
663
|
-
Arrows move between cells (skipping hidden columns); Home/End, Ctrl+Home/End, PageUp/PageDown; Enter edits an editable cell, otherwise acts like a row click (toggles group/tree rows); Tab leaves the grid (while editing it moves to the next editable cell); Shift+Space selects the row (Space toggles the checkbox or detail panel when those cells are focused); Ctrl/Cmd+A selects all; Ctrl/Cmd+C copies the selection; Alt+ArrowRight/Left expands/collapses; Enter/Space on a header sorts (Shift adds to the sort); Alt+ArrowDown or Ctrl+Enter on a header opens the column menu; Alt+ArrowLeft/Right on a header resizes it.
|
|
703
|
+
Arrows move between cells (skipping hidden columns); Home/End, Ctrl+Home/End, PageUp/PageDown; Enter edits an editable cell, otherwise acts like a row click (toggles group/tree rows); Tab leaves the grid (while editing it moves to the next editable cell); Shift+Space selects the row (Space toggles the checkbox or detail panel when those cells are focused); Ctrl/Cmd+A selects all; Ctrl/Cmd+C copies the selection; Alt+ArrowRight/Left expands/collapses; Enter/Space on a header sorts (Shift adds to the sort); Alt+ArrowDown or Ctrl+Enter on a header opens the column menu; Alt+ArrowLeft/Right on a header resizes it. With headerFilters (3.5.0+): ArrowDown on a header moves to its filter cell, ArrowDown again to the first row; Enter/Space or typing focuses the filter control, Escape returns to the cell, Alt+ArrowDown opens the operator menu, Delete clears the filter; controls are not Tab stops (Tab leaves the grid).
|
|
664
704
|
|
|
665
705
|
---
|
|
666
706
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencorestack/opengridx",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.1",
|
|
4
4
|
"description": "OpenGridX: High-performance React data infrastructure. Unlock advanced Row Grouping, Excel Export, and Column Pinning without the usual \"Pro\" gatekeeping. Built for speed, scale, and complete architectural freedom. Fully open, virtualization-ready, and feature-complete.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/opengridx.umd.js",
|
|
@@ -53,12 +53,13 @@
|
|
|
53
53
|
"build": "tsc --project tsconfig.build.json && vite build",
|
|
54
54
|
"build:lib": "tsc --project tsconfig.build.json && vite build --config vite.config.lib.js && vite build --config vite.config.lib.js --mode ai && cp lib/styles/opengridx.css.d.ts dist/opengridx.css.d.ts && node scripts/check-bundle.mjs",
|
|
55
55
|
"lint": "eslint .",
|
|
56
|
-
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit && tsc -p e2e/tsconfig.json",
|
|
56
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit && tsc -p e2e/tsconfig.json && tsc -p bench/tsconfig.json",
|
|
57
57
|
"preview": "vite preview",
|
|
58
58
|
"test": "vitest run --project unit",
|
|
59
59
|
"test:browser": "vitest run --project browser",
|
|
60
60
|
"test:all": "vitest run",
|
|
61
61
|
"test:smoke": "node scripts/smoke.mjs",
|
|
62
|
+
"bench": "node bench/run.mjs",
|
|
62
63
|
"test:watch": "vitest --project unit",
|
|
63
64
|
"coverage": "vitest run --coverage",
|
|
64
65
|
"prepublishOnly": "npm run build:lib",
|