@putdotio/taizn 1.0.1 → 1.2.0
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 +19 -2
- package/dist/taizn.mjs +48 -8
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ locally.
|
|
|
28
28
|
Create `taizn.json` in the app directory, keep `.taizn/` ignored, then run:
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
+
pnpm exec taizn check
|
|
31
32
|
pnpm exec taizn package
|
|
32
33
|
pnpm exec taizn install
|
|
33
34
|
```
|
|
@@ -42,18 +43,24 @@ Project files:
|
|
|
42
43
|
## Commands
|
|
43
44
|
|
|
44
45
|
```bash
|
|
46
|
+
taizn check
|
|
45
47
|
taizn profile
|
|
46
48
|
taizn package
|
|
47
49
|
taizn install
|
|
48
50
|
taizn --version
|
|
49
51
|
```
|
|
50
52
|
|
|
51
|
-
`
|
|
53
|
+
`check` verifies the configured Tizen CLI and `sdb`, then prints connected
|
|
54
|
+
targets without requiring `taizn.json`. `profile` imports
|
|
55
|
+
`.taizn/certificates/author.p12` and
|
|
52
56
|
`.taizn/certificates/distributor.p12` into a Tizen security profile.
|
|
53
57
|
`package` builds and signs a `.wgt`. `install` packages and sideloads it.
|
|
54
58
|
|
|
55
59
|
## Environment
|
|
56
60
|
|
|
61
|
+
Copy [.env.example](./.env.example) into `.taizn/.env` or export values in the
|
|
62
|
+
shell:
|
|
63
|
+
|
|
57
64
|
```bash
|
|
58
65
|
TAIZN_CERT_PASSWORD=...
|
|
59
66
|
TAIZN_DIST_PASSWORD=...
|
|
@@ -78,6 +85,7 @@ TAIZN_SDB=~/tizen-studio/tools/sdb
|
|
|
78
85
|
},
|
|
79
86
|
"widget": {
|
|
80
87
|
"configXml": "platforms/tizen/config.xml",
|
|
88
|
+
"excludeFiles": ["js/main.js.map", "css/main.css.map"],
|
|
81
89
|
"indexHtml": "platforms/tizen/index.html",
|
|
82
90
|
"injectWebapis": true,
|
|
83
91
|
"rewriteAssetUrls": false,
|
|
@@ -92,15 +100,24 @@ TAIZN_SDB=~/tizen-studio/tools/sdb
|
|
|
92
100
|
"production": {
|
|
93
101
|
"applicationId": "Example.app",
|
|
94
102
|
"bundleName": "example",
|
|
103
|
+
"excludeFiles": ["js/main.js.LICENSE.txt"],
|
|
95
104
|
"icon": "platforms/tizen/icon.png",
|
|
105
|
+
"indexHtml": "platforms/tizen/hosted.html",
|
|
106
|
+
"injectWebapis": true,
|
|
96
107
|
"name": "Example",
|
|
97
|
-
"packageId": "Example"
|
|
108
|
+
"packageId": "Example",
|
|
109
|
+
"rewriteAssetUrls": false
|
|
98
110
|
}
|
|
99
111
|
}
|
|
100
112
|
}
|
|
101
113
|
}
|
|
102
114
|
```
|
|
103
115
|
|
|
116
|
+
Variant `indexHtml`, `injectWebapis`, and `rewriteAssetUrls` values override
|
|
117
|
+
the top-level `widget` values. Variant `excludeFiles` values are added to
|
|
118
|
+
top-level `widget.excludeFiles`. Use them when development packages should
|
|
119
|
+
bundle local app assets but production packages should load hosted asset URLs.
|
|
120
|
+
|
|
104
121
|
## Docs
|
|
105
122
|
|
|
106
123
|
- [Contributing](./CONTRIBUTING.md)
|
package/dist/taizn.mjs
CHANGED
|
@@ -102,9 +102,13 @@ const readSecret = (prompt) => new Promise((resolve) => {
|
|
|
102
102
|
const TizenVariantSchema = Schema.Struct({
|
|
103
103
|
applicationId: Schema.NonEmptyString,
|
|
104
104
|
bundleName: Schema.NonEmptyString,
|
|
105
|
+
excludeFiles: Schema.optional(Schema.Array(Schema.NonEmptyString)),
|
|
105
106
|
icon: Schema.NonEmptyString,
|
|
107
|
+
indexHtml: Schema.optional(Schema.NonEmptyString),
|
|
108
|
+
injectWebapis: Schema.optional(Schema.Boolean),
|
|
106
109
|
name: Schema.NonEmptyString,
|
|
107
|
-
packageId: Schema.NonEmptyString
|
|
110
|
+
packageId: Schema.NonEmptyString,
|
|
111
|
+
rewriteAssetUrls: Schema.optional(Schema.Boolean)
|
|
108
112
|
});
|
|
109
113
|
const TizenConfigSchema = Schema.Struct({
|
|
110
114
|
build: Schema.Struct({
|
|
@@ -118,6 +122,7 @@ const TizenConfigSchema = Schema.Struct({
|
|
|
118
122
|
}),
|
|
119
123
|
widget: Schema.Struct({
|
|
120
124
|
configXml: Schema.NonEmptyString,
|
|
125
|
+
excludeFiles: Schema.optional(Schema.Array(Schema.NonEmptyString)),
|
|
121
126
|
indexHtml: Schema.NonEmptyString,
|
|
122
127
|
injectWebapis: Schema.optional(Schema.Boolean),
|
|
123
128
|
rewriteAssetUrls: Schema.optional(Schema.Boolean),
|
|
@@ -191,6 +196,19 @@ const setXmlAttribute = (tag, attribute, value) => {
|
|
|
191
196
|
};
|
|
192
197
|
//#endregion
|
|
193
198
|
//#region src/tizen.ts
|
|
199
|
+
const checkTizen = (env) => {
|
|
200
|
+
const tizenPath = tizenCli(env.tizenCli);
|
|
201
|
+
const sdbPath = sdb(env.sdb);
|
|
202
|
+
const devices = listSdbDevices(sdbPath);
|
|
203
|
+
console.log(`Tizen CLI: ${tizenPath}`);
|
|
204
|
+
console.log(`sdb: ${sdbPath}`);
|
|
205
|
+
if (devices.length === 0) {
|
|
206
|
+
console.log("connected targets: none");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
console.log("connected targets:");
|
|
210
|
+
for (const device of devices) console.log(`- ${device.id}${device.label ? ` (${device.label})` : ""}`);
|
|
211
|
+
};
|
|
194
212
|
const createProfile = async ({ config, env }) => {
|
|
195
213
|
const password = await readPassword(env.certPassword, "Tizen certificate password: ");
|
|
196
214
|
if (!password) fail("TAIZN_CERT_PASSWORD is required to create the signing profile.");
|
|
@@ -216,8 +234,9 @@ const createProfile = async ({ config, env }) => {
|
|
|
216
234
|
};
|
|
217
235
|
const packageWidget = ({ config, env }) => {
|
|
218
236
|
const [command, ...args] = config.build.command;
|
|
237
|
+
const variant = getVariant(config, env.variant);
|
|
219
238
|
run(command, args, { env: appBuildEnv() });
|
|
220
|
-
stageWidget(config,
|
|
239
|
+
stageWidget(config, variant);
|
|
221
240
|
run(tizenCli(env.tizenCli), [
|
|
222
241
|
"package",
|
|
223
242
|
"-t",
|
|
@@ -230,7 +249,7 @@ const packageWidget = ({ config, env }) => {
|
|
|
230
249
|
stageDir
|
|
231
250
|
]);
|
|
232
251
|
const built = findBuiltWidget();
|
|
233
|
-
const installable = join(outputDir, `${
|
|
252
|
+
const installable = join(outputDir, `${variant.bundleName}.wgt`);
|
|
234
253
|
if (built !== installable) copyFileSync(built, installable);
|
|
235
254
|
console.log(`Packaged ${installable}`);
|
|
236
255
|
return installable;
|
|
@@ -248,6 +267,12 @@ const installWidget = (context) => {
|
|
|
248
267
|
run(tizenCli(context.env.tizenCli), installArgs);
|
|
249
268
|
};
|
|
250
269
|
const getVariant = (config, variant) => config.widget.variants[variant];
|
|
270
|
+
const getWidgetStageOptions = (config, variant) => ({
|
|
271
|
+
excludeFiles: [...config.widget.excludeFiles ?? [], ...variant.excludeFiles ?? []],
|
|
272
|
+
indexHtml: variant.indexHtml ?? config.widget.indexHtml,
|
|
273
|
+
injectWebapis: variant.injectWebapis ?? config.widget.injectWebapis,
|
|
274
|
+
rewriteAssetUrls: variant.rewriteAssetUrls ?? config.widget.rewriteAssetUrls
|
|
275
|
+
});
|
|
251
276
|
const getCertificates = (config) => {
|
|
252
277
|
const certificatesDir = appPath(config.signing.certificateDir);
|
|
253
278
|
return {
|
|
@@ -262,12 +287,12 @@ const rewriteConfigForWidget = (variant) => {
|
|
|
262
287
|
widgetConfig = widgetConfig.replace(/<name>[^<]*<\/name>/, `<name>${escapeXml(variant.name)}</name>`);
|
|
263
288
|
writeFileSync(targetPath, widgetConfig);
|
|
264
289
|
};
|
|
265
|
-
const rewriteIndexForWidget = (
|
|
290
|
+
const rewriteIndexForWidget = (options) => {
|
|
266
291
|
const targetPath = join(stageDir, "index.html");
|
|
267
292
|
const webapisScript = "<script src=\"$WEBAPIS/webapis/webapis.js\"><\/script>";
|
|
268
|
-
let html = readFileSync(appPath(
|
|
269
|
-
if (
|
|
270
|
-
if (
|
|
293
|
+
let html = readFileSync(appPath(options.indexHtml), "utf8");
|
|
294
|
+
if (options.rewriteAssetUrls) html = html.replaceAll("href=\"/", "href=\"./").replaceAll("src=\"/", "src=\"./");
|
|
295
|
+
if (options.injectWebapis !== false && !html.includes("$WEBAPIS/webapis/webapis.js")) html = html.replace("</head>", `${webapisScript}</head>`);
|
|
271
296
|
writeFileSync(targetPath, html);
|
|
272
297
|
};
|
|
273
298
|
const assertBuildOutput = (config) => {
|
|
@@ -276,8 +301,15 @@ const assertBuildOutput = (config) => {
|
|
|
276
301
|
for (const requiredFile of config.build.requiredFiles || []) requireFile(join(sourceDir, requiredFile), `Tizen build output ${requiredFile}`);
|
|
277
302
|
return sourceDir;
|
|
278
303
|
};
|
|
304
|
+
const removeExcludedStageFiles = (excludeFiles) => {
|
|
305
|
+
for (const file of excludeFiles) rmSync(join(stageDir, file), {
|
|
306
|
+
force: true,
|
|
307
|
+
recursive: true
|
|
308
|
+
});
|
|
309
|
+
};
|
|
279
310
|
const stageWidget = (config, variant) => {
|
|
280
311
|
const sourceDir = assertBuildOutput(config);
|
|
312
|
+
const options = getWidgetStageOptions(config, variant);
|
|
281
313
|
rmSync(stageDir, {
|
|
282
314
|
force: true,
|
|
283
315
|
recursive: true
|
|
@@ -291,8 +323,9 @@ const stageWidget = (config, variant) => {
|
|
|
291
323
|
cpSync(sourceDir, stageDir, { recursive: true });
|
|
292
324
|
copyFileSync(appPath(config.widget.configXml), join(stageDir, "config.xml"));
|
|
293
325
|
copyFileSync(requireFile(appPath(variant.icon), "Tizen widget icon"), join(stageDir, "icon.png"));
|
|
326
|
+
removeExcludedStageFiles(options.excludeFiles);
|
|
294
327
|
rewriteConfigForWidget(variant);
|
|
295
|
-
rewriteIndexForWidget(
|
|
328
|
+
rewriteIndexForWidget(options);
|
|
296
329
|
};
|
|
297
330
|
const findBuiltWidget = () => {
|
|
298
331
|
const built = execFileSync("find", [
|
|
@@ -340,9 +373,15 @@ const resolveInstallTarget = (env) => {
|
|
|
340
373
|
const runSync = (operation) => Effect.sync(() => {
|
|
341
374
|
operation(loadContext());
|
|
342
375
|
});
|
|
376
|
+
const runEnvSync = (operation) => Effect.sync(() => {
|
|
377
|
+
operation(loadEnv());
|
|
378
|
+
});
|
|
343
379
|
const taizn = Command.make("taizn", {}, () => runSync((context) => {
|
|
344
380
|
packageWidget(context);
|
|
345
381
|
}));
|
|
382
|
+
const check = Command.make("check", {}, () => runEnvSync((env) => {
|
|
383
|
+
checkTizen(env);
|
|
384
|
+
}));
|
|
346
385
|
const profile = Command.make("profile", {}, () => Effect.promise(async () => {
|
|
347
386
|
await createProfile(loadContext());
|
|
348
387
|
}));
|
|
@@ -353,6 +392,7 @@ const install = Command.make("install", {}, () => runSync((context) => {
|
|
|
353
392
|
installWidget(context);
|
|
354
393
|
}));
|
|
355
394
|
const command = taizn.pipe(Command.withSubcommands([
|
|
395
|
+
check,
|
|
356
396
|
profile,
|
|
357
397
|
pack,
|
|
358
398
|
install
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@putdotio/taizn",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A tiny CLI companion for interacting with Tizen ecosystem.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"effect": "^3.21.2"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@types/node": "^
|
|
56
|
+
"@types/node": "^25.7.0",
|
|
57
57
|
"typescript": "^6.0.2",
|
|
58
58
|
"vite-plus": "^0.1.20",
|
|
59
|
-
"vitest": "^4.1.
|
|
59
|
+
"vitest": "^4.1.6"
|
|
60
60
|
},
|
|
61
61
|
"engines": {
|
|
62
62
|
"node": ">=24.14.0 <25"
|