odoro 1.0.9 → 2.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.
Files changed (88) hide show
  1. package/README.md +94 -0
  2. package/client.d.ts +90 -16
  3. package/dist/build-XJIP4GNT.js +5 -0
  4. package/dist/{chunk-34RGOZFA.js → chunk-4D56Z7G3.js} +49 -50
  5. package/dist/{chunk-JMEHF3KN.js → chunk-7ZB5MAM6.js} +4 -4
  6. package/dist/chunk-DF67LADH.js +735 -0
  7. package/dist/{chunk-LHZGX5ML.js → chunk-HS7NGZLM.js} +307 -196
  8. package/dist/chunk-LIKVHWB4.js +231 -0
  9. package/dist/chunk-QOVBLN7A.js +241 -0
  10. package/dist/chunk-RTWJ5GFB.js +729 -0
  11. package/dist/chunk-TONYIKCN.js +57 -0
  12. package/dist/cli.d.ts +12 -13
  13. package/dist/cli.js +86 -63
  14. package/dist/{commands-AHMXBWQQ.js → commands-GYA7NTCX.js} +124 -124
  15. package/dist/commands-UOWN3IK4.js +181 -0
  16. package/dist/{create-CYVSVDAD.js → create-B2TLV6XI.js} +198 -160
  17. package/dist/index.d.ts +603 -151
  18. package/dist/index.js +6 -6
  19. package/dist/{package-EIDLKAA6.js → package-3ZJOEXM4.js} +6 -5
  20. package/dist/preview-3IRG7MHV.js +4 -0
  21. package/dist/registry/index.d.ts +75 -76
  22. package/dist/registry/index.js +1 -1
  23. package/dist/{server-4UGN3SFS.js → server-ZB3P3EGS.js} +3 -3
  24. package/package.json +6 -5
  25. package/templates/react-ts/README.md +71 -35
  26. package/templates/react-ts/_env.example +9 -0
  27. package/templates/react-ts/_variants/with-engine/src/background.tsx +118 -0
  28. package/templates/react-ts/_variants/without-libs/src/App.tsx +380 -0
  29. package/templates/react-ts/_variants/without-libs/src/background.tsx +24 -0
  30. package/templates/react-ts/_variants/without-libs/src/entry-server.tsx +39 -0
  31. package/templates/react-ts/_variants/without-libs/src/main.tsx +26 -0
  32. package/templates/{react-ts-server/_variantes/sans-libs/client → react-ts/_variants/without-libs}/src/styles.css +137 -137
  33. package/templates/react-ts/{_variantes/sans-routeur → _variants/without-router}/src/App.tsx +141 -141
  34. package/templates/react-ts/_variants/without-router/src/entry-server.tsx +39 -0
  35. package/templates/react-ts/index.html +4 -4
  36. package/templates/react-ts/odoro.config.ts +5 -0
  37. package/templates/react-ts/src/App.tsx +219 -209
  38. package/templates/react-ts/src/background.tsx +66 -0
  39. package/templates/react-ts/src/entry-server.tsx +85 -0
  40. package/templates/react-ts/src/main.tsx +13 -4
  41. package/templates/react-ts/src/router.tsx +65 -45
  42. package/templates/react-ts/src/styles.css +5 -5
  43. package/templates/react-ts-server/Dockerfile +9 -9
  44. package/templates/react-ts-server/README.md +97 -45
  45. package/templates/react-ts-server/_env.example +31 -33
  46. package/templates/react-ts-server/_variants/with-engine/client/src/background.tsx +118 -0
  47. package/templates/react-ts-server/_variants/without-libs/client/src/App.tsx +380 -0
  48. package/templates/react-ts-server/_variants/without-libs/client/src/background.tsx +24 -0
  49. package/templates/react-ts-server/_variants/without-libs/client/src/entry-server.tsx +39 -0
  50. package/templates/react-ts-server/_variants/without-libs/client/src/main.tsx +26 -0
  51. package/templates/{react-ts/_variantes/sans-libs → react-ts-server/_variants/without-libs/client}/src/styles.css +137 -137
  52. package/templates/react-ts-server/{_variantes/sans-routeur → _variants/without-router}/client/src/App.tsx +141 -141
  53. package/templates/react-ts-server/_variants/without-router/client/src/entry-server.tsx +39 -0
  54. package/templates/react-ts-server/client/index.html +4 -4
  55. package/templates/react-ts-server/client/src/App.tsx +228 -210
  56. package/templates/react-ts-server/client/src/account.tsx +267 -0
  57. package/templates/react-ts-server/client/src/auth.tsx +139 -0
  58. package/templates/react-ts-server/client/src/background.tsx +66 -0
  59. package/templates/react-ts-server/client/src/entry-server.tsx +92 -0
  60. package/templates/react-ts-server/client/src/main.tsx +17 -5
  61. package/templates/react-ts-server/client/src/router.tsx +77 -45
  62. package/templates/react-ts-server/client/src/styles.css +5 -5
  63. package/templates/react-ts-server/odoro.config.ts +7 -4
  64. package/templates/react-ts-server/package.json +2 -0
  65. package/templates/react-ts-server/scripts/dev.mjs +14 -14
  66. package/templates/react-ts-server/server/src/main.ts +119 -45
  67. package/templates/react-ts-server/server/src/modules/auth/index.ts +238 -0
  68. package/templates/react-ts-server/server/src/modules/auth/password.ts +122 -0
  69. package/templates/react-ts-server/server/src/modules/auth/store.ts +193 -0
  70. package/templates/react-ts-server/server/src/modules/health/index.ts +45 -46
  71. package/dist/build-JFQHODAT.js +0 -5
  72. package/dist/chunk-22KJTV2R.js +0 -380
  73. package/dist/chunk-3SZIN6VG.js +0 -64
  74. package/dist/chunk-DL3NPC4H.js +0 -113
  75. package/dist/chunk-TQUJ3MFS.js +0 -268
  76. package/dist/chunk-ZVL7EXJO.js +0 -66
  77. package/dist/commands-4JRBD55Z.js +0 -245
  78. package/dist/preview-7DKEAQOQ.js +0 -4
  79. package/templates/react-ts/_variantes/avec-moteur/src/fond.tsx +0 -118
  80. package/templates/react-ts/_variantes/sans-libs/src/App.tsx +0 -382
  81. package/templates/react-ts/_variantes/sans-libs/src/fond.tsx +0 -23
  82. package/templates/react-ts/_variantes/sans-libs/src/main.tsx +0 -17
  83. package/templates/react-ts/src/fond.tsx +0 -66
  84. package/templates/react-ts-server/_variantes/avec-moteur/client/src/fond.tsx +0 -118
  85. package/templates/react-ts-server/_variantes/sans-libs/client/src/App.tsx +0 -382
  86. package/templates/react-ts-server/_variantes/sans-libs/client/src/fond.tsx +0 -23
  87. package/templates/react-ts-server/_variantes/sans-libs/client/src/main.tsx +0 -17
  88. 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
