@jskit-ai/create-app 0.1.26 → 0.1.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/create-app",
3
- "version": "0.1.26",
3
+ "version": "0.1.27",
4
4
  "description": "Scaffold minimal JSKIT app shells.",
5
5
  "type": "module",
6
6
  "files": [
@@ -53,7 +53,7 @@ function buildInitialBundleCommands(initialBundles) {
53
53
 
54
54
  const commands = [];
55
55
  if (normalizedPreset === "auth") {
56
- commands.push("npx jskit add auth-base --no-install");
56
+ commands.push("npx jskit add auth-base");
57
57
  }
58
58
 
59
59
  return commands;
@@ -634,7 +634,7 @@ export async function runCli(
634
634
  } else {
635
635
  stdout.write("First of all run npm install.:\n");
636
636
  stdout.write("Then add framework capabilities:\n");
637
- stdout.write("- npx jskit add auth-base --no-install\n");
637
+ stdout.write("- npx jskit add auth-base\n");
638
638
  stdout.write("- npx jskit list\n");
639
639
  stdout.write("Run server and client to see it in action:\n");
640
640
  stdout.write("- npm run dev\n");
@@ -29,5 +29,5 @@ App configuration files:
29
29
  ## Add Capabilities
30
30
 
31
31
  ```bash
32
- npx jskit add auth-base --no-install
32
+ npx jskit add auth-base
33
33
  ```
@@ -1,54 +1,8 @@
1
- import { access, constants as fsConstants } from "node:fs/promises";
2
- import path from "node:path";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
4
-
5
- async function fileExists(absolutePath) {
6
- try {
7
- await access(absolutePath, fsConstants.F_OK);
8
- return true;
9
- } catch {
10
- return false;
11
- }
12
- }
13
-
14
- async function resolveAppRootFrom(moduleDirectory) {
15
- let currentDirectory = path.resolve(moduleDirectory);
16
-
17
- while (true) {
18
- const candidateConfigPath = path.join(currentDirectory, "config", "public.js");
19
- if (await fileExists(candidateConfigPath)) {
20
- return currentDirectory;
21
- }
22
-
23
- const parentDirectory = path.dirname(currentDirectory);
24
- if (parentDirectory === currentDirectory) {
25
- throw new Error("Unable to locate app root (missing config/public.js).");
26
- }
27
- currentDirectory = parentDirectory;
28
- }
29
- }
30
-
31
- async function loadConfigModule(absolutePath) {
32
- if (!(await fileExists(absolutePath))) {
33
- return {};
34
- }
35
-
36
- const loadedModule = await import(pathToFileURL(absolutePath).href);
37
- const loadedConfig = loadedModule?.config;
38
- return loadedConfig && typeof loadedConfig === "object" && !Array.isArray(loadedConfig) ? loadedConfig : {};
39
- }
1
+ import { loadAppConfigFromModuleUrl } from "@jskit-ai/kernel/server/support";
40
2
 
41
3
  async function loadAppConfig({ moduleUrl = import.meta.url } = {}) {
42
- const moduleDirectory = path.dirname(fileURLToPath(moduleUrl));
43
- const appRoot = await resolveAppRootFrom(moduleDirectory);
44
- const [publicConfig, serverConfig] = await Promise.all([
45
- loadConfigModule(path.join(appRoot, "config", "public.js")),
46
- loadConfigModule(path.join(appRoot, "config", "server.js"))
47
- ]);
48
-
49
- return Object.freeze({
50
- ...publicConfig,
51
- ...serverConfig
4
+ return loadAppConfigFromModuleUrl({
5
+ moduleUrl
52
6
  });
53
7
  }
54
8
 
@@ -87,8 +87,7 @@ for (const parentDirectory of parentDirectories) {
87
87
 
88
88
  const packageRoot = path.join(parentDirectory, entry.name);
89
89
  const packageJsonPath = path.join(packageRoot, "package.json");
90
- const descriptorPath = path.join(packageRoot, "package.descriptor.mjs");
91
- if (!fs.existsSync(packageJsonPath) || !fs.existsSync(descriptorPath)) {
90
+ if (!fs.existsSync(packageJsonPath)) {
92
91
  continue;
93
92
  }
94
93
 
@@ -120,6 +119,68 @@ for (const [packageDirName, packageRoot] of packageMap.entries()) {
120
119
  NODE
121
120
  }
122
121
 
122
+ link_package_bin_entries() {
123
+ local package_dir_name="$1"
124
+ local source_dir="$2"
125
+
126
+ node - "$APP_ROOT" "$package_dir_name" "$source_dir" <<'NODE'
127
+ const fs = require("node:fs");
128
+ const path = require("node:path");
129
+
130
+ const appRoot = process.argv[2];
131
+ const packageDirName = process.argv[3];
132
+ const sourceDir = process.argv[4];
133
+
134
+ const packageJsonPath = path.join(sourceDir, "package.json");
135
+ if (!fs.existsSync(packageJsonPath)) {
136
+ process.exit(0);
137
+ }
138
+
139
+ let packageJson = {};
140
+ try {
141
+ packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
142
+ } catch {
143
+ process.exit(0);
144
+ }
145
+
146
+ const rawBin = packageJson?.bin;
147
+ let binEntries = [];
148
+ if (typeof rawBin === "string") {
149
+ binEntries = [[packageDirName, rawBin]];
150
+ } else if (rawBin && typeof rawBin === "object" && !Array.isArray(rawBin)) {
151
+ binEntries = Object.entries(rawBin);
152
+ }
153
+
154
+ if (binEntries.length < 1) {
155
+ process.exit(0);
156
+ }
157
+
158
+ const binDir = path.join(appRoot, "node_modules", ".bin");
159
+ const packageRoot = path.join(appRoot, "node_modules", "@jskit-ai", packageDirName);
160
+ fs.mkdirSync(binDir, { recursive: true });
161
+
162
+ for (const [rawBinName, rawBinTarget] of binEntries) {
163
+ const binName = String(rawBinName || "").trim();
164
+ const binTarget = String(rawBinTarget || "").trim();
165
+ if (!binName || !binTarget) {
166
+ continue;
167
+ }
168
+
169
+ const absoluteTarget = path.join(packageRoot, binTarget);
170
+ if (!fs.existsSync(absoluteTarget)) {
171
+ continue;
172
+ }
173
+
174
+ const binPath = path.join(binDir, binName);
175
+ fs.rmSync(binPath, { force: true, recursive: true });
176
+
177
+ const relativeTarget = path.relative(binDir, absoluteTarget) || absoluteTarget;
178
+ fs.symlinkSync(relativeTarget, binPath);
179
+ process.stdout.write(`[link-local] linked bin ${binName} -> ${relativeTarget}\n`);
180
+ }
181
+ NODE
182
+ }
183
+
123
184
  linked_count=0
124
185
 
125
186
  mkdir -p "$SCOPE_DIR"
@@ -132,6 +193,7 @@ while IFS=$'\t' read -r package_dir_name source_dir; do
132
193
  rm -rf "$target_path"
133
194
  ln -s "$source_dir" "$target_path"
134
195
  echo "[link-local] linked @jskit-ai/$package_dir_name -> $source_dir"
196
+ link_package_bin_entries "$package_dir_name" "$source_dir"
135
197
  linked_count=$((linked_count + 1))
136
198
  done < <(discover_local_package_map)
137
199
 
@@ -113,7 +113,7 @@ if [[ "$dry_run_enabled" != "true" ]]; then
113
113
  echo "[jskit:update] generating managed migrations for changed packages."
114
114
  (
115
115
  cd "$APP_ROOT"
116
- npx jskit migrations changed --no-install
116
+ npx jskit migrations changed
117
117
  )
118
118
  fi
119
119
 
@@ -10,9 +10,11 @@ import {
10
10
  resolveRuntimeProfileFromSurface,
11
11
  tryCreateProviderRuntimeFromApp
12
12
  } from "@jskit-ai/kernel/server/platform";
13
+ import { matchesPathPrefix, normalizePathname } from "@jskit-ai/kernel/shared/surface/paths";
13
14
  import { surfaceRuntime } from "./server/lib/surfaceRuntime.js";
14
15
 
15
16
  const SPA_INDEX_FILE = "index.html";
17
+ const API_BASE_PATH = "/api";
16
18
  const STATIC_GLOBAL_UI_PATHS = Object.freeze([
17
19
  "/assets",
18
20
  "/favicon.svg",
@@ -24,19 +26,18 @@ const STATIC_GLOBAL_UI_PATHS = Object.freeze([
24
26
  function toRequestPathname(urlValue) {
25
27
  const rawUrl = String(urlValue || "").trim() || "/";
26
28
  try {
27
- return new URL(rawUrl, "http://localhost").pathname || "/";
29
+ return normalizePathname(new URL(rawUrl, "http://localhost").pathname || "/");
28
30
  } catch {
29
- return rawUrl.split("?")[0] || "/";
31
+ return normalizePathname(rawUrl.split("?")[0] || "/");
30
32
  }
31
33
  }
32
34
 
33
35
  function isApiPath(pathname) {
34
- const normalizedPathname = String(pathname || "").trim() || "/";
35
- return normalizedPathname === "/api" || normalizedPathname.startsWith("/api/");
36
+ return matchesPathPrefix(pathname, API_BASE_PATH);
36
37
  }
37
38
 
38
39
  function hasFileExtension(pathname) {
39
- return path.extname(String(pathname || "").trim()) !== "";
40
+ return path.extname(normalizePathname(pathname)) !== "";
40
41
  }
41
42
 
42
43
  function resolveGlobalUiPaths(runtimeGlobalUiPaths = []) {
@@ -48,10 +49,7 @@ function resolveGlobalUiPaths(runtimeGlobalUiPaths = []) {
48
49
  }
49
50
 
50
51
  function resolveStaticFilePath(pathname) {
51
- const normalizedPathname = String(pathname || "").trim() || "/";
52
- if (!normalizedPathname.startsWith("/")) {
53
- return "";
54
- }
52
+ const normalizedPathname = normalizePathname(pathname);
55
53
 
56
54
  const relativePath = normalizedPathname.replace(/^\/+/, "");
57
55
  if (!relativePath || relativePath.endsWith("/")) {