@zsukim/ctv-run 1.0.12 → 1.0.13

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/README.md CHANGED
@@ -90,6 +90,7 @@
90
90
  | `appId` | | Tizen 앱 고유 ID (없으면 자동 생성) |
91
91
  | `tizenPath` | | tizen CLI 실행 경로 (기본값: `tizen`) |
92
92
  | `sdbPath` | | sdb 실행 경로 (기본값: `sdb`) |
93
+ | `configXmlPath` | | 사용할 config.xml 경로 (우선순위: dist > 지정경로 > 루트 > 기본 생성) |
93
94
 
94
95
  **WebOS**
95
96
 
@@ -99,6 +100,7 @@
99
100
  | `url` | | TV가 로드할 URL |
100
101
  | `port` | | TV가 로드할 URL의 포트 |
101
102
  | `appId` | | webOS 앱 ID (기본값: `com.ctvrun.app`) |
103
+ | `appInfoPath` | | 사용할 appinfo.json 경로 (우선순위: dist > 지정경로 > 루트 > 기본 생성) |
102
104
 
103
105
  **Common**
104
106
 
@@ -19,9 +19,13 @@ const path_1 = __importDefault(require("path"));
19
19
  const config_1 = require("../utils/config");
20
20
  const ip_1 = require("../utils/ip");
21
21
  const platform_1 = require("../utils/platform");
