tempest-react-sdk 0.5.1 → 0.8.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 (51) hide show
  1. package/README.md +206 -35
  2. package/bin/create-tempest-app.mjs +248 -0
  3. package/bin/tempest.mjs +282 -0
  4. package/dist/styles.css +1 -1
  5. package/dist/sw.cjs +2 -0
  6. package/dist/sw.cjs.map +1 -0
  7. package/dist/sw.d.ts +103 -0
  8. package/dist/sw.js +95 -0
  9. package/dist/sw.js.map +1 -0
  10. package/dist/tempest-react-sdk.cjs +4 -4
  11. package/dist/tempest-react-sdk.cjs.map +1 -1
  12. package/dist/tempest-react-sdk.d.ts +1697 -7
  13. package/dist/tempest-react-sdk.js +4485 -2989
  14. package/dist/tempest-react-sdk.js.map +1 -1
  15. package/dist/vite.cjs +2 -0
  16. package/dist/vite.cjs.map +1 -0
  17. package/dist/vite.d.ts +62 -0
  18. package/dist/vite.js +46 -0
  19. package/dist/vite.js.map +1 -0
  20. package/package.json +34 -2
  21. package/template/README.md +37 -0
  22. package/template/_env.example +2 -0
  23. package/template/_gitignore +9 -0
  24. package/template/_prettierrc.json +9 -0
  25. package/template/eslint.config.js +44 -0
  26. package/template/index.html +12 -0
  27. package/template/package.json +38 -0
  28. package/template/src/App.tsx +15 -0
  29. package/template/src/layouts/RootLayout.tsx +28 -0
  30. package/template/src/lib/api.ts +17 -0
  31. package/template/src/main.tsx +10 -0
  32. package/template/src/pages/Dashboard.tsx +19 -0
  33. package/template/src/pages/Home.tsx +16 -0
  34. package/template/src/pages/Login.tsx +27 -0
  35. package/template/src/routes.tsx +27 -0
  36. package/template/src/stores/auth.ts +15 -0
  37. package/template/src/vite-env.d.ts +1 -0
  38. package/template/tsconfig.json +26 -0
  39. package/template/vite.config.ts +7 -0
  40. package/template-pwa/README.md +64 -0
  41. package/template-pwa/_env.example +7 -0
  42. package/template-pwa/index.html +22 -0
  43. package/template-pwa/package.json +6 -0
  44. package/template-pwa/public/icon-maskable.svg +4 -0
  45. package/template-pwa/public/icon.svg +4 -0
  46. package/template-pwa/public/manifest.webmanifest +35 -0
  47. package/template-pwa/src/main.tsx +36 -0
  48. package/template-pwa/src/pages/Dashboard.tsx +73 -0
  49. package/template-pwa/src/sw.ts +35 -0
  50. package/template-pwa/src/vite-env.d.ts +12 -0
  51. package/template-pwa/vite.sw.config.ts +27 -0
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env node
2
+ // tempest — project CLI shipped inside tempest-react-sdk.
3
+ //
4
+ // tempest doctor health-check the current project (à la flutter doctor)
5
+ // tempest lint [paths…] run ESLint (report only)
6
+ // tempest fix [paths…] ESLint --fix (sort imports, drop unused, tidy whitespace) + Prettier
7
+ // tempest format [paths…] Prettier --write
8
+ // tempest --help | --version
9
+ import { spawnSync } from "node:child_process";
10
+ import { existsSync, readFileSync } from "node:fs";
11
+ import { join, resolve } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const ROOT = process.cwd();
15
+ const SELF_DIR = resolve(fileURLToPath(import.meta.url), "..");
16
+
17
+ const c = {
18
+ reset: "\x1b[0m",
19
+ bold: "\x1b[1m",
20
+ dim: "\x1b[2m",
21
+ green: "\x1b[32m",
22
+ yellow: "\x1b[33m",
23
+ red: "\x1b[31m",
24
+ cyan: "\x1b[36m",
25
+ };
26
+
27
+ function selfVersion() {
28
+ try {
29
+ return (
30
+ JSON.parse(readFileSync(join(SELF_DIR, "..", "package.json"), "utf8")).version ?? "?"
31
+ );
32
+ } catch {
33
+ return "?";
34
+ }
35
+ }
36
+
37
+ /** Resolve a project-local CLI binary (e.g. eslint, prettier). */
38
+ function localBin(name) {
39
+ const p = join(ROOT, "node_modules", ".bin", name);
40
+ return existsSync(p) ? p : null;
41
+ }
42
+
43
+ function run(bin, args) {
44
+ const res = spawnSync(bin, args, { stdio: "inherit", cwd: ROOT });
45
+ return res.status ?? 1;
46
+ }
47
+
48
+ function readJSON(path) {
49
+ try {
50
+ return JSON.parse(readFileSync(path, "utf8"));
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+
56
+ // ---------------------------------------------------------------- doctor ----
57
+
58
+ function fmt(status, label, detail) {
59
+ const mark =
60
+ status === "ok"
61
+ ? `${c.green}✓${c.reset}`
62
+ : status === "warn"
63
+ ? `${c.yellow}!${c.reset}`
64
+ : `${c.red}✗${c.reset}`;
65
+ const tail = detail ? ` ${c.dim}— ${detail}${c.reset}` : "";
66
+ return ` [${mark}] ${label}${tail}`;
67
+ }
68
+
69
+ function fileIncludes(path, needle) {
70
+ try {
71
+ return readFileSync(path, "utf8").includes(needle);
72
+ } catch {
73
+ return false;
74
+ }
75
+ }
76
+
77
+ function firstExisting(paths) {
78
+ return paths.find((p) => existsSync(join(ROOT, p))) ?? null;
79
+ }
80
+
81
+ function doctor() {
82
+ const checks = [];
83
+ const pkg = readJSON(join(ROOT, "package.json"));
84
+
85
+ // Node
86
+ const [maj, min] = process.versions.node.split(".").map(Number);
87
+ const nodeOk = maj > 20 || (maj === 20 && min >= 19);
88
+ checks.push([
89
+ nodeOk ? "ok" : "fail",
90
+ `Node ${process.versions.node}`,
91
+ nodeOk ? "" : "requires >= 20.19",
92
+ ]);
93
+
94
+ // package.json
95
+ if (!pkg) {
96
+ checks.push(["fail", "package.json", "not found — run inside your project root"]);
97
+ return report(checks);
98
+ }
99
+ checks.push(["ok", "package.json found"]);
100
+
101
+ // SDK dependency + installed
102
+ const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
103
+ checks.push(
104
+ deps["tempest-react-sdk"]
105
+ ? ["ok", "tempest-react-sdk in dependencies", deps["tempest-react-sdk"]]
106
+ : [
107
+ "fail",
108
+ "tempest-react-sdk in dependencies",
109
+ "add it: npm install tempest-react-sdk",
110
+ ],
111
+ );
112
+ checks.push(
113
+ existsSync(join(ROOT, "node_modules", "tempest-react-sdk"))
114
+ ? ["ok", "tempest-react-sdk installed"]
115
+ : ["fail", "tempest-react-sdk installed", "run npm install"],
116
+ );
117
+
118
+ // React peers
119
+ const hasReact = deps.react && deps["react-dom"];
120
+ checks.push(
121
+ hasReact
122
+ ? ["ok", "react + react-dom present"]
123
+ : ["fail", "react + react-dom present", "install react react-dom"],
124
+ );
125
+
126
+ // Vite config + createViteConfig
127
+ const viteCfg = firstExisting(["vite.config.ts", "vite.config.js", "vite.config.mjs"]);
128
+ if (!viteCfg) {
129
+ checks.push(["warn", "vite config", "no vite.config.* found"]);
130
+ } else {
131
+ checks.push(
132
+ fileIncludes(join(ROOT, viteCfg), "createViteConfig")
133
+ ? ["ok", `${viteCfg} uses createViteConfig`]
134
+ : ["warn", `${viteCfg}`, "not using createViteConfig from tempest-react-sdk/vite"],
135
+ );
136
+ }
137
+
138
+ // tsconfig @ alias
139
+ const tsc = readJSON(join(ROOT, "tsconfig.json"));
140
+ const paths = tsc?.compilerOptions?.paths ?? {};
141
+ checks.push(
142
+ paths["@/*"]
143
+ ? ["ok", 'tsconfig "@/*" alias']
144
+ : ["warn", 'tsconfig "@/*" alias', 'add "paths": { "@/*": ["./src/*"] }'],
145
+ );
146
+
147
+ // styles.css imported at entry
148
+ const entry = firstExisting(["src/main.tsx", "src/main.ts", "src/index.tsx", "src/index.ts"]);
149
+ if (entry) {
150
+ checks.push(
151
+ fileIncludes(join(ROOT, entry), "tempest-react-sdk/styles.css")
152
+ ? ["ok", `${entry} imports styles.css`]
153
+ : ["warn", `${entry}`, 'add import "tempest-react-sdk/styles.css"'],
154
+ );
155
+ } else {
156
+ checks.push(["warn", "app entry", "no src/main.tsx found"]);
157
+ }
158
+
159
+ // tooling
160
+ checks.push(
161
+ firstExisting(["eslint.config.js", "eslint.config.mjs", ".eslintrc.cjs", ".eslintrc.json"])
162
+ ? ["ok", "ESLint config present"]
163
+ : ["warn", "ESLint config", "no eslint config — `tempest fix` needs it"],
164
+ );
165
+ checks.push(
166
+ localBin("eslint")
167
+ ? ["ok", "eslint installed"]
168
+ : ["warn", "eslint installed", "npm i -D eslint"],
169
+ );
170
+ checks.push(
171
+ localBin("prettier")
172
+ ? ["ok", "prettier installed"]
173
+ : ["warn", "prettier installed", "npm i -D prettier"],
174
+ );
175
+
176
+ // .env
177
+ if (existsSync(join(ROOT, ".env"))) checks.push(["ok", ".env present"]);
178
+ else if (existsSync(join(ROOT, ".env.example")))
179
+ checks.push(["warn", ".env", "only .env.example — copy it: cp .env.example .env"]);
180
+
181
+ return report(checks);
182
+ }
183
+
184
+ function report(checks) {
185
+ console.log(`\n${c.bold}${c.cyan}tempest doctor${c.reset} ${c.dim}(${ROOT})${c.reset}\n`);
186
+ for (const [status, label, detail] of checks) console.log(fmt(status, label, detail));
187
+ const fails = checks.filter((x) => x[0] === "fail").length;
188
+ const warns = checks.filter((x) => x[0] === "warn").length;
189
+ console.log("");
190
+ if (fails)
191
+ console.log(
192
+ `${c.red}✗ ${fails} problem(s)${c.reset}${warns ? `, ${c.yellow}${warns} warning(s)${c.reset}` : ""}.`,
193
+ );
194
+ else if (warns)
195
+ console.log(`${c.yellow}! ${warns} warning(s)${c.reset} — usable, but worth fixing.`);
196
+ else console.log(`${c.green}✓ No issues found.${c.reset}`);
197
+ console.log("");
198
+ return fails ? 1 : 0;
199
+ }
200
+
201
+ // ------------------------------------------------------- lint / fix / fmt ----
202
+
203
+ function requireBin(name) {
204
+ const bin = localBin(name);
205
+ if (!bin) {
206
+ console.error(
207
+ `${c.red}✗ ${name} not found in node_modules.${c.reset} Install it: ${c.bold}npm i -D ${name}${c.reset}`,
208
+ );
209
+ process.exit(1);
210
+ }
211
+ return bin;
212
+ }
213
+
214
+ function lint(paths) {
215
+ return run(requireBin("eslint"), paths.length ? paths : ["."]);
216
+ }
217
+
218
+ function fix(paths) {
219
+ const targets = paths.length ? paths : ["."];
220
+ console.log(`${c.dim}→ eslint --fix (sort imports · drop unused · tidy whitespace)${c.reset}`);
221
+ const eslintStatus = run(requireBin("eslint"), [...targets, "--fix"]);
222
+ const prettier = localBin("prettier");
223
+ let prettierStatus = 0;
224
+ if (prettier) {
225
+ console.log(`${c.dim}→ prettier --write${c.reset}`);
226
+ prettierStatus = run(prettier, ["--write", ...targets]);
227
+ } else {
228
+ console.log(`${c.yellow}! prettier not installed — skipping format pass${c.reset}`);
229
+ }
230
+ return eslintStatus || prettierStatus;
231
+ }
232
+
233
+ function format(paths) {
234
+ return run(requireBin("prettier"), ["--write", ...(paths.length ? paths : ["."])]);
235
+ }
236
+
237
+ // ------------------------------------------------------------------ main ----
238
+
239
+ function usage() {
240
+ console.log(`
241
+ ${c.bold}${c.cyan}tempest${c.reset} ${c.dim}v${selfVersion()}${c.reset} — project CLI for tempest-react-sdk apps
242
+
243
+ ${c.bold}Usage${c.reset}
244
+ tempest <command> [paths…]
245
+
246
+ ${c.bold}Commands${c.reset}
247
+ ${c.bold}doctor${c.reset} Health-check the current project
248
+ ${c.bold}lint${c.reset} [paths] Run ESLint (report only)
249
+ ${c.bold}fix${c.reset} [paths] ESLint --fix (sort imports, remove unused, tidy whitespace) + Prettier
250
+ ${c.bold}format${c.reset} [paths] Prettier --write
251
+
252
+ ${c.bold}Options${c.reset}
253
+ -h, --help Show this help
254
+ -v, --version Show version
255
+ `);
256
+ }
257
+
258
+ const [cmd, ...rest] = process.argv.slice(2);
259
+
260
+ if (cmd === "-v" || cmd === "--version") {
261
+ console.log(selfVersion());
262
+ process.exit(0);
263
+ }
264
+ if (!cmd || cmd === "-h" || cmd === "--help" || cmd === "help") {
265
+ usage();
266
+ process.exit(0);
267
+ }
268
+
269
+ const commands = {
270
+ doctor: () => doctor(),
271
+ lint: () => lint(rest),
272
+ fix: () => fix(rest),
273
+ format: () => format(rest),
274
+ };
275
+
276
+ if (!commands[cmd]) {
277
+ console.error(`${c.red}✗ Unknown command: ${cmd}${c.reset}`);
278
+ usage();
279
+ process.exit(1);
280
+ }
281
+
282
+ process.exit(commands[cmd]());