tempest-react-sdk 0.5.0 → 0.7.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/dist/vite.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("node:path"),v=require("vite"),f=require("@vitejs/plugin-react");function d(t){const r={};for(const[n,e]of Object.entries(t))r[n]=typeof e=="string"?{target:e,changeOrigin:!0}:e;return r}function y(t={}){const{srcDir:r="src",port:n=5173,host:e="127.0.0.1",open:c=!1,proxy:i,alias:l={},plugins:u=[],overrides:a={}}=t,o=a,s={plugins:[f(),...u],resolve:{alias:{"@":p.resolve(process.cwd(),r),...l}},server:{port:n,host:e,open:c,...i?{proxy:d(i)}:{}}},g={...s,...o,plugins:[...s.plugins??[],...o.plugins??[]],resolve:{...s.resolve,...o.resolve},server:{...s.server,...o.server}};return v.defineConfig(g)}exports.createViteConfig=y;
2
+ //# sourceMappingURL=vite.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.cjs","sources":["../src/vite/create-vite-config.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { defineConfig } from \"vite\";\nimport type { ProxyOptions, UserConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\n\n/**\n * A Vite proxy entry: either a target URL string (expanded to\n * `{ target, changeOrigin: true }`) or a raw Vite `ProxyOptions` object.\n */\nexport type ProxyEntry = string | Record<string, unknown>;\n\nexport interface CreateViteConfigOptions {\n /**\n * Source directory aliased to `@`, relative to the project root.\n * Default: `\"src\"` (so `@/components/Button` → `<root>/src/components/Button`).\n */\n srcDir?: string;\n /** Dev server port. Default: `5173`. */\n port?: number;\n /** Dev server host. Default: `\"127.0.0.1\"`. */\n host?: string | boolean;\n /** Open the browser on `dev` start. Default: `false`. */\n open?: boolean;\n /**\n * Dev proxy table. String values are expanded to\n * `{ target, changeOrigin: true }`; objects are passed through untouched.\n *\n * @example { \"/api\": \"http://127.0.0.1:8000\" }\n */\n proxy?: Record<string, ProxyEntry>;\n /** Extra path aliases merged on top of the default `@` → src alias. */\n alias?: Record<string, string>;\n /** Vite plugins appended after `@vitejs/plugin-react`. */\n plugins?: unknown[];\n /**\n * Arbitrary Vite config (a `UserConfig` object) deep-merged last, for\n * escape-hatch overrides (build target, define, extra `server` keys, …).\n */\n overrides?: Record<string, unknown>;\n}\n\n/**\n * The resulting Vite config object. Typed loosely so the SDK's published\n * declarations stay free of `vite`'s internal types; assign it straight to a\n * `vite.config.ts` default export.\n */\nexport type TempestViteConfig = Record<string, unknown>;\n\nfunction normalizeProxy(proxy: Record<string, ProxyEntry>): Record<string, ProxyOptions> {\n const out: Record<string, ProxyOptions> = {};\n for (const [path, value] of Object.entries(proxy)) {\n out[path] =\n typeof value === \"string\"\n ? { target: value, changeOrigin: true }\n : (value as ProxyOptions);\n }\n return out;\n}\n\n/**\n * Build a Tempest-flavored Vite config for a React app: the `@vitejs/plugin-react`\n * plugin, the `@` → `src` import alias, and sane dev-server defaults — so a\n * consuming app's `vite.config.ts` is a single call instead of repeated\n * boilerplate. Everything is overridable.\n *\n * Import it from the dedicated Node entry point:\n *\n * @example\n * // vite.config.ts\n * import { createViteConfig } from \"tempest-react-sdk/vite\";\n *\n * export default createViteConfig({\n * proxy: { \"/api\": \"http://127.0.0.1:8000\" },\n * });\n */\nexport function createViteConfig(options: CreateViteConfigOptions = {}): TempestViteConfig {\n const {\n srcDir = \"src\",\n port = 5173,\n host = \"127.0.0.1\",\n open = false,\n proxy,\n alias = {},\n plugins = [],\n overrides = {},\n } = options;\n\n const overridesConfig = overrides as UserConfig;\n\n const base: UserConfig = {\n plugins: [react(), ...plugins] as UserConfig[\"plugins\"],\n resolve: {\n alias: {\n \"@\": resolve(process.cwd(), srcDir),\n ...alias,\n },\n },\n server: {\n port,\n host,\n open,\n ...(proxy ? { proxy: normalizeProxy(proxy) } : {}),\n },\n };\n\n const merged: UserConfig = {\n ...base,\n ...overridesConfig,\n plugins: [...(base.plugins ?? []), ...(overridesConfig.plugins ?? [])],\n resolve: { ...base.resolve, ...overridesConfig.resolve },\n server: { ...base.server, ...overridesConfig.server },\n };\n\n return defineConfig(merged) as TempestViteConfig;\n}\n"],"names":["normalizeProxy","proxy","out","path","value","createViteConfig","options","srcDir","port","host","open","alias","plugins","overrides","overridesConfig","base","react","resolve","merged","defineConfig"],"mappings":"iKAgDA,SAASA,EAAeC,EAAiE,CACrF,MAAMC,EAAoC,CAAA,EAC1C,SAAW,CAACC,EAAMC,CAAK,IAAK,OAAO,QAAQH,CAAK,EAC5CC,EAAIC,CAAI,EACJ,OAAOC,GAAU,SACX,CAAE,OAAQA,EAAO,aAAc,EAAA,EAC9BA,EAEf,OAAOF,CACX,CAkBO,SAASG,EAAiBC,EAAmC,GAAuB,CACvF,KAAM,CACF,OAAAC,EAAS,MACT,KAAAC,EAAO,KACP,KAAAC,EAAO,YACP,KAAAC,EAAO,GACP,MAAAT,EACA,MAAAU,EAAQ,CAAA,EACR,QAAAC,EAAU,CAAA,EACV,UAAAC,EAAY,CAAA,CAAC,EACbP,EAEEQ,EAAkBD,EAElBE,EAAmB,CACrB,QAAS,CAACC,IAAS,GAAGJ,CAAO,EAC7B,QAAS,CACL,MAAO,CACH,IAAKK,EAAAA,QAAQ,QAAQ,IAAA,EAAOV,CAAM,EAClC,GAAGI,CAAA,CACP,EAEJ,OAAQ,CACJ,KAAAH,EACA,KAAAC,EACA,KAAAC,EACA,GAAIT,EAAQ,CAAE,MAAOD,EAAeC,CAAK,CAAA,EAAM,CAAA,CAAC,CACpD,EAGEiB,EAAqB,CACvB,GAAGH,EACH,GAAGD,EACH,QAAS,CAAC,GAAIC,EAAK,SAAW,CAAA,EAAK,GAAID,EAAgB,SAAW,EAAG,EACrE,QAAS,CAAE,GAAGC,EAAK,QAAS,GAAGD,EAAgB,OAAA,EAC/C,OAAQ,CAAE,GAAGC,EAAK,OAAQ,GAAGD,EAAgB,MAAA,CAAO,EAGxD,OAAOK,EAAAA,aAAaD,CAAM,CAC9B"}
package/dist/vite.d.ts ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Build a Tempest-flavored Vite config for a React app: the `@vitejs/plugin-react`
3
+ * plugin, the `@` → `src` import alias, and sane dev-server defaults — so a
4
+ * consuming app's `vite.config.ts` is a single call instead of repeated
5
+ * boilerplate. Everything is overridable.
6
+ *
7
+ * Import it from the dedicated Node entry point:
8
+ *
9
+ * @example
10
+ * // vite.config.ts
11
+ * import { createViteConfig } from "tempest-react-sdk/vite";
12
+ *
13
+ * export default createViteConfig({
14
+ * proxy: { "/api": "http://127.0.0.1:8000" },
15
+ * });
16
+ */
17
+ export declare function createViteConfig(options?: CreateViteConfigOptions): TempestViteConfig;
18
+
19
+ export declare interface CreateViteConfigOptions {
20
+ /**
21
+ * Source directory aliased to `@`, relative to the project root.
22
+ * Default: `"src"` (so `@/components/Button` → `<root>/src/components/Button`).
23
+ */
24
+ srcDir?: string;
25
+ /** Dev server port. Default: `5173`. */
26
+ port?: number;
27
+ /** Dev server host. Default: `"127.0.0.1"`. */
28
+ host?: string | boolean;
29
+ /** Open the browser on `dev` start. Default: `false`. */
30
+ open?: boolean;
31
+ /**
32
+ * Dev proxy table. String values are expanded to
33
+ * `{ target, changeOrigin: true }`; objects are passed through untouched.
34
+ *
35
+ * @example { "/api": "http://127.0.0.1:8000" }
36
+ */
37
+ proxy?: Record<string, ProxyEntry>;
38
+ /** Extra path aliases merged on top of the default `@` → src alias. */
39
+ alias?: Record<string, string>;
40
+ /** Vite plugins appended after `@vitejs/plugin-react`. */
41
+ plugins?: unknown[];
42
+ /**
43
+ * Arbitrary Vite config (a `UserConfig` object) deep-merged last, for
44
+ * escape-hatch overrides (build target, define, extra `server` keys, …).
45
+ */
46
+ overrides?: Record<string, unknown>;
47
+ }
48
+
49
+ /**
50
+ * A Vite proxy entry: either a target URL string (expanded to
51
+ * `{ target, changeOrigin: true }`) or a raw Vite `ProxyOptions` object.
52
+ */
53
+ export declare type ProxyEntry = string | Record<string, unknown>;
54
+
55
+ /**
56
+ * The resulting Vite config object. Typed loosely so the SDK's published
57
+ * declarations stay free of `vite`'s internal types; assign it straight to a
58
+ * `vite.config.ts` default export.
59
+ */
60
+ export declare type TempestViteConfig = Record<string, unknown>;
61
+
62
+ export { }
package/dist/vite.js ADDED
@@ -0,0 +1,46 @@
1
+ import { resolve as g } from "node:path";
2
+ import { defineConfig as u } from "vite";
3
+ import v from "@vitejs/plugin-react";
4
+ function m(t) {
5
+ const r = {};
6
+ for (const [n, e] of Object.entries(t))
7
+ r[n] = typeof e == "string" ? { target: e, changeOrigin: !0 } : e;
8
+ return r;
9
+ }
10
+ function h(t = {}) {
11
+ const {
12
+ srcDir: r = "src",
13
+ port: n = 5173,
14
+ host: e = "127.0.0.1",
15
+ open: c = !1,
16
+ proxy: i,
17
+ alias: p = {},
18
+ plugins: l = [],
19
+ overrides: a = {}
20
+ } = t, o = a, s = {
21
+ plugins: [v(), ...l],
22
+ resolve: {
23
+ alias: {
24
+ "@": g(process.cwd(), r),
25
+ ...p
26
+ }
27
+ },
28
+ server: {
29
+ port: n,
30
+ host: e,
31
+ open: c,
32
+ ...i ? { proxy: m(i) } : {}
33
+ }
34
+ }, f = {
35
+ ...s,
36
+ ...o,
37
+ plugins: [...s.plugins ?? [], ...o.plugins ?? []],
38
+ resolve: { ...s.resolve, ...o.resolve },
39
+ server: { ...s.server, ...o.server }
40
+ };
41
+ return u(f);
42
+ }
43
+ export {
44
+ h as createViteConfig
45
+ };
46
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.js","sources":["../src/vite/create-vite-config.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { defineConfig } from \"vite\";\nimport type { ProxyOptions, UserConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\n\n/**\n * A Vite proxy entry: either a target URL string (expanded to\n * `{ target, changeOrigin: true }`) or a raw Vite `ProxyOptions` object.\n */\nexport type ProxyEntry = string | Record<string, unknown>;\n\nexport interface CreateViteConfigOptions {\n /**\n * Source directory aliased to `@`, relative to the project root.\n * Default: `\"src\"` (so `@/components/Button` → `<root>/src/components/Button`).\n */\n srcDir?: string;\n /** Dev server port. Default: `5173`. */\n port?: number;\n /** Dev server host. Default: `\"127.0.0.1\"`. */\n host?: string | boolean;\n /** Open the browser on `dev` start. Default: `false`. */\n open?: boolean;\n /**\n * Dev proxy table. String values are expanded to\n * `{ target, changeOrigin: true }`; objects are passed through untouched.\n *\n * @example { \"/api\": \"http://127.0.0.1:8000\" }\n */\n proxy?: Record<string, ProxyEntry>;\n /** Extra path aliases merged on top of the default `@` → src alias. */\n alias?: Record<string, string>;\n /** Vite plugins appended after `@vitejs/plugin-react`. */\n plugins?: unknown[];\n /**\n * Arbitrary Vite config (a `UserConfig` object) deep-merged last, for\n * escape-hatch overrides (build target, define, extra `server` keys, …).\n */\n overrides?: Record<string, unknown>;\n}\n\n/**\n * The resulting Vite config object. Typed loosely so the SDK's published\n * declarations stay free of `vite`'s internal types; assign it straight to a\n * `vite.config.ts` default export.\n */\nexport type TempestViteConfig = Record<string, unknown>;\n\nfunction normalizeProxy(proxy: Record<string, ProxyEntry>): Record<string, ProxyOptions> {\n const out: Record<string, ProxyOptions> = {};\n for (const [path, value] of Object.entries(proxy)) {\n out[path] =\n typeof value === \"string\"\n ? { target: value, changeOrigin: true }\n : (value as ProxyOptions);\n }\n return out;\n}\n\n/**\n * Build a Tempest-flavored Vite config for a React app: the `@vitejs/plugin-react`\n * plugin, the `@` → `src` import alias, and sane dev-server defaults — so a\n * consuming app's `vite.config.ts` is a single call instead of repeated\n * boilerplate. Everything is overridable.\n *\n * Import it from the dedicated Node entry point:\n *\n * @example\n * // vite.config.ts\n * import { createViteConfig } from \"tempest-react-sdk/vite\";\n *\n * export default createViteConfig({\n * proxy: { \"/api\": \"http://127.0.0.1:8000\" },\n * });\n */\nexport function createViteConfig(options: CreateViteConfigOptions = {}): TempestViteConfig {\n const {\n srcDir = \"src\",\n port = 5173,\n host = \"127.0.0.1\",\n open = false,\n proxy,\n alias = {},\n plugins = [],\n overrides = {},\n } = options;\n\n const overridesConfig = overrides as UserConfig;\n\n const base: UserConfig = {\n plugins: [react(), ...plugins] as UserConfig[\"plugins\"],\n resolve: {\n alias: {\n \"@\": resolve(process.cwd(), srcDir),\n ...alias,\n },\n },\n server: {\n port,\n host,\n open,\n ...(proxy ? { proxy: normalizeProxy(proxy) } : {}),\n },\n };\n\n const merged: UserConfig = {\n ...base,\n ...overridesConfig,\n plugins: [...(base.plugins ?? []), ...(overridesConfig.plugins ?? [])],\n resolve: { ...base.resolve, ...overridesConfig.resolve },\n server: { ...base.server, ...overridesConfig.server },\n };\n\n return defineConfig(merged) as TempestViteConfig;\n}\n"],"names":["normalizeProxy","proxy","out","path","value","createViteConfig","options","srcDir","port","host","open","alias","plugins","overrides","overridesConfig","base","react","resolve","merged","defineConfig"],"mappings":";;;AAgDA,SAASA,EAAeC,GAAiE;AACrF,QAAMC,IAAoC,CAAA;AAC1C,aAAW,CAACC,GAAMC,CAAK,KAAK,OAAO,QAAQH,CAAK;AAC5C,IAAAC,EAAIC,CAAI,IACJ,OAAOC,KAAU,WACX,EAAE,QAAQA,GAAO,cAAc,GAAA,IAC9BA;AAEf,SAAOF;AACX;AAkBO,SAASG,EAAiBC,IAAmC,IAAuB;AACvF,QAAM;AAAA,IACF,QAAAC,IAAS;AAAA,IACT,MAAAC,IAAO;AAAA,IACP,MAAAC,IAAO;AAAA,IACP,MAAAC,IAAO;AAAA,IACP,OAAAT;AAAA,IACA,OAAAU,IAAQ,CAAA;AAAA,IACR,SAAAC,IAAU,CAAA;AAAA,IACV,WAAAC,IAAY,CAAA;AAAA,EAAC,IACbP,GAEEQ,IAAkBD,GAElBE,IAAmB;AAAA,IACrB,SAAS,CAACC,KAAS,GAAGJ,CAAO;AAAA,IAC7B,SAAS;AAAA,MACL,OAAO;AAAA,QACH,KAAKK,EAAQ,QAAQ,IAAA,GAAOV,CAAM;AAAA,QAClC,GAAGI;AAAA,MAAA;AAAA,IACP;AAAA,IAEJ,QAAQ;AAAA,MACJ,MAAAH;AAAA,MACA,MAAAC;AAAA,MACA,MAAAC;AAAA,MACA,GAAIT,IAAQ,EAAE,OAAOD,EAAeC,CAAK,EAAA,IAAM,CAAA;AAAA,IAAC;AAAA,EACpD,GAGEiB,IAAqB;AAAA,IACvB,GAAGH;AAAA,IACH,GAAGD;AAAA,IACH,SAAS,CAAC,GAAIC,EAAK,WAAW,CAAA,GAAK,GAAID,EAAgB,WAAW,EAAG;AAAA,IACrE,SAAS,EAAE,GAAGC,EAAK,SAAS,GAAGD,EAAgB,QAAA;AAAA,IAC/C,QAAQ,EAAE,GAAGC,EAAK,QAAQ,GAAGD,EAAgB,OAAA;AAAA,EAAO;AAGxD,SAAOK,EAAaD,CAAM;AAC9B;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tempest-react-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "SDK público da Tempest com componentes, hooks e integrações para projetos React.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,9 +23,14 @@
23
23
  ],
