uniweb 0.21.0 → 0.22.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/package.json +6 -6
- package/partials/agents.md +106 -6
- package/src/commands/doctor.js +104 -1
- package/src/framework-index.json +5 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -42,13 +42,13 @@
|
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
44
|
"@uniweb/core": "^0.8.5",
|
|
45
|
-
"@uniweb/
|
|
46
|
-
"@uniweb/
|
|
45
|
+
"@uniweb/kit": "^0.12.0",
|
|
46
|
+
"@uniweb/runtime": "^0.11.7"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@uniweb/
|
|
50
|
-
"@uniweb/
|
|
51
|
-
"@uniweb/
|
|
49
|
+
"@uniweb/content-reader": "^1.2.2",
|
|
50
|
+
"@uniweb/build": "^0.22.0",
|
|
51
|
+
"@uniweb/semantic-parser": "^1.2.2"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
54
|
"@uniweb/build": {
|
package/partials/agents.md
CHANGED
|
@@ -649,6 +649,50 @@ seo:
|
|
|
649
649
|
|
|
650
650
|
**Localized URLs:** on a multilingual site (`languages:` in site.yml), `slug: { <lang>: <segment> }` gives a page a native URL segment per language; the folder name stays the canonical route. Nested folders compose automatically, and localized URLs flow through navigation, the language switcher, and the sitemap. See Part 5 for the translation workflow.
|
|
651
651
|
|
|
652
|
+
**Knowledge pages — content for an AI agent, not for a visitor.** `knowledge: true` in a `page.yml` or `folder.yml` marks a page as agent-only: it is **never rendered** — no route, no HTML — and it cascades to the whole subtree by route prefix, so one marker on `pages/kb/` covers everything under it and `/kb` never claims `/kbase`. Write plain markdown; a section `type:` there never selects a component, because nothing renders these pages.
|
|
653
|
+
|
|
654
|
+
⚠️ **A knowledge page is not published to anyone — it powers a service your site offers.** Everything your site *does* publish is published on equal terms: an AI visiting your site sees exactly what a person sees. `llms.txt` and the per-page `.md` files are a convenience for that reader, not a privileged tier — no visitor, human or machine, gets more than another.
|
|
655
|
+
|
|
656
|
+
A knowledge page is different in kind, not in audience. It is never a page anyone reads; it is source material for an assistant the site offers **to its visitors** — they ask, they get an answer, and the material behind it stays unpublished. That is why it is kept out of `llms.txt`, the `.md` projections and the search index: not because some readers are trusted less, but because a knowledge page was never a page.
|
|
657
|
+
|
|
658
|
+
⇒ If what you want is "make this readable by any AI that visits", write an ordinary page. It is already published to them, on the same terms as to everyone else.
|
|
659
|
+
|
|
660
|
+
⛔ **`knowledge:` is not a security control — don't put secrets there.** "Not published" is about who the prose is *written for*, not about confidentiality. The assistant's job is to answer visitors using this material and it can quote it back to whoever asks, so a visitor who prompts it can surface what a knowledge page says — **by design, not by leak.** The test for what belongs here is "is this written for the assistant to reason with?", not "do I want to keep this from people?" Anything that genuinely must not reach a visitor doesn't belong in your site's content at all.
|
|
661
|
+
|
|
662
|
+
```yaml
|
|
663
|
+
# pages/kb/page.yml
|
|
664
|
+
title: Product Knowledge
|
|
665
|
+
knowledge: true
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
What can actually *read* it depends on where you deploy, because reading it needs a server:
|
|
669
|
+
|
|
670
|
+
- **`uniweb deploy`** (backend-hosted) — the content travels with the site, so an assistant running over it can grep and read your knowledge material alongside the public content when answering a visitor's question.
|
|
671
|
+
- **`uniweb export` / `uniweb deploy --host <adapter>`** (static host) — **the build drops these pages and says so**: `Dropped 2 knowledge page(s) from this build: /kb, /kb/pricing`. Files are served as files here; there is no assistant, so nothing would read them. The warning means the flag was honoured.
|
|
672
|
+
|
|
673
|
+
The artifacts **your build emits** to describe the public site never name them — `llms.txt`, the per-page `.md` projections, and the search index all describe pages a visitor reads, and a knowledge page's prose was written for the assistant instead. Two settings **outrank** `knowledge:`, so a contradiction resolves toward the narrower reach: `agents.exclude` in `site.yml`, and any `_`-prefixed route segment. *(A host that derives these artifacts itself, rather than serving the ones your build produced, applies its own rules — ask your host what it does with `knowledge:` before relying on it there.)*
|
|
674
|
+
|
|
675
|
+
Don't confuse it with the visibility flags: `hidden: true` is a **draft** (not published at all), `hideIn` only controls **nav placement** (still reachable by URL), and `knowledge: true` is a **different audience** (never rendered for anyone).
|
|
676
|
+
|
|
677
|
+
**A site can be nothing but knowledge — that is a real and useful shape.** A site is a set of routes; it does not have to have HTML pages. Mark the root `knowledge: true` and every page inherits it, so the site renders nothing at all and exists to *be* an agent: a `/_agent/chat` URL that a web app, a mobile app, or someone else's backend sends requests to.
|
|
678
|
+
|
|
679
|
+
```
|
|
680
|
+
site/pages/
|
|
681
|
+
├── page.yml # knowledge: true — cascades to everything
|
|
682
|
+
├── house-style.md
|
|
683
|
+
├── pricing.md
|
|
684
|
+
└── support.md
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
Measured on exactly that shape: **the agent corpus holds every page; the public projections hold nothing** — `llms.txt` lists no pages, the search index has 0 entries, and no `.md` files are emitted. Nothing leaks, by construction rather than by configuration, because there is no public surface to leak onto.
|
|
688
|
+
|
|
689
|
+
⛔ **This shape needs a host that actually runs an agent, and deploying is not the same as having one.** Two ways to end up with nothing:
|
|
690
|
+
|
|
691
|
+
- **A static host** (`uniweb export`, `deploy --host`) drops every page — they have no reader there — and you get an empty SPA shell. The build still says *"complete"*, because 0 pages is not an error: it reports `Collected 0 pages` and pre-renders none.
|
|
692
|
+
- **A backend-hosted deployment that does not offer the service.** Whether an agent endpoint exists is the host's to decide, per site — it is not implied by deploying successfully.
|
|
693
|
+
|
|
694
|
+
⇒ **The way to know is to ask, at render:** `resolveService(website, 'assistant')` returns a `url` only where the host declared one. On a site that is *only* knowledge there is no component to ask — so confirm with your host that the agent is enabled for that site before you build an integration against it. If you meant to build an agent endpoint and got silence, this is where to look.
|
|
695
|
+
|
|
652
696
|
### Your site is readable by agents, automatically
|
|
653
697
|
|
|
654
698
|
Every build emits two things an AI agent can use directly, alongside the HTML. **Free, on by default, nothing to install.**
|
|
@@ -674,6 +718,38 @@ agents:
|
|
|
674
718
|
agents: false # or turn the whole thing off in one word
|
|
675
719
|
```
|
|
676
720
|
|
|
721
|
+
#### Expecting agent traffic from somewhere specific
|
|
722
|
+
|
|
723
|
+
If your site runs an agent (see *Knowledge pages* above), you can declare where its requests are expected to come from. Useful when the site exists to serve someone else's app rather than its own visitors — a chat endpoint your web app calls.
|
|
724
|
+
|
|
725
|
+
```yaml
|
|
726
|
+
# site.yml
|
|
727
|
+
agents:
|
|
728
|
+
expectedOrigins:
|
|
729
|
+
- https://app.example.com
|
|
730
|
+
- https://partner.example.org
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
**It is a declaration, not a gate — the name is the contract.** You are telling the host where you expect callers from; a host that offers an agent may then decline requests whose browser-sent `Origin` is not one of them, before it spends anything answering. Behaviour where it is honoured:
|
|
734
|
+
|
|
735
|
+
| | |
|
|
736
|
+
|---|---|
|
|
737
|
+
| not declared | no check at all — nothing happens unless you ask for it |
|
|
738
|
+
| your own site's origin | always fine, without listing it — declaring a partner must not take down your own chat box |
|
|
739
|
+
| a request with **no** `Origin` | **allowed** — see below, this is deliberate |
|
|
740
|
+
| matching | exact, per entry; no wildcards |
|
|
741
|
+
|
|
742
|
+
⛔ **It is not a spend limit, and it cannot be.** `Origin` is set by the browser and enforced by the browser: anything that is not a browser sends whatever it likes, or nothing at all. So this stops **casual misuse and third-party embedding** — someone dropping your endpoint into their own page — and it does **not** stop anyone determined to run up your bill. Do not size your budget on it.
|
|
743
|
+
|
|
744
|
+
⭐ **And that is why a request with no `Origin` is allowed rather than refused.** There are two shapes of caller and this check only sees one:
|
|
745
|
+
|
|
746
|
+
- your app's **JavaScript**, in a browser — sends `Origin`, covered here;
|
|
747
|
+
- your app's **server**, calling from its own backend — never sends one, and refusing it would break the integration this feature partly exists for.
|
|
748
|
+
|
|
749
|
+
Server-to-server callers are authenticated by other means, arranged with your host — not by anything in `site.yml`. **Never put a shared secret in `site.yml`:** everything in it is delivered to every visitor as part of the site payload.
|
|
750
|
+
|
|
751
|
+
⚠️ Spelling matters and nothing downstream will catch it — the block is forwarded to your host as opaque data, so a typo is carried and simply never acted on. `uniweb doctor` flags unknown keys in `agents:` for exactly this reason; run it before you rely on one.
|
|
752
|
+
|
|
677
753
|
**Set `seo.baseUrl` if you want absolute links** in the index — without it the links are root-relative, which still works for an agent that arrived via the index. `uniweb doctor` warns when it's unset.
|
|
678
754
|
|
|
679
755
|
**What's excluded, and it's deliberate:** `seo.noindex` pages, `hidden` pages, `_`-prefixed drafts, and dynamic route templates. An index *describes* pages rather than merely listing them, so an unlinked page would become both discoverable and summarized — which is why these exclusions are load-bearing rather than tidy-up. `noindex` or `hidden` on a **folder** takes the whole branch with it.
|
|
@@ -1781,6 +1857,21 @@ resolution for anything, so a foundation can define a service the framework has
|
|
|
1781
1857
|
never heard of and a host can fill it. Same escalation `fetcher.transports`
|
|
1782
1858
|
offers for data.
|
|
1783
1859
|
|
|
1860
|
+
**Building an "Ask AI" component?** The service name is `assistant`, and a host that runs an agent for a site typically serves it at the conventional path `/_agent`. **You should never need to write that path** — ask the runtime instead:
|
|
1861
|
+
|
|
1862
|
+
```jsx
|
|
1863
|
+
const { url } = resolveService(website, 'assistant')
|
|
1864
|
+
if (!url) return null // this site has no agent — render nothing, or a static fallback
|
|
1865
|
+
```
|
|
1866
|
+
|
|
1867
|
+
**This is a synchronous read, not a request.** Which services a site has was settled when the site was last published and travels in its metadata, so the runtime already holds the answer — there is no handshake, no probe, no await. Your component asks the runtime; the runtime does not ask anyone.
|
|
1868
|
+
|
|
1869
|
+
⛔ **Absent is the answer, not a lookup that failed.** No `url` means the site has no agent — never enabled, or this host runs none. Render for that case; don't retry it. And don't hardcode `/_agent/chat` when nothing was declared: on a static host that turns "no agent here" into a 404 your component can't tell from a broken endpoint. The path is named above so you recognize the shape, not so you can construct it.
|
|
1870
|
+
|
|
1871
|
+
⛔ **And don't tell the visitor.** `resolveService` also returns a `reason`, and it is **not visitor copy** — a visitor has no stake in which services the operator provisioned, and "this site has no assistant configured" reports someone's billing state to the public while reading like a breakage. It is neither. **Absence is a rendering decision, not a message**: a generic component is expected to be smart about it. No assistant → no Ask-AI affordance. No submit endpoint → no form, or degrade to a `mailto:` the site already carries in its content. The `reason` string is there for *you*, while you wire a site up.
|
|
1872
|
+
|
|
1873
|
+
*(A live agent that errors mid-conversation is a different problem — that's ordinary request failure, handled where you make the request.)*
|
|
1874
|
+
|
|
1784
1875
|
```yaml
|
|
1785
1876
|
# site.yml — only when YOU are providing the endpoint. Publishing to Uniweb
|
|
1786
1877
|
# Cloud needs nothing here; `uniweb export` and most `deploy --host` targets do.
|
|
@@ -1791,14 +1882,16 @@ submit: https://forms.example.com/intake # or another origin
|
|
|
1791
1882
|
```jsx
|
|
1792
1883
|
import { useFormSubmit } from '@uniweb/kit'
|
|
1793
1884
|
|
|
1794
|
-
const { submit, status, error, canSubmit
|
|
1885
|
+
const { submit, status, error, canSubmit } = useFormSubmit({
|
|
1795
1886
|
block, // supplies section + page context
|
|
1796
1887
|
context: { formId: 'contact' },
|
|
1797
1888
|
summary: (v) => ({ title: v.name, subtitle: v.email }),
|
|
1798
1889
|
})
|
|
1799
1890
|
|
|
1800
|
-
|
|
1801
|
-
|
|
1891
|
+
if (!canSubmit) return null // nowhere to send — render no form, or fall back
|
|
1892
|
+
// to contact details from the site's own content
|
|
1893
|
+
|
|
1894
|
+
<button type="submit" disabled={status === 'submitting'}>Send</button>
|
|
1802
1895
|
```
|
|
1803
1896
|
|
|
1804
1897
|
> **The framework never invents an endpoint — but a host may supply one.** Don't
|
|
@@ -1807,11 +1900,18 @@ const { submit, status, error, canSubmit, unavailableReason } = useFormSubmit({
|
|
|
1807
1900
|
> one hosting.
|
|
1808
1901
|
>
|
|
1809
1902
|
> `canSubmit` is false only when neither a declaration nor a host supplies a
|
|
1810
|
-
> destination. **Check it when you render, not only on the button press
|
|
1811
|
-
>
|
|
1812
|
-
> `unavailableReason` — it explains which case you are in. A read that 404s
|
|
1903
|
+
> destination. **Check it when you render, not only on the button press** — a
|
|
1904
|
+
> form nobody can send should not be on the page at all. A read that 404s
|
|
1813
1905
|
> degrades to `[]` and the page still renders; a write that 404s loses what a
|
|
1814
1906
|
> person typed, so it gets no silent fallback.
|
|
1907
|
+
>
|
|
1908
|
+
> ⛔ **Don't tell the visitor why.** There is deliberately no explanatory string:
|
|
1909
|
+
> which services an operator bought is none of a visitor's business, "not enabled
|
|
1910
|
+
> for this site" reads like a breakage when nothing is broken, and any such
|
|
1911
|
+
> sentence would be one language on a site that is often multilingual and rarely
|
|
1912
|
+
> English. Text a visitor reads is **site content** — authored, and localized with
|
|
1913
|
+
> everything else. Degrade to something useful instead: a `mailto:`, a phone
|
|
1914
|
+
> number, an address the site already carries.
|
|
1815
1915
|
|
|
1816
1916
|
`status` runs `idle → submitting → success | error`; a non-2xx becomes a thrown
|
|
1817
1917
|
`Error` carrying the endpoint's own `error` message when it sends one. For file
|
package/src/commands/doctor.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
classifyPackage,
|
|
18
18
|
isExtensionPackage as buildIsExtensionPackage
|
|
19
19
|
} from '@uniweb/build'
|
|
20
|
-
import { loadDeployYml } from '@uniweb/build/site'
|
|
20
|
+
import { loadDeployYml, AGENTS_KEYS } from '@uniweb/build/site'
|
|
21
21
|
import { listAdapters } from '@uniweb/build/hosts'
|
|
22
22
|
import { getCliVersion } from '../versions.js'
|
|
23
23
|
import { readAgentsVersion } from '../utils/agents-stamp.js'
|
|
@@ -255,6 +255,108 @@ export function findFormContent(sitePath, siteYml) {
|
|
|
255
255
|
return found
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
/**
|
|
259
|
+
* A misspelled key in `agents:` is silent everywhere else, forever.
|
|
260
|
+
*
|
|
261
|
+
* The block reaches a backend as **opaque JSON** — measured 2026-08-13, and it
|
|
262
|
+
* is the right design: the vocabulary is the framework's, and a backend that
|
|
263
|
+
* validated it would be inventing our language. The cost is that nothing
|
|
264
|
+
* downstream can object. A host receives `expectedOrgins`, stores it, forwards
|
|
265
|
+
* it, and enforces nothing; the author sees a configured site and gets no
|
|
266
|
+
* check. **This is the only lane that can catch it.**
|
|
267
|
+
*
|
|
268
|
+
* ⛔ Severity is deliberate. It is a `warning` for an unknown key generally,
|
|
269
|
+
* but the failure it prevents is worst for the keys that RESTRICT something —
|
|
270
|
+
* an author who writes `expectedOrgins` believes they asked for a check they
|
|
271
|
+
* did not get. A key that silently does nothing is the recurring wart of this
|
|
272
|
+
* block: `exclude`'s glob spelling excludes nothing, and a carried key nobody
|
|
273
|
+
* reads enforces nothing.
|
|
274
|
+
*
|
|
275
|
+
* `agents: false` turns the capability off in one word and is not an object —
|
|
276
|
+
* flagging its absence of keys would be nonsense.
|
|
277
|
+
*/
|
|
278
|
+
export function checkAgentsBlock({ siteName, siteYml, issues }) {
|
|
279
|
+
const agents = siteYml?.agents
|
|
280
|
+
if (agents === undefined || agents === false) return
|
|
281
|
+
if (!agents || typeof agents !== 'object' || Array.isArray(agents)) {
|
|
282
|
+
const id = 'agents-not-an-object'
|
|
283
|
+
issues.push({
|
|
284
|
+
id,
|
|
285
|
+
type: 'warning',
|
|
286
|
+
site: siteName,
|
|
287
|
+
message: `site.yml: \`agents:\` should be a map of options, or \`false\` to turn it off`
|
|
288
|
+
})
|
|
289
|
+
warn(`[${id}] ${siteName}: \`agents:\` is neither a map of options nor \`false\`.`)
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const known = new Set(AGENTS_KEYS)
|
|
294
|
+
const unknown = Object.keys(agents).filter((k) => !known.has(k))
|
|
295
|
+
if (unknown.length === 0) return
|
|
296
|
+
|
|
297
|
+
const id = 'agents-unknown-key'
|
|
298
|
+
issues.push({
|
|
299
|
+
id,
|
|
300
|
+
type: 'warning',
|
|
301
|
+
site: siteName,
|
|
302
|
+
message: `site.yml: \`agents:\` has ${unknown.length === 1 ? 'an unknown key' : 'unknown keys'}: ${unknown.join(', ')}`
|
|
303
|
+
})
|
|
304
|
+
warn(
|
|
305
|
+
`[${id}] ${siteName}: \`agents:\` ${unknown.length === 1 ? 'key' : 'keys'} ${unknown
|
|
306
|
+
.map((k) => `'${k}'`)
|
|
307
|
+
.join(', ')} ${unknown.length === 1 ? 'is' : 'are'} not recognized.`
|
|
308
|
+
)
|
|
309
|
+
for (const key of unknown) {
|
|
310
|
+
const near = nearestAgentsKey(key, known)
|
|
311
|
+
if (near) log(` ${colors.dim}'${key}' — did you mean ${colors.reset}${colors.green}${near}${colors.reset}${colors.dim}?${colors.reset}`)
|
|
312
|
+
}
|
|
313
|
+
log(
|
|
314
|
+
` ${colors.dim}Nothing downstream will reject it: the block is forwarded to the host as opaque data,${colors.reset}`
|
|
315
|
+
)
|
|
316
|
+
log(
|
|
317
|
+
` ${colors.dim}so an unrecognized key is carried and never acted on. Known: ${AGENTS_KEYS.join(', ')}.${colors.reset}`
|
|
318
|
+
)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* The closest known key within a small edit distance, or null.
|
|
323
|
+
*
|
|
324
|
+
* Suggestions are capped at distance 3 rather than "closest wins": on a
|
|
325
|
+
* six-word vocabulary an uncapped nearest-match confidently proposes `index`
|
|
326
|
+
* for `origins`, and a wrong suggestion is worse than none — it sends the
|
|
327
|
+
* author to change a line that was not their mistake.
|
|
328
|
+
*/
|
|
329
|
+
function nearestAgentsKey(input, known) {
|
|
330
|
+
let best = null
|
|
331
|
+
let bestScore = Infinity
|
|
332
|
+
for (const candidate of known) {
|
|
333
|
+
const score = editDistance(input.toLowerCase(), candidate.toLowerCase())
|
|
334
|
+
if (score < bestScore) {
|
|
335
|
+
bestScore = score
|
|
336
|
+
best = candidate
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return bestScore <= 3 ? best : null
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Levenshtein distance, iterative two-row form. */
|
|
343
|
+
function editDistance(a, b) {
|
|
344
|
+
if (a === b) return 0
|
|
345
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i)
|
|
346
|
+
for (let i = 1; i <= a.length; i++) {
|
|
347
|
+
const row = [i]
|
|
348
|
+
for (let j = 1; j <= b.length; j++) {
|
|
349
|
+
row[j] = Math.min(
|
|
350
|
+
prev[j] + 1,
|
|
351
|
+
row[j - 1] + 1,
|
|
352
|
+
prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1)
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
prev = row
|
|
356
|
+
}
|
|
357
|
+
return prev[b.length]
|
|
358
|
+
}
|
|
359
|
+
|
|
258
360
|
/**
|
|
259
361
|
* A site whose content declares a form needs somewhere to send it.
|
|
260
362
|
*
|
|
@@ -657,6 +759,7 @@ export async function doctor(args = []) {
|
|
|
657
759
|
// anyone who knows the URL, listed by nothing.
|
|
658
760
|
// Forms need a destination, and having none is only visible on the page.
|
|
659
761
|
await checkFormSubmitTarget({ sitePath, siteName, siteYml, issues })
|
|
762
|
+
checkAgentsBlock({ siteName, siteYml, issues })
|
|
660
763
|
|
|
661
764
|
checkGeneratedDataDir({
|
|
662
765
|
sitePath,
|
package/src/framework-index.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-08-
|
|
3
|
+
"generatedAt": "2026-08-13T20:52:45.396Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"@uniweb/build": {
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.22.0",
|
|
7
7
|
"path": "framework/build",
|
|
8
8
|
"deps": [
|
|
9
9
|
"@uniweb/content-reader",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"deps": []
|
|
47
47
|
},
|
|
48
48
|
"@uniweb/kit": {
|
|
49
|
-
"version": "0.
|
|
49
|
+
"version": "0.12.0",
|
|
50
50
|
"path": "framework/kit",
|
|
51
51
|
"deps": [
|
|
52
52
|
"@uniweb/core",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"deps": []
|
|
66
66
|
},
|
|
67
67
|
"@uniweb/projections": {
|
|
68
|
-
"version": "0.3.
|
|
68
|
+
"version": "0.3.1",
|
|
69
69
|
"path": "framework/projections",
|
|
70
70
|
"deps": [
|
|
71
71
|
"@uniweb/content-writer",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"deps": []
|
|
112
112
|
},
|
|
113
113
|
"@uniweb/unipress": {
|
|
114
|
-
"version": "0.8.
|
|
114
|
+
"version": "0.8.7",
|
|
115
115
|
"path": "framework/unipress",
|
|
116
116
|
"deps": [
|
|
117
117
|
"@uniweb/build",
|