@jskit-ai/create-app 0.1.2 → 0.1.6

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/bin/jskit-create-app.js +2 -2
  2. package/package.json +7 -5
  3. package/src/client/index.js +1 -0
  4. package/src/index.js +1 -0
  5. package/src/{shared → server}/index.js +56 -61
  6. package/templates/base-shell/.jskit/lock.json +31 -0
  7. package/templates/base-shell/README.md +24 -20
  8. package/templates/base-shell/app.scripts.config.mjs +1 -1
  9. package/templates/base-shell/config/public.js +30 -0
  10. package/templates/base-shell/config/server.js +1 -0
  11. package/templates/base-shell/config/surfaceAccessPolicies.js +12 -0
  12. package/templates/base-shell/eslint.config.mjs +1 -1
  13. package/templates/base-shell/gitignore +2 -0
  14. package/templates/base-shell/index.html +1 -1
  15. package/templates/base-shell/jsconfig.json +8 -0
  16. package/templates/base-shell/package.json +43 -18
  17. package/templates/base-shell/packages/main/package.descriptor.mjs +55 -0
  18. package/templates/base-shell/packages/main/package.json +12 -0
  19. package/templates/base-shell/packages/main/src/client/index.js +13 -0
  20. package/templates/base-shell/packages/main/src/client/providers/MainClientProvider.js +33 -0
  21. package/templates/base-shell/packages/main/src/server/controllers/index.js +9 -0
  22. package/templates/base-shell/packages/main/src/server/index.js +1 -0
  23. package/templates/base-shell/packages/main/src/server/providers/MainServiceProvider.js +22 -0
  24. package/templates/base-shell/packages/main/src/server/routes/index.js +9 -0
  25. package/templates/base-shell/packages/main/src/server/services/index.js +9 -0
  26. package/templates/base-shell/packages/main/src/server/support/loadAppConfig.js +55 -0
  27. package/templates/base-shell/packages/main/src/shared/index.js +8 -0
  28. package/templates/base-shell/packages/main/src/shared/schemas/index.js +20 -0
  29. package/templates/base-shell/scripts/dev-bootstrap-jskit.sh +110 -0
  30. package/templates/base-shell/scripts/just_run_verde +37 -0
  31. package/templates/base-shell/scripts/link-local-jskit-packages.sh +90 -0
  32. package/templates/base-shell/scripts/update-jskit-packages.sh +73 -0
  33. package/templates/base-shell/scripts/verdaccio/config.yaml +26 -0
  34. package/templates/base-shell/scripts/verdaccio-reset-and-publish-packages.sh +314 -0
  35. package/templates/base-shell/server/lib/runtimeEnv.js +29 -0
  36. package/templates/base-shell/server/lib/surfaceRuntime.js +10 -0
  37. package/templates/base-shell/server.js +39 -68
  38. package/templates/base-shell/src/App.vue +11 -22
  39. package/templates/base-shell/src/main.js +87 -1
  40. package/templates/base-shell/src/pages/console/index.vue +12 -0
  41. package/templates/base-shell/src/pages/console.vue +13 -0
  42. package/templates/base-shell/src/pages/home/index.vue +12 -0
  43. package/templates/base-shell/src/pages/home.vue +13 -0
  44. package/templates/base-shell/src/views/NotFound.vue +13 -0
  45. package/templates/base-shell/tests/server/{minimalShell.contract.test.js → minimalShell.validator.test.js} +44 -6
  46. package/templates/base-shell/tests/server/smoke.test.js +3 -6
  47. package/templates/base-shell/vite.config.mjs +24 -3
  48. package/templates/base-shell/vite.shared.mjs +51 -1
  49. package/README.md +0 -24
  50. package/templates/base-shell/package.json.ACTUAL_CORRECT +0 -38
  51. /package/src/{shared → server}/cliEntrypoint.js +0 -0
@@ -9,17 +9,22 @@ const __dirname = path.dirname(__filename);
9
9
  const APP_ROOT = path.resolve(__dirname, "../..");
