@kmlckj/licos-ai-cli 1.0.16 → 1.0.19

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.
@@ -42,15 +42,17 @@ info "==================== 依赖安装完成!====================\n"
42
42
  info "==================== dist打包 ===================="
43
43
  info "开始执行:expo export --platform web (client)"
44
44
  rm -rf "$ROOT_DIR/server/public"
45
- (pushd "$ROOT_DIR/client" > /dev/null && pnpm expo export --platform web --output-dir ../server/public; popd > /dev/null) || error "client web 打包失败"
46
-
47
45
  BASE_URL="${BASE_PATH:-/}"
48
46
  if [ "${BASE_URL}" != "/" ]; then
49
- BASE_URL="/$(printf '%s' "${BASE_URL}" | sed 's#^/*##; s#/*$##')/"
47
+ BASE_URL="/$(printf '%s' "${BASE_URL}" | sed 's#^/*##; s#/*$##')"
48
+ fi
49
+ if [ "${BASE_URL}" != "/" ]; then
50
+ info "使用 Expo Web baseUrl:${BASE_URL}"
50
51
  fi
52
+ (pushd "$ROOT_DIR/client" > /dev/null && BASE_PATH="${BASE_PATH:-}" pnpm expo export --platform web --output-dir ../server/public; popd > /dev/null) || error "client web 打包失败"
51
53
  if [ "${BASE_URL}" != "/" ]; then
52
- info "重写 Expo Web 静态资源前缀:${BASE_URL}"
53
- BASE_URL="${BASE_URL}" python3 - <<'PY'
54
+ info "校正 Expo Web 静态资源前缀:${BASE_URL}/"
55
+ BASE_URL="${BASE_URL}/" python3 - <<'PY'
54
56
  import os
55
57
  from pathlib import Path
56
58
 