- * Types ambiants pour le code client d'un projet Odoro.
2
+ * Ambient types for the client code of an Odoro project.
3
3
  *
4
- * A referencer une fois dans le projet :
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
- /** Variables d'environnement exposees au navigateur. */
13
+ /** Environment variables exposed to the browser. */
14
14
  interface OdoroEnv {
15
- /** Mode de compilation. */
16
- readonly MODE: 'development' | 'production'
17
- /** Vrai en developpement. */
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
- /** Vrai en production. */
25
+ /** True in production. */
20
26
  readonly PROD: boolean
21
- /** Prefixe des URL publiques. */
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
- /** Variables du projet portant le prefixe configure. */
31
+ /** Project variables carrying the configured prefix. */
24
32
  readonly [key: string]: string | boolean | undefined
25
33
  }
26
34
 
27
- /** API de rechargement a chaud exposee a chaque module. */
35
+ /** Hot reloading API exposed to every module. */
28
36
  interface OdoroHot {
29
- /** Donnees conservees d'une version de module a la suivante. */
37
+ /** Data kept from one module version to the next. */
30
38
  readonly data: Record<string, unknown>
31
- /** Declare que ce module sait se remplacer a chaud. */
39
+ /** Declares that this module knows how to replace itself hot. */
32
40
  accept(callback?: (module: unknown) => void): void
33
- /** Enregistre un nettoyage a executer avant le remplacement. */
41
+ /** Registers a cleanup to run before the replacement. */
34
42
  dispose(callback: (data: Record<string, unknown>) => void): void
35
- /** Renonce au remplacement a chaud et recharge la page. */
43
+ /** Gives up hot replacement and reloads the page. */
36
44
  invalidate(): void
37
45
  }
