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
@@ -1,113 +0,0 @@
1
- #!/usr/bin/env node
2
- import { guessAliasPaths } from './chunk-T6RLHSCW.js';
3
- import { mkdir, writeFile, rm } from 'fs/promises';
4
- import { existsSync } from 'fs';
5
- import { resolve, join } from 'path';
6
- import { pathToFileURL } from 'url';
7
- import { build } from 'esbuild';
8
-
9
- function defineConfig(config) {
10
- return config;
11
- }
12
- var CONFIG_FILES = ["odoro.config.ts", "odoro.config.js", "odoro.config.mjs"];
13
- async function importConfigFile(file, root) {
14
- const directory = join(root, "node_modules", ".odoro");
15
- const output = join(directory, `config.${Date.now().toString(36)}.mjs`);
16
- await mkdir(directory, { recursive: true });
17
- try {
18
- const result = await build({
19
- entryPoints: [file],
20
- bundle: true,
21
- format: "esm",
22
- platform: "node",
23
- target: "node20",
24
- write: false,
25
- // Seul le code du projet est inline ; ses dependances restent externes,
26
- // sans quoi il faudrait resoudre tout node_modules pour lire trois lignes.
27
- packages: "external",
28
- // `packages: 'external'` ne suffit pas : un `baseUrl` dans le
29
- // `tsconfig.json` fait chercher les imports nus depuis la racine du
30
- // projet, ou `odoro.json` — le fichier du registre — est trouve avant le
31
- // paquet. L'import cesse alors d'etre un import de paquet, la regle
32
- // ci-dessus ne s'applique plus, et la compilation echoue sur un
33
- // `defineConfig` introuvable dans un fichier de configuration.
34
- //
35
- // Le nommer explicitement le met hors d'atteinte de cette resolution. La
36
- // liste vaut pour les projets deja crees : eux portent encore un
37
- // `baseUrl`, et on ne peut pas reecrire leur tsconfig.
38
- external: ["odoro"]
39
- });
40
- const code = result.outputFiles[0]?.text;
41
- if (code === void 0) {
42
- throw new Error(`[odoro] La configuration "${file}" n'a produit aucun code.`);
43
- }
44
- await writeFile(output, code, "utf8");
45
- const module = await import(pathToFileURL(output).href);
46
- if (module.default === void 0) {
47
- throw new Error(
48
- `[odoro] La configuration "${file}" doit avoir un export par defaut.`
49
- );
50
- }
51
- return module.default;
52
- } finally {
53
- await rm(output, { force: true });
54
- }
55
- }
56
- async function loadConfig(root, overrides = {}) {
57
- const absoluteRoot = resolve(root);
58
- let file;
59
- let loaded = {};
60
- for (const candidate of CONFIG_FILES) {
61
- const path = join(absoluteRoot, candidate);
62
- if (existsSync(path)) {
63
- file = path;
64
- loaded = await importConfigFile(path, absoluteRoot);
65
- break;
66
- }
67
- }
68
- const merged = {
69
- ...loaded,
70
- ...overrides,
71
- server: { ...loaded.server, ...overrides.server },
72
- build: { ...loaded.build, ...overrides.build },
73
- alias: { ...loaded.alias, ...overrides.alias },
74
- define: { ...loaded.define, ...overrides.define }
75
- };
76
- const base = merged.base ?? "/";
77
- const projectRoot = merged.root === void 0 ? absoluteRoot : resolve(absoluteRoot, merged.root);
78
- return {
79
- root: projectRoot,
80
- base: base.endsWith("/") ? base : `${base}/`,
81
- publicDir: resolve(projectRoot, merged.publicDir ?? "public"),
82
- outDir: resolve(projectRoot, merged.build?.outDir ?? "dist"),
83
- server: {
84
- port: merged.server?.port ?? 5180,
85
- host: merged.server?.host ?? "localhost",
86
- proxy: merged.server?.proxy ?? {}
87
- },
88
- build: {
89
- outDir: merged.build?.outDir ?? "dist",
90
- minify: merged.build?.minify ?? true,
91
- sourcemap: merged.build?.sourcemap ?? true,
92
- target: merged.build?.target ?? "es2022",
93
- // Actif par defaut : une feuille qui contient toutes les classes
94
- // possibles est un accident de generation, pas une intention.
95
- elaguer: merged.build?.elaguer ?? true,
96
- safelist: merged.build?.safelist ?? []
97
- },
98
- // Les alias declares dans `tsconfig.json` sont repris d'office. Sans
99
- // cela, un projet qui suit `odoro init` — lequel deduit son prefixe du
100
- // tsconfig — aurait a redeclarer le meme alias ici pour que le serveur
101
- // sache le resoudre. Deux endroits pour la meme verite, et une erreur
102
- // qui n'apparait qu'au premier import.
103
- //
104
- // La configuration l'emporte : c'est elle qu'on ecrit pour corriger un
105
- // cas que la deduction n'attrape pas.
106
- alias: { ...await guessAliasPaths(projectRoot), ...merged.alias },
107
- define: merged.define ?? {},
108
- envPrefix: merged.envPrefix ?? "ODORO_",
109
- configFile: file
110
- };
111
- }
112
-
113
- export { defineConfig, loadConfig };
@@ -1,268 +0,0 @@
1
- #!/usr/bin/env node
2
- import { relative, resolve } from 'path';
3
- import { build } from 'esbuild';
4
-
5
- // src/shared/ecouter.ts
6
- var ESSAIS = 10;
7
- async function ecouter(server, port, host, essais = ESSAIS) {
8
- for (let decalage = 0; decalage < essais; decalage += 1) {
9
- const candidat = port + decalage;
10
- const pris = await new Promise((resolve2, reject) => {
11
- const surErreur = (cause) => {
12
- server.removeListener("listening", surEcoute);
13
- if (cause.code === "EADDRINUSE") {
14
- resolve2(true);
15
- return;
16
- }
17
- reject(cause);
18
- };
19
- const surEcoute = () => {
20
- server.removeListener("error", surErreur);
21
- resolve2(false);
22
- };
23
- server.once("error", surErreur);
24
- server.once("listening", surEcoute);
25
- server.listen(candidat, host);
26
- });
27
- if (!pris) {
28
- const adresse = server.address();
29
- const obtenu = typeof adresse === "object" && adresse !== null ? adresse.port : candidat;
30
- return decalage === 0 ? { port: obtenu } : { port: obtenu, demande: port };
31
- }
32
- }
33
- throw new Error(
34
- `[odoro] Aucun port libre entre ${String(port)} et ${String(port + essais - 1)}.`
35
- );
36
- }
37
- var DEPS_PREFIX = "/@deps/";
38
- var INTERNAL_PREFIX = "/@odoro/";
39
- var SOURCE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
40
- var STYLE_EXTENSIONS = [".css"];
41
- var ASSET_EXTENSIONS = [
42
- ".svg",
43
- ".png",
44
- ".jpg",
45
- ".jpeg",
46
- ".gif",
47
- ".webp",
48
- ".avif",
49
- ".ico",
50
- ".woff",
51
- ".woff2",
52
- ".mp4",
53
- ".webm"
54
- ];
55
- function depFileName(specifier) {
56
- return `${specifier.replace(/^@/, "").split("/").join("_")}.js`;
57
- }
58
- function isBareSpecifier(specifier) {
59
- return !specifier.startsWith(".") && !specifier.startsWith("/") && !specifier.startsWith("\\") && !/^[a-zA-Z]:[\\/]/.test(specifier) && !specifier.startsWith("data:") && !specifier.startsWith("http:") && !specifier.startsWith("https:");
60
- }
61
- function hasExtension(path, extensions) {
62
- const clean = path.split("?")[0] ?? path;
63
- return extensions.some((extension) => clean.toLowerCase().endsWith(extension));
64
- }
65
- function fileToUrl(file, root) {
66
- const relativePath = relative(root, file).split("\\").join("/");
67
- if (!relativePath.startsWith("..")) return `/${relativePath}`;
68
- return `/@fs/${file.split("\\").join("/").replace(/^\//, "")}`;
69
- }
70
- function urlToFile(url, root) {
71
- const path = (url.split("?")[0] ?? url).split("#")[0] ?? url;
72
- if (path.startsWith("/@fs/")) {
73
- const absolute = path.slice("/@fs/".length);
74
- return /^[a-zA-Z]:/.test(absolute) ? absolute : `/${absolute}`;
75
- }
76
- return resolve(root, `.${path}`);
77
- }
78
- function applyAlias(specifier, config) {
79
- for (const [prefix, target] of Object.entries(config.alias)) {
80
- if (specifier === prefix || specifier.startsWith(`${prefix}/`)) {
81
- return resolve(
82
- config.root,
83
- target,
84
- specifier.slice(prefix.length).replace(/^\//, "")
85
- );
86
- }
87
- }
88
- return specifier;
89
- }
90
- function externalizeImports(config, dependencies) {
91
- return {
92
- name: "odoro-externalize",
93
- setup(builder) {
94
- builder.onResolve({ filter: /.*/ }, async (args) => {
95
- if (args.kind === "entry-point") return null;
96
- if (args.pluginData?.resolving === true) {
97
- return null;
98
- }
99
- if (args.path.startsWith(INTERNAL_PREFIX) || args.path.startsWith(DEPS_PREFIX)) {
100
- return { path: args.path, external: true };
101
- }
102
- const aliased = applyAlias(args.path, config);
103
- const isFileLike = hasExtension(aliased, STYLE_EXTENSIONS) || hasExtension(aliased, ASSET_EXTENSIONS);
104
- if (isBareSpecifier(aliased) && !isFileLike) {
105
- return { path: `${DEPS_PREFIX}${depFileName(aliased)}`, external: true };
106
- }
107
- const resolved = await builder.resolve(aliased, {
108
- kind: "import-statement",
109
- resolveDir: args.resolveDir,
110
- importer: args.importer,
111
- pluginData: { resolving: true }
112
- });
113
- if (resolved.errors.length > 0) {
114
- return { path: args.path, external: true };
115
- }
116
- dependencies.add(resolved.path);
117
- const url = fileToUrl(resolved.path, config.root);
118
- return {
119
- path: hasExtension(url, ASSET_EXTENSIONS) ? `${url}?import` : url,
120
- external: true
121
- };
122
- });
123
- }
124
- };
125
- }
126
- async function transformModule(file, config, env) {
127
- const dependencies = /* @__PURE__ */ new Set();
128
- const result = await build({
129
- entryPoints: [file],
130
- bundle: true,
131
- write: false,
132
- format: "esm",
133
- platform: "browser",
134
- target: "es2022",
135
- sourcemap: "inline",
136
- jsx: "automatic",
137
- jsxDev: true,
138
- logLevel: "silent",
139
- absWorkingDir: config.root,
140
- define: {
141
- "import.meta.env": JSON.stringify(env),
142
- "process.env.NODE_ENV": JSON.stringify("development"),
143
- ...config.define
144
- },
145
- plugins: [externalizeImports(config, dependencies)]
146
- });
147
- const code = result.outputFiles[0]?.text;
148
- if (code === void 0) {
149
- throw new Error(`[odoro] La compilation de "${file}" n'a produit aucun code.`);
150
- }
151
- return { code, dependencies: [...dependencies] };
152
- }
153
- var IDENTIFIANT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
154
- var RESERVES = /* @__PURE__ */ new Set([
155
- "arguments",
156
- "await",
157
- "break",
158
- "case",
159
- "catch",
160
- "class",
161
- "const",
162
- "continue",
163
- "debugger",
164
- "default",
165
- "delete",
166
- "do",
167
- "else",
168
- "enum",
169
- "eval",
170
- "export",
171
- "extends",
172
- "false",
173
- "finally",
174
- "for",
175
- "function",
176
- "if",
177
- "implements",
178
- "import",
179
- "in",
180
- "instanceof",
181
- "interface",
182
- "let",
183
- "new",
184
- "null",
185
- "package",
186
- "private",
187
- "protected",
188
- "public",
189
- "return",
190
- "static",
191
- "super",
192
- "switch",
193
- "this",
194
- "throw",
195
- "true",
196
- "try",
197
- "typeof",
198
- "var",
199
- "void",
200
- "while",
201
- "with",
202
- "yield"
203
- ]);
204
- function wrapJson(json) {
205
- let valeur;
206
- try {
207
- valeur = JSON.parse(json);
208
- } catch {
209
- return 'throw new SyntaxError("JSON illisible")';
210
- }
211
- const lignes = ["export default " + json.trim()];
212
- if (typeof valeur === "object" && valeur !== null && !Array.isArray(valeur)) {
213
- for (const [cle, contenu] of Object.entries(valeur)) {
214
- if (!IDENTIFIANT.test(cle) || RESERVES.has(cle)) continue;
215
- lignes.push("export const " + cle + " = " + JSON.stringify(contenu));
216
- }
217
- }
218
- return lignes.join("\n");
219
- }
220
- var DESTINATIONS_RESSOURCE = /* @__PURE__ */ new Set([
221
- "script",
222
- "style",
223
- "image",
224
- "font",
225
- "audio",
226
- "video",
227
- "track",
228
- "manifest",
229
- "worker",
230
- "sharedworker",
231
- "serviceworker"
232
- ]);
233
- function estUneRessource(entetes) {
234
- const destination = entetes["sec-fetch-dest"];
235
- return typeof destination === "string" && DESTINATIONS_RESSOURCE.has(destination);
236
- }
237
- function feuilleDemandee(entetes, url) {
238
- if (url.includes("?direct")) return true;
239
- if (entetes["sec-fetch-dest"] === "style") return true;
240
- const accepte = entetes["accept"];
241
- return typeof accepte === "string" && accepte.includes("text/css");
242
- }
243
- function wrapStyle(url, css) {
244
- return `const id = ${JSON.stringify(`odoro-style:${url}`)}
245
- const css = ${JSON.stringify(css)}
246
-
247
- let element = document.querySelector(\`style[data-odoro-id="\${id}"]\`)
248
- if (element === null) {
249
- element = document.createElement('style')
250
- element.setAttribute('data-odoro-id', id)
251
- document.head.appendChild(element)
252
- }
253
- element.textContent = css
254
-
255
- import.meta.hot?.accept()
256
- import.meta.hot?.dispose(() => {
257
- // La feuille suivante recreera l'element : le retirer evite d'empiler les
258
- // regles mortes a chaque rechargement.
259
- element?.remove()
260
- })
261
- `;
262
- }
263
- function wrapAsset(url) {
264
- return `export default ${JSON.stringify(url)}
265
- `;
266
- }
267
-
268
- export { ASSET_EXTENSIONS, DEPS_PREFIX, INTERNAL_PREFIX, SOURCE_EXTENSIONS, STYLE_EXTENSIONS, applyAlias, depFileName, ecouter, estUneRessource, feuilleDemandee, fileToUrl, hasExtension, isBareSpecifier, transformModule, urlToFile, wrapAsset, wrapJson, wrapStyle };
@@ -1,66 +0,0 @@
1
- #!/usr/bin/env node
2
- import { estUneRessource, ecouter } from './chunk-TQUJ3MFS.js';
3
- import { warn, success, info, colors } from './chunk-JMEHF3KN.js';
4
- import { existsSync, statSync, createReadStream } from 'fs';
5
- import { createServer } from 'http';
6
- import { normalize, join, extname } from 'path';
7
-
8
- var MIME = {
9
- ".html": "text/html; charset=utf-8",
10
- ".js": "text/javascript; charset=utf-8",
11
- ".css": "text/css; charset=utf-8",
12
- ".json": "application/json; charset=utf-8",
13
- ".svg": "image/svg+xml",
14
- ".png": "image/png",
15
- ".jpg": "image/jpeg",
16
- ".webp": "image/webp",
17
- ".ico": "image/x-icon",
18
- ".woff2": "font/woff2",
19
- ".map": "application/json; charset=utf-8",
20
- ".txt": "text/plain; charset=utf-8",
21
- ".md": "text/markdown; charset=utf-8",
22
- ".markdown": "text/markdown; charset=utf-8"
23
- };
24
- async function startPreviewServer(config, port = config.server.port + 1) {
25
- if (!existsSync(config.outDir)) {
26
- throw new Error(`[odoro] Rien a previsualiser : lancez "odoro build" d'abord.`);
27
- }
28
- const server = createServer((incoming, response) => {
29
- const path = (incoming.url ?? "/").split("?")[0] ?? "/";
30
- const relativePath = normalize(decodeURIComponent(path)).split(/[\\/]/).filter(Boolean).join("/");
31
- const candidate = join(config.outDir, relativePath);
32
- const dansLeDossier = ["index.html", "index.md"].map((nom) => join(candidate, nom)).find((chemin) => existsSync(chemin) && statSync(chemin).isFile());
33
- const existant = existsSync(candidate) && statSync(candidate).isFile() ? candidate : dansLeDossier;
34
- if (existant === void 0 && (extname(relativePath) !== "" || estUneRessource(incoming.headers))) {
35
- response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
36
- response.end(`Introuvable : /${relativePath}`);
37
- return;
38
- }
39
- const file = existant ?? join(config.outDir, "index.html");
40
- if (!file.startsWith(config.outDir)) {
41
- response.writeHead(403, { "Content-Type": "text/plain" });
42
- response.end("Interdit");
43
- return;
44
- }
45
- const type = MIME[extname(file).toLowerCase()] ?? "application/octet-stream";
46
- const immutable = relativePath.startsWith("assets/");
47
- response.writeHead(200, {
48
- "Content-Type": type,
49
- "Cache-Control": immutable ? "public, max-age=31536000, immutable" : "no-cache"
50
- });
51
- createReadStream(file).pipe(response);
52
- });
53
- const { port: obtenu, demande } = await ecouter(server, port, config.server.host);
54
- if (demande !== void 0) {
55
- warn(`port ${String(demande)} occupe \u2014 l apercu ecoute sur ${String(obtenu)}`);
56
- }
57
- const url = `http://${config.server.host}:${String(obtenu)}${config.base}`;
58
- success("previsualisation du build de production");
59
- info(` ${colors.cyan(url)}`);
60
- return {
61
- url,
62
- close: () => new Promise((done) => server.close(() => done()))
63
- };
64
- }
65
-
66
- export { startPreviewServer };
@@ -1,245 +0,0 @@
1
- #!/usr/bin/env node
2
- import { writeDatabaseUrl, assertEnvIgnored } from './chunk-3SZIN6VG.js';
3
- import { info, success, colors, warn, error } from './chunk-JMEHF3KN.js';
4
- import { randomBytes } from 'crypto';
5
- import { readFile, mkdir, writeFile, chmod } from 'fs/promises';
6
- import { platform, homedir } from 'os';
7
- import { dirname, join } from 'path';
8
-
9
- function configPath(env = processEnv()) {
10
- const xdg = env["XDG_CONFIG_HOME"];
11
- if (xdg !== void 0 && xdg.length > 0) return join(xdg, "odoro", "config.json");
12
- if (platform() === "win32") {
13
- const appData = env["APPDATA"];
14
- if (appData !== void 0 && appData.length > 0) {
15
- return join(appData, "odoro", "config.json");
16
- }
17
- }
18
- return join(homedir(), ".config", "odoro", "config.json");
19
- }
20
- function processEnv() {
21
- return process.env;
22
- }
23
- async function readUserConfig(path = configPath()) {
24
- try {
25
- return JSON.parse(await readFile(path, "utf8"));
26
- } catch {
27
- return {};
28
- }
29
- }
30
- async function writeUserConfig(config, path = configPath()) {
31
- await mkdir(dirname(path), { recursive: true });
32
- await writeFile(path, `${JSON.stringify(config, null, 2)}
33
- `, "utf8");
34
- if (platform() === "win32") return { path, restricted: false };
35
- try {
36
- await chmod(path, 384);
37
- return { path, restricted: true };
38
- } catch {
39
- return { path, restricted: false };
40
- }
41
- }
42
- async function storeToken(apiUrl, token, path = configPath()) {
43
- const current = await readUserConfig(path);
44
- return await writeUserConfig(
45
- {
46
- ...current,
47
- tokens: { ...current.tokens, [apiUrl]: token },
48
- defaultApiUrl: current.defaultApiUrl ?? apiUrl
49
- },
50
- path
51
- );
52
- }
53
- async function findToken(apiUrl, path = configPath(), env = processEnv()) {
54
- const fromEnv = env["ODORO_TOKEN"];
55
- if (fromEnv !== void 0 && fromEnv.length > 0) return fromEnv;
56
- const config = await readUserConfig(path);
57
- return config.tokens?.[apiUrl];
58
- }
59
-
60
- // src/db/sdk.ts
61
- var SDK_PACKAGE = "@odoro-cli/cloud-sdk";
62
- async function loadSdk() {
63
- try {
64
- const specifier = SDK_PACKAGE;
65
- const sdk = await import(specifier);
66
- return { ok: true, sdk };
67
- } catch {
68
- return {
69
- ok: false,
70
- reason: `Cette commande a besoin de ${SDK_PACKAGE}, qui n'est pas installe.
71
-
72
- npm install --save-dev ${SDK_PACKAGE}
73
-
74
- Il n'est pas fourni avec odoro : ce binaire est telecharge a chaque
75
- creation de projet, et la plupart n'emploient pas la plateforme.`
76
- };
77
- }
78
- }
79
-
80
- // src/db/commands.ts
81
- var DEFAULT_API_URL = "https://db.odoro.dev";
82
- function idempotencyKey() {
83
- return randomBytes(24).toString("hex");
84
- }
85
- async function connect(options) {
86
- const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
87
- const load = await loadSdk();
88
- if (!load.ok) {
89
- error(load.reason);
90
- return void 0;
91
- }
92
- const token = await findToken(apiUrl);
93
- if (token === void 0) {
94
- error(
95
- `Aucun jeton pour ${apiUrl}.
96
-
97
- odoro db:login
98
-
99
- Ou fournissez-le par la variable ODORO_TOKEN, ce que fait une
100
- integration continue.`
101
- );
102
- return void 0;
103
- }
104
- return { client: load.sdk.createClient({ baseUrl: apiUrl, token }), sdk: load.sdk };
105
- }
106
- async function loginCommand(options) {
107
- const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
108
- const prompts = await import('@clack/prompts');
109
- const value = await prompts.password({
110
- message: `Jeton pour ${apiUrl}`,
111
- validate: (input) => input.startsWith("odk_") ? void 0 : "Un jeton commence par odk_live_ ou odk_test_"
112
- });
113
- if (prompts.isCancel(value)) {
114
- info("Annule.");
115
- return 0;
116
- }
117
- const report = await storeToken(apiUrl, value);
118
- success(`Jeton enregistre dans ${colors.dim(report.path)}`);
119
- if (!report.restricted) {
120
- warn(
121
- "Les droits restrictifs du fichier n ont pas pu etre poses sur ce systeme : verifiez que ce dossier n est pas partage ni synchronise."
122
- );
123
- }
124
- return 0;
125
- }
126
- async function statusCommand(options) {
127
- const connection = await connect(options);
128
- if (connection === void 0) return 1;
129
- const { databases } = await connection.client.databases.list(
130
- options.env === void 0 ? {} : { environmentId: options.env }
131
- );
132
- if (databases.length === 0) {
133
- info("Aucune base. `odoro db:create` en provisionne une.");
134
- return 0;
135
- }
136
- for (const base of databases) {
137
- const etat = base.state === "ready" ? colors.green(base.state) : base.state === "failed" || base.state === "quarantined" ? colors.red(base.state) : colors.dim(base.state);
138
- console.log(` ${base.id} ${etat} ${colors.dim(base.region)}`);
139
- }
140
- return 0;
141
- }
142
- async function createCommand(options) {
143
- const connection = await connect(options);
144
- if (connection === void 0) return 1;
145
- const environmentId = options.env;
146
- if (environmentId === void 0) {
147
- error("Precisez l environnement : `odoro db:create --env production`.");
148
- return 1;
149
- }
150
- const prompts = await import('@clack/prompts');
151
- const spinner = prompts.spinner();
152
- spinner.start("Provisionnement");
153
- const abort = new AbortController();
154
- const onInterrupt = () => abort.abort();
155
- process.once("SIGINT", onInterrupt);
156
- try {
157
- const fini = await connection.client.databases.createAndWait(
158
- { idempotencyKey: idempotencyKey(), environmentId, region: "eu-central-1" },
159
- { signal: abort.signal }
160
- );
161
- spinner.stop("Base provisionnee");
162
- const databaseId = fini.subject;
163
- if (databaseId === void 0) {
164
- warn(
165
- "L operation a abouti sans nommer la base creee. `odoro db:status` la montrera."
166
- );
167
- return 0;
168
- }
169
- const { connectionString } = await connection.client.credentials.rotate({
170
- databaseId
171
- });
172
- await writeDatabaseUrl(options.root, connectionString);
173
- success("DATABASE_URL ecrite dans .env");
174
- const risque = await assertEnvIgnored(options.root);
175
- if (risque !== void 0) warn(risque);
176
- return 0;
177
- } catch (cause) {
178
- spinner.stop("Provisionnement interrompu");
179
- if (abort.signal.aborted) {
180
- info(
181
- "Attente abandonnee. Le provisionnement continue : `odoro db:status` en montrera l aboutissement."
182
- );
183
- return 0;
184
- }
185
- error(describe(cause, connection.sdk));
186
- return 1;
187
- } finally {
188
- process.off("SIGINT", onInterrupt);
189
- }
190
- }
191
- async function branchCommand(options) {
192
- const connection = await connect(options);
193
- if (connection === void 0) return 1;
194
- if (options.from === void 0 || options.name === void 0) {
195
- error("Usage : `odoro db:branch --from production --name preview-42`");
196
- return 1;
197
- }
198
- const prompts = await import('@clack/prompts');
199
- const spinner = prompts.spinner();
200
- spinner.start(`Branche depuis ${options.from}`);
201
- try {
202
- const fini = await connection.client.databases.branchAndWait({
203
- idempotencyKey: idempotencyKey(),
204
- parentEnvironmentId: options.from,
205
- name: options.name,
206
- // Sans regle declaree, la plateforme refuse. On ne devine pas a sa
207
- // place : une regle inventee ici anonymiserait la mauvaise colonne, ou
208
- // aucune.
209
- anonymization: []
210
- });
211
- spinner.stop("Branche creee");
212
- info(`Base : ${fini.subject ?? "voir odoro db:status"}`);
213
- return 0;
214
- } catch (cause) {
215
- spinner.stop("Branche refusee");
216
- error(describe(cause, connection.sdk));
217
- return 1;
218
- }
219
- }
220
- function describe(cause, sdk) {
221
- if (sdk.isApiError(cause, "VALIDATION")) {
222
- const errors = cause.options?.errors;
223
- return [
224
- "La demande a ete refusee :",
225
- ...(errors ?? []).map(({ field, message }) => ` ${field} \u2014 ${message}`)
226
- ].join("\n");
227
- }
228
- if (sdk.isApiError(cause, "RATE_LIMIT")) {
229
- return "Trop de demandes. Les routes qui provisionnent sont volontairement limitees : chaque creation coute.";
230
- }
231
- if (sdk.isApiError(cause, "UNAUTHORIZED")) {
232
- return `Jeton refuse. \`odoro db:login\` en enregistre un autre.`;
233
- }
234
- return cause instanceof Error ? cause.message : String(cause);
235
- }
236
- var DB_HELP = [
237
- " db:login Enregistre un jeton de plateforme",
238
- " db:status Liste les bases du projet",
239
- " db:create --env <e> Provisionne une base et ecrit .env",
240
- " db:branch --from <e> --name <n>",
241
- " Cree une previsualisation par branche",
242
- ` (necessite ${SDK_PACKAGE})`
243
- ].join("\n");
244
-
245
- export { DB_HELP, branchCommand, createCommand, loginCommand, statusCommand };
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env node
2
- export { startPreviewServer } from './chunk-ZVL7EXJO.js';
3
- import './chunk-TQUJ3MFS.js';
4
- import './chunk-JMEHF3KN.js';