@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 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
- `profile` imports `.taizn/certificates/author.p12` and
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, getVariant(config, env.variant));
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, `${getVariant(config, env.variant).bundleName}.wgt`);
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 = (config) => {
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(config.widget.indexHtml), "utf8");
269
- if (config.widget.rewriteAssetUrls) html = html.replaceAll("href=\"/", "href=\"./").replaceAll("src=\"/", "src=\"./");
270
- if (config.widget.injectWebapis !== false && !html.includes("$WEBAPIS/webapis/webapis.js")) html = html.replace("</head>", `${webapisScript}</head>`);
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(config);
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.1",
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": "^24.12.2",
56
+ "@types/node": "^25.7.0",
57
57
  "typescript": "^6.0.2",
58
58
  "vite-plus": "^0.1.20",
59
- "vitest": "^4.1.5"
59
+ "vitest": "^4.1.6"
60
60
  },
61
61
  "engines": {
62
62
  "node": ">=24.14.0 <25"