@table-js/platform 0.0.1

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 ADDED
@@ -0,0 +1,31 @@
1
+ # @tablejs/platform
2
+
3
+ Build tools and platform adapters for Table.js.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -D @tablejs/platform
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ # Build for all platforms
15
+ table build --platform all
16
+
17
+ # Build for specific platform
18
+ table build --platform tizen
19
+ table build --platform webos
20
+ table build --platform android
21
+ ```
22
+
23
+ ## Supported Platforms
24
+
25
+ - **Tizen** - Samsung Smart TV (.wgt)
26
+ - **webOS** - LG Smart TV (.ipk)
27
+ - **Android TV** - Android TV (.apk)
28
+
29
+ ## License
30
+
31
+ MIT
package/dist/cli.mjs ADDED
@@ -0,0 +1,357 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { Command } from "commander";
5
+ import chalk from "chalk";
6
+ import ora from "ora";
7
+
8
+ // src/builder.ts
9
+ import { build as viteBuild } from "vite";
10
+
11
+ // src/adapters/tizen.ts
12
+ import path from "path";
13
+ import fs from "fs-extra";
14
+ import archiver from "archiver";
15
+ import { createWriteStream } from "fs";
16
+ var TizenAdapter = class {
17
+ name = "Tizen (Samsung)";
18
+ async build(options) {
19
+ const distDir = `${options.outDir}/tizen`;
20
+ await this.createConfig(distDir);
21
+ }
22
+ async package(distDir) {
23
+ const outputPath = path.join(distDir, "..", "app.wgt");
24
+ await new Promise((resolve, reject) => {
25
+ const output = createWriteStream(outputPath);
26
+ const archive = archiver("zip", { zlib: { level: 9 } });
27
+ output.on("close", () => resolve());
28
+ archive.on("error", reject);
29
+ archive.pipe(output);
30
+ archive.directory(distDir, false);
31
+ archive.finalize();
32
+ });
33
+ return outputPath;
34
+ }
35
+ async createConfig(distDir) {
36
+ const pkg = await this.readPackageJson();
37
+ const config = `<?xml version="1.0" encoding="UTF-8"?>
38
+ <widget xmlns="http://www.w3.org/ns/widgets"
39
+ xmlns:tizen="http://tizen.org/ns/widgets"
40
+ id="${pkg.id || "com.example.app"}"
41
+ version="${pkg.version}"
42
+ viewmodes="maximized">
43
+ <tizen:application id="${pkg.id || "com.example.app"}.App"
44
+ package="${pkg.id || "com.example.app"}"
45
+ required_version="6.0"/>
46
+ <content src="index.html"/>
47
+ <feature name="http://tizen.org/feature/screen.size.all"/>
48
+ <icon src="icon.png"/>
49
+ <name>${pkg.name}</name>
50
+ <tizen:profile name="tv"/>
51
+ <tizen:setting screen-orientation="landscape"
52
+ context-menu="disable"
53
+ background-support="disable"
54
+ encryption="disable"
55
+ install-location="auto"/>
56
+ </widget>`;
57
+ await fs.writeFile(path.join(distDir, "config.xml"), config);
58
+ }
59
+ async readPackageJson() {
60
+ try {
61
+ const pkg = await fs.readJson("package.json");
62
+ return {
63
+ id: pkg.tizenAppId || pkg.name,
64
+ name: pkg.name,
65
+ version: pkg.version,
66
+ description: pkg.description
67
+ };
68
+ } catch {
69
+ return {
70
+ id: "com.example.app",
71
+ name: "Table App",
72
+ version: "1.0.0"
73
+ };
74
+ }
75
+ }
76
+ };
77
+
78
+ // src/adapters/webos.ts
79
+ import path2 from "path";
80
+ import fs2 from "fs-extra";
81
+ import archiver2 from "archiver";
82
+ import { createWriteStream as createWriteStream2 } from "fs";
83
+ var WebOSAdapter = class {
84
+ name = "webOS (LG)";
85
+ async build(options) {
86
+ const distDir = `${options.outDir}/webos`;
87
+ await this.createAppInfo(distDir);
88
+ }
89
+ async package(distDir) {
90
+ const outputPath = path2.join(distDir, "..", "app.ipk");
91
+ await new Promise((resolve, reject) => {
92
+ const output = createWriteStream2(outputPath);
93
+ const archive = archiver2("tar", { gzip: true });
94
+ output.on("close", () => resolve());
95
+ archive.on("error", reject);
96
+ archive.pipe(output);
97
+ archive.directory(distDir, false);
98
+ archive.finalize();
99
+ });
100
+ return outputPath;
101
+ }
102
+ async createAppInfo(distDir) {
103
+ const pkg = await this.readPackageJson();
104
+ const appInfo = {
105
+ id: pkg.id || "com.example.app",
106
+ version: pkg.version,
107
+ vendor: "Table.js",
108
+ type: "web",
109
+ main: "index.html",
110
+ title: pkg.name,
111
+ icon: "icon.png",
112
+ largeIcon: "icon.png",
113
+ bgImage: "splash.png",
114
+ resolution: "1920x1080",
115
+ disallowScrollingInMainWindow: true
116
+ };
117
+ await fs2.writeJson(path2.join(distDir, "appinfo.json"), appInfo, { spaces: 2 });
118
+ }
119
+ async readPackageJson() {
120
+ try {
121
+ const pkg = await fs2.readJson("package.json");
122
+ return {
123
+ id: pkg.webosAppId || pkg.name,
124
+ name: pkg.name,
125
+ version: pkg.version,
126
+ description: pkg.description
127
+ };
128
+ } catch {
129
+ return {
130
+ id: "com.example.app",
131
+ name: "Table App",
132
+ version: "1.0.0"
133
+ };
134
+ }
135
+ }
136
+ };
137
+
138
+ // src/adapters/android.ts
139
+ import path3 from "path";
140
+ import fs3 from "fs-extra";
141
+ import { execa } from "execa";
142
+ var AndroidAdapter = class {
143
+ name = "Android TV";
144
+ async build(options) {
145
+ const distDir = `${options.outDir}/android`;
146
+ await this.createWebViewProject(distDir);
147
+ }
148
+ async package(distDir) {
149
+ const projectDir = path3.join(distDir, "android-project");
150
+ try {
151
+ await execa("./gradlew", ["assembleRelease"], {
152
+ cwd: projectDir,
153
+ stdio: "inherit"
154
+ });
155
+ const apkPath = path3.join(projectDir, "app/build/outputs/apk/release/app-release.apk");
156
+ const outputPath = path3.join(distDir, "..", "app.apk");
157
+ await fs3.copy(apkPath, outputPath);
158
+ return outputPath;
159
+ } catch (error) {
160
+ throw new Error("Android build failed. Make sure Android SDK is installed.");
161
+ }
162
+ }
163
+ async createWebViewProject(distDir) {
164
+ const pkg = await this.readPackageJson();
165
+ const projectDir = path3.join(distDir, "android-project");
166
+ await fs3.ensureDir(projectDir);
167
+ await fs3.copy(distDir, path3.join(projectDir, "app/src/main/assets/www"));
168
+ await this.createManifest(projectDir, pkg);
169
+ await this.createGradleFiles(projectDir, pkg);
170
+ await this.createMainActivity(projectDir, pkg);
171
+ }
172
+ async createManifest(projectDir, pkg) {
173
+ const manifest = `<?xml version="1.0" encoding="utf-8"?>
174
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
175
+ package="${pkg.id || "com.example.app"}">
176
+
177
+ <uses-permission android:name="android.permission.INTERNET" />
178
+ <uses-feature android:name="android.software.leanback" android:required="true" />
179
+ <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
180
+
181
+ <application
182
+ android:allowBackup="true"
183
+ android:icon="@mipmap/ic_launcher"
184
+ android:label="${pkg.name}"
185
+ android:banner="@drawable/banner"
186
+ android:theme="@style/Theme.Leanback">
187
+
188
+ <activity
189
+ android:name=".MainActivity"
190
+ android:exported="true"
191
+ android:screenOrientation="landscape">
192
+ <intent-filter>
193
+ <action android:name="android.intent.action.MAIN" />
194
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
195
+ </intent-filter>
196
+ </activity>
197
+ </application>
198
+ </manifest>`;
199
+ const manifestPath = path3.join(projectDir, "app/src/main/AndroidManifest.xml");
200
+ await fs3.ensureDir(path3.dirname(manifestPath));
201
+ await fs3.writeFile(manifestPath, manifest);
202
+ }
203
+ async createGradleFiles(projectDir, pkg) {
204
+ const buildGradle = `plugins {
205
+ id 'com.android.application'
206
+ }
207
+
208
+ android {
209
+ namespace '${pkg.id || "com.example.app"}'
210
+ compileSdk 34
211
+
212
+ defaultConfig {
213
+ applicationId "${pkg.id || "com.example.app"}"
214
+ minSdk 21
215
+ targetSdk 34
216
+ versionCode 1
217
+ versionName "${pkg.version}"
218
+ }
219
+
220
+ buildTypes {
221
+ release {
222
+ minifyEnabled true
223
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
224
+ }
225
+ }
226
+ }
227
+
228
+ dependencies {
229
+ implementation 'androidx.leanback:leanback:1.0.0'
230
+ }`;
231
+ await fs3.writeFile(path3.join(projectDir, "app/build.gradle"), buildGradle);
232
+ }
233
+ async createMainActivity(projectDir, pkg) {
234
+ const packageName = pkg.id || "com.example.app";
235
+ const activity = `package ${packageName};
236
+
237
+ import android.app.Activity;
238
+ import android.os.Bundle;
239
+ import android.webkit.WebView;
240
+ import android.webkit.WebSettings;
241
+
242
+ public class MainActivity extends Activity {
243
+ private WebView webView;
244
+
245
+ @Override
246
+ protected void onCreate(Bundle savedInstanceState) {
247
+ super.onCreate(savedInstanceState);
248
+
249
+ webView = new WebView(this);
250
+ setContentView(webView);
251
+
252
+ WebSettings settings = webView.getSettings();
253
+ settings.setJavaScriptEnabled(true);
254
+ settings.setDomStorageEnabled(true);
255
+ settings.setAllowFileAccess(true);
256
+
257
+ webView.loadUrl("file:///android_asset/www/index.html");
258
+ }
259
+ }`;
260
+ const activityPath = path3.join(
261
+ projectDir,
262
+ `app/src/main/java/${packageName.replace(/\./g, "/")}/MainActivity.java`
263
+ );
264
+ await fs3.ensureDir(path3.dirname(activityPath));
265
+ await fs3.writeFile(activityPath, activity);
266
+ }
267
+ async readPackageJson() {
268
+ try {
269
+ const pkg = await fs3.readJson("package.json");
270
+ return {
271
+ id: pkg.androidAppId || pkg.name.replace(/[^a-z0-9]/gi, ".").toLowerCase(),
272
+ name: pkg.name,
273
+ version: pkg.version,
274
+ description: pkg.description
275
+ };
276
+ } catch {
277
+ return {
278
+ id: "com.example.app",
279
+ name: "Table App",
280
+ version: "1.0.0"
281
+ };
282
+ }
283
+ }
284
+ };
285
+
286
+ // src/builder.ts
287
+ async function build(platform, options = {}) {
288
+ const opts = {
289
+ platform,
290
+ outDir: options.outDir || "dist",
291
+ minify: options.minify ?? true,
292
+ sourcemap: options.sourcemap ?? false
293
+ };
294
+ if (platform === "all") {
295
+ await Promise.all([
296
+ buildPlatform("tizen", opts),
297
+ buildPlatform("webos", opts),
298
+ buildPlatform("android", opts)
299
+ ]);
300
+ return;
301
+ }
302
+ await buildPlatform(platform, opts);
303
+ }
304
+ async function buildPlatform(platform, options) {
305
+ const adapter = getAdapter(platform);
306
+ await viteBuild({
307
+ build: {
308
+ outDir: `${options.outDir}/${platform}`,
309
+ minify: options.minify,
310
+ sourcemap: options.sourcemap,
311
+ emptyOutDir: true
312
+ },
313
+ define: {
314
+ __TABLE_PLATFORM__: JSON.stringify(platform)
315
+ }
316
+ });
317
+ await adapter.build(options);
318
+ const packagePath = await adapter.package(`${options.outDir}/${platform}`);
319
+ console.log(`\u2713 ${adapter.name} package created: ${packagePath}`);
320
+ }
321
+ function getAdapter(platform) {
322
+ switch (platform) {
323
+ case "tizen":
324
+ return new TizenAdapter();
325
+ case "webos":
326
+ return new WebOSAdapter();
327
+ case "android":
328
+ return new AndroidAdapter();
329
+ default:
330
+ throw new Error(`Unknown platform: ${platform}`);
331
+ }
332
+ }
333
+
334
+ // src/cli.ts
335
+ var program = new Command();
336
+ program.name("table").description("Table.js build tool for Smart TV platforms").version("0.0.1");
337
+ program.command("build").description("Build for target platform").option("-p, --platform <platform>", "Target platform (tizen, webos, android, all)", "all").option("-o, --out <dir>", "Output directory", "dist").option("--no-minify", "Disable minification").option("--sourcemap", "Generate sourcemaps").action(async (options) => {
338
+ const platform = options.platform;
339
+ console.log();
340
+ console.log(chalk.bold(" table.js") + chalk.dim(" \u2014 Building for Smart TV"));
341
+ console.log();
342
+ const spinner = ora(`Building for ${platform}...`).start();
343
+ try {
344
+ await build(platform, {
345
+ outDir: options.out,
346
+ minify: options.minify,
347
+ sourcemap: options.sourcemap
348
+ });
349
+ spinner.succeed("Build complete!");
350
+ console.log();
351
+ } catch (error) {
352
+ spinner.fail("Build failed");
353
+ console.error(error);
354
+ process.exit(1);
355
+ }
356
+ });
357
+ program.parse();
@@ -0,0 +1,50 @@
1
+ type Platform = 'tizen' | 'webos' | 'android' | 'all';
2
+ interface BuildOptions {
3
+ platform: Platform;
4
+ outDir: string;
5
+ minify: boolean;
6
+ sourcemap: boolean;
7
+ }
8
+ interface PlatformAdapter {
9
+ name: string;
10
+ build(options: BuildOptions): Promise<void>;
11
+ package(distDir: string): Promise<string>;
12
+ }
13
+ interface ManifestBase {
14
+ id: string;
15
+ name: string;
16
+ version: string;
17
+ description?: string;
18
+ icon?: string;
19
+ }
20
+
21
+ declare function build(platform: Platform, options?: Partial<BuildOptions>): Promise<void>;
22
+
23
+ declare class TizenAdapter implements PlatformAdapter {
24
+ name: string;
25
+ build(options: BuildOptions): Promise<void>;
26
+ package(distDir: string): Promise<string>;
27
+ private createConfig;
28
+ private readPackageJson;
29
+ }
30
+
31
+ declare class WebOSAdapter implements PlatformAdapter {
32
+ name: string;
33
+ build(options: BuildOptions): Promise<void>;
34
+ package(distDir: string): Promise<string>;
35
+ private createAppInfo;
36
+ private readPackageJson;
37
+ }
38
+
39
+ declare class AndroidAdapter implements PlatformAdapter {
40
+ name: string;
41
+ build(options: BuildOptions): Promise<void>;
42
+ package(distDir: string): Promise<string>;
43
+ private createWebViewProject;
44
+ private createManifest;
45
+ private createGradleFiles;
46
+ private createMainActivity;
47
+ private readPackageJson;
48
+ }
49
+
50
+ export { AndroidAdapter, type BuildOptions, type ManifestBase, type Platform, type PlatformAdapter, TizenAdapter, WebOSAdapter, build };
@@ -0,0 +1,50 @@
1
+ type Platform = 'tizen' | 'webos' | 'android' | 'all';
2
+ interface BuildOptions {
3
+ platform: Platform;
4
+ outDir: string;
5
+ minify: boolean;
6
+ sourcemap: boolean;
7
+ }
8
+ interface PlatformAdapter {
9
+ name: string;
10
+ build(options: BuildOptions): Promise<void>;
11
+ package(distDir: string): Promise<string>;
12
+ }
13
+ interface ManifestBase {
14
+ id: string;
15
+ name: string;
16
+ version: string;
17
+ description?: string;
18
+ icon?: string;
19
+ }
20
+
21
+ declare function build(platform: Platform, options?: Partial<BuildOptions>): Promise<void>;
22
+
23
+ declare class TizenAdapter implements PlatformAdapter {
24
+ name: string;
25
+ build(options: BuildOptions): Promise<void>;
26
+ package(distDir: string): Promise<string>;
27
+ private createConfig;
28
+ private readPackageJson;
29
+ }
30
+
31
+ declare class WebOSAdapter implements PlatformAdapter {
32
+ name: string;
33
+ build(options: BuildOptions): Promise<void>;
34
+ package(distDir: string): Promise<string>;
35
+ private createAppInfo;
36
+ private readPackageJson;
37
+ }
38
+
39
+ declare class AndroidAdapter implements PlatformAdapter {
40
+ name: string;
41
+ build(options: BuildOptions): Promise<void>;
42
+ package(distDir: string): Promise<string>;
43
+ private createWebViewProject;
44
+ private createManifest;
45
+ private createGradleFiles;
46
+ private createMainActivity;
47
+ private readPackageJson;
48
+ }
49
+
50
+ export { AndroidAdapter, type BuildOptions, type ManifestBase, type Platform, type PlatformAdapter, TizenAdapter, WebOSAdapter, build };
package/dist/index.js ADDED
@@ -0,0 +1,372 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ AndroidAdapter: () => AndroidAdapter,
34
+ TizenAdapter: () => TizenAdapter,
35
+ WebOSAdapter: () => WebOSAdapter,
36
+ build: () => build
37
+ });
38
+ module.exports = __toCommonJS(index_exports);
39
+
40
+ // src/builder.ts
41
+ var import_vite = require("vite");
42
+
43
+ // src/adapters/tizen.ts
44
+ var import_path = __toESM(require("path"));
45
+ var import_fs_extra = __toESM(require("fs-extra"));
46
+ var import_archiver = __toESM(require("archiver"));
47
+ var import_fs = require("fs");
48
+ var TizenAdapter = class {
49
+ name = "Tizen (Samsung)";
50
+ async build(options) {
51
+ const distDir = `${options.outDir}/tizen`;
52
+ await this.createConfig(distDir);
53
+ }
54
+ async package(distDir) {
55
+ const outputPath = import_path.default.join(distDir, "..", "app.wgt");
56
+ await new Promise((resolve, reject) => {
57
+ const output = (0, import_fs.createWriteStream)(outputPath);
58
+ const archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } });
59
+ output.on("close", () => resolve());
60
+ archive.on("error", reject);
61
+ archive.pipe(output);
62
+ archive.directory(distDir, false);
63
+ archive.finalize();
64
+ });
65
+ return outputPath;
66
+ }
67
+ async createConfig(distDir) {
68
+ const pkg = await this.readPackageJson();
69
+ const config = `<?xml version="1.0" encoding="UTF-8"?>
70
+ <widget xmlns="http://www.w3.org/ns/widgets"
71
+ xmlns:tizen="http://tizen.org/ns/widgets"
72
+ id="${pkg.id || "com.example.app"}"
73
+ version="${pkg.version}"
74
+ viewmodes="maximized">
75
+ <tizen:application id="${pkg.id || "com.example.app"}.App"
76
+ package="${pkg.id || "com.example.app"}"
77
+ required_version="6.0"/>
78
+ <content src="index.html"/>
79
+ <feature name="http://tizen.org/feature/screen.size.all"/>
80
+ <icon src="icon.png"/>
81
+ <name>${pkg.name}</name>
82
+ <tizen:profile name="tv"/>
83
+ <tizen:setting screen-orientation="landscape"
84
+ context-menu="disable"
85
+ background-support="disable"
86
+ encryption="disable"
87
+ install-location="auto"/>
88
+ </widget>`;
89
+ await import_fs_extra.default.writeFile(import_path.default.join(distDir, "config.xml"), config);
90
+ }
91
+ async readPackageJson() {
92
+ try {
93
+ const pkg = await import_fs_extra.default.readJson("package.json");
94
+ return {
95
+ id: pkg.tizenAppId || pkg.name,
96
+ name: pkg.name,
97
+ version: pkg.version,
98
+ description: pkg.description
99
+ };
100
+ } catch {
101
+ return {
102
+ id: "com.example.app",
103
+ name: "Table App",
104
+ version: "1.0.0"
105
+ };
106
+ }
107
+ }
108
+ };
109
+
110
+ // src/adapters/webos.ts
111
+ var import_path2 = __toESM(require("path"));
112
+ var import_fs_extra2 = __toESM(require("fs-extra"));
113
+ var import_archiver2 = __toESM(require("archiver"));
114
+ var import_fs2 = require("fs");
115
+ var WebOSAdapter = class {
116
+ name = "webOS (LG)";
117
+ async build(options) {
118
+ const distDir = `${options.outDir}/webos`;
119
+ await this.createAppInfo(distDir);
120
+ }
121
+ async package(distDir) {
122
+ const outputPath = import_path2.default.join(distDir, "..", "app.ipk");
123
+ await new Promise((resolve, reject) => {
124
+ const output = (0, import_fs2.createWriteStream)(outputPath);
125
+ const archive = (0, import_archiver2.default)("tar", { gzip: true });
126
+ output.on("close", () => resolve());
127
+ archive.on("error", reject);
128
+ archive.pipe(output);
129
+ archive.directory(distDir, false);
130
+ archive.finalize();
131
+ });
132
+ return outputPath;
133
+ }
134
+ async createAppInfo(distDir) {
135
+ const pkg = await this.readPackageJson();
136
+ const appInfo = {
137
+ id: pkg.id || "com.example.app",
138
+ version: pkg.version,
139
+ vendor: "Table.js",
140
+ type: "web",
141
+ main: "index.html",
142
+ title: pkg.name,
143
+ icon: "icon.png",
144
+ largeIcon: "icon.png",
145
+ bgImage: "splash.png",
146
+ resolution: "1920x1080",
147
+ disallowScrollingInMainWindow: true
148
+ };
149
+ await import_fs_extra2.default.writeJson(import_path2.default.join(distDir, "appinfo.json"), appInfo, { spaces: 2 });
150
+ }
151
+ async readPackageJson() {
152
+ try {
153
+ const pkg = await import_fs_extra2.default.readJson("package.json");
154
+ return {
155
+ id: pkg.webosAppId || pkg.name,
156
+ name: pkg.name,
157
+ version: pkg.version,
158
+ description: pkg.description
159
+ };
160
+ } catch {
161
+ return {
162
+ id: "com.example.app",
163
+ name: "Table App",
164
+ version: "1.0.0"
165
+ };
166
+ }
167
+ }
168
+ };
169
+
170
+ // src/adapters/android.ts
171
+ var import_path3 = __toESM(require("path"));
172
+ var import_fs_extra3 = __toESM(require("fs-extra"));
173
+ var import_execa = require("execa");
174
+ var AndroidAdapter = class {
175
+ name = "Android TV";
176
+ async build(options) {
177
+ const distDir = `${options.outDir}/android`;
178
+ await this.createWebViewProject(distDir);
179
+ }
180
+ async package(distDir) {
181
+ const projectDir = import_path3.default.join(distDir, "android-project");
182
+ try {
183
+ await (0, import_execa.execa)("./gradlew", ["assembleRelease"], {
184
+ cwd: projectDir,
185
+ stdio: "inherit"
186
+ });
187
+ const apkPath = import_path3.default.join(projectDir, "app/build/outputs/apk/release/app-release.apk");
188
+ const outputPath = import_path3.default.join(distDir, "..", "app.apk");
189
+ await import_fs_extra3.default.copy(apkPath, outputPath);
190
+ return outputPath;
191
+ } catch (error) {
192
+ throw new Error("Android build failed. Make sure Android SDK is installed.");
193
+ }
194
+ }
195
+ async createWebViewProject(distDir) {
196
+ const pkg = await this.readPackageJson();
197
+ const projectDir = import_path3.default.join(distDir, "android-project");
198
+ await import_fs_extra3.default.ensureDir(projectDir);
199
+ await import_fs_extra3.default.copy(distDir, import_path3.default.join(projectDir, "app/src/main/assets/www"));
200
+ await this.createManifest(projectDir, pkg);
201
+ await this.createGradleFiles(projectDir, pkg);
202
+ await this.createMainActivity(projectDir, pkg);
203
+ }
204
+ async createManifest(projectDir, pkg) {
205
+ const manifest = `<?xml version="1.0" encoding="utf-8"?>
206
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
207
+ package="${pkg.id || "com.example.app"}">
208
+
209
+ <uses-permission android:name="android.permission.INTERNET" />
210
+ <uses-feature android:name="android.software.leanback" android:required="true" />
211
+ <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
212
+
213
+ <application
214
+ android:allowBackup="true"
215
+ android:icon="@mipmap/ic_launcher"
216
+ android:label="${pkg.name}"
217
+ android:banner="@drawable/banner"
218
+ android:theme="@style/Theme.Leanback">
219
+
220
+ <activity
221
+ android:name=".MainActivity"
222
+ android:exported="true"
223
+ android:screenOrientation="landscape">
224
+ <intent-filter>
225
+ <action android:name="android.intent.action.MAIN" />
226
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
227
+ </intent-filter>
228
+ </activity>
229
+ </application>
230
+ </manifest>`;
231
+ const manifestPath = import_path3.default.join(projectDir, "app/src/main/AndroidManifest.xml");
232
+ await import_fs_extra3.default.ensureDir(import_path3.default.dirname(manifestPath));
233
+ await import_fs_extra3.default.writeFile(manifestPath, manifest);
234
+ }
235
+ async createGradleFiles(projectDir, pkg) {
236
+ const buildGradle = `plugins {
237
+ id 'com.android.application'
238
+ }
239
+
240
+ android {
241
+ namespace '${pkg.id || "com.example.app"}'
242
+ compileSdk 34
243
+
244
+ defaultConfig {
245
+ applicationId "${pkg.id || "com.example.app"}"
246
+ minSdk 21
247
+ targetSdk 34
248
+ versionCode 1
249
+ versionName "${pkg.version}"
250
+ }
251
+
252
+ buildTypes {
253
+ release {
254
+ minifyEnabled true
255
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
256
+ }
257
+ }
258
+ }
259
+
260
+ dependencies {
261
+ implementation 'androidx.leanback:leanback:1.0.0'
262
+ }`;
263
+ await import_fs_extra3.default.writeFile(import_path3.default.join(projectDir, "app/build.gradle"), buildGradle);
264
+ }
265
+ async createMainActivity(projectDir, pkg) {
266
+ const packageName = pkg.id || "com.example.app";
267
+ const activity = `package ${packageName};
268
+
269
+ import android.app.Activity;
270
+ import android.os.Bundle;
271
+ import android.webkit.WebView;
272
+ import android.webkit.WebSettings;
273
+
274
+ public class MainActivity extends Activity {
275
+ private WebView webView;
276
+
277
+ @Override
278
+ protected void onCreate(Bundle savedInstanceState) {
279
+ super.onCreate(savedInstanceState);
280
+
281
+ webView = new WebView(this);
282
+ setContentView(webView);
283
+
284
+ WebSettings settings = webView.getSettings();
285
+ settings.setJavaScriptEnabled(true);
286
+ settings.setDomStorageEnabled(true);
287
+ settings.setAllowFileAccess(true);
288
+
289
+ webView.loadUrl("file:///android_asset/www/index.html");
290
+ }
291
+ }`;
292
+ const activityPath = import_path3.default.join(
293
+ projectDir,
294
+ `app/src/main/java/${packageName.replace(/\./g, "/")}/MainActivity.java`
295
+ );
296
+ await import_fs_extra3.default.ensureDir(import_path3.default.dirname(activityPath));
297
+ await import_fs_extra3.default.writeFile(activityPath, activity);
298
+ }
299
+ async readPackageJson() {
300
+ try {
301
+ const pkg = await import_fs_extra3.default.readJson("package.json");
302
+ return {
303
+ id: pkg.androidAppId || pkg.name.replace(/[^a-z0-9]/gi, ".").toLowerCase(),
304
+ name: pkg.name,
305
+ version: pkg.version,
306
+ description: pkg.description
307
+ };
308
+ } catch {
309
+ return {
310
+ id: "com.example.app",
311
+ name: "Table App",
312
+ version: "1.0.0"
313
+ };
314
+ }
315
+ }
316
+ };
317
+
318
+ // src/builder.ts
319
+ async function build(platform, options = {}) {
320
+ const opts = {
321
+ platform,
322
+ outDir: options.outDir || "dist",
323
+ minify: options.minify ?? true,
324
+ sourcemap: options.sourcemap ?? false
325
+ };
326
+ if (platform === "all") {
327
+ await Promise.all([
328
+ buildPlatform("tizen", opts),
329
+ buildPlatform("webos", opts),
330
+ buildPlatform("android", opts)
331
+ ]);
332
+ return;
333
+ }
334
+ await buildPlatform(platform, opts);
335
+ }
336
+ async function buildPlatform(platform, options) {
337
+ const adapter = getAdapter(platform);
338
+ await (0, import_vite.build)({
339
+ build: {
340
+ outDir: `${options.outDir}/${platform}`,
341
+ minify: options.minify,
342
+ sourcemap: options.sourcemap,
343
+ emptyOutDir: true
344
+ },
345
+ define: {
346
+ __TABLE_PLATFORM__: JSON.stringify(platform)
347
+ }
348
+ });
349
+ await adapter.build(options);
350
+ const packagePath = await adapter.package(`${options.outDir}/${platform}`);
351
+ console.log(`\u2713 ${adapter.name} package created: ${packagePath}`);
352
+ }
353
+ function getAdapter(platform) {
354
+ switch (platform) {
355
+ case "tizen":
356
+ return new TizenAdapter();
357
+ case "webos":
358
+ return new WebOSAdapter();
359
+ case "android":
360
+ return new AndroidAdapter();
361
+ default:
362
+ throw new Error(`Unknown platform: ${platform}`);
363
+ }
364
+ }
365
+ // Annotate the CommonJS export names for ESM import in node:
366
+ 0 && (module.exports = {
367
+ AndroidAdapter,
368
+ TizenAdapter,
369
+ WebOSAdapter,
370
+ build
371
+ });
372
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/builder.ts","../src/adapters/tizen.ts","../src/adapters/webos.ts","../src/adapters/android.ts"],"sourcesContent":["export { build } from './builder'\nexport type { Platform, BuildOptions, PlatformAdapter, ManifestBase } from './types'\nexport { TizenAdapter } from './adapters/tizen'\nexport { WebOSAdapter } from './adapters/webos'\nexport { AndroidAdapter } from './adapters/android'\n","import { build as viteBuild } from 'vite'\nimport type { BuildOptions, Platform, PlatformAdapter } from './types'\nimport { TizenAdapter } from './adapters/tizen'\nimport { WebOSAdapter } from './adapters/webos'\nimport { AndroidAdapter } from './adapters/android'\n\nexport async function build(platform: Platform, options: Partial<BuildOptions> = {}) {\n const opts: BuildOptions = {\n platform,\n outDir: options.outDir || 'dist',\n minify: options.minify ?? true,\n sourcemap: options.sourcemap ?? false,\n }\n\n if (platform === 'all') {\n await Promise.all([\n buildPlatform('tizen', opts),\n buildPlatform('webos', opts),\n buildPlatform('android', opts),\n ])\n return\n }\n\n await buildPlatform(platform, opts)\n}\n\nasync function buildPlatform(platform: Platform, options: BuildOptions) {\n const adapter = getAdapter(platform)\n\n await viteBuild({\n build: {\n outDir: `${options.outDir}/${platform}`,\n minify: options.minify,\n sourcemap: options.sourcemap,\n emptyOutDir: true,\n },\n define: {\n __TABLE_PLATFORM__: JSON.stringify(platform),\n },\n })\n\n await adapter.build(options)\n\n const packagePath = await adapter.package(`${options.outDir}/${platform}`)\n console.log(`✓ ${adapter.name} package created: ${packagePath}`)\n}\n\nfunction getAdapter(platform: Platform): PlatformAdapter {\n switch (platform) {\n case 'tizen':\n return new TizenAdapter()\n case 'webos':\n return new WebOSAdapter()\n case 'android':\n return new AndroidAdapter()\n default:\n throw new Error(`Unknown platform: ${platform}`)\n }\n}\n","import path from 'path'\nimport fs from 'fs-extra'\nimport archiver from 'archiver'\nimport { createWriteStream } from 'fs'\nimport type { BuildOptions, PlatformAdapter, ManifestBase } from '../types'\n\nexport class TizenAdapter implements PlatformAdapter {\n name = 'Tizen (Samsung)'\n\n async build(options: BuildOptions): Promise<void> {\n const distDir = `${options.outDir}/tizen`\n await this.createConfig(distDir)\n }\n\n async package(distDir: string): Promise<string> {\n const outputPath = path.join(distDir, '..', 'app.wgt')\n\n await new Promise<void>((resolve, reject) => {\n const output = createWriteStream(outputPath)\n const archive = archiver('zip', { zlib: { level: 9 } })\n\n output.on('close', () => resolve())\n archive.on('error', reject)\n\n archive.pipe(output)\n archive.directory(distDir, false)\n archive.finalize()\n })\n\n return outputPath\n }\n\n private async createConfig(distDir: string) {\n const pkg = await this.readPackageJson()\n\n const config = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<widget xmlns=\"http://www.w3.org/ns/widgets\" \n xmlns:tizen=\"http://tizen.org/ns/widgets\"\n id=\"${pkg.id || 'com.example.app'}\"\n version=\"${pkg.version}\"\n viewmodes=\"maximized\">\n <tizen:application id=\"${pkg.id || 'com.example.app'}.App\" \n package=\"${pkg.id || 'com.example.app'}\"\n required_version=\"6.0\"/>\n <content src=\"index.html\"/>\n <feature name=\"http://tizen.org/feature/screen.size.all\"/>\n <icon src=\"icon.png\"/>\n <name>${pkg.name}</name>\n <tizen:profile name=\"tv\"/>\n <tizen:setting screen-orientation=\"landscape\" \n context-menu=\"disable\" \n background-support=\"disable\" \n encryption=\"disable\" \n install-location=\"auto\"/>\n</widget>`\n\n await fs.writeFile(path.join(distDir, 'config.xml'), config)\n }\n\n private async readPackageJson(): Promise<ManifestBase> {\n try {\n const pkg = await fs.readJson('package.json')\n return {\n id: pkg.tizenAppId || pkg.name,\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n }\n } catch {\n return {\n id: 'com.example.app',\n name: 'Table App',\n version: '1.0.0',\n }\n }\n }\n}\n","import path from 'path'\nimport fs from 'fs-extra'\nimport archiver from 'archiver'\nimport { createWriteStream } from 'fs'\nimport type { BuildOptions, PlatformAdapter, ManifestBase } from '../types'\n\nexport class WebOSAdapter implements PlatformAdapter {\n name = 'webOS (LG)'\n\n async build(options: BuildOptions): Promise<void> {\n const distDir = `${options.outDir}/webos`\n await this.createAppInfo(distDir)\n }\n\n async package(distDir: string): Promise<string> {\n const outputPath = path.join(distDir, '..', 'app.ipk')\n\n await new Promise<void>((resolve, reject) => {\n const output = createWriteStream(outputPath)\n const archive = archiver('tar', { gzip: true })\n\n output.on('close', () => resolve())\n archive.on('error', reject)\n\n archive.pipe(output)\n archive.directory(distDir, false)\n archive.finalize()\n })\n\n return outputPath\n }\n\n private async createAppInfo(distDir: string) {\n const pkg = await this.readPackageJson()\n\n const appInfo = {\n id: pkg.id || 'com.example.app',\n version: pkg.version,\n vendor: 'Table.js',\n type: 'web',\n main: 'index.html',\n title: pkg.name,\n icon: 'icon.png',\n largeIcon: 'icon.png',\n bgImage: 'splash.png',\n resolution: '1920x1080',\n disallowScrollingInMainWindow: true,\n }\n\n await fs.writeJson(path.join(distDir, 'appinfo.json'), appInfo, { spaces: 2 })\n }\n\n private async readPackageJson(): Promise<ManifestBase> {\n try {\n const pkg = await fs.readJson('package.json')\n return {\n id: pkg.webosAppId || pkg.name,\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n }\n } catch {\n return {\n id: 'com.example.app',\n name: 'Table App',\n version: '1.0.0',\n }\n }\n }\n}\n","import path from 'path'\nimport fs from 'fs-extra'\nimport { execa } from 'execa'\nimport type { BuildOptions, PlatformAdapter, ManifestBase } from '../types'\n\nexport class AndroidAdapter implements PlatformAdapter {\n name = 'Android TV'\n\n async build(options: BuildOptions): Promise<void> {\n const distDir = `${options.outDir}/android`\n await this.createWebViewProject(distDir)\n }\n\n async package(distDir: string): Promise<string> {\n const projectDir = path.join(distDir, 'android-project')\n\n try {\n await execa('./gradlew', ['assembleRelease'], {\n cwd: projectDir,\n stdio: 'inherit',\n })\n\n const apkPath = path.join(projectDir, 'app/build/outputs/apk/release/app-release.apk')\n\n const outputPath = path.join(distDir, '..', 'app.apk')\n await fs.copy(apkPath, outputPath)\n\n return outputPath\n } catch (error) {\n throw new Error('Android build failed. Make sure Android SDK is installed.')\n }\n }\n\n private async createWebViewProject(distDir: string) {\n const pkg = await this.readPackageJson()\n const projectDir = path.join(distDir, 'android-project')\n\n await fs.ensureDir(projectDir)\n await fs.copy(distDir, path.join(projectDir, 'app/src/main/assets/www'))\n\n await this.createManifest(projectDir, pkg)\n await this.createGradleFiles(projectDir, pkg)\n await this.createMainActivity(projectDir, pkg)\n }\n\n private async createManifest(projectDir: string, pkg: ManifestBase) {\n const manifest = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"${pkg.id || 'com.example.app'}\">\n\n <uses-permission android:name=\"android.permission.INTERNET\" />\n <uses-feature android:name=\"android.software.leanback\" android:required=\"true\" />\n <uses-feature android:name=\"android.hardware.touchscreen\" android:required=\"false\" />\n\n <application\n android:allowBackup=\"true\"\n android:icon=\"@mipmap/ic_launcher\"\n android:label=\"${pkg.name}\"\n android:banner=\"@drawable/banner\"\n android:theme=\"@style/Theme.Leanback\">\n \n <activity\n android:name=\".MainActivity\"\n android:exported=\"true\"\n android:screenOrientation=\"landscape\">\n <intent-filter>\n <action android:name=\"android.intent.action.MAIN\" />\n <category android:name=\"android.intent.category.LEANBACK_LAUNCHER\" />\n </intent-filter>\n </activity>\n </application>\n</manifest>`\n\n const manifestPath = path.join(projectDir, 'app/src/main/AndroidManifest.xml')\n await fs.ensureDir(path.dirname(manifestPath))\n await fs.writeFile(manifestPath, manifest)\n }\n\n private async createGradleFiles(projectDir: string, pkg: ManifestBase) {\n const buildGradle = `plugins {\n id 'com.android.application'\n}\n\nandroid {\n namespace '${pkg.id || 'com.example.app'}'\n compileSdk 34\n\n defaultConfig {\n applicationId \"${pkg.id || 'com.example.app'}\"\n minSdk 21\n targetSdk 34\n versionCode 1\n versionName \"${pkg.version}\"\n }\n\n buildTypes {\n release {\n minifyEnabled true\n proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')\n }\n }\n}\n\ndependencies {\n implementation 'androidx.leanback:leanback:1.0.0'\n}`\n\n await fs.writeFile(path.join(projectDir, 'app/build.gradle'), buildGradle)\n }\n\n private async createMainActivity(projectDir: string, pkg: ManifestBase) {\n const packageName = pkg.id || 'com.example.app'\n const activity = `package ${packageName};\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.webkit.WebView;\nimport android.webkit.WebSettings;\n\npublic class MainActivity extends Activity {\n private WebView webView;\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n \n webView = new WebView(this);\n setContentView(webView);\n \n WebSettings settings = webView.getSettings();\n settings.setJavaScriptEnabled(true);\n settings.setDomStorageEnabled(true);\n settings.setAllowFileAccess(true);\n \n webView.loadUrl(\"file:///android_asset/www/index.html\");\n }\n}`\n\n const activityPath = path.join(\n projectDir,\n `app/src/main/java/${packageName.replace(/\\./g, '/')}/MainActivity.java`,\n )\n await fs.ensureDir(path.dirname(activityPath))\n await fs.writeFile(activityPath, activity)\n }\n\n private async readPackageJson(): Promise<ManifestBase> {\n try {\n const pkg = await fs.readJson('package.json')\n return {\n id: pkg.androidAppId || pkg.name.replace(/[^a-z0-9]/gi, '.').toLowerCase(),\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n }\n } catch {\n return {\n id: 'com.example.app',\n name: 'Table App',\n version: '1.0.0',\n }\n }\n }\n}\n"],"mappings":"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","names":["path","archiver","fs","import_path","import_fs_extra","import_archiver","import_fs","path","archiver","fs","import_path","import_fs_extra","path","fs","viteBuild"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,332 @@
1
+ // src/builder.ts
2
+ import { build as viteBuild } from "vite";
3
+
4
+ // src/adapters/tizen.ts
5
+ import path from "path";
6
+ import fs from "fs-extra";
7
+ import archiver from "archiver";
8
+ import { createWriteStream } from "fs";
9
+ var TizenAdapter = class {
10
+ name = "Tizen (Samsung)";
11
+ async build(options) {
12
+ const distDir = `${options.outDir}/tizen`;
13
+ await this.createConfig(distDir);
14
+ }
15
+ async package(distDir) {
16
+ const outputPath = path.join(distDir, "..", "app.wgt");
17
+ await new Promise((resolve, reject) => {
18
+ const output = createWriteStream(outputPath);
19
+ const archive = archiver("zip", { zlib: { level: 9 } });
20
+ output.on("close", () => resolve());
21
+ archive.on("error", reject);
22
+ archive.pipe(output);
23
+ archive.directory(distDir, false);
24
+ archive.finalize();
25
+ });
26
+ return outputPath;
27
+ }
28
+ async createConfig(distDir) {
29
+ const pkg = await this.readPackageJson();
30
+ const config = `<?xml version="1.0" encoding="UTF-8"?>
31
+ <widget xmlns="http://www.w3.org/ns/widgets"
32
+ xmlns:tizen="http://tizen.org/ns/widgets"
33
+ id="${pkg.id || "com.example.app"}"
34
+ version="${pkg.version}"
35
+ viewmodes="maximized">
36
+ <tizen:application id="${pkg.id || "com.example.app"}.App"
37
+ package="${pkg.id || "com.example.app"}"
38
+ required_version="6.0"/>
39
+ <content src="index.html"/>
40
+ <feature name="http://tizen.org/feature/screen.size.all"/>
41
+ <icon src="icon.png"/>
42
+ <name>${pkg.name}</name>
43
+ <tizen:profile name="tv"/>
44
+ <tizen:setting screen-orientation="landscape"
45
+ context-menu="disable"
46
+ background-support="disable"
47
+ encryption="disable"
48
+ install-location="auto"/>
49
+ </widget>`;
50
+ await fs.writeFile(path.join(distDir, "config.xml"), config);
51
+ }
52
+ async readPackageJson() {
53
+ try {
54
+ const pkg = await fs.readJson("package.json");
55
+ return {
56
+ id: pkg.tizenAppId || pkg.name,
57
+ name: pkg.name,
58
+ version: pkg.version,
59
+ description: pkg.description
60
+ };
61
+ } catch {
62
+ return {
63
+ id: "com.example.app",
64
+ name: "Table App",
65
+ version: "1.0.0"
66
+ };
67
+ }
68
+ }
69
+ };
70
+
71
+ // src/adapters/webos.ts
72
+ import path2 from "path";
73
+ import fs2 from "fs-extra";
74
+ import archiver2 from "archiver";
75
+ import { createWriteStream as createWriteStream2 } from "fs";
76
+ var WebOSAdapter = class {
77
+ name = "webOS (LG)";
78
+ async build(options) {
79
+ const distDir = `${options.outDir}/webos`;
80
+ await this.createAppInfo(distDir);
81
+ }
82
+ async package(distDir) {
83
+ const outputPath = path2.join(distDir, "..", "app.ipk");
84
+ await new Promise((resolve, reject) => {
85
+ const output = createWriteStream2(outputPath);
86
+ const archive = archiver2("tar", { gzip: true });
87
+ output.on("close", () => resolve());
88
+ archive.on("error", reject);
89
+ archive.pipe(output);
90
+ archive.directory(distDir, false);
91
+ archive.finalize();
92
+ });
93
+ return outputPath;
94
+ }
95
+ async createAppInfo(distDir) {
96
+ const pkg = await this.readPackageJson();
97
+ const appInfo = {
98
+ id: pkg.id || "com.example.app",
99
+ version: pkg.version,
100
+ vendor: "Table.js",
101
+ type: "web",
102
+ main: "index.html",
103
+ title: pkg.name,
104
+ icon: "icon.png",
105
+ largeIcon: "icon.png",
106
+ bgImage: "splash.png",
107
+ resolution: "1920x1080",
108
+ disallowScrollingInMainWindow: true
109
+ };
110
+ await fs2.writeJson(path2.join(distDir, "appinfo.json"), appInfo, { spaces: 2 });
111
+ }
112
+ async readPackageJson() {
113
+ try {
114
+ const pkg = await fs2.readJson("package.json");
115
+ return {
116
+ id: pkg.webosAppId || pkg.name,
117
+ name: pkg.name,
118
+ version: pkg.version,
119
+ description: pkg.description
120
+ };
121
+ } catch {
122
+ return {
123
+ id: "com.example.app",
124
+ name: "Table App",
125
+ version: "1.0.0"
126
+ };
127
+ }
128
+ }
129
+ };
130
+
131
+ // src/adapters/android.ts
132
+ import path3 from "path";
133
+ import fs3 from "fs-extra";
134
+ import { execa } from "execa";
135
+ var AndroidAdapter = class {
136
+ name = "Android TV";
137
+ async build(options) {
138
+ const distDir = `${options.outDir}/android`;
139
+ await this.createWebViewProject(distDir);
140
+ }
141
+ async package(distDir) {
142
+ const projectDir = path3.join(distDir, "android-project");
143
+ try {
144
+ await execa("./gradlew", ["assembleRelease"], {
145
+ cwd: projectDir,
146
+ stdio: "inherit"
147
+ });
148
+ const apkPath = path3.join(projectDir, "app/build/outputs/apk/release/app-release.apk");
149
+ const outputPath = path3.join(distDir, "..", "app.apk");
150
+ await fs3.copy(apkPath, outputPath);
151
+ return outputPath;
152
+ } catch (error) {
153
+ throw new Error("Android build failed. Make sure Android SDK is installed.");
154
+ }
155
+ }
156
+ async createWebViewProject(distDir) {
157
+ const pkg = await this.readPackageJson();
158
+ const projectDir = path3.join(distDir, "android-project");
159
+ await fs3.ensureDir(projectDir);
160
+ await fs3.copy(distDir, path3.join(projectDir, "app/src/main/assets/www"));
161
+ await this.createManifest(projectDir, pkg);
162
+ await this.createGradleFiles(projectDir, pkg);
163
+ await this.createMainActivity(projectDir, pkg);
164
+ }
165
+ async createManifest(projectDir, pkg) {
166
+ const manifest = `<?xml version="1.0" encoding="utf-8"?>
167
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
168
+ package="${pkg.id || "com.example.app"}">
169
+
170
+ <uses-permission android:name="android.permission.INTERNET" />
171
+ <uses-feature android:name="android.software.leanback" android:required="true" />
172
+ <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
173
+
174
+ <application
175
+ android:allowBackup="true"
176
+ android:icon="@mipmap/ic_launcher"
177
+ android:label="${pkg.name}"
178
+ android:banner="@drawable/banner"
179
+ android:theme="@style/Theme.Leanback">
180
+
181
+ <activity
182
+ android:name=".MainActivity"
183
+ android:exported="true"
184
+ android:screenOrientation="landscape">
185
+ <intent-filter>
186
+ <action android:name="android.intent.action.MAIN" />
187
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
188
+ </intent-filter>
189
+ </activity>
190
+ </application>
191
+ </manifest>`;
192
+ const manifestPath = path3.join(projectDir, "app/src/main/AndroidManifest.xml");
193
+ await fs3.ensureDir(path3.dirname(manifestPath));
194
+ await fs3.writeFile(manifestPath, manifest);
195
+ }
196
+ async createGradleFiles(projectDir, pkg) {
197
+ const buildGradle = `plugins {
198
+ id 'com.android.application'
199
+ }
200
+
201
+ android {
202
+ namespace '${pkg.id || "com.example.app"}'
203
+ compileSdk 34
204
+
205
+ defaultConfig {
206
+ applicationId "${pkg.id || "com.example.app"}"
207
+ minSdk 21
208
+ targetSdk 34
209
+ versionCode 1
210
+ versionName "${pkg.version}"
211
+ }
212
+
213
+ buildTypes {
214
+ release {
215
+ minifyEnabled true
216
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
217
+ }
218
+ }
219
+ }
220
+
221
+ dependencies {
222
+ implementation 'androidx.leanback:leanback:1.0.0'
223
+ }`;
224
+ await fs3.writeFile(path3.join(projectDir, "app/build.gradle"), buildGradle);
225
+ }
226
+ async createMainActivity(projectDir, pkg) {
227
+ const packageName = pkg.id || "com.example.app";
228
+ const activity = `package ${packageName};
229
+
230
+ import android.app.Activity;
231
+ import android.os.Bundle;
232
+ import android.webkit.WebView;
233
+ import android.webkit.WebSettings;
234
+
235
+ public class MainActivity extends Activity {
236
+ private WebView webView;
237
+
238
+ @Override
239
+ protected void onCreate(Bundle savedInstanceState) {
240
+ super.onCreate(savedInstanceState);
241
+
242
+ webView = new WebView(this);
243
+ setContentView(webView);
244
+
245
+ WebSettings settings = webView.getSettings();
246
+ settings.setJavaScriptEnabled(true);
247
+ settings.setDomStorageEnabled(true);
248
+ settings.setAllowFileAccess(true);
249
+
250
+ webView.loadUrl("file:///android_asset/www/index.html");
251
+ }
252
+ }`;
253
+ const activityPath = path3.join(
254
+ projectDir,
255
+ `app/src/main/java/${packageName.replace(/\./g, "/")}/MainActivity.java`
256
+ );
257
+ await fs3.ensureDir(path3.dirname(activityPath));
258
+ await fs3.writeFile(activityPath, activity);
259
+ }
260
+ async readPackageJson() {
261
+ try {
262
+ const pkg = await fs3.readJson("package.json");
263
+ return {
264
+ id: pkg.androidAppId || pkg.name.replace(/[^a-z0-9]/gi, ".").toLowerCase(),
265
+ name: pkg.name,
266
+ version: pkg.version,
267
+ description: pkg.description
268
+ };
269
+ } catch {
270
+ return {
271
+ id: "com.example.app",
272
+ name: "Table App",
273
+ version: "1.0.0"
274
+ };
275
+ }
276
+ }
277
+ };
278
+
279
+ // src/builder.ts
280
+ async function build(platform, options = {}) {
281
+ const opts = {
282
+ platform,
283
+ outDir: options.outDir || "dist",
284
+ minify: options.minify ?? true,
285
+ sourcemap: options.sourcemap ?? false
286
+ };
287
+ if (platform === "all") {
288
+ await Promise.all([
289
+ buildPlatform("tizen", opts),
290
+ buildPlatform("webos", opts),
291
+ buildPlatform("android", opts)
292
+ ]);
293
+ return;
294
+ }
295
+ await buildPlatform(platform, opts);
296
+ }
297
+ async function buildPlatform(platform, options) {
298
+ const adapter = getAdapter(platform);
299
+ await viteBuild({
300
+ build: {
301
+ outDir: `${options.outDir}/${platform}`,
302
+ minify: options.minify,
303
+ sourcemap: options.sourcemap,
304
+ emptyOutDir: true
305
+ },
306
+ define: {
307
+ __TABLE_PLATFORM__: JSON.stringify(platform)
308
+ }
309
+ });
310
+ await adapter.build(options);
311
+ const packagePath = await adapter.package(`${options.outDir}/${platform}`);
312
+ console.log(`\u2713 ${adapter.name} package created: ${packagePath}`);
313
+ }
314
+ function getAdapter(platform) {
315
+ switch (platform) {
316
+ case "tizen":
317
+ return new TizenAdapter();
318
+ case "webos":
319
+ return new WebOSAdapter();
320
+ case "android":
321
+ return new AndroidAdapter();
322
+ default:
323
+ throw new Error(`Unknown platform: ${platform}`);
324
+ }
325
+ }
326
+ export {
327
+ AndroidAdapter,
328
+ TizenAdapter,
329
+ WebOSAdapter,
330
+ build
331
+ };
332
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/builder.ts","../src/adapters/tizen.ts","../src/adapters/webos.ts","../src/adapters/android.ts"],"sourcesContent":["import { build as viteBuild } from 'vite'\nimport type { BuildOptions, Platform, PlatformAdapter } from './types'\nimport { TizenAdapter } from './adapters/tizen'\nimport { WebOSAdapter } from './adapters/webos'\nimport { AndroidAdapter } from './adapters/android'\n\nexport async function build(platform: Platform, options: Partial<BuildOptions> = {}) {\n const opts: BuildOptions = {\n platform,\n outDir: options.outDir || 'dist',\n minify: options.minify ?? true,\n sourcemap: options.sourcemap ?? false,\n }\n\n if (platform === 'all') {\n await Promise.all([\n buildPlatform('tizen', opts),\n buildPlatform('webos', opts),\n buildPlatform('android', opts),\n ])\n return\n }\n\n await buildPlatform(platform, opts)\n}\n\nasync function buildPlatform(platform: Platform, options: BuildOptions) {\n const adapter = getAdapter(platform)\n\n await viteBuild({\n build: {\n outDir: `${options.outDir}/${platform}`,\n minify: options.minify,\n sourcemap: options.sourcemap,\n emptyOutDir: true,\n },\n define: {\n __TABLE_PLATFORM__: JSON.stringify(platform),\n },\n })\n\n await adapter.build(options)\n\n const packagePath = await adapter.package(`${options.outDir}/${platform}`)\n console.log(`✓ ${adapter.name} package created: ${packagePath}`)\n}\n\nfunction getAdapter(platform: Platform): PlatformAdapter {\n switch (platform) {\n case 'tizen':\n return new TizenAdapter()\n case 'webos':\n return new WebOSAdapter()\n case 'android':\n return new AndroidAdapter()\n default:\n throw new Error(`Unknown platform: ${platform}`)\n }\n}\n","import path from 'path'\nimport fs from 'fs-extra'\nimport archiver from 'archiver'\nimport { createWriteStream } from 'fs'\nimport type { BuildOptions, PlatformAdapter, ManifestBase } from '../types'\n\nexport class TizenAdapter implements PlatformAdapter {\n name = 'Tizen (Samsung)'\n\n async build(options: BuildOptions): Promise<void> {\n const distDir = `${options.outDir}/tizen`\n await this.createConfig(distDir)\n }\n\n async package(distDir: string): Promise<string> {\n const outputPath = path.join(distDir, '..', 'app.wgt')\n\n await new Promise<void>((resolve, reject) => {\n const output = createWriteStream(outputPath)\n const archive = archiver('zip', { zlib: { level: 9 } })\n\n output.on('close', () => resolve())\n archive.on('error', reject)\n\n archive.pipe(output)\n archive.directory(distDir, false)\n archive.finalize()\n })\n\n return outputPath\n }\n\n private async createConfig(distDir: string) {\n const pkg = await this.readPackageJson()\n\n const config = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<widget xmlns=\"http://www.w3.org/ns/widgets\" \n xmlns:tizen=\"http://tizen.org/ns/widgets\"\n id=\"${pkg.id || 'com.example.app'}\"\n version=\"${pkg.version}\"\n viewmodes=\"maximized\">\n <tizen:application id=\"${pkg.id || 'com.example.app'}.App\" \n package=\"${pkg.id || 'com.example.app'}\"\n required_version=\"6.0\"/>\n <content src=\"index.html\"/>\n <feature name=\"http://tizen.org/feature/screen.size.all\"/>\n <icon src=\"icon.png\"/>\n <name>${pkg.name}</name>\n <tizen:profile name=\"tv\"/>\n <tizen:setting screen-orientation=\"landscape\" \n context-menu=\"disable\" \n background-support=\"disable\" \n encryption=\"disable\" \n install-location=\"auto\"/>\n</widget>`\n\n await fs.writeFile(path.join(distDir, 'config.xml'), config)\n }\n\n private async readPackageJson(): Promise<ManifestBase> {\n try {\n const pkg = await fs.readJson('package.json')\n return {\n id: pkg.tizenAppId || pkg.name,\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n }\n } catch {\n return {\n id: 'com.example.app',\n name: 'Table App',\n version: '1.0.0',\n }\n }\n }\n}\n","import path from 'path'\nimport fs from 'fs-extra'\nimport archiver from 'archiver'\nimport { createWriteStream } from 'fs'\nimport type { BuildOptions, PlatformAdapter, ManifestBase } from '../types'\n\nexport class WebOSAdapter implements PlatformAdapter {\n name = 'webOS (LG)'\n\n async build(options: BuildOptions): Promise<void> {\n const distDir = `${options.outDir}/webos`\n await this.createAppInfo(distDir)\n }\n\n async package(distDir: string): Promise<string> {\n const outputPath = path.join(distDir, '..', 'app.ipk')\n\n await new Promise<void>((resolve, reject) => {\n const output = createWriteStream(outputPath)\n const archive = archiver('tar', { gzip: true })\n\n output.on('close', () => resolve())\n archive.on('error', reject)\n\n archive.pipe(output)\n archive.directory(distDir, false)\n archive.finalize()\n })\n\n return outputPath\n }\n\n private async createAppInfo(distDir: string) {\n const pkg = await this.readPackageJson()\n\n const appInfo = {\n id: pkg.id || 'com.example.app',\n version: pkg.version,\n vendor: 'Table.js',\n type: 'web',\n main: 'index.html',\n title: pkg.name,\n icon: 'icon.png',\n largeIcon: 'icon.png',\n bgImage: 'splash.png',\n resolution: '1920x1080',\n disallowScrollingInMainWindow: true,\n }\n\n await fs.writeJson(path.join(distDir, 'appinfo.json'), appInfo, { spaces: 2 })\n }\n\n private async readPackageJson(): Promise<ManifestBase> {\n try {\n const pkg = await fs.readJson('package.json')\n return {\n id: pkg.webosAppId || pkg.name,\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n }\n } catch {\n return {\n id: 'com.example.app',\n name: 'Table App',\n version: '1.0.0',\n }\n }\n }\n}\n","import path from 'path'\nimport fs from 'fs-extra'\nimport { execa } from 'execa'\nimport type { BuildOptions, PlatformAdapter, ManifestBase } from '../types'\n\nexport class AndroidAdapter implements PlatformAdapter {\n name = 'Android TV'\n\n async build(options: BuildOptions): Promise<void> {\n const distDir = `${options.outDir}/android`\n await this.createWebViewProject(distDir)\n }\n\n async package(distDir: string): Promise<string> {\n const projectDir = path.join(distDir, 'android-project')\n\n try {\n await execa('./gradlew', ['assembleRelease'], {\n cwd: projectDir,\n stdio: 'inherit',\n })\n\n const apkPath = path.join(projectDir, 'app/build/outputs/apk/release/app-release.apk')\n\n const outputPath = path.join(distDir, '..', 'app.apk')\n await fs.copy(apkPath, outputPath)\n\n return outputPath\n } catch (error) {\n throw new Error('Android build failed. Make sure Android SDK is installed.')\n }\n }\n\n private async createWebViewProject(distDir: string) {\n const pkg = await this.readPackageJson()\n const projectDir = path.join(distDir, 'android-project')\n\n await fs.ensureDir(projectDir)\n await fs.copy(distDir, path.join(projectDir, 'app/src/main/assets/www'))\n\n await this.createManifest(projectDir, pkg)\n await this.createGradleFiles(projectDir, pkg)\n await this.createMainActivity(projectDir, pkg)\n }\n\n private async createManifest(projectDir: string, pkg: ManifestBase) {\n const manifest = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"${pkg.id || 'com.example.app'}\">\n\n <uses-permission android:name=\"android.permission.INTERNET\" />\n <uses-feature android:name=\"android.software.leanback\" android:required=\"true\" />\n <uses-feature android:name=\"android.hardware.touchscreen\" android:required=\"false\" />\n\n <application\n android:allowBackup=\"true\"\n android:icon=\"@mipmap/ic_launcher\"\n android:label=\"${pkg.name}\"\n android:banner=\"@drawable/banner\"\n android:theme=\"@style/Theme.Leanback\">\n \n <activity\n android:name=\".MainActivity\"\n android:exported=\"true\"\n android:screenOrientation=\"landscape\">\n <intent-filter>\n <action android:name=\"android.intent.action.MAIN\" />\n <category android:name=\"android.intent.category.LEANBACK_LAUNCHER\" />\n </intent-filter>\n </activity>\n </application>\n</manifest>`\n\n const manifestPath = path.join(projectDir, 'app/src/main/AndroidManifest.xml')\n await fs.ensureDir(path.dirname(manifestPath))\n await fs.writeFile(manifestPath, manifest)\n }\n\n private async createGradleFiles(projectDir: string, pkg: ManifestBase) {\n const buildGradle = `plugins {\n id 'com.android.application'\n}\n\nandroid {\n namespace '${pkg.id || 'com.example.app'}'\n compileSdk 34\n\n defaultConfig {\n applicationId \"${pkg.id || 'com.example.app'}\"\n minSdk 21\n targetSdk 34\n versionCode 1\n versionName \"${pkg.version}\"\n }\n\n buildTypes {\n release {\n minifyEnabled true\n proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')\n }\n }\n}\n\ndependencies {\n implementation 'androidx.leanback:leanback:1.0.0'\n}`\n\n await fs.writeFile(path.join(projectDir, 'app/build.gradle'), buildGradle)\n }\n\n private async createMainActivity(projectDir: string, pkg: ManifestBase) {\n const packageName = pkg.id || 'com.example.app'\n const activity = `package ${packageName};\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.webkit.WebView;\nimport android.webkit.WebSettings;\n\npublic class MainActivity extends Activity {\n private WebView webView;\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n \n webView = new WebView(this);\n setContentView(webView);\n \n WebSettings settings = webView.getSettings();\n settings.setJavaScriptEnabled(true);\n settings.setDomStorageEnabled(true);\n settings.setAllowFileAccess(true);\n \n webView.loadUrl(\"file:///android_asset/www/index.html\");\n }\n}`\n\n const activityPath = path.join(\n projectDir,\n `app/src/main/java/${packageName.replace(/\\./g, '/')}/MainActivity.java`,\n )\n await fs.ensureDir(path.dirname(activityPath))\n await fs.writeFile(activityPath, activity)\n }\n\n private async readPackageJson(): Promise<ManifestBase> {\n try {\n const pkg = await fs.readJson('package.json')\n return {\n id: pkg.androidAppId || pkg.name.replace(/[^a-z0-9]/gi, '.').toLowerCase(),\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n }\n } catch {\n return {\n id: 'com.example.app',\n name: 'Table App',\n version: '1.0.0',\n }\n }\n }\n}\n"],"mappings":"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","names":["path","fs","archiver","createWriteStream","path","fs"]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@table-js/platform",
3
+ "version": "0.0.1",
4
+ "description": "Table.js platform adapters and build tools for Smart TV",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "table": "./dist/cli.mjs"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "typecheck": "tsc --noEmit",
25
+ "clean": "rm -rf dist"
26
+ },
27
+ "keywords": [
28
+ "smart-tv",
29
+ "tizen",
30
+ "webos",
31
+ "android-tv",
32
+ "build-tool",
33
+ "vite"
34
+ ],
35
+ "author": "Table.js Team",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/tablejs/tablejs"
40
+ },
41
+ "dependencies": {
42
+ "vite": "^6.4.1",
43
+ "chalk": "^5.6.2",
44
+ "commander": "^12.1.0",
45
+ "execa": "^8.0.1",
46
+ "fs-extra": "^11.3.4",
47
+ "archiver": "^7.0.1",
48
+ "ora": "^8.2.0"
49
+ },
50
+ "devDependencies": {
51
+ "@table/tsconfig": "workspace:*",
52
+ "@types/archiver": "^7.0.0",
53
+ "@types/fs-extra": "^11.0.4",
54
+ "@types/node": "^25.5.0",
55
+ "tsup": "^8.0.1",
56
+ "typescript": "^5.3.3"
57
+ }
58
+ }