@loadbare/app 0.4.0 → 0.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/README.md +53 -82
- package/dist/build/assemble.d.ts +7 -5
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +29 -9
- package/dist/build/cli.d.ts +20 -12
- package/dist/build/cli.d.ts.map +1 -1
- package/dist/build/cli.js +34 -16
- package/dist/build/elements.d.ts +15 -29
- package/dist/build/elements.d.ts.map +1 -1
- package/dist/build/elements.js +25 -111
- package/dist/build/expand.d.ts +1 -1
- package/dist/build/expand.js +1 -1
- package/dist/build/format.d.ts +6 -3
- package/dist/build/format.d.ts.map +1 -1
- package/dist/build/format.js +6 -3
- package/dist/build/locations.d.ts +14 -37
- package/dist/build/locations.d.ts.map +1 -1
- package/dist/build/locations.js +31 -69
- package/dist/build/origins.d.ts +109 -0
- package/dist/build/origins.d.ts.map +1 -0
- package/dist/build/origins.js +270 -0
- package/dist/core/lb-constants.d.ts +1 -0
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +15 -8
- package/dist/core/lb-types.d.ts +2 -2
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +1 -1
- package/dist/hub/lb-hub.d.ts.map +1 -1
- package/dist/hub/lb-hub.js +44 -17
- package/dist/hub/lb-rows.d.ts.map +1 -1
- package/dist/hub/lb-rows.js +3 -3
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-server.d.ts +5 -4
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/tests/assemble.test.js +11 -4
- package/dist/tests/elements.test.js +47 -51
- package/dist/tests/expand.test.d.ts +1 -1
- package/dist/tests/expand.test.js +2 -2
- package/dist/tests/fixtures/elements/collision/imports.d.ts +3 -0
- package/dist/tests/fixtures/elements/collision/imports.d.ts.map +1 -0
- package/dist/tests/fixtures/elements/collision/imports.js +1 -0
- package/dist/tests/fixtures/elements/manifest/imports.d.ts +3 -0
- package/dist/tests/fixtures/elements/manifest/imports.d.ts.map +1 -0
- package/dist/tests/fixtures/elements/manifest/imports.js +1 -0
- package/dist/tests/fixtures/elements/manifest-bad-entry/imports.d.ts +3 -0
- package/dist/tests/fixtures/elements/manifest-bad-entry/imports.d.ts.map +1 -0
- package/dist/tests/fixtures/elements/manifest-bad-entry/imports.js +1 -0
- package/dist/tests/fixtures/elements/{collision/elements.d.ts → manifest-not-array/imports.d.ts} +1 -1
- package/dist/tests/fixtures/elements/manifest-not-array/imports.d.ts.map +1 -0
- package/dist/tests/fixtures/elements/manifest-not-array/imports.js +1 -0
- package/dist/tests/fixtures/elements/pkg/acme-widget.d.ts +2 -0
- package/dist/tests/fixtures/elements/pkg/acme-widget.d.ts.map +1 -0
- package/dist/tests/fixtures/elements/pkg/acme-widget.js +1 -0
- package/dist/tests/lb-express.test.js +1 -1
- package/dist/tests/origins.test.d.ts +10 -0
- package/dist/tests/origins.test.d.ts.map +1 -0
- package/dist/tests/origins.test.js +326 -0
- package/dist/tests/pages.test.js +3 -3
- package/dist/tests/styles.test.js +7 -4
- package/docs/reference/builder.md +128 -0
- package/docs/reference/chrome.md +75 -0
- package/docs/reference/css.md +44 -0
- package/docs/reference/custom-elements.md +327 -0
- package/docs/reference/data-binding.md +240 -0
- package/docs/reference/overview.md +38 -0
- package/docs/reference/page-files.md +175 -0
- package/docs/reference/server.md +123 -0
- package/docs/reference/widgets.md +163 -0
- package/docs/roadmap.md +130 -0
- package/docs/testing.md +228 -0
- package/docs/theory.md +344 -223
- package/docs/tutorials/000-getting-started.md +86 -0
- package/docs/tutorials/010-pages-and-navigation.md +129 -0
- package/docs/tutorials/020-css.md +103 -0
- package/docs/tutorials/030-html-decomposition.md +79 -0
- package/docs/tutorials/040-displaying-data.md +169 -0
- package/docs/tutorials/050-actions.md +77 -0
- package/docs/tutorials/060-custom-element-code.md +73 -0
- package/docs/tutorials/065-conditional-rendering.md +161 -0
- package/docs/tutorials/070-displaying-a-list.md +137 -0
- package/docs/tutorials/072-inserting-into-a-list.md +88 -0
- package/docs/tutorials/074-deleting-from-a-list.md +77 -0
- package/docs/tutorials/076-updating-a-list-item.md +86 -0
- package/docs/tutorials/080-widget-requests.md +124 -0
- package/docs/tutorials/090-using-widget-libraries.md +75 -0
- package/package.json +10 -18
- package/dist/client.js +0 -522
- package/dist/demo-static/src/widgets/app-box.d.ts +0 -15
- package/dist/demo-static/src/widgets/app-box.d.ts.map +0 -1
- package/dist/demo-static/src/widgets/app-box.js +0 -19
- package/dist/tests/fixtures/elements/collision/elements.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/collision/elements.js +0 -3
- package/dist/tests/fixtures/elements/manifest/elements.d.ts +0 -5
- package/dist/tests/fixtures/elements/manifest/elements.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/manifest/elements.js +0 -3
- package/dist/tests/fixtures/elements/manifest-bad-tag/elements.d.ts +0 -5
- package/dist/tests/fixtures/elements/manifest-bad-tag/elements.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/manifest-bad-tag/elements.js +0 -3
- package/dist/tests/fixtures/elements/manifest-bad-value/elements.d.ts +0 -5
- package/dist/tests/fixtures/elements/manifest-bad-value/elements.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/manifest-bad-value/elements.js +0 -3
- package/dist/tests/golden.test.d.ts +0 -19
- package/dist/tests/golden.test.d.ts.map +0 -1
- package/dist/tests/golden.test.js +0 -60
- package/dist/tests/helpers/window.d.ts +0 -43
- package/dist/tests/helpers/window.d.ts.map +0 -1
- package/dist/tests/helpers/window.js +0 -78
- package/dist/tests/lb-input.test.d.ts +0 -9
- package/dist/tests/lb-input.test.d.ts.map +0 -1
- package/dist/tests/lb-input.test.js +0 -78
- package/dist/tests/lb-list.test.d.ts +0 -12
- package/dist/tests/lb-list.test.d.ts.map +0 -1
- package/dist/tests/lb-list.test.js +0 -44
- package/dist/tests/lb-options.test.d.ts +0 -10
- package/dist/tests/lb-options.test.d.ts.map +0 -1
- package/dist/tests/lb-options.test.js +0 -121
- package/dist/tests/lb-picker.test.d.ts +0 -14
- package/dist/tests/lb-picker.test.d.ts.map +0 -1
- package/dist/tests/lb-picker.test.js +0 -59
- package/dist/tests/lb-select.test.d.ts +0 -9
- package/dist/tests/lb-select.test.d.ts.map +0 -1
- package/dist/tests/lb-select.test.js +0 -71
- package/dist/tests/lb-table.test.d.ts +0 -15
- package/dist/tests/lb-table.test.d.ts.map +0 -1
- package/dist/tests/lb-table.test.js +0 -205
- package/dist/widgets/index.d.ts +0 -7
- package/dist/widgets/index.d.ts.map +0 -1
- package/dist/widgets/index.js +0 -6
- package/dist/widgets/lb-input.d.ts +0 -2
- package/dist/widgets/lb-input.d.ts.map +0 -1
- package/dist/widgets/lb-input.js +0 -48
- package/dist/widgets/lb-list.d.ts +0 -2
- package/dist/widgets/lb-list.d.ts.map +0 -1
- package/dist/widgets/lb-list.js +0 -17
- package/dist/widgets/lb-options.d.ts +0 -26
- package/dist/widgets/lb-options.d.ts.map +0 -1
- package/dist/widgets/lb-options.js +0 -72
- package/dist/widgets/lb-picker.d.ts +0 -2
- package/dist/widgets/lb-picker.d.ts.map +0 -1
- package/dist/widgets/lb-picker.js +0 -25
- package/dist/widgets/lb-select.d.ts +0 -2
- package/dist/widgets/lb-select.d.ts.map +0 -1
- package/dist/widgets/lb-select.js +0 -43
- package/dist/widgets/lb-table.d.ts +0 -2
- package/dist/widgets/lb-table.d.ts.map +0 -1
- package/dist/widgets/lb-table.js +0 -113
- package/docs/application-chrome.md +0 -36
- package/docs/building-html-pages.md +0 -130
- package/docs/getting-started.md +0 -120
- package/docs/guide.md +0 -1164
- package/docs/hosting.md +0 -218
- package/docs/latent-risks.md +0 -20
- package/widgets/index.ts +0 -6
- package/widgets/lb-input.html +0 -1
- package/widgets/lb-input.ts +0 -64
- package/widgets/lb-list.html +0 -1
- package/widgets/lb-list.ts +0 -21
- package/widgets/lb-options.html +0 -4
- package/widgets/lb-options.ts +0 -88
- package/widgets/lb-picker.html +0 -7
- package/widgets/lb-picker.ts +0 -27
- package/widgets/lb-select.html +0 -4
- package/widgets/lb-select.ts +0 -55
- package/widgets/lb-table.html +0 -8
- package/widgets/lb-table.ts +0 -126
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Widget Requests
|
|
2
|
+
|
|
3
|
+
Our list example showed the use of forms and submit. The inputs
|
|
4
|
+
were passive in the sense that they did not trigger any change on their
|
|
5
|
+
own.
|
|
6
|
+
|
|
7
|
+
Now we will see how to make a widget that fires events when its value
|
|
8
|
+
changes.
|
|
9
|
+
|
|
10
|
+
## Writing the widget
|
|
11
|
+
|
|
12
|
+
Our new custom input will no longer rely on Loadbare's form handling,
|
|
13
|
+
and so it must reimplement the data scoping logic that is in
|
|
14
|
+
Loadbare. This reimplementation approach is neither encouraged nor
|
|
15
|
+
discouraged. This tutorial shows only that it is possible, and exposes
|
|
16
|
+
how Loadbare internals work.
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<!-- src/note-input.html -->
|
|
20
|
+
<input type="text" />
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// src/note-input.ts
|
|
25
|
+
import {
|
|
26
|
+
ATTR_CELL,
|
|
27
|
+
ATTR_KEY,
|
|
28
|
+
ATTR_QUERY,
|
|
29
|
+
ATTR_VALUE,
|
|
30
|
+
LB_EVENT_NAME,
|
|
31
|
+
} from "@loadbare/app/constants";
|
|
32
|
+
|
|
33
|
+
class NoteInput extends HTMLElement {
|
|
34
|
+
static observedAttributes = [ATTR_VALUE];
|
|
35
|
+
|
|
36
|
+
attributeChangedCallback(_name: string, _old: string, value: string) {
|
|
37
|
+
const input = this.querySelector("input");
|
|
38
|
+
if (input) input.value = value;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
connectedCallback() {
|
|
42
|
+
this.addEventListener("change", () => {
|
|
43
|
+
const input = this.querySelector("input");
|
|
44
|
+
if (!input) return;
|
|
45
|
+
const query = this.closest(`[${ATTR_QUERY}]`)?.getAttribute(ATTR_QUERY);
|
|
46
|
+
const key = this.closest(`[${ATTR_KEY}]`)?.getAttribute(ATTR_KEY);
|
|
47
|
+
const cell = this.getAttribute(ATTR_CELL);
|
|
48
|
+
if (!query || !key || !cell) return;
|
|
49
|
+
this.dispatchEvent(
|
|
50
|
+
new CustomEvent(LB_EVENT_NAME, {
|
|
51
|
+
bubbles: true,
|
|
52
|
+
detail: { op: "cell-change", query, key, cell, value: input.value },
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
customElements.define("note-input", NoteInput);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
A widget with both a `.html` and a `.ts` file shares one tag name; the
|
|
63
|
+
build finds each half independently. On change, it reads its own
|
|
64
|
+
`lb-query`/`lb-key`/`lb-cell` coordinates and dispatches a `cell-change`
|
|
65
|
+
request itself, the way `lb-update` does for a whole form.
|
|
66
|
+
|
|
67
|
+
## Using it
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<!-- src/pages/about.page.html -->
|
|
71
|
+
<lb-list lb-query="notes">
|
|
72
|
+
<ul>
|
|
73
|
+
<template lb-key="id">
|
|
74
|
+
<li>
|
|
75
|
+
<note-input lb-cell="text"></note-input>
|
|
76
|
+
<button lb-delete>Delete</button>
|
|
77
|
+
</li>
|
|
78
|
+
</template>
|
|
79
|
+
</ul>
|
|
80
|
+
</lb-list>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The `<form lb-update>` and Save button are gone — `note-input` commits on
|
|
84
|
+
every change, so there's nothing left to batch.
|
|
85
|
+
|
|
86
|
+
## Answering it server-side
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
// src/pages/about.hooks.ts
|
|
90
|
+
import { patch } from "@loadbare/app/server";
|
|
91
|
+
|
|
92
|
+
export const hooks = {
|
|
93
|
+
// ...beforeGet and actions unchanged...
|
|
94
|
+
crud: {
|
|
95
|
+
notes: {
|
|
96
|
+
// ...tupleInsert, tupleDelete, tupleUpdate unchanged...
|
|
97
|
+
cellChange: {
|
|
98
|
+
run: async (ctx, { key, value }) => {
|
|
99
|
+
const note = await ctx.db.updateNote(key, value);
|
|
100
|
+
return { notes: patch({ rows: [note] }) };
|
|
101
|
+
},
|
|
102
|
+
refresh: [],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`cellChange` reuses `updateNote` from [Updating a List Item](./076-updating-a-list-item.md)
|
|
110
|
+
— the database doesn't care whether the edit came from a form's values
|
|
111
|
+
map or one widget's value.
|
|
112
|
+
|
|
113
|
+
## Run it
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
npm run dev
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Edit a note's text and click elsewhere — it commits immediately, no Save
|
|
120
|
+
button. Reload — the change is still there.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
Prev: [Updating a List Item](./076-updating-a-list-item.md)
|
|
124
|
+
Next: [Using Widget Libraries](./090-using-widget-libraries.md)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Using Widget Libraries
|
|
2
|
+
|
|
3
|
+
[Displaying a List](./070-displaying-a-list.md) already installed one widget
|
|
4
|
+
library, `@loadbare/widgets`. This tutorial covers what that step actually
|
|
5
|
+
did, and why it is the same step for a library from anywhere else.
|
|
6
|
+
|
|
7
|
+
[Custom Element Code](./060-custom-element-code.md) and
|
|
8
|
+
[Widget Requests](./080-widget-requests.md) wrote widgets by hand, one
|
|
9
|
+
file per tag, discovered because the tag turned up in a page. A widget
|
|
10
|
+
installed from a package works the same way once the package is listed —
|
|
11
|
+
listing the package is the only new piece.
|
|
12
|
+
|
|
13
|
+
## Installing the library
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
npm install @loadbare/widgets
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Declaring the package
|
|
20
|
+
|
|
21
|
+
The builder finds a widget by scanning for its filename. It scans the
|
|
22
|
+
application's own `src/` without being asked; an installed package has to
|
|
23
|
+
be listed first. That list lives in one file, `imports.ts`, at the root of
|
|
24
|
+
`src/`:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// src/imports.ts
|
|
28
|
+
export default ["@loadbare/widgets"];
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
List the package, not its tags. The builder scans it the same way it scans
|
|
32
|
+
`src/`, so `lb-select.html` and `lb-select.js` inside the package define and
|
|
33
|
+
register `<lb-select>` with nothing else written down. A package that ships
|
|
34
|
+
compiled says which of its directories holds those files — see
|
|
35
|
+
[Widgets from packages](../reference/builder.md#widgets-from-packages) — and
|
|
36
|
+
that is the package author's line to write, not the application's.
|
|
37
|
+
|
|
38
|
+
Only tags actually used in the chrome file or a page are bundled. Listing a
|
|
39
|
+
package says where to look; it does not import anything on its own.
|
|
40
|
+
|
|
41
|
+
## Using a tag
|
|
42
|
+
|
|
43
|
+
Once the package is listed, a tag from the library is used exactly like a
|
|
44
|
+
widget written by hand — the query scope and cell attributes work the same
|
|
45
|
+
regardless of where the script came from:
|
|
46
|
+
|
|
47
|
+
```html
|
|
48
|
+
<!-- src/pages/index.page.html -->
|
|
49
|
+
<div lb-query="status">
|
|
50
|
+
<lb-select lb-cell="state">
|
|
51
|
+
<option value="open">Open</option>
|
|
52
|
+
<option value="closed">Closed</option>
|
|
53
|
+
</lb-select>
|
|
54
|
+
</div>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`lb-select` follows the `lb-value` contract
|
|
58
|
+
[Custom Element Code](./060-custom-element-code.md) described: the hub
|
|
59
|
+
writes the query result to `lb-value`, and the widget's own class —
|
|
60
|
+
imported from `@loadbare/widgets`, not written in this
|
|
61
|
+
application — reacts to it.
|
|
62
|
+
|
|
63
|
+
## Where this stops
|
|
64
|
+
|
|
65
|
+
This only covers consuming a published widget, not writing one for
|
|
66
|
+
publication — that's the same class shape
|
|
67
|
+
[Custom Element Code](./060-custom-element-code.md) and
|
|
68
|
+
[Widget Requests](./080-widget-requests.md) already wrote, packaged and
|
|
69
|
+
given an import specifier instead of living in an application's `src/`.
|
|
70
|
+
It doesn't cover `lb-table`'s footer destination or `lb-picker`'s
|
|
71
|
+
expansion parameters, which are in
|
|
72
|
+
[The Basic Widget Library](../reference/widgets.md).
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
Prev: [Widget Requests](./080-widget-requests.md)
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loadbare/app",
|
|
3
3
|
"description": "High performance web app framework for server-bound applications",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
8
|
-
"widgets",
|
|
9
8
|
"docs",
|
|
10
9
|
"README.md"
|
|
11
10
|
],
|
|
@@ -22,27 +21,20 @@
|
|
|
22
21
|
"./rows": "./dist/hub/lb-rows.js",
|
|
23
22
|
"./server": "./dist/server/lb-server.js",
|
|
24
23
|
"./express": "./dist/server/lb-express.js",
|
|
25
|
-
"./build": "./dist/build/elements.js"
|
|
26
|
-
"./widgets/*": "./dist/widgets/*.js"
|
|
24
|
+
"./build": "./dist/build/elements.js"
|
|
27
25
|
},
|
|
28
26
|
"scripts": {
|
|
29
27
|
"prepublishOnly": "npm run typecheck && npm run test && npm run build",
|
|
30
|
-
"preflight": "node scripts/preflight-release.mjs",
|
|
28
|
+
"preflight": "node ../../scripts/preflight-release.mjs",
|
|
31
29
|
"release": "npm run preflight && npm publish",
|
|
32
|
-
"release:patch": "node scripts/bump-release.mjs patch",
|
|
33
|
-
"release:minor": "node scripts/bump-release.mjs minor",
|
|
34
|
-
"release:major": "node scripts/bump-release.mjs major",
|
|
30
|
+
"release:patch": "node ../../scripts/bump-release.mjs patch",
|
|
31
|
+
"release:minor": "node ../../scripts/bump-release.mjs minor",
|
|
32
|
+
"release:major": "node ../../scripts/bump-release.mjs major",
|
|
35
33
|
"prebuild": "node --eval \"fs.rmSync('dist',{recursive:true,force:true})\" --input-type=module",
|
|
36
|
-
"build:client": "esbuild client/main.ts --bundle --format=iife --outfile=dist/client.js",
|
|
37
34
|
"build:server": "tsc --project tsconfig.build.json",
|
|
38
|
-
"build": "npm run build:server
|
|
39
|
-
"
|
|
40
|
-
"dev": "npm run build:demo && (tsx build/cli.ts --src demo --out dist/demo --watch & tsx demo/server.ts)",
|
|
41
|
-
"build:demo-static": "npm run build:server && tsx build/cli.ts --src demo-static/src --out dist/demo-static",
|
|
42
|
-
"dev:demo-static": "npm run build:demo-static -- --watch & node demo-static/serve.mjs",
|
|
35
|
+
"build": "npm run build:server",
|
|
36
|
+
"postbuild": "node --eval \"fs.chmodSync('dist/build/cli.js', 0o755)\" --input-type=module",
|
|
43
37
|
"test": "tsx --test \"tests/**/*.test.ts\"",
|
|
44
|
-
"test:golden": "UPDATE_GOLDEN=1 tsx --test tests/golden.test.ts",
|
|
45
|
-
"pretypecheck": "npm run build:demo",
|
|
46
38
|
"typecheck": "tsc --noEmit",
|
|
47
39
|
"format": "prettier --write .",
|
|
48
40
|
"format:check": "prettier --check ."
|
|
@@ -63,7 +55,8 @@
|
|
|
63
55
|
},
|
|
64
56
|
"dependencies": {
|
|
65
57
|
"esbuild": "^0.28.1",
|
|
66
|
-
"jsdom": "^25.0.0"
|
|
58
|
+
"jsdom": "^25.0.0",
|
|
59
|
+
"prettier": "^3.8.4"
|
|
67
60
|
},
|
|
68
61
|
"peerDependencies": {
|
|
69
62
|
"express": "^5.0.0"
|
|
@@ -78,7 +71,6 @@
|
|
|
78
71
|
"@types/jsdom": "^21.1.7",
|
|
79
72
|
"@types/node": "^22.0.0",
|
|
80
73
|
"express": "^5.2.1",
|
|
81
|
-
"prettier": "^3.8.4",
|
|
82
74
|
"tsx": "^4.19.0",
|
|
83
75
|
"typescript": "^5.6.0"
|
|
84
76
|
}
|