38
46
 
39
47
  interface ImportMeta {
40
- /** Variables d'environnement du projet. */
48
+ /** Environment variables of the project. */
41
49
  readonly env: OdoroEnv
42
- /** Present uniquement en developpement. */
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' {
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ export { buildProject, reportBuild } from './chunk-DF67LADH.js';
3
+ import './chunk-HS7NGZLM.js';
4
+ import './chunk-RTWJ5GFB.js';
5
+ import './chunk-7ZB5MAM6.js';
@@ -1642,11 +1642,11 @@ var CATEGORIES = [
1642
1642
  "ui",
1643
1643
  "section",
1644
1644
  /**
1645
- * Le rideau d'ouverture.
1645
+ * The opening curtain.
1646
1646
  *
1647
- * Pas une section : une section occupe une place dans le flux de la page,
1648
- * un chargeur couvre l'ecran entier et disparait. Les ranger ensemble
1649
- * obligerait chaque section a declarer laquelle des deux elle est.
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
- /** Chemin dans le dossier du composant. */
1658
+ /** Path inside the component directory. */
1659
1659
  path: string2().check(_minLength(1)),
1660
1660
  /**
1661
- * Destination dans le projet, relative a l'alias de composants. Les chemins
1662
- * absolus et les remontees sont refuses : la CLI ecrit chez l'utilisateur,
1663
- * et un chemin non borne y serait une porte ouverte.
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: "La destination doit rester relative et ne pas remonter dans l arborescence."
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
- * Plugins d'orchestration requis. `core` designe la bibliotheque de base,
1675
- * toujours presente avec le moteur.
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
- /** Backend graphique requis, ou `false` si le composant n'en demande aucun. */
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
- /** Nom de la propriete. */
1682
+ /** Name of the property. */
1683
1683
  name: string2().check(_minLength(1)),
1684
- /** Type TypeScript, tel qu'il sera affiche dans la documentation. */
1684
+ /** TypeScript type, as it will be shown in the documentation. */
1685
1685
  type: string2().check(_minLength(1)),
1686
- /** Obligatoire ou non. @defaultValue false */
1686
+ /** Mandatory or not. @defaultValue false */
1687
1687
  required: _default(boolean2(), false),
1688
- /** Valeur par defaut, en representation source. */
1688
+ /** Default value, in source form. */
1689
1689
  default: optional(union([string2(), number2(), boolean2()])),
1690
1690
  /**
1691
- * Unite de la valeur. Les durees sont **toujours** en millisecondes : c'est
1692
- * une regle du registre, pas une convention locale.
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
- /** Explication affichee dans la table des proprietes. */
1695
+ /** Explanation shown in the properties table. */
1696
1696
  description: optional(string2()),
1697
1697
  /**
1698
- * Bornes d'un reglage numerique.
1698
+ * Bounds of a numeric setting.
1699
1699
  *
1700
- * Elles servent a la documentation, qui en fabrique un curseur. Sans elles,
1701
- * la page devrait redeclarer ce que le meta sait deja — et les deux
1702
- * divergeraient au premier changement de valeur par defaut.
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
- /** Valeurs possibles d'un reglage a choix. */
1707
+ /** Possible values of a choice setting. */
1708
1708
  options: optional(array(string2()))
1709
1709
  });