10
10
 
11
11
  const EXPECTED_RUNTIME_DEPENDENCIES = Object.freeze([
12
- "@jskit-ai/app-scripts",
13
- "@jskit-ai/server-runtime-core",
12
+ "@fastify/type-provider-typebox",
13
+ "@jskit-ai/http-runtime",
14
+ "@jskit-ai/kernel",
15
+ "@local/main",
14
16
  "fastify",
15
- "vue"
17
+ "vue",
18
+ "vue-router",
19
+ "vuetify"
16
20
  ]);
17
21
 
18
22
  const EXPECTED_DEV_DEPENDENCIES = Object.freeze([
19
23
  "@jskit-ai/config-eslint",
20
- "@jskit-ai/jskit",
24
+ "@jskit-ai/jskit-cli",
21
25
  "@vitejs/plugin-vue",
22
26
  "eslint",
27
+ "unplugin-vue-router",
23
28
  "vite",
24
29
  "vitest"
25
30
  ]);
@@ -29,13 +34,15 @@ const EXPECTED_TOP_LEVEL_ENTRIES = Object.freeze([
29
34
  "README.md",
30
35
  "app.scripts.config.mjs",
31
36
  "bin",
37
+ "config",
32
38
  "eslint.config.mjs",
33
39
  "favicon.svg",
34
- "gitignore",
35
40
  "index.html",
41
+ "jsconfig.json",
36
42
  "package.json",
37
- "package.json.ACTUAL_CORRECT",
43
+ "packages",
38
44
  "server.js",
45
+ "scripts",
39
46
  "server",
40
47
  "src",
41
48
  "tests",
@@ -74,6 +81,20 @@ async function readTopLevelEntries() {
74
81
  .filter((name) => !ignored.has(name));
75
82
  }
76
83
 
84
+ async function listFilesRecursive(directory) {
85
+ const entries = await readdir(directory, { withFileTypes: true });
86
+ const files = [];
87
+ for (const entry of entries) {
88
+ const absolutePath = path.join(directory, entry.name);
89
+ if (entry.isDirectory()) {
90
+ files.push(...(await listFilesRecursive(absolutePath)));
91
+ continue;
92
+ }
93
+ files.push(absolutePath);
94
+ }
95
+ return files;
96
+ }
97
+
77
98
  test("minimal shell keeps strict dependency allowlist", async () => {
78
99
  const packageJson = await readPackageJson();
79
100
  assert.deepEqual(
@@ -94,3 +115,20 @@ test("starter shell keeps a strict top-level footprint", async () => {
94
115
  test("legacy app.manifest scaffold is removed from starter shell", async () => {
95
116
  await assert.rejects(access(path.join(APP_ROOT, "framework/app.manifest.mjs")), /ENOENT/);
96
117
  });
118
+
119
+ test("local package source avoids brittle deep relative imports", async () => {
120
+ const packageSourceFiles = await listFilesRecursive(path.join(APP_ROOT, "packages"));
121
+ const brittleImportPattern = /\bfrom\s+["'](?:\.\.\/){5,}[^"']+["']/;
122
+
123
+ for (const filePath of packageSourceFiles) {
124
+ if (!filePath.endsWith(".js") && !filePath.endsWith(".mjs")) {
125
+ continue;
126
+ }
127
+ const source = await readFile(filePath, "utf8");
128
+ assert.equal(
129
+ brittleImportPattern.test(source),
130
+ false,
131
+ `Found brittle deep relative import in ${path.relative(APP_ROOT, filePath)}`
132
+ );
133
+ }
134
+ });
@@ -2,18 +2,15 @@ import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
3
  import { createServer } from "../../server.js";
4
4
 
5
- test("GET /api/v1/health returns ok payload", async () => {
5
+ test("GET /api/health returns built-in health response", async () => {
6
6
  const app = await createServer();
7
7
  const response = await app.inject({
8
8
  method: "GET",
9
- url: "/api/v1/health"
9
+ url: "/api/health"
10
10
  });
11
11
 
12
12
  assert.equal(response.statusCode, 200);
13
- assert.deepEqual(response.json(), {
14
- ok: true,
15
- app: "__APP_NAME__"
16
- });
13
+ assert.equal(response.json().ok, true);
17
14
 
18
15
  await app.close();
19
16
  });
@@ -1,9 +1,16 @@
1
+ import { fileURLToPath, URL } from "node:url";
1
2
  import { defineConfig } from "vite";
2
3
  import vue from "@vitejs/plugin-vue";
3
- import { toPositiveInt } from "./vite.shared.mjs";
4
+ import VueRouter from "unplugin-vue-router/vite";
5
+ import { createJskitClientBootstrapPlugin } from "@jskit-ai/kernel/client/vite";
6
+ import { loadViteDevProxyEntries, toPositiveInt } from "./vite.shared.mjs";
4
7
 
5
8
  const devPort = toPositiveInt(process.env.VITE_DEV_PORT, 5173);
6
9
  const apiProxyTarget = String(process.env.VITE_API_PROXY_TARGET || "").trim() || "http://localhost:3000";
10
+ const viteModuleProxyEntries = loadViteDevProxyEntries({
11
+ appRootUrl: import.meta.url,
12
+ fallbackTarget: apiProxyTarget
13
+ });
7
14
  const clientEntry = (() => {
8
15
  const normalized = String(process.env.VITE_CLIENT_ENTRY || "").trim();
9
16
  if (!normalized) {
@@ -19,12 +26,25 @@ const clientEntry = (() => {
19
26
  })();
20
27
 
21
28
  export default defineConfig({
29
+ resolve: {
30
+ preserveSymlinks: true,
31
+ alias: {
32
+ "@": fileURLToPath(new URL("./src", import.meta.url))
33
+ }
34
+ },
22
35
  plugins: [
36
+ createJskitClientBootstrapPlugin(),
37
+ VueRouter({
38
+ routesFolder: "src/pages",
39
+ dts: "src/typed-router.d.ts"
40
+ }),
23
41
  vue(),
24
42
  {
25
43
  name: "jskit-client-entry",
26
44
  transformIndexHtml(source) {
27
- return String(source || "").replace(/\/src\/main\.js/g, clientEntry);
45
+ return String(source || "")
46
+ .replace(/\/src\/%VITE_CLIENT_ENTRY%/g, clientEntry)
47
+ .replace(/\/src\/main\.js/g, clientEntry);
28
48
  }
29
49
  }
30
50
  ],
@@ -37,7 +57,8 @@ export default defineConfig({
37
57
  "/api": {
38
58
  target: apiProxyTarget,
39
59
  changeOrigin: true
40
- }
60
+ },
61
+ ...viteModuleProxyEntries
41
62
  }
42
63
  }
43
64
  });
@@ -1,3 +1,9 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const VITE_DEV_PROXY_CONFIG_RELATIVE_PATH = ".jskit/vite.dev.proxy.json";
6
+
1
7
  function toPositiveInt(value, fallback) {
2
8
  const parsed = Number.parseInt(String(value || "").trim(), 10);
3
9
  if (Number.isInteger(parsed) && parsed > 0) {
@@ -6,4 +12,48 @@ function toPositiveInt(value, fallback) {
6
12
  return fallback;
7
13
  }
8
14
 
9
- export { toPositiveInt };
15
+ function loadViteDevProxyEntries({ appRootUrl = import.meta.url, fallbackTarget = "" } = {}) {
16
+ const appRootPath = fileURLToPath(new URL(".", appRootUrl));
17
+ const absoluteConfigPath = path.join(appRootPath, VITE_DEV_PROXY_CONFIG_RELATIVE_PATH);
18
+ if (!existsSync(absoluteConfigPath)) {
19
+ return Object.freeze({});
20
+ }
21
+
22
+ let source = {};
23
+ try {
24
+ source = JSON.parse(readFileSync(absoluteConfigPath, "utf8"));
25
+ } catch {
26
+ return Object.freeze({});
27
+ }
28
+
29
+ const entries = Array.isArray(source?.entries) ? source.entries : [];
30
+ const proxy = {};
31
+ for (const entry of entries) {
32
+ const record = entry && typeof entry === "object" && !Array.isArray(entry) ? entry : {};
33
+ const routePath = String(record.path || "").trim();
34
+ if (!routePath || !routePath.startsWith("/")) {
35
+ continue;
36
+ }
37
+
38
+ const target = String(record.target || "").trim() || String(fallbackTarget || "").trim();
39
+ if (!target) {
40
+ continue;
41
+ }
42
+
43
+ const proxyConfig = {
44
+ target
45
+ };
46
+ if (Object.hasOwn(record, "changeOrigin")) {
47
+ proxyConfig.changeOrigin = record.changeOrigin === true;
48
+ }
49
+ if (Object.hasOwn(record, "ws")) {
50
+ proxyConfig.ws = record.ws === true;
51
+ }
52
+
53
+ proxy[routePath] = proxyConfig;
54
+ }
55
+
56
+ return Object.freeze(proxy);
57
+ }
58
+
59
+ export { toPositiveInt, loadViteDevProxyEntries };
package/README.md DELETED
@@ -1,24 +0,0 @@
1
- # @jskit-ai/create-app
2
-
3
- Scaffold a minimal JSKIT app shell from in-repo templates.
4
-
5
- ## Usage
6
-
7
- ```bash
8
- jskit-create-app my-app
9
- ```
10
-
11
- ```bash
12
- jskit-create-app --interactive
13
- ```
14
-
15
- ## Options
16
-
17
- - `--template <name>` template name under `templates/` (default `base-shell`)
18
- - `--title <text>` override the generated app title placeholder
19
- - `--target <path>` output directory (default `./<app-name>`)
20
- - `--initial-bundles <preset>` optional framework preset: `none`, `db`, or `db-auth`
21
- - `--db-provider <provider>` provider for `db` presets: `mysql` or `postgres`
22
- - `--force` allow writes into non-empty target directories
23
- - `--dry-run` preview writes only
24
- - `--interactive` prompt for app values
@@ -1,38 +0,0 @@
1
- {
2
- "name": "__APP_NAME__",
3
- "version": "0.1.0",
4
- "private": true,
5
- "type": "module",
6
- "description": "Minimal JSKIT base app (Fastify + Vue)",
7
- "engines": {
8
- "node": "20.x"
9
- },
10
- "bin": {
11
- "jskit": "node_modules/@jskit-ai/jskit/packages/tooling/jskit/bin/jskit.js"
12
- },
13
- "scripts": {
14
- "server": "jskit-app-scripts server",
15
- "start": "jskit-app-scripts start",
16
- "dev": "jskit-app-scripts dev",
17
- "build": "jskit-app-scripts build",
18
- "preview": "jskit-app-scripts preview",
19
- "lint": "jskit-app-scripts lint",
20
- "lint:process-env": "jskit-app-scripts lint:process-env",
21
- "test": "jskit-app-scripts test",
22
- "test:client": "jskit-app-scripts test:client"
23
- },
24
- "dependencies": {
25
- "@jskit-ai/app-scripts": "0.1.0",
26
- "@jskit-ai/server-runtime-core": "file:node_modules/@jskit-ai/jskit/packages/runtime/server-runtime-core",
27
- "fastify": "^5.7.4",
28
- "vue": "^3.5.13"
29
- },
30
- "devDependencies": {
31
- "@jskit-ai/config-eslint": "0.1.0",
32
- "@jskit-ai/jskit": "github:mobily-enterprises/jskit-ai",
33
- "@vitejs/plugin-vue": "^5.2.1",
34
- "eslint": "^9.39.1",
35
- "vite": "^6.1.0",
36
- "vitest": "^4.0.18"
37
- }
38
- }
File without changes