24
24
  "files": [
25
25
  "dist",
26
+ "bin",
27
+ "template",
26
28
  "README.md",
27
29
  "LICENSE"
28
30
  ],
31
+ "bin": {
32
+ "create-tempest-app": "./bin/create-tempest-app.mjs"
33
+ },
29
34
  "main": "./dist/tempest-react-sdk.cjs",
30
35
  "module": "./dist/tempest-react-sdk.js",
31
36
  "types": "./dist/tempest-react-sdk.d.ts",
@@ -43,6 +48,11 @@
43
48
  "import": "./dist/testing.js",
44
49
  "require": "./dist/testing.cjs"
45
50
  },
51
+ "./vite": {
52
+ "types": "./dist/vite.d.ts",
53
+ "import": "./dist/vite.js",
54
+ "require": "./dist/vite.cjs"
55
+ },
46
56
  "./styles.css": "./dist/styles.css",
47
57
  "./package.json": "./package.json"
48
58
  },
@@ -57,6 +67,7 @@
57
67
  "test:run": "vitest run",
58
68
  "test:coverage": "vitest run --coverage",
59
69
  "clean": "rm -rf dist coverage",
70
+ "size": "size-limit",
60
71
  "prepare": "husky",
61
72
  "prepublishOnly": "npm run typecheck && npm run lint && npm run test:run && npm run build"
