@manfred-kunze-dev/iot-cli 3.6.0-dev.14 → 3.6.0-dev.18

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
@@ -1,6 +1,6 @@
1
1
  # iot CLI
2
2
 
3
- Command-line interface for the [iot platform](https://iot.manfred-kunze.dev) by Manfred Kunze Development.
3
+ Command-line interface for the [2kw.io IoT platform](https://app.2kw.io) by Manfred Kunze Development.
4
4
 
5
5
  Manage devices, sensors, sites, readings, events and more — straight from your terminal.
6
6
 
@@ -44,6 +44,11 @@ The CLI supports multiple authentication methods (highest priority first):
44
44
  | Local `.iot` file | JSON file in the current directory or any ancestor |
45
45
  | Config store | `~/.config/iot-cli/config.json` (set via `iot auth login`) |
46
46
 
47
+ The base URL defaults to `https://api.2kw.io`. Contexts created before the move to 2kw.io
48
+ (pointing at `https://iot.manfred-kunze.dev/api`) are rewritten to the new host automatically
49
+ the next time the CLI runs; a `.iot` file or `IOT_BASE_URL` naming the old host keeps working
50
+ as-is, since the old hostname stays up as an alias.
51
+
47
52
  ```bash
48
53
  iot auth login # Interactive setup
49
54
  iot auth status # Verify credentials
@@ -1,6 +1,7 @@
1
1
  import { Command } from "commander";
2
2
  import { getClient } from "../lib/client.js";
3
3
  import { isJsonOutput } from "../lib/config.js";
4
+ import { appUrlFromBase } from "../lib/urls.js";
4
5
  import { printJson, printKeyValue, printSuccess } from "../lib/output.js";
5
6
  import { handleError, CLIError } from "../lib/errors.js";
6
7
  import { promptText, promptSecret } from "../lib/prompt.js";
@@ -127,7 +128,7 @@ export function makeFlashCommand() {
127
128
  intervalMs: 5000,
128
129
  });
129
130
  if (!result.online) {
130
- const dashboard = `${config.baseUrl.replace(/\/api\/?$/, "")}/devices/${mint.deviceId}`;
131
+ const dashboard = `${appUrlFromBase(config.baseUrl)}/devices/${mint.deviceId}`;
131
132
  throw new Error(`Device has not enrolled within ${flags.timeout}s (last status: ${result.status}). ` +
132
133
  `The card is written and the token is valid until ${mint.expiresAt}. ` +
133
134
  `Check ${dashboard}`);
@@ -16,8 +16,13 @@ export interface IotConfig {
16
16
  * Fallback base URL when the user has no context, env var, or local config.
17
17
  * Override at build time by setting IOT_DEFAULT_BASE_URL — e.g. for distributions
18
18
  * targeting a different deployment.
19
+ *
20
+ * The 2kw.io API host serves `/v1/...` at the root — no `/api` suffix, unlike
21
+ * the retired single-host deployment.
19
22
  */
20
23
  export declare const DEFAULT_BASE_URL: string;
24
+ /** Return the 2kw.io replacement for a legacy base URL, or the URL unchanged. */
25
+ export declare function migrateLegacyBaseUrl(baseUrl: string): string;
21
26
  /**
22
27
  * Conf store. The cwd override allows tests (and users who want strict env
23
28
  * isolation) to redirect the store via IOT_CLI_CONFIG_DIR.
@@ -5,8 +5,27 @@ import { dirname, resolve } from "node:path";
5
5
  * Fallback base URL when the user has no context, env var, or local config.
6
6
  * Override at build time by setting IOT_DEFAULT_BASE_URL — e.g. for distributions
7
7
  * targeting a different deployment.
8
+ *
9
+ * The 2kw.io API host serves `/v1/...` at the root — no `/api` suffix, unlike
10
+ * the retired single-host deployment.
8
11
  */
9
- export const DEFAULT_BASE_URL = process.env.IOT_DEFAULT_BASE_URL ?? "https://iot.manfred-kunze.dev/api";
12
+ export const DEFAULT_BASE_URL = process.env.IOT_DEFAULT_BASE_URL ?? "https://api.2kw.io";
13
+ /**
14
+ * Base URLs of the retired `manfred-kunze.dev` / `2kw.dev` deployments and
15
+ * the 2kw.io hosts that replaced them. Stored contexts still pointing at a
16
+ * legacy URL are rewritten once when the store loads (see below). The old
17
+ * hosts keep serving as aliases, so a `.iot` file or env var that names one
18
+ * is left alone — only the CLI's own store is migrated.
19
+ */
20
+ const LEGACY_BASE_URLS = {
21
+ "https://iot.manfred-kunze.dev/api": "https://api.2kw.io",
22
+ "https://iot-dev.2kw.dev/api": "https://api-dev.2kw.io",
23
+ };
24
+ /** Return the 2kw.io replacement for a legacy base URL, or the URL unchanged. */
25
+ export function migrateLegacyBaseUrl(baseUrl) {
26
+ const normalised = baseUrl.replace(/\/+$/, "");
27
+ return LEGACY_BASE_URLS[normalised] ?? baseUrl;
28
+ }
10
29
  const CONFIG_DEFAULTS = {
11
30
  currentContext: "default",
12
31
  contexts: {},
@@ -22,6 +41,23 @@ const store = new Conf({
22
41
  defaults: CONFIG_DEFAULTS,
23
42
  });
24
43
  export { store };
44
+ // One-shot migration of contexts created before the 2kw.io domain move.
45
+ // Runs at module load so every command sees the rewritten URLs; writes the
46
+ // store only when something actually changed, so a migrated (or fresh) store
47
+ // is never touched again.
48
+ (function migrateLegacyContexts() {
49
+ const contexts = store.get("contexts") ?? {};
50
+ let changed = false;
51
+ for (const entry of Object.values(contexts)) {
52
+ const migrated = migrateLegacyBaseUrl(entry.baseUrl);
53
+ if (migrated !== entry.baseUrl) {
54
+ entry.baseUrl = migrated;
55
+ changed = true;
56
+ }
57
+ }
58
+ if (changed)
59
+ store.set("contexts", contexts);
60
+ })();
25
61
  const CONTEXT_NAME_RE = /^[a-zA-Z0-9_-]+$/;
26
62
  export function validateContextName(name) {
27
63
  if (!CONTEXT_NAME_RE.test(name)) {
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Derive the browser-facing app URL from an API base URL.
3
+ *
4
+ * The platform runs purpose-split hosts: `api.2kw.io` serves the API and
5
+ * `app.2kw.io` the frontend (same pattern for `api-dev` / `app-dev`). Older
6
+ * single-host deployments (and local dev) serve the API under an `/api`
7
+ * suffix next to the frontend, so for those the app URL is just the base
8
+ * without the suffix.
9
+ */
10
+ export declare function appUrlFromBase(baseUrl: string): string;
11
+ //# sourceMappingURL=urls.d.ts.map
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Derive the browser-facing app URL from an API base URL.
3
+ *
4
+ * The platform runs purpose-split hosts: `api.2kw.io` serves the API and
5
+ * `app.2kw.io` the frontend (same pattern for `api-dev` / `app-dev`). Older
6
+ * single-host deployments (and local dev) serve the API under an `/api`
7
+ * suffix next to the frontend, so for those the app URL is just the base
8
+ * without the suffix.
9
+ */
10
+ export function appUrlFromBase(baseUrl) {
11
+ let url;
12
+ try {
13
+ url = new URL(baseUrl);
14
+ }
15
+ catch {
16
+ return baseUrl.replace(/\/api\/?$/, "").replace(/\/+$/, "");
17
+ }
18
+ url.pathname = url.pathname.replace(/\/api\/?$/, "/");
19
+ url.hostname = url.hostname.replace(/^api(?=[.-])/, "app");
20
+ return url.toString().replace(/\/+$/, "");
21
+ }
22
+ //# sourceMappingURL=urls.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manfred-kunze-dev/iot-cli",
3
- "version": "3.6.0-dev.14",
3
+ "version": "3.6.0-dev.18",
4
4
  "description": "Command-line interface for the iot platform by Manfred Kunze Development",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -46,7 +46,7 @@
46
46
  "registry": "https://registry.npmjs.org",
47
47
  "access": "public"
48
48
  },
49
- "homepage": "https://iot.manfred-kunze.dev",
49
+ "homepage": "https://app.2kw.io",
50
50
  "repository": {
51
51
  "type": "git",
52
52
  "url": "git+https://gitlab.com/manfred-kunze-dev/iot.git",