1710
1710
  var perfSchema = object({
1711
- /** Niveau de cout. */
1711
+ /** Cost level. */
1712
1712
  tier: _enum(PERF_TIERS),
1713
- /** Backend graphique employe, s'il y en a un. */
1713
+ /** Graphics backend used, when there is one. */
1714
1714
  backend: _default(union([literal(false), _enum(GL_BACKENDS)]), false),
1715
- /** Remarques affichees dans la documentation. */
1715
+ /** Remarks shown in the documentation. */
1716
1716
  notes: optional(string2()),
1717
1717
  /**
1718
- * Nature du repli visuel. Obligatoire pour un composant couteux : le repli
1719
- * fait partie du composant, pas de sa documentation.
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
- /** Identifiant, unique dans sa categorie. */
1724
+ /** Identifier, unique within its category. */
1725
1725
  name: string2().check(
1726
1726
  _regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, {
1727
- error: "Le nom doit etre en minuscules, avec des tirets pour separateurs."
1727
+ error: "The name must be lowercase, with dashes as separators."
1728
1728
  })
1729
1729
  ),
1730
- /** Categorie. */
1730
+ /** Category. */
1731
1731
  category: _enum(CATEGORIES),
1732
- /** Titre affiche. */
1732
+ /** Displayed title. */
1733
1733
  title: string2().check(_minLength(1)),
1734
- /** Description affichee, en une phrase. */
1734
+ /** Displayed description, in one sentence. */
1735
1735
  description: string2().check(_minLength(1)),
1736
- /** Ce que le composant demande au moteur. */
1736
+ /** What the component asks of the engine. */
1737
1737
  engine: _default(engineSchema, { gsap: [], gl: false }),
1738
- /** Fichiers copies chez l'utilisateur. Au moins un. */
1738
+ /** Files copied into the user project. At least one. */
1739
1739
  files: array(fileSchema).check(_minLength(1)),
1740
- /** Paquets npm a installer. */
1740
+ /** npm packages to install. */
1741
1741
  dependencies: _default(array(string2().check(_minLength(1))), []),
1742
1742
  /**
1743
- * Autres entrees du registre dont celle-ci depend, sous la forme
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: 'Une dependance de registre s ecrit "categorie/nom".'
1749
+ error: 'A registry dependency is written "category/name".'
1751
1750
  })
1752
1751
  )
1753
1752
  ),
1754
1753
  []
1755
1754
  ),
1756
- /** Variables CSS que le composant consomme. */
1755
+ /** CSS variables the component consumes. */
1757
1756
  tokens: _default(array(string2().check(_startsWith("--o-"))), []),
1758
- /** Proprietes exposees. */
1757
+ /** Properties exposed. */
1759
1758
  props: _default(array(propSchema), []),
1760
- /** Cout du composant. */
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: "Un composant de cout eleve doit declarer un repli visuel : il est affiche pendant le chargement, sans WebGL, et en mouvement reduit."
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: `Le backend declare dans "perf" (${String(meta2.perf.backend)}) ne correspond pas a celui de "engine" (${String(meta2.engine.gl)}).`
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: "Un composant employant une scene 3D est necessairement de cout eleve."
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: `Plusieurs fichiers visent la meme destination : ${[...new Set(duplicates)].join(", ")}.`
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 `Cycle de dependances : ${problem.path.join(" \u2192 ")}`;
1821
+ return `Dependency cycle: ${problem.path.join(" \u2192 ")}`;
1823
1822
  }
1824
- return problem.requiredBy === null ? `Entree introuvable : ${problem.id}` : `Entree introuvable : ${problem.id}, reclamee par ${problem.requiredBy}`;
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: "introuvable", id, requiredBy });
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("fr-FR", { hour12: false }));
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} o`;
31
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} Ko`;
32
- return `${(bytes / (1024 * 1024)).toFixed(2)} Mo`;
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 };