62
73
  },
@@ -74,15 +85,27 @@
74
85
  "dexie": "^4.4.2",
75
86
  "lucide-react": ">=0.400.0",
76
87
  "react-hook-form": "^7.76.0",
88
+ "react-router-dom": "^7.18.0",
77
89
  "zod": "^3.23.0 || ^4.0.0",
78
90
  "zustand": "^4.0.0 || ^5.0.0"
79
91
  },
80
92
  "peerDependencies": {
93
+ "@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
81
94
  "react": "^18.0.0 || ^19.0.0",
82
- "react-dom": "^18.0.0 || ^19.0.0"
95
+ "react-dom": "^18.0.0 || ^19.0.0",
96
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
97
+ },
98
+ "peerDependenciesMeta": {
99
+ "vite": {
100
+ "optional": true
101
+ },
102
+ "@vitejs/plugin-react": {
103
+ "optional": true
104
+ }
83
105
  },
84
106
  "devDependencies": {
85
107
  "@eslint/js": "^9.36.0",
108
+ "@size-limit/preset-small-lib": "^12.1.0",
86
109
  "@tanstack/react-query": "^5.90.0",
87
110
  "@testing-library/jest-dom": "^6.9.1",
88
111
  "@testing-library/react": "^16.3.2",
@@ -106,6 +129,7 @@
106
129
  "react": "^19.1.0",
107
130
  "react-dom": "^19.1.0",
108
131
  "react-hook-form": "^7.76.0",
132
+ "size-limit": "^12.1.0",
109
133
  "typescript": "~5.9.0",
110
134
  "typescript-eslint": "^8.45.0",
111
135
  "vite": "^7.0.0",
@@ -0,0 +1,37 @@
1
+ # Tempest App
2
+
3
+ Scaffolded with [`create-tempest-app`](https://www.npmjs.com/package/create-tempest-app) and powered by [`tempest-react-sdk`](https://www.npmjs.com/package/tempest-react-sdk).
4
+
5
+ ## Stack
6
+
7
+ - **Vite** with the `@` → `src` alias (`tempest-react-sdk/vite` → `createViteConfig`)
8
+ - **React Router v7** declarative routing (`defineRoutes` + `<AppRouter>`)
9
+ - **Zustand** state (`createAuthStore` + `createSelectors`)
10
+ - **TanStack Query** cache (mounted by `<AppProviders>`)
11
+
12
+ ## Getting started
13
+
14
+ ```bash
15
+ npm install
16
+ cp .env.example .env # adjust VITE_API_URL
17
+ npm run dev # http://127.0.0.1:5173
18
+ ```
19
+
20
+ ## Layout
21
+
22
+ ```text
23
+ src/
24
+ ├── main.tsx # mounts <App /> + SDK styles
25
+ ├── App.tsx # <AppProviders> + <AppRouter>
26
+ ├── routes.tsx # declarative route tree (lazy + guard)
27
+ ├── layouts/RootLayout.tsx
28
+ ├── pages/ # Home, Login, Dashboard (lazy + guarded)
29
+ ├── stores/auth.ts # persisted Zustand auth store
30
+ └── lib/api.ts # typed HTTP client + query keys
31
+ ```
32
+
33
+ ## Next steps
34
+
35
+ - Add a route: drop a page in `src/pages/` and an entry in `src/routes.tsx`.
36
+ - Add state: `createStore<T>()` in `src/stores/`.
37
+ - Fetch data: `useQuery({ queryKey: queryKeys.me(), queryFn: () => api.get("/me") })`.
@@ -0,0 +1,2 @@
1
+ # Base URL of your backend API (consumed by src/lib/api.ts).
2
+ VITE_API_URL=http://127.0.0.1:8000
@@ -0,0 +1,9 @@
1
+ node_modules
2
+ dist
3
+ dist-ssr
4
+ *.local
5
+ .env
6
+ .env.*
7
+ !.env.example
8
+ .DS_Store
9
+ *.log
@@ -0,0 +1,27 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import reactHooks from "eslint-plugin-react-hooks";
4
+ import reactRefresh from "eslint-plugin-react-refresh";
5
+ import tseslint from "typescript-eslint";
6
+
7
+ export default tseslint.config(
8
+ { ignores: ["dist", "node_modules"] },
9
+ {
10
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
11
+ files: ["**/*.{ts,tsx}"],
12
+ languageOptions: {
13
+ ecmaVersion: 2022,
14
+ globals: globals.browser,
15
+ },
16
+ plugins: {
17
+ "react-hooks": reactHooks,
18
+ "react-refresh": reactRefresh,
19
+ },
20
+ rules: {
21
+ ...reactHooks.configs.recommended.rules,
22
+ "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
23
+ "@typescript-eslint/consistent-type-imports": "error",
24
+ "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
25
+ },
26
+ },
27
+ );
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Tempest App</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "tempest-app",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc --noEmit && vite build",
9
+ "preview": "vite preview",
10
+ "typecheck": "tsc --noEmit",
11
+ "lint": "eslint .",
12
+ "lint:fix": "eslint . --fix"
13
+ },
14
+ "dependencies": {
15
+ "react": "^19.0.0",
16
+ "react-dom": "^19.0.0",
17
+ "tempest-react-sdk": "^0.6.0"
18
+ },
19
+ "devDependencies": {
20
+ "@eslint/js": "^9.36.0",
21
+ "@types/react": "^19.0.0",
22
+ "@types/react-dom": "^19.0.0",
23
+ "@vitejs/plugin-react": "^5.0.0",
24
+ "eslint": "^9.36.0",
25
+ "eslint-plugin-react-hooks": "^5.2.0",
26
+ "eslint-plugin-react-refresh": "^0.4.22",
27
+ "globals": "^16.0.0",
28
+ "typescript": "~5.9.0",
29
+ "typescript-eslint": "^8.45.0",
30
+ "vite": "^7.0.0"
31
+ }
32
+ }
@@ -0,0 +1,15 @@
1
+ import { AppProviders, AppRouter } from "tempest-react-sdk";
2
+ import { routes } from "@/routes";
3
+
4
+ /**
5
+ * App root. `AppProviders` composes the error boundary, TanStack Query and
6
+ * theme; `AppRouter` renders the declarative route tree with a Suspense
7
+ * fallback for lazy routes.
8
+ */
9
+ export function App() {
10
+ return (
11
+ <AppProviders errorBoundary={{ fallback: <p>Something went wrong.</p> }}>
12
+ <AppRouter routes={routes} fallback={<p>Loading…</p>} />
13
+ </AppProviders>
14
+ );
15
+ }
@@ -0,0 +1,28 @@
1
+ import { Link, Outlet } from "tempest-react-sdk";
2
+ import { useAuth } from "@/stores/auth";
3
+
4
+ /** App shell: nav bar + routed content via `<Outlet />`. */
5
+ export function RootLayout() {
6
+ const isAuthenticated = useAuth.use.isAuthenticated();
7
+ const logout = useAuth.use.logout();
8
+
9
+ return (
10
+ <div style={{ fontFamily: "system-ui, sans-serif", maxWidth: 720, margin: "0 auto", padding: 24 }}>
11
+ <header style={{ display: "flex", gap: 16, alignItems: "center", marginBottom: 24 }}>
12
+ <strong>Tempest App</strong>
13
+ <nav style={{ display: "flex", gap: 12 }}>
14
+ <Link to="/">Home</Link>
15
+ <Link to="/dashboard">Dashboard</Link>
16
+ {isAuthenticated ? (
17
+ <button onClick={logout}>Logout</button>
18
+ ) : (
19
+ <Link to="/login">Login</Link>
20
+ )}
21
+ </nav>
22
+ </header>
23
+ <main>
24
+ <Outlet />
25
+ </main>
26
+ </div>
27
+ );
28
+ }
@@ -0,0 +1,17 @@
1
+ import { createApiClient, createQueryKeys } from "tempest-react-sdk";
2
+ import { useAuth } from "@/stores/auth";
3
+
4
+ /**
5
+ * Typed HTTP client. Reads the bearer token from the auth store on every
6
+ * request and points at `VITE_API_URL`.
7
+ */
8
+ export const api = createApiClient({
9
+ baseURL: import.meta.env.VITE_API_URL ?? "http://127.0.0.1:8000",
10
+ getToken: () => useAuth.getState().token,
11
+ onUnauthorized: () => useAuth.getState().logout(),
12
+ });
13
+
14
+ /** Stable, namespaced query keys for TanStack Query. */
15
+ export const queryKeys = createQueryKeys("app", {
16
+ me: () => ["me"],
17
+ });
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import "tempest-react-sdk/styles.css";
4
+ import { App } from "@/App";
5
+
6
+ createRoot(document.getElementById("root")!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ );
@@ -0,0 +1,19 @@
1
+ import { useAuth } from "@/stores/auth";
2
+
3
+ /**
4
+ * Protected page (see the `guard` in src/routes.tsx). Lazy-loaded, so it is
5
+ * code-split into its own chunk. Default export because `lazy` expects one.
6
+ */
7
+ export default function Dashboard() {
8
+ const user = useAuth.use.user();
9
+
10
+ return (
11
+ <section>
12
+ <h1>Dashboard</h1>
13
+ <p>
14
+ Signed in as <strong>{user?.name}</strong> ({user?.email}).
15
+ </p>
16
+ <p>This route is only reachable while authenticated.</p>
17
+ </section>
18
+ );
19
+ }
@@ -0,0 +1,16 @@
1
+ export function Home() {
2
+ return (
3
+ <section>
4
+ <h1>👋 Welcome</h1>
5
+ <p>
6
+ This app is wired with <code>tempest-react-sdk</code>: Vite (<code>@</code> alias),
7
+ React Router (declarative), a Zustand auth store and TanStack Query — all from one
8
+ place.
9
+ </p>
10
+ <p>
11
+ Edit <code>src/routes.tsx</code> to add pages and <code>src/stores/</code> to add
12
+ state.
13
+ </p>
14
+ </section>
15
+ );
16
+ }
@@ -0,0 +1,27 @@
1
+ import { useNavigate } from "tempest-react-sdk";
2
+ import { useAuth } from "@/stores/auth";
3
+
4
+ /**
5
+ * Demo login: fakes a session and redirects to the (guarded) dashboard. Swap
6
+ * the fake `setSession` for a real call to `api.post("/auth/login", …)`.
7
+ */
8
+ export function Login() {
9
+ const navigate = useNavigate();
10
+ const setSession = useAuth.use.setSession();
11
+
12
+ function handleLogin() {
13
+ setSession({
14
+ user: { id: "1", name: "Ada Lovelace", email: "ada@example.com" },
15
+ token: "demo-token",
16
+ });
17
+ navigate("/dashboard");
18
+ }
19
+
20
+ return (
21
+ <section>
22
+ <h1>Login</h1>
23
+ <p>Sign in to reach the protected dashboard.</p>
24
+ <button onClick={handleLogin}>Sign in (demo)</button>
25
+ </section>
26
+ );
27
+ }
@@ -0,0 +1,27 @@
1
+ import { defineRoutes } from "tempest-react-sdk";
2
+ import { useAuth } from "@/stores/auth";
3
+ import { RootLayout } from "@/layouts/RootLayout";
4
+ import { Home } from "@/pages/Home";
5
+ import { Login } from "@/pages/Login";
6
+
7
+ /**
8
+ * Declarative route tree. `lazy` code-splits a page (with retry on stale
9
+ * chunks); `guard` redirects when the predicate is falsy — here, reading the
10
+ * auth store keeps protected pages behind login.
11
+ */
12
+ export const routes = defineRoutes([
13
+ {
14
+ path: "/",
15
+ element: <RootLayout />,
16
+ children: [
17
+ { index: true, element: <Home /> },
18
+ { path: "login", element: <Login /> },
19
+ {
20
+ path: "dashboard",
21
+ lazy: () => import("@/pages/Dashboard"),
22
+ guard: () => useAuth.getState().isAuthenticated,
23
+ redirectTo: "/login",
24
+ },
25
+ ],
26
+ },
27
+ ]);
@@ -0,0 +1,15 @@
1
+ import { createAuthStore, createSelectors } from "tempest-react-sdk";
2
+
3
+ /** The user shape your backend returns. Adjust to match your API. */
4
+ export interface User {
5
+ id: string;
6
+ name: string;
7
+ email: string;
8
+ }
9
+
10
+ /**
11
+ * App-wide auth store: persisted user + token in localStorage, with auto
12
+ * `isAuthenticated`. `createSelectors` adds `useAuth.use.<field>()` hooks that
13
+ * subscribe to a single slice.
14
+ */
15
+ export const useAuth = createSelectors(createAuthStore<User>({ name: "app-auth" }));
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "jsx": "react-jsx",
8
+ "types": ["vite/client"],
9
+ "strict": true,
10
+ "noUnusedLocals": true,
11
+ "noUnusedParameters": true,
12
+ "noFallthroughCasesInSwitch": true,
13
+ "noImplicitOverride": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "esModuleInterop": true,
16
+ "isolatedModules": true,
17
+ "verbatimModuleSyntax": true,
18
+ "skipLibCheck": true,
19
+ "resolveJsonModule": true,
20
+ "noEmit": true,
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": ["src", "vite.config.ts"]
26
+ }
@@ -0,0 +1,7 @@
1
+ import { createViteConfig } from "tempest-react-sdk/vite";
2
+
3
+ // One call wires `@vitejs/plugin-react`, the `@` → `src` alias and dev-server
4
+ // defaults. Override anything (proxy, port, build target) inline.
5
+ export default createViteConfig({
6
+ // proxy: { "/api": "http://127.0.0.1:8000" },
7
+ });