@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 +1 -1
- package/src/server/index.js +2 -2
- package/templates/base-shell/README.md +1 -1
- package/templates/base-shell/packages/main/src/server/support/loadAppConfig.js +3 -49
- package/templates/base-shell/scripts/link-local-jskit-packages.sh +64 -2
- package/templates/base-shell/scripts/update-jskit-packages.sh +1 -1
- package/templates/base-shell/server.js +7 -9
package/package.json
CHANGED
package/src/server/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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");
|
|
@@ -1,54 +1,8 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
|
|
@@ -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
|
-
|
|
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(
|
|
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 =
|
|
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("/")) {
|