@everysk/apps-devkit 0.1.0-beta.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 (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/eslint/index.d.ts +20 -0
  4. package/dist/eslint/index.d.ts.map +1 -0
  5. package/dist/eslint/index.js +85 -0
  6. package/dist/eslint/index.js.map +1 -0
  7. package/dist/prettier/index.json +8 -0
  8. package/dist/vite/index.d.ts +30 -0
  9. package/dist/vite/index.d.ts.map +1 -0
  10. package/dist/vite/index.js +70 -0
  11. package/dist/vite/index.js.map +1 -0
  12. package/dist/vite/plugins/envVarsLocation.d.ts +3 -0
  13. package/dist/vite/plugins/envVarsLocation.d.ts.map +1 -0
  14. package/dist/vite/plugins/envVarsLocation.js +10 -0
  15. package/dist/vite/plugins/envVarsLocation.js.map +1 -0
  16. package/dist/vite/plugins/serveDevAppConfig.d.ts +15 -0
  17. package/dist/vite/plugins/serveDevAppConfig.d.ts.map +1 -0
  18. package/dist/vite/plugins/serveDevAppConfig.js +47 -0
  19. package/dist/vite/plugins/serveDevAppConfig.js.map +1 -0
  20. package/dist/vite/serverProxy.d.ts +16 -0
  21. package/dist/vite/serverProxy.d.ts.map +1 -0
  22. package/dist/vite/serverProxy.js +81 -0
  23. package/dist/vite/serverProxy.js.map +1 -0
  24. package/dist/vitest/index.d.ts +33 -0
  25. package/dist/vitest/index.d.ts.map +1 -0
  26. package/dist/vitest/index.js +76 -0
  27. package/dist/vitest/index.js.map +1 -0
  28. package/package.json +90 -0
  29. package/src/eslint/index.ts +90 -0
  30. package/src/prettier/index.json +8 -0
  31. package/src/vite/index.ts +82 -0
  32. package/src/vite/plugins/envVarsLocation.ts +11 -0
  33. package/src/vite/plugins/serveDevAppConfig.ts +51 -0
  34. package/src/vite/serverProxy.ts +88 -0
  35. package/src/vitest/index.ts +81 -0
  36. package/tsconfig/app.json +35 -0
  37. package/tsconfig/node.json +25 -0
  38. package/tsconfig/vitest.json +10 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Everysk Technologies
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @everysk/apps-devkit
2
+
3
+ (C) Copyright 2026 EVERYSK TECHNOLOGIES
4
+
5
+ The build configuration every Everysk app extends: Vite, ESLint, Vitest, TypeScript and
6
+ Prettier presets — and the toolchain itself. Declared as a `devDependency`.
7
+
8
+ Part of [everysk/apps-sdk](https://github.com/everysk/apps-sdk), alongside
9
+ [`@everysk/apps-sdk`](../apps-sdk) (the runtime) and [`@everysk/apps-cli`](../apps-cli) (the
10
+ `everysk-apps` bin).
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install --save-dev @everysk/apps-devkit
16
+ ```
17
+
18
+ Vite, ESLint, Vitest and Prettier are its own `dependencies`, not peers, so an app gets the
19
+ whole toolchain from this one line — and `npm ci --omit=dev` still drops every bit of it from a
20
+ deploy image. That is the boundary the package exists to draw: a required peer of a
21
+ `dependency` **is** installed under `--omit=dev`, measured, so putting the runner there would
22
+ have shipped it to production.
23
+
24
+ ## Use
25
+
26
+ Each preset takes overrides, merged with Vite's own `mergeConfig`, so an app adds to the preset
27
+ rather than replacing it.
28
+
29
+ ```ts
30
+ // vite.config.ts
31
+ import { defineAppConfig } from "@everysk/apps-devkit/vite";
32
+
33
+ export default defineAppConfig();
34
+ ```
35
+
36
+ ```ts
37
+ // vitest.config.ts
38
+ import { defineAppTestConfig } from "@everysk/apps-devkit/vitest";
39
+
40
+ export default defineAppTestConfig();
41
+ ```
42
+
43
+ ```js
44
+ // eslint.config.js
45
+ import { everyskConfig } from "@everysk/apps-devkit/eslint";
46
+
47
+ export default everyskConfig();
48
+ ```
49
+
50
+ ```jsonc
51
+ // tsconfig.app.json
52
+ {
53
+ "extends": "@everysk/apps-devkit/tsconfig",
54
+ // paths is re-declared here on purpose — see below
55
+ "compilerOptions": { "paths": { "@/*": ["./src/*"] } },
56
+ "include": ["src"]
57
+ }
58
+ ```
59
+
60
+ ```
61
+ "@everysk/apps-devkit/prettier" // .prettierrc
62
+ ```
63
+
64
+ | Subpath | |
65
+ |---|---|
66
+ | `/vite` | `defineAppConfig`, plus the dev proxy and the two config plugins on their own |
67
+ | `/vitest` | `defineAppTestConfig` |
68
+ | `/eslint` | `everyskConfig` |
69
+ | `/prettier` | the Prettier config as JSON |
70
+ | `/tsconfig`, `/tsconfig/node`, `/tsconfig/vitest` | the TypeScript bases |
71
+
72
+ ## What the presets decide
73
+
74
+ **Vite** — `base: "./"`, `envDir` at `PROJECT_ROOT` (an app builds from `apps/<name>/project`
75
+ but `.env` lives at the repository root), the `@` alias, React with the compiler, Tailwind, and
76
+ the `/api` dev proxy that authenticates with OAuth2 client credentials and refreshes the token
77
+ before it expires.
78
+
79
+ It also serves the app's `config.json` `env_vars` at `/app-config.json` in dev, read **one level
80
+ above** the Vite root. That is why an app is `<name>/{config.json, project/}`: flatten it and the
81
+ app boots with no configuration, silently.
82
+
83
+ **ESLint** — the conventions lint can actually check: no MUI barrel imports, and no direct data
84
+ access from `src/pages/**` or `src/components/**`.
85
+
86
+ **Vitest** — jsdom, `@everysk/apps-sdk/test/setup` as the setup file, a 30s timeout (Vitest's 5s
87
+ default trips MUI transition-driven tests under `--coverage`, and every app was raising it by
88
+ hand) and an 80 % coverage floor.
89
+
90
+ ## Two traps this package encodes
91
+
92
+ **`tsconfig/app.json` deliberately omits `paths`.** TypeScript resolves a config's paths relative
93
+ to the file that *declares* them, so an `@/*` mapping written here would point at this package's
94
+ own `src`. Each app re-declares it.
95
+
96
+ **Barrels are excluded from coverage at exactly one level.** The recursive form also matches every
97
+ `index.tsx`, which silently drops real components out of the report — found while building the
98
+ SDK, encoded here so no app repeats it.
99
+
100
+ ## Requirements
101
+
102
+ Node 22 or newer, npm 12 or newer.
103
+
104
+ ## License
105
+
106
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from "eslint/config";
2
+ /**
3
+ * everyskConfig
4
+ *
5
+ * The ESLint configuration every Everysk app shares, so an app's `eslint.config.js` is:
6
+ *
7
+ * ```js
8
+ * import { everyskConfig } from "@everysk/apps-devkit/eslint";
9
+ * export default everyskConfig();
10
+ * ```
11
+ *
12
+ * It encodes the conventions that lint can actually check: no MUI barrel imports, and no
13
+ * direct data access from pages or components. The rules that lint cannot express — which
14
+ * subpath to import, which provider to wire — belong to the `everysk-apps` generator.
15
+ *
16
+ * @param {ReturnType<typeof defineConfig>} [extra] - Appended after the preset, so an app can
17
+ * add or override rules for its own files.
18
+ */
19
+ export declare const everyskConfig: (extra?: ReturnType<typeof defineConfig>) => import("eslint/config").Config[];
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AAmB5D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa,GAAI,QAAO,UAAU,CAAC,OAAO,YAAY,CAAM,qCAgDnE,CAAC"}
@@ -0,0 +1,85 @@
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
+ import { defineConfig, globalIgnores } from "eslint/config";
7
+ // Barrel bans applied to every file: faster dev startup and reliable tree-shaking.
8
+ const noBarrelPaths = [
9
+ {
10
+ name: "@mui/material",
11
+ message: "Avoid the barrel. Import from the deep path, e.g. `@mui/material/Button` or `@mui/material/styles`.",
12
+ },
13
+ {
14
+ name: "@mui/icons-material",
15
+ message: "Avoid the barrel. Import the specific icon, e.g. `@mui/icons-material/Search`.",
16
+ },
17
+ ];
18
+ // Data-layer rule: pages and components reach data only through entity hooks.
19
+ const dataLayerMessage = "Data access only via entity hooks (@everysk/apps-sdk/<entity> or @/hooks/...). Pages and components must not call axios or an api module directly.";
20
+ /**
21
+ * everyskConfig
22
+ *
23
+ * The ESLint configuration every Everysk app shares, so an app's `eslint.config.js` is:
24
+ *
25
+ * ```js
26
+ * import { everyskConfig } from "@everysk/apps-devkit/eslint";
27
+ * export default everyskConfig();
28
+ * ```
29
+ *
30
+ * It encodes the conventions that lint can actually check: no MUI barrel imports, and no
31
+ * direct data access from pages or components. The rules that lint cannot express — which
32
+ * subpath to import, which provider to wire — belong to the `everysk-apps` generator.
33
+ *
34
+ * @param {ReturnType<typeof defineConfig>} [extra] - Appended after the preset, so an app can
35
+ * add or override rules for its own files.
36
+ */
37
+ export const everyskConfig = (extra = []) => defineConfig([
38
+ globalIgnores(["dist", "coverage"]),
39
+ {
40
+ files: ["**/*.{ts,tsx}"],
41
+ extends: [
42
+ js.configs.recommended,
43
+ tseslint.configs.recommended,
44
+ reactHooks.configs.flat["recommended-latest"],
45
+ reactRefresh.configs.vite,
46
+ ],
47
+ languageOptions: {
48
+ ecmaVersion: 2020,
49
+ globals: globals.browser,
50
+ },
51
+ rules: {
52
+ "@typescript-eslint/no-restricted-imports": ["error", { paths: noBarrelPaths }],
53
+ },
54
+ },
55
+ {
56
+ // A same-named rule REPLACES the base one for these files rather than merging, so
57
+ // the barrel bans are repeated here.
58
+ files: ["src/pages/**/*.{ts,tsx}", "src/components/**/*.{ts,tsx}"],
59
+ rules: {
60
+ "@typescript-eslint/no-restricted-imports": [
61
+ "error",
62
+ {
63
+ paths: [
64
+ ...noBarrelPaths,
65
+ { name: "axios", message: dataLayerMessage },
66
+ { name: "@/api", message: dataLayerMessage },
67
+ ],
68
+ patterns: [{ group: ["@/api/*"], message: dataLayerMessage }],
69
+ },
70
+ ],
71
+ },
72
+ },
73
+ {
74
+ // Tests may reach the data layer directly, to mock an api module or build axios
75
+ // stubs. Only the barrel bans remain, and the Fast Refresh rule is relaxed for
76
+ // test utilities that export helpers.
77
+ files: ["src/**/*.{test,spec}.{ts,tsx}", "src/test/**/*.{ts,tsx}"],
78
+ rules: {
79
+ "@typescript-eslint/no-restricted-imports": ["error", { paths: noBarrelPaths }],
80
+ "react-refresh/only-export-components": "off",
81
+ },
82
+ },
83
+ ...extra,
84
+ ]);
85
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,UAAU,MAAM,2BAA2B,CAAC;AACnD,OAAO,YAAY,MAAM,6BAA6B,CAAC;AACvD,OAAO,QAAQ,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE5D,mFAAmF;AACnF,MAAM,aAAa,GAAG;IAClB;QACI,IAAI,EAAE,eAAe;QACrB,OAAO,EACH,qGAAqG;KAC5G;IACD;QACI,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,gFAAgF;KAC5F;CACJ,CAAC;AAEF,8EAA8E;AAC9E,MAAM,gBAAgB,GAClB,oJAAoJ,CAAC;AAEzJ;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAyC,EAAE,EAAE,EAAE,CACzE,YAAY,CAAC;IACT,aAAa,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC;QACI,KAAK,EAAE,CAAC,eAAe,CAAC;QACxB,OAAO,EAAE;YACL,EAAE,CAAC,OAAO,CAAC,WAAW;YACtB,QAAQ,CAAC,OAAO,CAAC,WAAW;YAC5B,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC;YAC7C,YAAY,CAAC,OAAO,CAAC,IAAI;SAC5B;QACD,eAAe,EAAE;YACb,WAAW,EAAE,IAAI;YACjB,OAAO,EAAE,OAAO,CAAC,OAAO;SAC3B;QACD,KAAK,EAAE;YACH,0CAA0C,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;SAClF;KACJ;IACD;QACI,kFAAkF;QAClF,qCAAqC;QACrC,KAAK,EAAE,CAAC,yBAAyB,EAAE,8BAA8B,CAAC;QAClE,KAAK,EAAE;YACH,0CAA0C,EAAE;gBACxC,OAAO;gBACP;oBACI,KAAK,EAAE;wBACH,GAAG,aAAa;wBAChB,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE;wBAC5C,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE;qBAC/C;oBACD,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;iBAChE;aACJ;SACJ;KACJ;IACD;QACI,gFAAgF;QAChF,+EAA+E;QAC/E,sCAAsC;QACtC,KAAK,EAAE,CAAC,+BAA+B,EAAE,wBAAwB,CAAC;QAClE,KAAK,EAAE;YACH,0CAA0C,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;YAC/E,sCAAsC,EAAE,KAAK;SAChD;KACJ;IACD,GAAG,KAAK;CACX,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "trailingComma": "all",
5
+ "printWidth": 100,
6
+ "tabWidth": 4,
7
+ "endOfLine": "lf"
8
+ }
@@ -0,0 +1,30 @@
1
+ import { type UserConfig } from "vite";
2
+ export { createDevServerProxy } from "./serverProxy.js";
3
+ export { envVarsLocationPlugin } from "./plugins/envVarsLocation.js";
4
+ export { serveDevAppConfigPlugin } from "./plugins/serveDevAppConfig.js";
5
+ /**
6
+ * defineAppConfig
7
+ *
8
+ * The Vite configuration every Everysk app shares, so an app's own `vite.config.ts` is three
9
+ * lines instead of a copy that drifts:
10
+ *
11
+ * ```ts
12
+ * import { defineAppConfig } from "@everysk/apps-devkit/vite";
13
+ * export default defineAppConfig();
14
+ * ```
15
+ *
16
+ * What it sets up:
17
+ *
18
+ * - `base: "./"` and `envDir` at `PROJECT_ROOT`, because an app is built from
19
+ * `apps/<name>/project/` but its `.env` lives at the repository root.
20
+ * - The `@` alias to the app's `src/`.
21
+ * - The dev server on `PORT` (default 5173, `strictPort`), with the `/api` proxy that
22
+ * authenticates against `EVERYSK_API_URL` using OAuth2 client credentials.
23
+ * - React with the compiler preset, Tailwind, and the two plugins that carry the app's
24
+ * `config.json` `env_vars` into the page — a meta tag in build, `/app-config.json` in dev.
25
+ *
26
+ * @param {UserConfig} [overrides] - Merged over the preset with Vite's own `mergeConfig`, so
27
+ * arrays (plugins, aliases) are concatenated rather than replaced.
28
+ */
29
+ export declare const defineAppConfig: (overrides?: UserConfig) => import("vite").UserConfigFnObject;
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAU3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,eAAe,GAAI,YAAW,UAAe,sCAyCpD,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { fileURLToPath, URL } from "node:url";
2
+ import { defineConfig, loadEnv, mergeConfig } from "vite";
3
+ import react, { reactCompilerPreset } from "@vitejs/plugin-react";
4
+ import babel from "@rolldown/plugin-babel";
5
+ import tailwindcss from "@tailwindcss/vite";
6
+ import { createDevServerProxy } from "./serverProxy.js";
7
+ import { envVarsLocationPlugin } from "./plugins/envVarsLocation.js";
8
+ import { serveDevAppConfigPlugin } from "./plugins/serveDevAppConfig.js";
9
+ export { createDevServerProxy } from "./serverProxy.js";
10
+ export { envVarsLocationPlugin } from "./plugins/envVarsLocation.js";
11
+ export { serveDevAppConfigPlugin } from "./plugins/serveDevAppConfig.js";
12
+ /**
13
+ * defineAppConfig
14
+ *
15
+ * The Vite configuration every Everysk app shares, so an app's own `vite.config.ts` is three
16
+ * lines instead of a copy that drifts:
17
+ *
18
+ * ```ts
19
+ * import { defineAppConfig } from "@everysk/apps-devkit/vite";
20
+ * export default defineAppConfig();
21
+ * ```
22
+ *
23
+ * What it sets up:
24
+ *
25
+ * - `base: "./"` and `envDir` at `PROJECT_ROOT`, because an app is built from
26
+ * `apps/<name>/project/` but its `.env` lives at the repository root.
27
+ * - The `@` alias to the app's `src/`.
28
+ * - The dev server on `PORT` (default 5173, `strictPort`), with the `/api` proxy that
29
+ * authenticates against `EVERYSK_API_URL` using OAuth2 client credentials.
30
+ * - React with the compiler preset, Tailwind, and the two plugins that carry the app's
31
+ * `config.json` `env_vars` into the page — a meta tag in build, `/app-config.json` in dev.
32
+ *
33
+ * @param {UserConfig} [overrides] - Merged over the preset with Vite's own `mergeConfig`, so
34
+ * arrays (plugins, aliases) are concatenated rather than replaced.
35
+ */
36
+ export const defineAppConfig = (overrides = {}) => defineConfig(({ mode, command }) => {
37
+ // The app is built from apps/<name>/project, but .env lives at the repo root; the
38
+ // devcontainer exports PROJECT_ROOT for exactly this.
39
+ const root = process.env.PROJECT_ROOT ?? process.cwd();
40
+ const env = loadEnv(mode, root, "");
41
+ Object.assign(process.env, env);
42
+ const preset = {
43
+ base: "./",
44
+ envDir: root,
45
+ resolve: {
46
+ alias: {
47
+ "@": fileURLToPath(new URL("./src", `file://${process.cwd()}/`)),
48
+ },
49
+ },
50
+ build: {
51
+ outDir: "./dist",
52
+ emptyOutDir: true,
53
+ },
54
+ server: {
55
+ host: true,
56
+ port: Number(process.env.PORT) || 5173,
57
+ strictPort: true,
58
+ proxy: command === "serve" ? createDevServerProxy() : undefined,
59
+ },
60
+ plugins: [
61
+ react(),
62
+ babel({ presets: [reactCompilerPreset()] }),
63
+ tailwindcss(),
64
+ envVarsLocationPlugin(),
65
+ serveDevAppConfigPlugin(),
66
+ ],
67
+ };
68
+ return mergeConfig(preset, overrides);
69
+ });
70
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAmB,MAAM,MAAM,CAAC;AAE3E,OAAO,KAAK,EAAE,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,MAAM,wBAAwB,CAAC;AAC3C,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAE5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAAwB,EAAE,EAAE,EAAE,CAC1D,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IAC/B,kFAAkF;IAClF,sDAAsD;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEvD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACpC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAEhC,MAAM,MAAM,GAAe;QACvB,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,IAAI;QAEZ,OAAO,EAAE;YACL,KAAK,EAAE;gBACH,GAAG,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,UAAU,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;aACnE;SACJ;QAED,KAAK,EAAE;YACH,MAAM,EAAE,QAAQ;YAChB,WAAW,EAAE,IAAI;SACpB;QAED,MAAM,EAAE;YACJ,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI;YACtC,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,SAAS;SAClE;QAED,OAAO,EAAE;YACL,KAAK,EAAE;YACP,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,mBAAmB,EAAE,CAAC,EAAE,CAAC;YAC3C,WAAW,EAAE;YACb,qBAAqB,EAAE;YACvB,uBAAuB,EAAE;SAC5B;KACJ,CAAC;IAEF,OAAO,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from "vite";
2
+ export declare function envVarsLocationPlugin(): Plugin;
3
+ //# sourceMappingURL=envVarsLocation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envVarsLocation.d.ts","sourceRoot":"","sources":["../../../src/vite/plugins/envVarsLocation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,wBAAgB,qBAAqB,IAAI,MAAM,CAQ9C"}
@@ -0,0 +1,10 @@
1
+ export function envVarsLocationPlugin() {
2
+ return {
3
+ name: "env_vars_location",
4
+ apply: "build",
5
+ transformIndexHtml() {
6
+ return [{ tag: "meta", attrs: { name: "app-config" }, injectTo: "head" }];
7
+ },
8
+ };
9
+ }
10
+ //# sourceMappingURL=envVarsLocation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envVarsLocation.js","sourceRoot":"","sources":["../../../src/vite/plugins/envVarsLocation.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,KAAK,EAAE,OAAO;QACd,kBAAkB;YAChB,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5E,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Plugin } from "vite";
2
+ /**
3
+ * In production the platform injects `window.APP_CONFIG` from the app's `config.json` `env_vars`
4
+ * (via the `app-config` meta tag added by the build plugin). There is no platform in dev, so this
5
+ * plugin serves that same `env_vars` object at `/app-config.json`, read from the app's `config.json`
6
+ * one level up from the Vite root (apps/<name>/config.json, sibling of project/). `main.tsx` fetches
7
+ * it on bootstrap and merges it into `window.APP_CONFIG`, so dev mirrors production from a single
8
+ * source of truth — there is no separate dev config file to keep in sync.
9
+ *
10
+ * Because `config.json` lives outside the Vite root it is not watched by default, and `main.tsx`
11
+ * only reads it once at bootstrap. So we also add it to the watcher and trigger a full page reload
12
+ * on change — a full reload re-runs the bootstrap fetch, picking up edits to `env_vars` live.
13
+ */
14
+ export declare function serveDevAppConfigPlugin(): Plugin;
15
+ //# sourceMappingURL=serveDevAppConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serveDevAppConfig.d.ts","sourceRoot":"","sources":["../../../src/vite/plugins/serveDevAppConfig.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAiChD"}
@@ -0,0 +1,47 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs/promises";
3
+ /**
4
+ * In production the platform injects `window.APP_CONFIG` from the app's `config.json` `env_vars`
5
+ * (via the `app-config` meta tag added by the build plugin). There is no platform in dev, so this
6
+ * plugin serves that same `env_vars` object at `/app-config.json`, read from the app's `config.json`
7
+ * one level up from the Vite root (apps/<name>/config.json, sibling of project/). `main.tsx` fetches
8
+ * it on bootstrap and merges it into `window.APP_CONFIG`, so dev mirrors production from a single
9
+ * source of truth — there is no separate dev config file to keep in sync.
10
+ *
11
+ * Because `config.json` lives outside the Vite root it is not watched by default, and `main.tsx`
12
+ * only reads it once at bootstrap. So we also add it to the watcher and trigger a full page reload
13
+ * on change — a full reload re-runs the bootstrap fetch, picking up edits to `env_vars` live.
14
+ */
15
+ export function serveDevAppConfigPlugin() {
16
+ return {
17
+ name: "serve-dev-app-config",
18
+ apply: "serve",
19
+ configureServer(server) {
20
+ // apps/<name>/config.json — one level up from the Vite root (the app's project/ dir).
21
+ const configPath = path.resolve(process.cwd(), "..", "config.json");
22
+ server.middlewares.use(async (req, res, next) => {
23
+ if (req.url !== "/app-config.json")
24
+ return next();
25
+ try {
26
+ const content = await fs.readFile(configPath, "utf-8");
27
+ const envVars = (JSON.parse(content).env_vars ?? {});
28
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
29
+ res.statusCode = 200;
30
+ res.end(JSON.stringify(envVars));
31
+ }
32
+ catch {
33
+ res.statusCode = 404;
34
+ res.end();
35
+ }
36
+ });
37
+ // config.json is outside the Vite root, so watch it explicitly and full-reload on change.
38
+ server.watcher.add(configPath);
39
+ server.watcher.on("change", (file) => {
40
+ if (path.resolve(file) === configPath) {
41
+ server.hot.send({ type: "full-reload" });
42
+ }
43
+ });
44
+ },
45
+ };
46
+ }
47
+ //# sourceMappingURL=serveDevAppConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serveDevAppConfig.js","sourceRoot":"","sources":["../../../src/vite/plugins/serveDevAppConfig.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAIlC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,IAAI,EAAE,sBAAsB;QAC5B,KAAK,EAAE,OAAO;QACd,eAAe,CAAC,MAAM;YACpB,sFAAsF;YACtF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;YAEpE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;gBAC9C,IAAI,GAAG,CAAC,GAAG,KAAK,kBAAkB;oBAAE,OAAO,IAAI,EAAE,CAAC;gBAElD,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;oBACvD,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,IAAI,EAAE,CAA4B,CAAC;oBAEhF,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,iCAAiC,CAAC,CAAC;oBACjE,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;oBACrB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;gBACnC,CAAC;gBAAC,MAAM,CAAC;oBACP,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;oBACrB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,0FAA0F;YAC1F,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC/B,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;gBACnC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,UAAU,EAAE,CAAC;oBACtC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;gBAC3C,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { ProxyOptions } from "vite";
2
+ /**
3
+ * createDevServerProxy — Vite dev proxy for `/api`, authenticated with OAuth2 client credentials.
4
+ *
5
+ * Forwards `/api/*` to `EVERYSK_API_URL` (stripping the `/api` prefix) and injects an
6
+ * `Authorization: Bearer <access_token>` header. The token is obtained from
7
+ * `${EVERYSK_API_URL}/oauth2/token` with the `client_credentials` grant, cached in memory, and
8
+ * refreshed in the background shortly before it expires. It is fetched eagerly at startup so a
9
+ * token is ready before the first API call.
10
+ *
11
+ * @returns {Record<string, string | ProxyOptions>} The Vite `server.proxy` config for `/api`.
12
+ * @throws {Error} If `EVERYSK_API_URL`, `EVERYSK_API_CLIENT_ID`, or `EVERYSK_API_CLIENT_SECRET`
13
+ * is missing.
14
+ */
15
+ export declare function createDevServerProxy(): Record<string, string | ProxyOptions>;
16
+ //# sourceMappingURL=serverProxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serverProxy.d.ts","sourceRoot":"","sources":["../../src/vite/serverProxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAMzC;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC,CAoE5E"}
@@ -0,0 +1,81 @@
1
+ // Refresh the OAuth2 token this many ms before it actually expires, so an in-flight
2
+ // request never races a just-expired token.
3
+ const REFRESH_SKEW_MS = 60_000;
4
+ /**
5
+ * createDevServerProxy — Vite dev proxy for `/api`, authenticated with OAuth2 client credentials.
6
+ *
7
+ * Forwards `/api/*` to `EVERYSK_API_URL` (stripping the `/api` prefix) and injects an
8
+ * `Authorization: Bearer <access_token>` header. The token is obtained from
9
+ * `${EVERYSK_API_URL}/oauth2/token` with the `client_credentials` grant, cached in memory, and
10
+ * refreshed in the background shortly before it expires. It is fetched eagerly at startup so a
11
+ * token is ready before the first API call.
12
+ *
13
+ * @returns {Record<string, string | ProxyOptions>} The Vite `server.proxy` config for `/api`.
14
+ * @throws {Error} If `EVERYSK_API_URL`, `EVERYSK_API_CLIENT_ID`, or `EVERYSK_API_CLIENT_SECRET`
15
+ * is missing.
16
+ */
17
+ export function createDevServerProxy() {
18
+ const EVERYSK_API_URL = process.env.EVERYSK_API_URL;
19
+ if (!EVERYSK_API_URL)
20
+ throw new Error("EVERYSK_API_URL must be set.");
21
+ const clientId = process.env.EVERYSK_API_CLIENT_ID;
22
+ const clientSecret = process.env.EVERYSK_API_CLIENT_SECRET;
23
+ if (!clientId || !clientSecret) {
24
+ throw new Error("EVERYSK_API_CLIENT_ID and EVERYSK_API_CLIENT_SECRET must be set (OAuth2 client credentials).");
25
+ }
26
+ // Captured into an object so the narrowed `string` type survives inside the async closure below.
27
+ const credentials = { clientId, clientSecret };
28
+ const tokenUrl = `${EVERYSK_API_URL.replace(/\/$/, "")}/oauth2/token`;
29
+ let accessToken = null;
30
+ let refreshTimer = null;
31
+ /**
32
+ * refreshToken — fetch a fresh access token and schedule the next refresh before it expires.
33
+ *
34
+ * @returns {Promise<void>} Resolves once `accessToken` is updated.
35
+ * @throws {Error} If the token request fails or returns no `access_token`.
36
+ */
37
+ async function refreshToken() {
38
+ const res = await fetch(tokenUrl, {
39
+ method: "POST",
40
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
41
+ body: new URLSearchParams({
42
+ grant_type: "client_credentials",
43
+ client_id: credentials.clientId,
44
+ client_secret: credentials.clientSecret,
45
+ }),
46
+ });
47
+ if (!res.ok)
48
+ throw new Error(`OAuth2 token request failed: ${res.status} ${res.statusText}`);
49
+ const data = (await res.json());
50
+ if (!data.access_token)
51
+ throw new Error("OAuth2 token response had no access_token.");
52
+ accessToken = data.access_token;
53
+ const ttlMs = (data.expires_in ?? 3600) * 1000;
54
+ if (refreshTimer)
55
+ clearTimeout(refreshTimer);
56
+ refreshTimer = setTimeout(() => {
57
+ void refreshToken().catch((error) => console.error("[dev proxy] OAuth2 token refresh failed:", error));
58
+ }, Math.max(ttlMs - REFRESH_SKEW_MS, 30_000));
59
+ refreshTimer.unref?.();
60
+ }
61
+ // Warm the token before the first request; a failure is logged, not fatal (the request will 401).
62
+ void refreshToken().catch((error) => console.error("[dev proxy] initial OAuth2 token fetch failed:", error));
63
+ return {
64
+ "/api": {
65
+ target: EVERYSK_API_URL,
66
+ changeOrigin: true,
67
+ xfwd: true,
68
+ rewrite: (p) => p.replace(/^\/api(?=\/|$)/, ""),
69
+ configure: (proxy) => {
70
+ proxy.on("proxyReq", (proxyReq) => {
71
+ proxyReq.removeHeader("origin");
72
+ proxyReq.removeHeader("referer");
73
+ if (accessToken) {
74
+ proxyReq.setHeader("Authorization", `Bearer ${accessToken}`);
75
+ }
76
+ });
77
+ },
78
+ },
79
+ };
80
+ }
81
+ //# sourceMappingURL=serverProxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serverProxy.js","sourceRoot":"","sources":["../../src/vite/serverProxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { type ViteUserConfig } from "vitest/config";
2
+ /**
3
+ * defineAppTestConfig
4
+ *
5
+ * The Vitest configuration every Everysk app shares:
6
+ *
7
+ * ```ts
8
+ * import { defineAppTestConfig } from "@everysk/apps-devkit/vitest";
9
+ * export default defineAppTestConfig();
10
+ * ```
11
+ *
12
+ * Standalone from the Vite config on purpose — the same split the template kept. The library
13
+ * build, the dev proxy and the React Compiler pass are irrelevant to tests; all they need is
14
+ * the React transform, the `@` alias and jsdom.
15
+ *
16
+ * Notable defaults:
17
+ *
18
+ * - `setupFiles` points at `@everysk/apps-sdk/test/setup`, which installs the jsdom gaps MUI
19
+ * needs (matchMedia, ResizeObserver). It seeds no page globals: an app injects configuration
20
+ * per test with `renderWithProviders(ui, { appId, appEnvironmentVar })`.
21
+ * - `testTimeout` is 30s, not Vitest's 5s. The template's default trips MUI transition-driven
22
+ * tests under `--coverage`, and every app had to raise it by hand.
23
+ * - Coverage thresholds at 80% on all four counters, which the deploy gate enforces. `branches`
24
+ * is listed explicitly: leaving it out does not inherit the others, it leaves that counter
25
+ * unenforced, and an untested `if` is exactly what a coverage floor is there to catch. Barrels
26
+ * are excluded at
27
+ * exactly one level deep. A recursive glob would also swallow every `index.tsx` and quietly
28
+ * drop real components out of the report — which is what happened while building the SDK.
29
+ *
30
+ * @param {ViteUserConfig} [overrides] - Merged over the preset with Vite's `mergeConfig`.
31
+ */
32
+ export declare const defineAppTestConfig: (overrides?: ViteUserConfig) => ViteUserConfig;
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vitest/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAI/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,mBAAmB,GAAI,YAAW,cAAmB,mBA4CjE,CAAC"}