odoro 1.0.9 → 2.0.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 +94 -0
- package/client.d.ts +90 -16
- package/dist/build-LZAUDJST.js +5 -0
- package/dist/{chunk-34RGOZFA.js → chunk-4D56Z7G3.js} +49 -50
- package/dist/{chunk-JMEHF3KN.js → chunk-7ZB5MAM6.js} +4 -4
- package/dist/{chunk-LHZGX5ML.js → chunk-OMHEQVIW.js} +295 -160
- package/dist/{chunk-3SZIN6VG.js → chunk-P3DJITWE.js} +10 -10
- package/dist/{chunk-ZVL7EXJO.js → chunk-PRWVZ2SM.js} +22 -14
- package/dist/chunk-Q2KCMTB5.js +741 -0
- package/dist/chunk-QOVBLN7A.js +241 -0
- package/dist/chunk-WWTDEV4Y.js +604 -0
- package/dist/cli.d.ts +12 -13
- package/dist/cli.js +84 -63
- package/dist/{commands-4JRBD55Z.js → commands-EUGVLQWL.js} +44 -45
- package/dist/{commands-AHMXBWQQ.js → commands-GYA7NTCX.js} +124 -124
- package/dist/{create-CYVSVDAD.js → create-QX5LEWMS.js} +158 -154
- package/dist/index.d.ts +603 -151
- package/dist/index.js +6 -6
- package/dist/{package-EIDLKAA6.js → package-T4Z7OBOH.js} +5 -5
- package/dist/preview-P4WY5GEY.js +4 -0
- package/dist/registry/index.d.ts +75 -76
- package/dist/registry/index.js +1 -1
- package/dist/{server-4UGN3SFS.js → server-2WP562EV.js} +3 -3
- package/package.json +5 -5
- package/templates/react-ts/README.md +71 -35
- package/templates/react-ts/_env.example +9 -0
- package/templates/react-ts/_variants/with-engine/src/background.tsx +118 -0
- package/templates/react-ts/_variants/without-libs/src/App.tsx +380 -0
- package/templates/react-ts/_variants/without-libs/src/background.tsx +24 -0
- package/templates/react-ts/_variants/without-libs/src/entry-server.tsx +39 -0
- package/templates/react-ts/_variants/without-libs/src/main.tsx +26 -0
- package/templates/{react-ts-server/_variantes/sans-libs/client → react-ts/_variants/without-libs}/src/styles.css +137 -137
- package/templates/react-ts/{_variantes/sans-routeur → _variants/without-router}/src/App.tsx +141 -141
- package/templates/react-ts/_variants/without-router/src/entry-server.tsx +39 -0
- package/templates/react-ts/index.html +4 -4
- package/templates/react-ts/odoro.config.ts +5 -0
- package/templates/react-ts/src/App.tsx +219 -209
- package/templates/react-ts/src/background.tsx +66 -0
- package/templates/react-ts/src/entry-server.tsx +85 -0
- package/templates/react-ts/src/main.tsx +13 -4
- package/templates/react-ts/src/router.tsx +65 -45
- package/templates/react-ts/src/styles.css +5 -5
- package/templates/react-ts-server/Dockerfile +9 -9
- package/templates/react-ts-server/README.md +97 -45
- package/templates/react-ts-server/_env.example +31 -33
- package/templates/react-ts-server/_variants/with-engine/client/src/background.tsx +118 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/App.tsx +380 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/background.tsx +24 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/entry-server.tsx +39 -0
- package/templates/react-ts-server/_variants/without-libs/client/src/main.tsx +26 -0
- package/templates/{react-ts/_variantes/sans-libs → react-ts-server/_variants/without-libs/client}/src/styles.css +137 -137
- package/templates/react-ts-server/{_variantes/sans-routeur → _variants/without-router}/client/src/App.tsx +141 -141
- package/templates/react-ts-server/_variants/without-router/client/src/entry-server.tsx +39 -0
- package/templates/react-ts-server/client/index.html +4 -4
- package/templates/react-ts-server/client/src/App.tsx +228 -210
- package/templates/react-ts-server/client/src/account.tsx +267 -0
- package/templates/react-ts-server/client/src/auth.tsx +139 -0
- package/templates/react-ts-server/client/src/background.tsx +66 -0
- package/templates/react-ts-server/client/src/entry-server.tsx +92 -0
- package/templates/react-ts-server/client/src/main.tsx +17 -5
- package/templates/react-ts-server/client/src/router.tsx +77 -45
- package/templates/react-ts-server/client/src/styles.css +5 -5
- package/templates/react-ts-server/odoro.config.ts +7 -4
- package/templates/react-ts-server/package.json +2 -0
- package/templates/react-ts-server/scripts/dev.mjs +14 -14
- package/templates/react-ts-server/server/src/main.ts +119 -45
- package/templates/react-ts-server/server/src/modules/auth/index.ts +238 -0
- package/templates/react-ts-server/server/src/modules/auth/password.ts +122 -0
- package/templates/react-ts-server/server/src/modules/auth/store.ts +193 -0
- package/templates/react-ts-server/server/src/modules/health/index.ts +45 -46
- package/dist/build-JFQHODAT.js +0 -5
- package/dist/chunk-22KJTV2R.js +0 -380
- package/dist/chunk-DL3NPC4H.js +0 -113
- package/dist/chunk-TQUJ3MFS.js +0 -268
- package/dist/preview-7DKEAQOQ.js +0 -4
- package/templates/react-ts/_variantes/avec-moteur/src/fond.tsx +0 -118
- package/templates/react-ts/_variantes/sans-libs/src/App.tsx +0 -382
- package/templates/react-ts/_variantes/sans-libs/src/fond.tsx +0 -23
- package/templates/react-ts/_variantes/sans-libs/src/main.tsx +0 -17
- package/templates/react-ts/src/fond.tsx +0 -66
- package/templates/react-ts-server/_variantes/avec-moteur/client/src/fond.tsx +0 -118
- package/templates/react-ts-server/_variantes/sans-libs/client/src/App.tsx +0 -382
- package/templates/react-ts-server/_variantes/sans-libs/client/src/fond.tsx +0 -23
- package/templates/react-ts-server/_variantes/sans-libs/client/src/main.tsx +0 -17
- package/templates/react-ts-server/client/src/fond.tsx +0 -66
package/README.md
CHANGED
|
@@ -26,6 +26,10 @@ package is what it installs.
|
|
|
26
26
|
|
|
27
27
|
Run `odoro --help` for the full list, including the database commands.
|
|
28
28
|
|
|
29
|
+
Useful flags: `--mode <name>` picks the `.env` files and fills
|
|
30
|
+
`import.meta.env.MODE`; `--prerender` renders routes to HTML; `--open` opens the
|
|
31
|
+
browser; `--strict-port` fails instead of sliding to the next free port.
|
|
32
|
+
|
|
29
33
|
## Configuration
|
|
30
34
|
|
|
31
35
|
```ts
|
|
@@ -35,9 +39,99 @@ import { defineConfig } from 'odoro'
|
|
|
35
39
|
export default defineConfig({
|
|
36
40
|
alias: { '@': 'src' },
|
|
37
41
|
server: { port: 5180 },
|
|
42
|
+
build: { prerender: true },
|
|
38
43
|
})
|
|
39
44
|
```
|
|
40
45
|
|
|
46
|
+
## Environment variables
|
|
47
|
+
|
|
48
|
+
`.env` files are read for the current mode, least specific first:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
.env → .env.local → .env.<mode> → .env.<mode>.local
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
A variable already present in the process environment is **never** overwritten by
|
|
55
|
+
a file, so whatever your host injects wins.
|
|
56
|
+
|
|
57
|
+
Only variables prefixed `ODORO_` reach the browser, through `import.meta.env`.
|
|
58
|
+
Everything else stays on the machine — it is readable by the CLI and by your
|
|
59
|
+
backend, and never enters the published bundle.
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
# .env
|
|
63
|
+
ODORO_API=https://api.example.dev # shipped to the browser
|
|
64
|
+
DATABASE_URL=postgres://… # stays here
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Values may be quoted, span several lines (a PEM key), and refer to one another
|
|
68
|
+
with `$OTHER`. Single quotes disable both escapes and expansion, which is how you
|
|
69
|
+
write a password containing a `$`.
|
|
70
|
+
|
|
71
|
+
Pick the mode with `--mode`: `odoro build --mode staging` reads `.env.staging`
|
|
72
|
+
and sets `import.meta.env.MODE`.
|
|
73
|
+
|
|
74
|
+
## Pre-rendering
|
|
75
|
+
|
|
76
|
+
An SPA ships an empty document. A visitor never notices; a search engine, a link
|
|
77
|
+
preview and a screen reader do. `build.prerender` renders your routes to HTML at
|
|
78
|
+
build time, and the client hydrates them instead of rebuilding.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
// src/entry-server.tsx
|
|
82
|
+
import { renderToString } from 'react-dom/server'
|
|
83
|
+
import { App } from '@/App'
|
|
84
|
+
|
|
85
|
+
export const routes = ['/', '/pricing']
|
|
86
|
+
|
|
87
|
+
export function render(url: string) {
|
|
88
|
+
return { html: renderToString(<App url={url} />), head: `<title>…</title>` }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`/pricing` becomes `dist/pricing/index.html`, which any static host serves
|
|
93
|
+
without configuration. Nothing runs in production — the output is still files.
|
|
94
|
+
|
|
95
|
+
## Build output
|
|
96
|
+
|
|
97
|
+
`dist/manifest.json` maps every entry to its fingerprinted file, its stylesheets
|
|
98
|
+
and its chunks, so a backend that renders its own document knows what to point
|
|
99
|
+
at. Shared chunks are declared as `modulepreload` in the document, which removes
|
|
100
|
+
one round trip per level of import depth.
|
|
101
|
+
|
|
102
|
+
Sizes are reported both raw and gzipped, because gzipped is what ships.
|
|
103
|
+
|
|
104
|
+
## Import suffixes and patterns
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import charter from './CHARTER.md?raw' // the file's text
|
|
108
|
+
import logo from './logo.svg?url' // its public URL, nothing loaded
|
|
109
|
+
import Worker from './work.ts?worker' // compiled separately, run off-thread
|
|
110
|
+
|
|
111
|
+
const pages = import.meta.glob('./pages/*.tsx')
|
|
112
|
+
const titles = import.meta.glob('./pages/*.tsx', { eager: true, import: 'title' })
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Patterns are resolved at build time into ordinary static imports, so code
|
|
116
|
+
splitting and tree shaking still apply.
|
|
117
|
+
|
|
118
|
+
## Plugins
|
|
119
|
+
|
|
120
|
+
Three hooks, plus an escape hatch to esbuild for everything else.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { defineConfig, type OdoroPlugin } from 'odoro'
|
|
124
|
+
|
|
125
|
+
const stamp: OdoroPlugin = {
|
|
126
|
+
name: 'stamp',
|
|
127
|
+
transform: (code, { id }) => (id.endsWith('.tsx') ? code : null),
|
|
128
|
+
transformIndexHtml: (html) => html.replace('</head>', '<meta name="v"></head>'),
|
|
129
|
+
configureServer: ({ use }) => use((req, res, next) => next()),
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default defineConfig({ plugins: [stamp] })
|
|
133
|
+
```
|
|
134
|
+
|
|
41
135
|
## The registry is not a dependency
|
|
42
136
|
|
|
43
137
|
`odoro add text/count-up` **copies the source into your project**. The code is
|
package/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Ambient types for the client code of an Odoro project.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* To be referenced once in the project:
|
|
5
5
|
*
|
|
6
6
|
* ```ts
|
|
7
7
|
* /// <reference types="odoro/client" />
|
|
@@ -10,37 +10,111 @@
|
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
/**
|
|
13
|
+
/** Environment variables exposed to the browser. */
|
|
14
14
|
interface OdoroEnv {
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Build mode.
|
|
17
|
+
*
|
|
18
|
+
* `development` and `production` are the two default modes, but a project can
|
|
19
|
+
* name others — `staging`, `demo` — and each reads its own `.env.<mode>`
|
|
20
|
+
* files.
|
|
21
|
+
*/
|
|
22
|
+
readonly MODE: string
|
|
23
|
+
/** True in development. */
|
|
18
24
|
readonly DEV: boolean
|
|
19
|
-
/**
|
|
25
|
+
/** True in production. */
|
|
20
26
|
readonly PROD: boolean
|
|
21
|
-
/**
|
|
27
|
+
/** True during prerendering, absent in the browser. */
|
|
28
|
+
readonly SSR?: boolean
|
|
29
|
+
/** Prefix of the public URLs. */
|
|
22
30
|
readonly BASE_URL: string
|
|
23
|
-
/**
|
|
31
|
+
/** Project variables carrying the configured prefix. */
|
|
24
32
|
readonly [key: string]: string | boolean | undefined
|
|
25
33
|
}
|
|
26
34
|
|
|
27
|
-
/**
|
|
35
|
+
/** Hot reloading API exposed to every module. */
|
|
28
36
|
interface OdoroHot {
|
|
29
|
-
/**
|
|
37
|
+
/** Data kept from one module version to the next. */
|
|
30
38
|
readonly data: Record<string, unknown>
|
|
31
|
-
/**
|
|
39
|
+
/** Declares that this module knows how to replace itself hot. */
|
|
32
40
|
accept(callback?: (module: unknown) => void): void
|
|
33
|
-
/**
|
|
41
|
+
/** Registers a cleanup to run before the replacement. */
|
|
34
42
|
dispose(callback: (data: Record<string, unknown>) => void): void
|
|
35
|
-
/**
|
|
43
|
+
/** Gives up hot replacement and reloads the page. */
|
|
36
44
|
invalidate(): void
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
interface ImportMeta {
|
|
40
|
-
/**
|
|
48
|
+
/** Environment variables of the project. */
|
|
41
49
|
readonly env: OdoroEnv
|
|
42
|
-
/** Present
|
|
50
|
+
/** Present in development only. */
|
|
43
51
|
hot?: OdoroHot
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Imports every module matched by a pattern.
|
|
55
|
+
*
|
|
56
|
+
* The pattern is resolved at build time: what comes out of it is a table of
|
|
57
|
+
* static imports, whose keys are the paths as they were written.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* const pages = import.meta.glob('./pages/*.tsx')
|
|
61
|
+
* const module = await pages['./pages/home.tsx']?.()
|
|
62
|
+
*/
|
|
63
|
+
glob<T = Record<string, unknown>>(
|
|
64
|
+
pattern: string | readonly string[],
|
|
65
|
+
options?: { eager?: false; import?: string },
|
|
66
|
+
): Record<string, () => Promise<T>>
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The same thing, but everything is loaded right away.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* const titles = import.meta.glob('./pages/*.tsx', { eager: true, import: 'title' })
|
|
73
|
+
*/
|
|
74
|
+
glob<T = Record<string, unknown>>(
|
|
75
|
+
pattern: string | readonly string[],
|
|
76
|
+
options: { eager: true; import?: string },
|
|
77
|
+
): Record<string, T>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The content of a file, as a string.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* import charter from './CHARTER.md?raw'
|
|
85
|
+
*/
|
|
86
|
+
declare module '*?raw' {
|
|
87
|
+
const content: string
|
|
88
|
+
export default content
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The public address of a file, without loading it.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* import logo from './logo.svg?url'
|
|
96
|
+
*/
|
|
97
|
+
declare module '*?url' {
|
|
98
|
+
const address: string
|
|
99
|
+
export default address
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A module to run in a separate worker.
|
|
104
|
+
*
|
|
105
|
+
* The class is constructed like any other `Worker`; the file is built apart and
|
|
106
|
+
* loaded as a module.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* import Compute from './compute.ts?worker'
|
|
110
|
+
* const worker = new Compute()
|
|
111
|
+
* worker.postMessage(21)
|
|
112
|
+
*/
|
|
113
|
+
declare module '*?worker' {
|
|
114
|
+
const Worker_: {
|
|
115
|
+
new (options?: WorkerOptions): Worker
|
|
116
|
+
}
|
|
117
|
+
export default Worker_
|
|
44
118
|
}
|
|
45
119
|
|
|
46
120
|
declare module '*.css' {
|
|
@@ -1642,11 +1642,11 @@ var CATEGORIES = [
|
|
|
1642
1642
|
"ui",
|
|
1643
1643
|
"section",
|
|
1644
1644
|
/**
|
|
1645
|
-
*
|
|
1645
|
+
* The opening curtain.
|
|
1646
1646
|
*
|
|
1647
|
-
*
|
|
1648
|
-
*
|
|
1649
|
-
*
|
|
1647
|
+
* Not a section: a section takes a place in the flow of the page, a loader
|
|
1648
|
+
* covers the whole screen and disappears. Filing them together would force
|
|
1649
|
+
* every section to declare which of the two it is.
|
|
1650
1650
|
*/
|
|
1651
1651
|
"loader",
|
|
1652
1652
|
"hooks"
|
|
@@ -1655,109 +1655,108 @@ var PERF_TIERS = ["light", "medium", "heavy"];
|
|
|
1655
1655
|
var GL_BACKENDS = ["ogl", "three"];
|
|
1656
1656
|
var FALLBACKS = ["poster", "gradient", "static", "none"];
|
|
1657
1657
|
var fileSchema = object({
|
|
1658
|
-
/**
|
|
1658
|
+
/** Path inside the component directory. */
|
|
1659
1659
|
path: string2().check(_minLength(1)),
|
|
1660
1660
|
/**
|
|
1661
|
-
* Destination
|
|
1662
|
-
*
|
|
1663
|
-
*
|
|
1661
|
+
* Destination in the project, relative to the components alias. Absolute
|
|
1662
|
+
* paths and climbs are refused: the CLI writes into the user project, and an
|
|
1663
|
+
* unbounded path would be an open door.
|
|
1664
1664
|
*/
|
|
1665
1665
|
target: string2().check(
|
|
1666
1666
|
_minLength(1),
|
|
1667
1667
|
refine((value) => !value.startsWith("/") && !value.includes(".."), {
|
|
1668
|
-
error: "
|
|
1668
|
+
error: "The destination must stay relative and must not climb up the tree."
|
|
1669
1669
|
})
|
|
1670
1670
|
)
|
|
1671
1671
|
});
|
|
1672
1672
|
var engineSchema = object({
|
|
1673
1673
|
/**
|
|
1674
|
-
*
|
|
1675
|
-
*
|
|
1674
|
+
* Orchestration plugins required. `core` designates the base library, always
|
|
1675
|
+
* present with the engine.
|
|
1676
1676
|
*/
|
|
1677
1677
|
gsap: _default(array(string2().check(_minLength(1))), []),
|
|
1678
|
-
/**
|
|
1678
|
+
/** Graphics backend required, or `false` when the component asks for none. */
|
|
1679
1679
|
gl: _default(union([literal(false), _enum(GL_BACKENDS)]), false)
|
|
1680
1680
|
});
|
|
1681
1681
|
var propSchema = object({
|
|
1682
|
-
/**
|
|
1682
|
+
/** Name of the property. */
|
|
1683
1683
|
name: string2().check(_minLength(1)),
|
|
1684
|
-
/**
|
|
1684
|
+
/** TypeScript type, as it will be shown in the documentation. */
|
|
1685
1685
|
type: string2().check(_minLength(1)),
|
|
1686
|
-
/**
|
|
1686
|
+
/** Mandatory or not. @defaultValue false */
|
|
1687
1687
|
required: _default(boolean2(), false),
|
|
1688
|
-
/**
|
|
1688
|
+
/** Default value, in source form. */
|
|
1689
1689
|
default: optional(union([string2(), number2(), boolean2()])),
|
|
1690
1690
|
/**
|
|
1691
|
-
*
|
|
1692
|
-
*
|
|
1691
|
+
* Unit of the value. Durations are **always** in milliseconds: that is a rule
|
|
1692
|
+
* of the registry, not a local convention.
|
|
1693
1693
|
*/
|
|
1694
1694
|
unit: optional(string2()),
|
|
1695
|
-
/**
|
|
1695
|
+
/** Explanation shown in the properties table. */
|
|
1696
1696
|
description: optional(string2()),
|
|
1697
1697
|
/**
|
|
1698
|
-
*
|
|
1698
|
+
* Bounds of a numeric setting.
|
|
1699
1699
|
*
|
|
1700
|
-
*
|
|
1701
|
-
*
|
|
1702
|
-
*
|
|
1700
|
+
* They serve the documentation, which makes a slider out of them. Without
|
|
1701
|
+
* them, the page would have to redeclare what the meta already knows — and
|
|
1702
|
+
* the two would diverge at the first change of default value.
|
|
1703
1703
|
*/
|
|
1704
1704
|
min: optional(number2()),
|
|
1705
1705
|
max: optional(number2()),
|
|
1706
1706
|
step: optional(number2()),
|
|
1707
|
-
/**
|
|
1707
|
+
/** Possible values of a choice setting. */
|
|
1708
1708
|
options: optional(array(string2()))
|
|
1709
1709
|
});
|
|
1710
1710
|
var perfSchema = object({
|
|
1711
|
-
/**
|
|
1711
|
+
/** Cost level. */
|
|
1712
1712
|
tier: _enum(PERF_TIERS),
|
|
1713
|
-
/**
|
|
1713
|
+
/** Graphics backend used, when there is one. */
|
|
1714
1714
|
backend: _default(union([literal(false), _enum(GL_BACKENDS)]), false),
|
|
1715
|
-
/**
|
|
1715
|
+
/** Remarks shown in the documentation. */
|
|
1716
1716
|
notes: optional(string2()),
|
|
1717
1717
|
/**
|
|
1718
|
-
* Nature
|
|
1719
|
-
*
|
|
1718
|
+
* Nature of the visual fallback. Mandatory for an expensive component: the
|
|
1719
|
+
* fallback is part of the component, not of its documentation.
|
|
1720
1720
|
*/
|
|
1721
1721
|
fallback: optional(_enum(FALLBACKS))
|
|
1722
1722
|
});
|
|
1723
1723
|
var baseSchema = object({
|
|
1724
|
-
/**
|
|
1724
|
+
/** Identifier, unique within its category. */
|
|
1725
1725
|
name: string2().check(
|
|
1726
1726
|
_regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, {
|
|
1727
|
-
error: "
|
|
1727
|
+
error: "The name must be lowercase, with dashes as separators."
|
|
1728
1728
|
})
|
|
1729
1729
|
),
|
|
1730
|
-
/**
|
|
1730
|
+
/** Category. */
|
|
1731
1731
|
category: _enum(CATEGORIES),
|
|
1732
|
-
/**
|
|
1732
|
+
/** Displayed title. */
|
|
1733
1733
|
title: string2().check(_minLength(1)),
|
|
1734
|
-
/**
|
|
1734
|
+
/** Displayed description, in one sentence. */
|
|
1735
1735
|
description: string2().check(_minLength(1)),
|
|
1736
|
-
/**
|
|
1736
|
+
/** What the component asks of the engine. */
|
|
1737
1737
|
engine: _default(engineSchema, { gsap: [], gl: false }),
|
|
1738
|
-
/**
|
|
1738
|
+
/** Files copied into the user project. At least one. */
|
|
1739
1739
|
files: array(fileSchema).check(_minLength(1)),
|
|
1740
|
-
/**
|
|
1740
|
+
/** npm packages to install. */
|
|
1741
1741
|
dependencies: _default(array(string2().check(_minLength(1))), []),
|
|
1742
1742
|
/**
|
|
1743
|
-
*
|
|
1744
|
-
* `categorie/nom`.
|
|
1743
|
+
* Other registry entries this one depends on, in the form `category/name`.
|
|
1745
1744
|
*/
|
|
1746
1745
|
registryDependencies: _default(
|
|
1747
1746
|
array(
|
|
1748
1747
|
string2().check(
|
|
1749
1748
|
_regex(/^[a-z]+\/[a-z0-9]+(-[a-z0-9]+)*$/, {
|
|
1750
|
-
error: '
|
|
1749
|
+
error: 'A registry dependency is written "category/name".'
|
|
1751
1750
|
})
|
|
1752
1751
|
)
|
|
1753
1752
|
),
|
|
1754
1753
|
[]
|
|
1755
1754
|
),
|
|
1756
|
-
/**
|
|
1755
|
+
/** CSS variables the component consumes. */
|
|
1757
1756
|
tokens: _default(array(string2().check(_startsWith("--o-"))), []),
|
|
1758
|
-
/**
|
|
1757
|
+
/** Properties exposed. */
|
|
1759
1758
|
props: _default(array(propSchema), []),
|
|
1760
|
-
/**
|
|
1759
|
+
/** Cost of the component. */
|
|
1761
1760
|
perf: perfSchema
|
|
1762
1761
|
});
|
|
1763
1762
|
var metaSchema = baseSchema.check(
|
|
@@ -1768,7 +1767,7 @@ var metaSchema = baseSchema.check(
|
|
|
1768
1767
|
code: "custom",
|
|
1769
1768
|
input: meta2,
|
|
1770
1769
|
path: ["perf", "fallback"],
|
|
1771
|
-
message: "
|
|
1770
|
+
message: "A high-cost component must declare a visual fallback: it is shown while loading, without WebGL, and in reduced motion."
|
|
1772
1771
|
});
|
|
1773
1772
|
}
|
|
1774
1773
|
if (meta2.perf.backend !== false && meta2.engine.gl !== meta2.perf.backend) {
|
|
@@ -1776,7 +1775,7 @@ var metaSchema = baseSchema.check(
|
|
|
1776
1775
|
code: "custom",
|
|
1777
1776
|
input: meta2,
|
|
1778
1777
|
path: ["perf", "backend"],
|
|
1779
|
-
message: `
|
|
1778
|
+
message: `The backend declared in "perf" (${String(meta2.perf.backend)}) does not match the one of "engine" (${String(meta2.engine.gl)}).`
|
|
1780
1779
|
});
|
|
1781
1780
|
}
|
|
1782
1781
|
if (meta2.engine.gl === "three" && meta2.perf.tier !== "heavy") {
|
|
@@ -1784,7 +1783,7 @@ var metaSchema = baseSchema.check(
|
|
|
1784
1783
|
code: "custom",
|
|
1785
1784
|
input: meta2,
|
|
1786
1785
|
path: ["perf", "tier"],
|
|
1787
|
-
message: "
|
|
1786
|
+
message: "A component using a 3D scene is necessarily of high cost."
|
|
1788
1787
|
});
|
|
1789
1788
|
}
|
|
1790
1789
|
const targets = meta2.files.map((file) => file.target);
|
|
@@ -1796,7 +1795,7 @@ var metaSchema = baseSchema.check(
|
|
|
1796
1795
|
code: "custom",
|
|
1797
1796
|
input: meta2,
|
|
1798
1797
|
path: ["files"],
|
|
1799
|
-
message: `
|
|
1798
|
+
message: `Several files target the same destination: ${[...new Set(duplicates)].join(", ")}.`
|
|
1800
1799
|
});
|
|
1801
1800
|
}
|
|
1802
1801
|
})
|
|
@@ -1819,9 +1818,9 @@ function parseMeta(value, origin) {
|
|
|
1819
1818
|
// src/registry/resolve.ts
|
|
1820
1819
|
function describeProblem(problem) {
|
|
1821
1820
|
if (problem.kind === "cycle") {
|
|
1822
|
-
return `
|
|
1821
|
+
return `Dependency cycle: ${problem.path.join(" \u2192 ")}`;
|
|
1823
1822
|
}
|
|
1824
|
-
return problem.requiredBy === null ? `
|
|
1823
|
+
return problem.requiredBy === null ? `Entry not found: ${problem.id}` : `Entry not found: ${problem.id}, required by ${problem.requiredBy}`;
|
|
1825
1824
|
}
|
|
1826
1825
|
function resolveGraph(requested, available) {
|
|
1827
1826
|
const problems = [];
|
|
@@ -1838,7 +1837,7 @@ function resolveGraph(requested, available) {
|
|
|
1838
1837
|
}
|
|
1839
1838
|
const entry = available.get(id);
|
|
1840
1839
|
if (entry === void 0) {
|
|
1841
|
-
problems.push({ kind: "
|
|
1840
|
+
problems.push({ kind: "missing", id, requiredBy });
|
|
1842
1841
|
return;
|
|
1843
1842
|
}
|
|
1844
1843
|
path.push(id);
|
|
@@ -4,7 +4,7 @@ export { default as colors } from 'picocolors';
|
|
|
4
4
|
|
|
5
5
|
var TAG = colors.bold(colors.magenta("odoro"));
|
|
6
6
|
function stamp() {
|
|
7
|
-
return colors.dim((/* @__PURE__ */ new Date()).toLocaleTimeString("
|
|
7
|
+
return colors.dim((/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false }));
|
|
8
8
|
}
|
|
9
9
|
function info(message) {
|
|
10
10
|
console.log(`${stamp()} ${TAG} ${message}`);
|
|
@@ -27,9 +27,9 @@ function duration(milliseconds) {
|
|
|
27
27
|
return milliseconds < 1e3 ? `${Math.round(milliseconds)} ms` : `${(milliseconds / 1e3).toFixed(2)} s`;
|
|
28
28
|
}
|
|
29
29
|
function size(bytes) {
|
|
30
|
-
if (bytes < 1024) return `${bytes}
|
|
31
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}
|
|
32
|
-
return `${(bytes / (1024 * 1024)).toFixed(2)}
|
|
30
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
31
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} kB`;
|
|
32
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export { duration, error, info, size, success, warn };
|