22
+ const DEFAULT_APP_ID = 'A123456789.CtvRunApp';
23
+ const DEFAULT_APP_NAME = 'CtvRunApp';
24
+ const DEFAULT_CERT_FILE = 'ctv-run-cert';
25
+ const DEFAULT_CERT_PROFILE = 'ctv-run-profile';
22
26
  function runTizen() {
23
27
  return __awaiter(this, void 0, void 0, function* () {
24
- var _a, _b, _c, _d, _e, _f, _g;
28
+ var _a, _b, _c, _d, _e, _f, _g, _h;
25
29
  const config = (0, config_1.loadConfig)();
26
30
  const args = process.argv.slice(2);
27
31
  const getArg = (0, platform_1.makeArgParser)(args);
@@ -79,10 +83,11 @@ function runTizen() {
79
83
  const appId = getArg('appId') ||
80
84
  (xmlInfo === null || xmlInfo === void 0 ? void 0 : xmlInfo.appId) ||
81
85
  ((_g = config.tizen) === null || _g === void 0 ? void 0 : _g.appId) ||
82
- 'A123456789.CtvRunApp';
83
- const safeAppName = ((xmlInfo === null || xmlInfo === void 0 ? void 0 : xmlInfo.appName) || 'CtvRunApp').replace(/\s+/g, '');
86
+ DEFAULT_APP_ID;
87
+ const safeAppName = ((xmlInfo === null || xmlInfo === void 0 ? void 0 : xmlInfo.appName) || DEFAULT_APP_NAME).replace(/\s+/g, '');
84
88
  // static mode는 dist의 config.xml 유지, live mode는 개발서버 URL로 새로 생성
85
- yield ensureTizenFiles(appId, tempAppDir, safeAppName, !isLiveMode, isLiveMode ? appUrl : '');
89
+ const configXmlPath = getArg('configXmlPath') || ((_h = config.tizen) === null || _h === void 0 ? void 0 : _h.configXmlPath);
90
+ yield ensureTizenFiles(appId, tempAppDir, safeAppName, !isLiveMode, isLiveMode ? appUrl : '', configXmlPath);
86
91
  // Tizen 인증서 프로필 확인/생성/활성화
87
92
  console.log('\n🎫 Tizen 인증서 프로필 확인 중...');
88
93
  const profilesXmlPath = path_1.default.join(process.env.HOME || '', 'tizen-studio-data/profile/profiles.xml');
@@ -122,7 +127,7 @@ function runTizen() {
122
127
  existingProfiles.forEach((p, i) => {
123
128
  console.log(` ${i + 1}. ${p}`);
124
129
  });
125
- const answer = askQuestion('🔑 사용할 프로필 번호를 입력하세요 (새로운 ctv-run-cert 생성): ');
130
+ const answer = askQuestion(`🔑 사용할 프로필 번호를 입력하세요 (새로운 전용 인증서 ${DEFAULT_CERT_FILE} 생성): `);
126
131
  const idx = parseInt(answer, 10) - 1;
127
132
  if (!isNaN(idx) && idx >= 0 && idx < existingProfiles.length) {
128
133
  const chosen = existingProfiles[idx];
@@ -132,8 +137,8 @@ function runTizen() {
132
137
  }
133
138
  if (!activeProfile) {
134
139
  console.log('⚠️ 활성화된 프로필이 없습니다. 앱 전용 인증서를 세팅합니다.');
135
- const certFileName = 'ctv-run-cert';
136
- const profileName = 'ctv-run-profile';
140
+ const certFileName = DEFAULT_CERT_FILE;
141
+ const profileName = DEFAULT_CERT_PROFILE;
137
142
  const homeDir = process.env.HOME || '';
138
143
  const defaultCertDir = path_1.default.join(homeDir, 'tizen-studio-data/keystore/author');
139
144
  const p12Path = path_1.default.join(defaultCertDir, `${certFileName}.p12`);
@@ -232,21 +237,28 @@ function getInfoFromXml(dir) {
232
237
  return null;
233
238
  }
234
239
  function ensureTizenFiles(appId_1, tempDir_1, appName_1) {
235
- return __awaiter(this, arguments, void 0, function* (appId, tempDir, appName, keepExistingConfig = false, liveUrl = '') {
236
- const configXmlPath = path_1.default.join(tempDir, 'config.xml');
237
- if (keepExistingConfig && fs_extra_1.default.existsSync(configXmlPath)) {
240
+ return __awaiter(this, arguments, void 0, function* (appId, tempDir, appName, keepExistingConfig = false, liveUrl = '', specifiedPath) {
241
+ const destConfigXml = path_1.default.join(tempDir, 'config.xml');
242
+ if (keepExistingConfig && fs_extra_1.default.existsSync(destConfigXml)) {
238
243
  // static mode: dist의 config.xml을 그대로 유지
239
244
  (0, platform_1.resolveIcon)(tempDir);
240
245
  return;
241
246
  }
242
- // live mode: 기존 config.xml 삭제 새로 생성
243
- if (fs_extra_1.default.existsSync(configXmlPath)) {
244
- fs_extra_1.default.removeSync(configXmlPath);
245
- }
246
- console.log(`📝 config.xml 생성 중... (Name: ${appName}, ID: ${appId})`);
247
- // appId 추출
248
- const packageId = appId.split('.')[0] || 'TizenApp';
249
- const xmlContent = `<?xml version="1.0" encoding="UTF-8"?>
247
+ // config.xml 없으면 지정경로 루트 → 기본값 (우선순위: dist > 지정경로 > 루트 > 기본값)
248
+ if (!fs_extra_1.default.existsSync(destConfigXml)) {
249
+ const candidates = [
250
+ specifiedPath && path_1.default.resolve(process.cwd(), specifiedPath),
251
+ path_1.default.join(process.cwd(), 'config.xml'),
252
+ ].filter(Boolean);
253
+ const found = candidates.find((p) => fs_extra_1.default.existsSync(p));
254
+ if (found) {
255
+ fs_extra_1.default.copyFileSync(found, destConfigXml);
256
+ console.log(`📝 config.xml 복사: ${found}`);
257
+ }
258
+ else {
259
+ console.log(`📝 config.xml 생성 중... (Name: ${appName}, ID: ${appId})`);
260
+ const packageId = appId.split('.')[0] || 'TizenApp';
261
+ const xmlContent = `<?xml version="1.0" encoding="UTF-8"?>
250
262
  <widget xmlns:tizen="http://tizen.org/ns/widgets" xmlns="http://www.w3.org/ns/widgets" id="http://yourdomain/tizen/${appName}" version="1.0.0" viewmodes="maximized">
251
263
  <tizen:application id="${appId}" package="${packageId}" required_version="2.1"/>
252
264
  <content src="index.html"/>
@@ -260,7 +272,9 @@ function ensureTizenFiles(appId_1, tempDir_1, appName_1) {
260
272
  <tizen:privilege name="http://tizen.org/privilege/tv.inputdevice" />
261
273
  <tizen:setting screen-orientation="landscape" context-menu="enable" background-support="disable" encryption="disable" install-location="auto" hwkey-event="enable"/>
262
274
  </widget>`;
263
- fs_extra_1.default.writeFileSync(configXmlPath, xmlContent, 'utf8');
275
+ fs_extra_1.default.writeFileSync(destConfigXml, xmlContent, 'utf8');
276
+ }
277
+ }
264
278
  if (liveUrl) {
265
279
  const redirectHtml = `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Loading...</title><meta http-equiv="refresh" content="0; url=${liveUrl}"></head><body style="background:#000;"></body></html>`;
266
280
  fs_extra_1.default.writeFileSync(path_1.default.join(tempDir, 'index.html'), redirectHtml);
@@ -19,20 +19,23 @@ const path_1 = __importDefault(require("path"));
19
19
  const config_1 = require("../utils/config");
20
20
  const ip_1 = require("../utils/ip");
21
21
  const platform_1 = require("../utils/platform");
22
+ const DEFAULT_APP_ID = 'com.ctvrun.app';
22
23
  function runWebOS() {
23
24
  return __awaiter(this, void 0, void 0, function* () {
24
- var _a, _b, _c, _d, _e;
25
+ var _a, _b, _c, _d, _e, _f;
25
26
  const config = (0, config_1.loadConfig)();
26
27
  const args = process.argv.slice(2);
27
28
  const getArg = (0, platform_1.makeArgParser)(args);
28
29
  // 기본 설정값 로드
29
30
  const deviceName = getArg('device') || ((_a = config.webos) === null || _a === void 0 ? void 0 : _a.deviceName);
30
- const appId = getArg('appId') || ((_b = config.webos) === null || _b === void 0 ? void 0 : _b.appId) || 'com.ctvrun.app';
31
+ const appId = getArg('appId') || ((_b = config.webos) === null || _b === void 0 ? void 0 : _b.appId) || DEFAULT_APP_ID;
32
+ const appInfoPath = getArg('appInfoPath') || ((_c = config.webos) === null || _c === void 0 ? void 0 : _c.appInfoPath);
31
33
  const targetArg = getArg('target');
32
- const port = getArg('port') || ((_c = config.webos) === null || _c === void 0 ? void 0 : _c.port) || ((_d = config.common) === null || _d === void 0 ? void 0 : _d.devServerPort) || 3000;
33
- const appUrl = getArg('url') ||
34
- ((_e = config.webos) === null || _e === void 0 ? void 0 : _e.url) ||
35
- `http://${(0, ip_1.getLocalIp)()}:${port}`;
34
+ const port = getArg('port') ||
35
+ ((_d = config.webos) === null || _d === void 0 ? void 0 : _d.port) ||
36
+ ((_e = config.common) === null || _e === void 0 ? void 0 : _e.devServerPort) ||
37
+ 3000;
38
+ const appUrl = getArg('url') || ((_f = config.webos) === null || _f === void 0 ? void 0 : _f.url) || `http://${(0, ip_1.getLocalIp)()}:${port}`;
36
39
  // 등록된 기기가 없는 경우
37
40
  if (!deviceName) {
38
41
  console.log('\n📺 연결된 WebOS TV 정보가 없습니다.');
@@ -97,12 +100,12 @@ function runWebOS() {
97
100
  `;
98
101
  fs_extra_1.default.writeFileSync(path_1.default.join(tempAppDir, 'index.html'), redirectHtml);
99
102
  }
100
- // appinfo.json 생성 (dist 없으면 기본값으로 생성)
101
- yield ensureWebosAppInfo(appId, tempAppDir);
103
+ // appinfo.json 생성 (우선순위: dist > 지정경로 > 루트 > 기본값)
104
+ yield ensureWebosAppInfo(appId, tempAppDir, appInfoPath);
102
105
  // 실제 appId를 appinfo.json에서 읽음 (dist에 있던 값 우선)
103
- const appInfoPath = path_1.default.join(tempAppDir, 'appinfo.json');
104
- const resolvedAppId = fs_extra_1.default.existsSync(appInfoPath)
105
- ? fs_extra_1.default.readJsonSync(appInfoPath).id || appId
106
+ const resolvedAppInfoPath = path_1.default.join(tempAppDir, 'appinfo.json');
107
+ const resolvedAppId = fs_extra_1.default.existsSync(resolvedAppInfoPath)
108
+ ? fs_extra_1.default.readJsonSync(resolvedAppInfoPath).id || appId
106
109
  : appId;
107
110
  // 아이콘
108
111
  (0, platform_1.resolveIcon)(tempAppDir);
@@ -120,7 +123,9 @@ function runWebOS() {
120
123
  });
121
124
  // 런치
122
125
  console.log(`▶️ Launching App...`);
123
- (0, child_process_1.execSync)(`ares-launch -d ${deviceName} ${resolvedAppId}`, { stdio: 'inherit' });
126
+ (0, child_process_1.execSync)(`ares-launch -d ${deviceName} ${resolvedAppId}`, {
127
+ stdio: 'inherit',
128
+ });
124
129
  // 파일 정리
125
130
  fs_extra_1.default.removeSync(path_1.default.resolve(process.cwd(), ipkFile));
126
131
  fs_extra_1.default.removeSync(tempAppDir);
@@ -132,26 +137,31 @@ function runWebOS() {
132
137
  }
133
138
  });
134
139
  }
135
- // appinfo.json이 없으면 자동 생성
136
- function ensureWebosAppInfo(appId, tempDir) {
140
+ // appinfo.json이 없으면 자동 생성 (우선순위: dist > 지정경로 > 루트 > 기본값)
141
+ function ensureWebosAppInfo(appId, tempDir, specifiedPath) {
137
142
  return __awaiter(this, void 0, void 0, function* () {
138
- const appInfoPath = path_1.default.join(tempDir, 'appinfo.json');
139
- const rootAppInfo = path_1.default.resolve(process.cwd(), 'appinfo.json');
140
- if (fs_extra_1.default.existsSync(rootAppInfo)) {
141
- fs_extra_1.default.copySync(rootAppInfo, appInfoPath);
142
- }
143
- else {
144
- const defaultAppInfo = {
145
- id: appId,
146
- version: '1.0.0',
147
- vendor: 'CtvRun',
148
- type: 'web',
149
- main: 'index.html',
150
- title: 'CTV-Run-App',
151
- icon: 'icon.png',
152
- uiRevision: 2,
153
- };
154
- fs_extra_1.default.writeJsonSync(appInfoPath, defaultAppInfo, { spaces: 2 });
143
+ const destPath = path_1.default.join(tempDir, 'appinfo.json');
144
+ if (fs_extra_1.default.existsSync(destPath))
145
+ return;
146
+ const candidates = [
147
+ specifiedPath && path_1.default.resolve(process.cwd(), specifiedPath),
148
+ path_1.default.resolve(process.cwd(), 'appinfo.json'),
149
+ ].filter(Boolean);
150
+ for (const candidate of candidates) {
151
+ if (fs_extra_1.default.existsSync(candidate)) {
152
+ fs_extra_1.default.copySync(candidate, destPath);
153
+ return;
154
+ }
155
155
  }
156
+ fs_extra_1.default.writeJsonSync(destPath, {
157
+ id: appId,
158
+ version: '1.0.0',
159
+ vendor: 'CtvRun',
160
+ type: 'web',
161
+ main: 'index.html',
162
+ title: 'CTV-Run-App',
163
+ icon: 'icon.png',
164
+ uiRevision: 2,
165
+ }, { spaces: 2 });
156
166
  });
157
167
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zsukim/ctv-run",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Smart TV deployment CLI for Vizio, LG webOS, Fire TV, and Samsung Tizen",
5
5
  "keywords": [
6
6
  "ctv",