@@ -1,76 +1,87 @@
1
- import { ExpoConfig, ConfigContext } from 'expo/config';
2
-
3
- const appName = process.env.LICOS_PROJECT_NAME || process.env.EXPO_PUBLIC_LICOS_PROJECT_NAME || '应用';
4
- const projectId = process.env.LICOS_PROJECT_ID || process.env.EXPO_PUBLIC_LICOS_PROJECT_ID;
5
- const slugAppName = projectId ? `app${projectId}` : 'myapp';
6
-
7
- export default ({ config }: ConfigContext): ExpoConfig => {
8
- return {
9
- ...config,
10
- "name": appName,
11
- "slug": slugAppName,
12
- "version": "1.0.0",
13
- "orientation": "portrait",
14
- "icon": "./assets/images/icon.png",
15
- "scheme": "myapp",
16
- "userInterfaceStyle": "automatic",
17
- "newArchEnabled": true,
18
- "ios": {
19
- "supportsTablet": true
20
- },
21
- "android": {
22
- "adaptiveIcon": {
23
- "foregroundImage": "./assets/images/adaptive-icon.png",
24
- "backgroundColor": "#ffffff"
25
- },
26
- "package": `com.anonymous.x${projectId || '0'}`
27
- },
28
- "web": {
29
- "bundler": "metro",
30
- "output": "single",
31
- "favicon": "./assets/images/favicon.png"
32
- },
33
- "plugins": [
34
- process.env.EXPO_PUBLIC_BACKEND_BASE_URL ? [
35
- "expo-router",
36
- {
37
- "origin": process.env.EXPO_PUBLIC_BACKEND_BASE_URL
38
- }
39
- ] : 'expo-router',
40
- [
41
- "expo-splash-screen",
42
- {
43
- "image": "./assets/images/splash-icon.png",
44
- "imageWidth": 200,
45
- "resizeMode": "contain",
46
- "backgroundColor": "#ffffff"
47
- }
48
- ],
49
- [
50
- "expo-image-picker",
51
- {
52
- "photosPermission": `允许${appName}访问您的相册,以便您上传或保存图片。`,
53
- "cameraPermission": `允许${appName}使用您的相机,以便您直接拍摄照片上传。`,
54
- "microphonePermission": `允许${appName}访问您的麦克风,以便您拍摄带有声音的视频。`
55
- }
56
- ],
57
- [
58
- "expo-location",
59
- {
60
- "locationWhenInUsePermission": `${appName}需要访问您的位置以提供周边服务及导航功能。`
61
- }
62
- ],
63
- [
64
- "expo-camera",
65
- {
66
- "cameraPermission": `${appName}需要访问相机以拍摄照片和视频。`,
67
- "microphonePermission": `${appName}需要访问麦克风以录制视频声音。`,
68
- "recordAudioAndroid": true
69
- }
70
- ]
71
- ],
72
- "experiments": {
73
- "typedRoutes": true
74
- }
75
- }
76
- }
1
+ import { ExpoConfig, ConfigContext } from 'expo/config';
2
+
3
+ const appName = process.env.LICOS_PROJECT_NAME || process.env.EXPO_PUBLIC_LICOS_PROJECT_NAME || '应用';
4
+ const projectId = process.env.LICOS_PROJECT_ID || process.env.EXPO_PUBLIC_LICOS_PROJECT_ID;
5
+ const slugAppName = projectId ? `app${projectId}` : 'myapp';
6
+
7
+ const normalizeBaseUrl = (value?: string) => {
8
+ const trimmed = value?.trim();
9
+ if (!trimmed || trimmed === '/') {
10
+ return undefined;
11
+ }
12
+ return `/${trimmed.replace(/^\/+|\/+$/g, '')}`;
13
+ };
14
+
15
+ const baseUrl = normalizeBaseUrl(process.env.BASE_PATH || process.env.EXPO_PUBLIC_BASE_PATH);
16
+
17
+ export default ({ config }: ConfigContext): ExpoConfig => {
18
+ return {
19
+ ...config,
20
+ "name": appName,
21
+ "slug": slugAppName,
22
+ "version": "1.0.0",
23
+ "orientation": "portrait",
24
+ "icon": "./assets/images/icon.png",
25
+ "scheme": "myapp",
26
+ "userInterfaceStyle": "automatic",
27
+ "newArchEnabled": true,
28
+ "ios": {
29
+ "supportsTablet": true
30
+ },
31
+ "android": {
32
+ "adaptiveIcon": {
33
+ "foregroundImage": "./assets/images/adaptive-icon.png",
34
+ "backgroundColor": "#ffffff"
35
+ },
36
+ "package": `com.anonymous.x${projectId || '0'}`
37
+ },
38
+ "web": {
39
+ "bundler": "metro",
40
+ "output": "single",
41
+ "favicon": "./assets/images/favicon.png"
42
+ },
43
+ "plugins": [
44
+ process.env.EXPO_PUBLIC_BACKEND_BASE_URL ? [
45
+ "expo-router",
46
+ {
47
+ "origin": process.env.EXPO_PUBLIC_BACKEND_BASE_URL
48
+ }
49
+ ] : 'expo-router',
50
+ [
51
+ "expo-splash-screen",
52
+ {
53
+ "image": "./assets/images/splash-icon.png",
54
+ "imageWidth": 200,
55
+ "resizeMode": "contain",
56
+ "backgroundColor": "#ffffff"
57
+ }
58
+ ],
59
+ [
60
+ "expo-image-picker",
61
+ {
62
+ "photosPermission": `允许${appName}访问您的相册,以便您上传或保存图片。`,
63
+ "cameraPermission": `允许${appName}使用您的相机,以便您直接拍摄照片上传。`,
64
+ "microphonePermission": `允许${appName}访问您的麦克风,以便您拍摄带有声音的视频。`
65
+ }
66
+ ],
67
+ [
68
+ "expo-location",
69
+ {
70
+ "locationWhenInUsePermission": `${appName}需要访问您的位置以提供周边服务及导航功能。`
71
+ }
72
+ ],
73
+ [
74
+ "expo-camera",
75
+ {
76
+ "cameraPermission": `${appName}需要访问相机以拍摄照片和视频。`,
77
+ "microphonePermission": `${appName}需要访问麦克风以录制视频声音。`,
78
+ "recordAudioAndroid": true
79
+ }
80
+ ]
81
+ ],
82
+ "experiments": {
83
+ "typedRoutes": true,
84
+ ...(baseUrl ? { "baseUrl": baseUrl } : {})
85
+ }
86
+ }
87
+ }
@@ -1,35 +1,35 @@
1
- import type { NextConfig } from 'next';
2
-
3
- function normalizeBasePath(value?: string): string | undefined {
4
- const trimmed = value?.trim();
5
- if (!trimmed || trimmed === '/') return undefined;
6
- return `/${trimmed.replace(/^\/+|\/+$/g, '')}`;
7
- }
8
-
9
- function isProdProjectEnv(value?: string): boolean {
10
- const normalized = value?.trim().toLowerCase();
11
- return normalized === 'prod' || normalized === 'production' || normalized === 'release';
12
- }
13
-
14
- const deployBasePath = process.env.BASE_PATH;
15
- const shouldUseBasePath = Boolean(deployBasePath) || isProdProjectEnv(process.env.LICOS_PROJECT_ENV);
16
-
17
- const basePath = shouldUseBasePath ? normalizeBasePath(deployBasePath) : undefined;
18
-
19
- const nextConfig: NextConfig = {
20
- ...(basePath ? { basePath } : {}),
21
- // outputFileTracingRoot: path.resolve(__dirname, '../../'), // Uncomment and add 'import path from "path"' if needed
22
- /* config options here */
23
- allowedDevOrigins: ['*.dev.licos.local'],
24
- images: {
25
- remotePatterns: [
26
- {
27
- protocol: 'https',
28
- hostname: '*',
29
- pathname: '/**',
30
- },
31
- ],
32
- },
33
- };
34
-
35
- export default nextConfig;
1
+ import type { NextConfig } from 'next';
2
+
3
+ function normalizeBasePath(value?: string): string | undefined {
4
+ const trimmed = value?.trim();
5
+ if (!trimmed || trimmed === '/') return undefined;
6
+ return `/${trimmed.replace(/^\/+|\/+$/g, '')}`;
7
+ }
8
+
9
+ function isProdProjectEnv(value?: string): boolean {
10
+ const normalized = value?.trim().toLowerCase();
11
+ return normalized === 'prod' || normalized === 'production' || normalized === 'release';
12
+ }
13
+
14
+ const deployBasePath = process.env.BASE_PATH;
15
+ const shouldUseBasePath = isProdProjectEnv(process.env.LICOS_PROJECT_ENV) && Boolean(deployBasePath);
16
+
17
+ const basePath = shouldUseBasePath ? normalizeBasePath(deployBasePath) : undefined;
18
+
19
+ const nextConfig: NextConfig = {
20
+ ...(basePath ? { basePath } : {}),
21
+ // outputFileTracingRoot: path.resolve(__dirname, '../../'), // Uncomment and add 'import path from "path"' if needed
22
+ /* config options here */
23
+ allowedDevOrigins: ['*.dev.licos.local'],
24
+ images: {
25
+ remotePatterns: [
26
+ {
27
+ protocol: 'https',
28
+ hostname: '*',
29
+ pathname: '/**',
30
+ },
31
+ ],
32
+ },
33
+ };
34
+
35
+ export default nextConfig;
@@ -1,129 +1,129 @@
1
- import { createServer, type ServerResponse } from 'http';
2
- import { createReadStream, existsSync, statSync } from 'fs';
3
- import { extname, resolve, sep } from 'path';
4
- import { parse } from 'url';
5
- import next from 'next';
6
-
7
- function isProdProjectEnv(value?: string): boolean {
8
- const normalized = value?.trim().toLowerCase();
9
- return normalized === 'prod' || normalized === 'production' || normalized === 'release';
10
- }
11
-
12
- const dev = !isProdProjectEnv(process.env.LICOS_PROJECT_ENV);
13
- const hostname = process.env.HOSTNAME || 'localhost';
14
- const port = parseInt(process.env.PORT || '<%= port %>', 10);
15
- const projectAssetsDir = resolve(process.cwd(), 'assets');
16
-
17
- function normalizeBasePath(value?: string): string | undefined {
18
- const trimmed = value?.trim();
19
- if (!trimmed || trimmed === '/') return undefined;
20
- return `/${trimmed.replace(/^\/+|\/+$/g, '')}`;
21
- }
22
-
23
- const basePath = normalizeBasePath(process.env.BASE_PATH);
24
-
25
- function getContentType(filePath: string): string {
26
- const ext = extname(filePath).toLowerCase();
27
- const types: Record<string, string> = {
28
- '.avif': 'image/avif',
29
- '.css': 'text/css; charset=utf-8',
30
- '.gif': 'image/gif',
31
- '.html': 'text/html; charset=utf-8',
32
- '.ico': 'image/x-icon',
33
- '.jpg': 'image/jpeg',
34
- '.jpeg': 'image/jpeg',
35
- '.js': 'text/javascript; charset=utf-8',
36
- '.json': 'application/json; charset=utf-8',
37
- '.map': 'application/json; charset=utf-8',
38
- '.mp3': 'audio/mpeg',
39
- '.mp4': 'video/mp4',
40
- '.otf': 'font/otf',
41
- '.png': 'image/png',
42
- '.svg': 'image/svg+xml',
43
- '.ttf': 'font/ttf',
44
- '.txt': 'text/plain; charset=utf-8',
45
- '.wasm': 'application/wasm',
46
- '.webm': 'video/webm',
47
- '.webp': 'image/webp',
48
- '.woff': 'font/woff',
49
- '.woff2': 'font/woff2',
50
- '.xml': 'application/xml; charset=utf-8',
51
- };
52
- return types[ext] || 'application/octet-stream';
53
- }
54
-
55
- function normalizeAssetPath(pathname: string): string | null {
56
- if (pathname.startsWith('/assets/')) {
57
- return pathname;
58
- }
59
- if (basePath && pathname.startsWith(`${basePath}/assets/`)) {
60
- return pathname.slice(basePath.length);
61
- }
62
- return null;
63
- }
64
-
65
- function serveProjectAsset(pathname: string, res: ServerResponse): boolean {
66
- const assetPath = normalizeAssetPath(pathname);
67
- if (!assetPath || !existsSync(projectAssetsDir)) {
68
- return false;
69
- }
70
-
71
- let decodedPath: string;
72
- try {
73
- decodedPath = decodeURIComponent(assetPath.replace(/^\/assets\/+/, ''));
74
- } catch {
75
- return false;
76
- }
77
-
78
- const filePath = resolve(projectAssetsDir, decodedPath);
79
- if (filePath !== projectAssetsDir && !filePath.startsWith(`${projectAssetsDir}${sep}`)) {
80
- res.statusCode = 403;
81
- res.end('Forbidden');
82
- return true;
83
- }
84
-
85
- try {
86
- const stat = statSync(filePath);
87
- if (!stat.isFile()) {
88
- return false;
89
- }
90
- res.statusCode = 200;
91
- res.setHeader('Content-Type', getContentType(filePath));
92
- res.setHeader('Content-Length', stat.size);
93
- createReadStream(filePath).pipe(res);
94
- return true;
95
- } catch {
96
- return false;
97
- }
98
- }
99
-
100
- // Create Next.js app
101
- const app = next({ dev, hostname, port });
102
- const handle = app.getRequestHandler();
103
-
104
- app.prepare().then(() => {
105
- const server = createServer(async (req, res) => {
106
- try {
107
- const parsedUrl = parse(req.url!, true);
108
- if (serveProjectAsset(parsedUrl.pathname || '', res)) {
109
- return;
110
- }
111
- await handle(req, res, parsedUrl);
112
- } catch (err) {
113
- console.error('Error occurred handling', req.url, err);
114
- res.statusCode = 500;
115
- res.end('Internal server error');
116
- }
117
- });
118
- server.once('error', err => {
119
- console.error(err);
120
- process.exit(1);
121
- });
122
- server.listen(port, () => {
123
- console.log(
124
- `> Server listening at http://${hostname}:${port} as ${
125
- dev ? 'development' : process.env.LICOS_PROJECT_ENV
126
- }`,
127
- );
128
- });
129
- });
1
+ import { createServer, type ServerResponse } from 'http';
2
+ import { createReadStream, existsSync, statSync } from 'fs';
3
+ import { extname, resolve, sep } from 'path';
4
+ import { parse } from 'url';
5
+ import next from 'next';
6
+
7
+ function isProdProjectEnv(value?: string): boolean {
8
+ const normalized = value?.trim().toLowerCase();
9
+ return normalized === 'prod' || normalized === 'production' || normalized === 'release';
10
+ }
11
+
12
+ const dev = !isProdProjectEnv(process.env.LICOS_PROJECT_ENV);
13
+ const hostname = process.env.HOSTNAME || 'localhost';
14
+ const port = parseInt(process.env.PORT || '<%= port %>', 10);
15
+ const projectAssetsDir = resolve(process.cwd(), 'assets');
16
+
17
+ function normalizeBasePath(value?: string): string | undefined {
18
+ const trimmed = value?.trim();
19
+ if (!trimmed || trimmed === '/') return undefined;
20
+ return `/${trimmed.replace(/^\/+|\/+$/g, '')}`;
21
+ }
22
+
23
+ const basePath = dev ? undefined : normalizeBasePath(process.env.BASE_PATH);
24
+
25
+ function getContentType(filePath: string): string {
26
+ const ext = extname(filePath).toLowerCase();
27
+ const types: Record<string, string> = {
28
+ '.avif': 'image/avif',
29
+ '.css': 'text/css; charset=utf-8',
30
+ '.gif': 'image/gif',
31
+ '.html': 'text/html; charset=utf-8',
32
+ '.ico': 'image/x-icon',
33
+ '.jpg': 'image/jpeg',
34
+ '.jpeg': 'image/jpeg',
35
+ '.js': 'text/javascript; charset=utf-8',
36
+ '.json': 'application/json; charset=utf-8',
37
+ '.map': 'application/json; charset=utf-8',
38
+ '.mp3': 'audio/mpeg',
39
+ '.mp4': 'video/mp4',
40
+ '.otf': 'font/otf',
41
+ '.png': 'image/png',
42
+ '.svg': 'image/svg+xml',
43
+ '.ttf': 'font/ttf',
44
+ '.txt': 'text/plain; charset=utf-8',
45
+ '.wasm': 'application/wasm',
46
+ '.webm': 'video/webm',
47
+ '.webp': 'image/webp',
48
+ '.woff': 'font/woff',
49
+ '.woff2': 'font/woff2',
50
+ '.xml': 'application/xml; charset=utf-8',
51
+ };
52
+ return types[ext] || 'application/octet-stream';
53
+ }
54
+
55
+ function normalizeAssetPath(pathname: string): string | null {
56
+ if (pathname.startsWith('/assets/')) {
57
+ return pathname;
58
+ }
59
+ if (basePath && pathname.startsWith(`${basePath}/assets/`)) {
60
+ return pathname.slice(basePath.length);
61
+ }
62
+ return null;
63
+ }
64
+
65
+ function serveProjectAsset(pathname: string, res: ServerResponse): boolean {
66
+ const assetPath = normalizeAssetPath(pathname);
67
+ if (!assetPath || !existsSync(projectAssetsDir)) {
68
+ return false;
69
+ }
70
+
71
+ let decodedPath: string;
72
+ try {
73
+ decodedPath = decodeURIComponent(assetPath.replace(/^\/assets\/+/, ''));
74
+ } catch {
75
+ return false;
76
+ }
77
+
78
+ const filePath = resolve(projectAssetsDir, decodedPath);
79
+ if (filePath !== projectAssetsDir && !filePath.startsWith(`${projectAssetsDir}${sep}`)) {
80
+ res.statusCode = 403;
81
+ res.end('Forbidden');
82
+ return true;
83
+ }
84
+
85
+ try {
86
+ const stat = statSync(filePath);
87
+ if (!stat.isFile()) {
88
+ return false;
89
+ }
90
+ res.statusCode = 200;
91
+ res.setHeader('Content-Type', getContentType(filePath));
92
+ res.setHeader('Content-Length', stat.size);
93
+ createReadStream(filePath).pipe(res);
94
+ return true;
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
99
+
100
+ // Create Next.js app
101
+ const app = next({ dev, hostname, port });
102
+ const handle = app.getRequestHandler();
103
+
104
+ app.prepare().then(() => {
105
+ const server = createServer(async (req, res) => {
106
+ try {
107
+ const parsedUrl = parse(req.url!, true);
108
+ if (serveProjectAsset(parsedUrl.pathname || '', res)) {
109
+ return;
110
+ }
111
+ await handle(req, res, parsedUrl);
112
+ } catch (err) {
113
+ console.error('Error occurred handling', req.url, err);
114
+ res.statusCode = 500;
115
+ res.end('Internal server error');
116
+ }
117
+ });
118
+ server.once('error', err => {
119
+ console.error(err);
120
+ process.exit(1);
121
+ });
122
+ server.listen(port, () => {
123
+ console.log(
124
+ `> Server listening at http://${hostname}:${port} as ${
125
+ dev ? 'development' : process.env.LICOS_PROJECT_ENV
126
+ }`,
127
+ );
128
+ });
129
+ });