create-honua-app 0.1.7 → 0.1.9

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,10 +1,12 @@
1
1
  # create-honua-app
2
2
 
3
3
  Scaffold a [Honua JavaScript SDK](https://github.com/honua-io/honua-sdk-js) map application — Vite + TypeScript,
4
- pinned to the certified SDK release, running a map on the first `npm run dev`.
4
+ running a map on the first `npm run dev`. These commands explicitly pin the SDK version documented here;
5
+ omit `--sdk-version` to follow the promoted release channel or this scaffold's certified fallback.
5
6
 
7
+ <!-- doc-run: run ready-url="http://localhost:5173/" -->
6
8
  ```bash
7
- npm create honua-app@0.1.6 my-map
9
+ npm create honua-app@latest my-map -- --sdk-version 0.1.16 # x-release-please-version
8
10
  cd my-map
9
11
  npm install
10
12
  npm run dev
@@ -27,11 +29,17 @@ create-honua-app [directory] [options]
27
29
  With `npm create`, pass CLI options after `--`:
28
30
 
29
31
  ```bash
30
- npm create honua-app@0.1.6 my-react-map -- --template react-ts
32
+ npm create honua-app@latest my-react-map -- --template react-ts --sdk-version 0.1.16 # x-release-please-version
31
33
  ```
32
34
 
33
35
  ## Which SDK version a scaffold pins
34
36
 
37
+ The scaffold and SDK publish independently. `npm create honua-app@latest` selects the scaffold;
38
+ `--sdk-version` selects the SDK installed in the generated application. The explicit
39
+ SDK versions in this published README describe this scaffold release, even when a
40
+ newer SDK has shipped. Keep the flag when reproducing these examples, or select
41
+ another published SDK version deliberately.
42
+
35
43
  The scaffold resolves `@honua/sdk-js` when it runs, from the `release-2026.1` npm dist-tag. Only a Honua release
36
44
  promotion moves that tag, so a newly promoted SDK reaches fresh scaffolds without a new `create-honua-app`. The
37
45
  generated `package.json` still records one exact version, so the app stays reproducible.
@@ -42,7 +50,7 @@ version this release of `create-honua-app` ships with. The default path never pi
42
50
  yourself, pass `--sdk-version`:
43
51
 
44
52
  ```bash
45
- npm create honua-app@0.1.6 my-pinned-map -- --sdk-version 0.1.13
53
+ npm create honua-app@latest my-pinned-map -- --sdk-version 0.1.16 # x-release-please-version
46
54
  ```
47
55
 
48
56
  ## Templates
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-honua-app",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Scaffold a Honua JavaScript SDK map application: Vite + TypeScript + MapLibre starters that connect and mount a source without hand-assembling peers",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Honua",
@@ -62,3 +62,7 @@ npm run build
62
62
  ```
63
63
 
64
64
  The fixture data is synthetic demonstration data from the Honua SDK sample fixtures (Apache-2.0).
65
+
66
+ ## Live basemap
67
+
68
+ The default fixture lane stays offline. When `VITE_HONUA_ENDPOINT` selects a live endpoint, the map uses keyless OpenFreeMap Positron (or Dark for the system theme) and keeps source attribution visible. Set `VITE_HONUA_BASEMAP_STYLE` to a custom/self-hosted style URL. A basemap asset failure leaves operational data and controls available with an actionable status. Keep the expanded source credits in screenshots and exports.
@@ -16,7 +16,7 @@
16
16
  "@bufbuild/protobuf": "2.13.0",
17
17
  "@connectrpc/connect": "2.1.2",
18
18
  "@connectrpc/connect-web": "2.1.2",
19
- "@honua/sdk-js": "0.1.13",
19
+ "@honua/sdk-js": "0.1.14",
20
20
  "maplibre-gl": "6.4.1",
21
21
  "react": "19.2.8",
22
22
  "react-dom": "19.2.8"
@@ -4,6 +4,7 @@ import { maplibreRenderer } from "@honua/sdk-js/runtime";
4
4
  import * as maplibregl from "maplibre-gl";
5
5
  import type { RefObject } from "react";
6
6
  import { useEffect, useRef, useState } from "react";
7
+ import { mountSampleOnlineBasemap } from "./online-basemap.js";
7
8
 
8
9
  import { FIXTURE_LAYER_PATH } from "./fixture-endpoint.js";
9
10
 
@@ -54,11 +55,17 @@ function useExternalMap(): { containerRef: RefObject<HTMLDivElement | null>; map
54
55
  style: BASEMAP_STYLE,
55
56
  center: INITIAL_VIEW.center,
56
57
  zoom: INITIAL_VIEW.zoom,
57
- attributionControl: false,
58
+ attributionControl: { compact: true },
58
59
  });
60
+ const disposeBasemap = configuredEndpoint
61
+ ? mountSampleOnlineBasemap(created, {
62
+ styleUrl: import.meta.env.VITE_HONUA_BASEMAP_STYLE?.trim() || undefined,
63
+ })
64
+ : () => {};
59
65
  setMap(created);
60
66
  return () => {
61
67
  setMap(null);
68
+ disposeBasemap();
62
69
  created.remove();
63
70
  };
64
71
  }, []);
@@ -0,0 +1,84 @@
1
+ import * as runtime from "@honua/sdk-js/runtime";
2
+
3
+ type HonuaOnlineBasemapTheme = "positron" | "liberty" | "dark";
4
+ interface OnlineBasemapBinding {
5
+ activate(options: { theme: HonuaOnlineBasemapTheme; styleUrl?: string }): Promise<boolean>;
6
+ dispose(): void;
7
+ }
8
+ type OnlineBasemapConstructor = new (
9
+ map: MapLibreMap,
10
+ options: { onError: (message: string) => void; onReady: () => void },
11
+ ) => OnlineBasemapBinding;
12
+ import type { Map as MapLibreMap } from "maplibre-gl";
13
+
14
+ /** Explicit live-lane enhancement. Local fixture lanes never call this helper. */
15
+ export function mountSampleOnlineBasemap(
16
+ map: MapLibreMap,
17
+ options: {
18
+ readonly styleUrl?: string;
19
+ readonly lightTheme?: Exclude<HonuaOnlineBasemapTheme, "dark">;
20
+ readonly styleEnvironmentVariable?: string;
21
+ } = {},
22
+ ): () => void {
23
+ const notice = document.createElement("div");
24
+ notice.setAttribute("role", "status");
25
+ notice.dataset.basemapStatus = "loading";
26
+ notice.style.cssText =
27
+ "position:absolute;left:12px;right:12px;bottom:40px;z-index:5;padding:8px 12px;background:Canvas;color:CanvasText;border:1px solid currentColor;border-radius:6px;font:13px system-ui;pointer-events:none;display:none";
28
+ map.getContainer().append(notice);
29
+ // Older published SDKs can still run the local fixture lane. A live map
30
+ // explicitly reports the required upgrade instead of failing module loading.
31
+ const Binding = (runtime as unknown as { readonly HonuaOnlineBasemapBinding?: OnlineBasemapConstructor })
32
+ .HonuaOnlineBasemapBinding;
33
+ if (typeof Binding !== "function") {
34
+ notice.textContent =
35
+ "Online basemaps require a newer @honua/sdk-js release with HonuaOnlineBasemapBinding. Upgrade @honua/sdk-js after the basemap SDK release is published, then reload. Operational data remains usable.";
36
+ notice.dataset.basemapStatus = "error";
37
+ notice.style.display = "block";
38
+ return () => notice.remove();
39
+ }
40
+ const binding = new Binding(map, {
41
+ onError: (message) => {
42
+ notice.textContent = `${message} Set ${options.styleEnvironmentVariable ?? "VITE_HONUA_BASEMAP_STYLE"} to your custom/self-hosted style URL.`;
43
+ notice.dataset.basemapStatus = "error";
44
+ notice.style.display = "block";
45
+ },
46
+ onReady: () => {
47
+ notice.textContent = "";
48
+ notice.dataset.basemapStatus = "ready";
49
+ notice.style.display = "none";
50
+ },
51
+ });
52
+ const preferred = matchMedia("(prefers-color-scheme: dark)");
53
+ let pendingTheme: HonuaOnlineBasemapTheme | undefined;
54
+ const flush = () => {
55
+ if (!pendingTheme || !map.isStyleLoaded()) return;
56
+ const theme = pendingTheme;
57
+ pendingTheme = undefined;
58
+ void binding.activate({ theme, styleUrl: options.styleUrl });
59
+ };
60
+ const update = () => {
61
+ const selected = document.documentElement.dataset.theme;
62
+ const dark = selected === "dark" || (!selected && preferred.matches);
63
+ pendingTheme = dark ? "dark" : (options.lightTheme ?? "positron");
64
+ flush();
65
+ };
66
+ const observer = new MutationObserver(update);
67
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
68
+ preferred.addEventListener("change", update);
69
+ // Theme changes during tile/sprite loading must survive until the renderer
70
+ // is ready again. Consume only the latest pending theme, once per update.
71
+ map.on("idle", flush);
72
+ map.once("load", flush);
73
+ update();
74
+ const dispose = () => {
75
+ map.off("load", flush);
76
+ map.off("idle", flush);
77
+ observer.disconnect();
78
+ preferred.removeEventListener("change", update);
79
+ binding.dispose();
80
+ notice.remove();
81
+ };
82
+ // Dispose before remove(), while the renderer's style resources still exist.
83
+ return dispose;
84
+ }
@@ -59,3 +59,7 @@ npm run build
59
59
  ```
60
60
 
61
61
  The fixture data is synthetic demonstration data from the Honua SDK sample fixtures (Apache-2.0).
62
+
63
+ ## Live basemap
64
+
65
+ The default fixture lane stays offline. When `VITE_HONUA_ENDPOINT` selects a live endpoint, the map uses keyless OpenFreeMap Positron (or Dark for the system theme) and keeps source attribution visible. Set `VITE_HONUA_BASEMAP_STYLE` to a custom/self-hosted style URL. A basemap asset failure leaves operational data and controls available with an actionable status. Keep the expanded source credits in screenshots and exports.
@@ -16,7 +16,7 @@
16
16
  "@bufbuild/protobuf": "2.13.0",
17
17
  "@connectrpc/connect": "2.1.2",
18
18
  "@connectrpc/connect-web": "2.1.2",
19
- "@honua/sdk-js": "0.1.13",
19
+ "@honua/sdk-js": "0.1.14",
20
20
  "maplibre-gl": "6.4.1"
21
21
  },
22
22
  "devDependencies": {
@@ -1,3 +1,4 @@
1
+ import { mountSampleOnlineBasemap } from "./online-basemap.js";
1
2
  import "./maplibre-worker.js";
2
3
  import "maplibre-gl/dist/maplibre-gl.css";
3
4
 
@@ -16,7 +17,7 @@ const BASEMAP_STYLE = {
16
17
  layers: [{ id: "background", type: "background", paint: { "background-color": "#0e1a17" } }],
17
18
  };
18
19
 
19
- const MAP_OPTIONS = { center: [-157.873, 21.2985], zoom: 11.4, attributionControl: false };
20
+ const MAP_OPTIONS = { center: [-157.873, 21.2985], zoom: 11.4, attributionControl: { compact: true } };
20
21
 
21
22
  /** Bounded row budget. Honua never mounts a truncated result silently. */
22
23
  const MAX_FEATURES = 250;
@@ -99,6 +100,21 @@ async function run(): Promise<void> {
99
100
  rendererOptions: { mapOptions: MAP_OPTIONS },
100
101
  });
101
102
  await mounted.ready;
103
+ const rawMap = mounted.raw("maplibre");
104
+ const disposeBasemap =
105
+ configuredEndpoint && rawMap
106
+ ? mountSampleOnlineBasemap(rawMap as maplibregl.Map, {
107
+ styleUrl: import.meta.env.VITE_HONUA_BASEMAP_STYLE?.trim() || undefined,
108
+ })
109
+ : () => {};
110
+ window.addEventListener(
111
+ "pagehide",
112
+ () => {
113
+ disposeBasemap();
114
+ void honua.dispose();
115
+ },
116
+ { once: true },
117
+ );
102
118
  stage("mount", "done", "mounted");
103
119
  element("status").textContent = "The accepted plan is mounted. Every stage above ran through the public SDK API.";
104
120
  } catch (error) {
@@ -0,0 +1,84 @@
1
+ import * as runtime from "@honua/sdk-js/runtime";
2
+
3
+ type HonuaOnlineBasemapTheme = "positron" | "liberty" | "dark";
4
+ interface OnlineBasemapBinding {
5
+ activate(options: { theme: HonuaOnlineBasemapTheme; styleUrl?: string }): Promise<boolean>;
6
+ dispose(): void;
7
+ }
8
+ type OnlineBasemapConstructor = new (
9
+ map: MapLibreMap,
10
+ options: { onError: (message: string) => void; onReady: () => void },
11
+ ) => OnlineBasemapBinding;
12
+ import type { Map as MapLibreMap } from "maplibre-gl";
13
+
14
+ /** Explicit live-lane enhancement. Local fixture lanes never call this helper. */
15
+ export function mountSampleOnlineBasemap(
16
+ map: MapLibreMap,
17
+ options: {
18
+ readonly styleUrl?: string;
19
+ readonly lightTheme?: Exclude<HonuaOnlineBasemapTheme, "dark">;
20
+ readonly styleEnvironmentVariable?: string;
21
+ } = {},
22
+ ): () => void {
23
+ const notice = document.createElement("div");
24
+ notice.setAttribute("role", "status");
25
+ notice.dataset.basemapStatus = "loading";
26
+ notice.style.cssText =
27
+ "position:absolute;left:12px;right:12px;bottom:40px;z-index:5;padding:8px 12px;background:Canvas;color:CanvasText;border:1px solid currentColor;border-radius:6px;font:13px system-ui;pointer-events:none;display:none";
28
+ map.getContainer().append(notice);
29
+ // Older published SDKs can still run the local fixture lane. A live map
30
+ // explicitly reports the required upgrade instead of failing module loading.
31
+ const Binding = (runtime as unknown as { readonly HonuaOnlineBasemapBinding?: OnlineBasemapConstructor })
32
+ .HonuaOnlineBasemapBinding;
33
+ if (typeof Binding !== "function") {
34
+ notice.textContent =
35
+ "Online basemaps require a newer @honua/sdk-js release with HonuaOnlineBasemapBinding. Upgrade @honua/sdk-js after the basemap SDK release is published, then reload. Operational data remains usable.";
36
+ notice.dataset.basemapStatus = "error";
37
+ notice.style.display = "block";
38
+ return () => notice.remove();
39
+ }
40
+ const binding = new Binding(map, {
41
+ onError: (message) => {
42
+ notice.textContent = `${message} Set ${options.styleEnvironmentVariable ?? "VITE_HONUA_BASEMAP_STYLE"} to your custom/self-hosted style URL.`;
43
+ notice.dataset.basemapStatus = "error";
44
+ notice.style.display = "block";
45
+ },
46
+ onReady: () => {
47
+ notice.textContent = "";
48
+ notice.dataset.basemapStatus = "ready";
49
+ notice.style.display = "none";
50
+ },
51
+ });
52
+ const preferred = matchMedia("(prefers-color-scheme: dark)");
53
+ let pendingTheme: HonuaOnlineBasemapTheme | undefined;
54
+ const flush = () => {
55
+ if (!pendingTheme || !map.isStyleLoaded()) return;
56
+ const theme = pendingTheme;
57
+ pendingTheme = undefined;
58
+ void binding.activate({ theme, styleUrl: options.styleUrl });
59
+ };
60
+ const update = () => {
61
+ const selected = document.documentElement.dataset.theme;
62
+ const dark = selected === "dark" || (!selected && preferred.matches);
63
+ pendingTheme = dark ? "dark" : (options.lightTheme ?? "positron");
64
+ flush();
65
+ };
66
+ const observer = new MutationObserver(update);
67
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
68
+ preferred.addEventListener("change", update);
69
+ // Theme changes during tile/sprite loading must survive until the renderer
70
+ // is ready again. Consume only the latest pending theme, once per update.
71
+ map.on("idle", flush);
72
+ map.once("load", flush);
73
+ update();
74
+ const dispose = () => {
75
+ map.off("load", flush);
76
+ map.off("idle", flush);
77
+ observer.disconnect();
78
+ preferred.removeEventListener("change", update);
79
+ binding.dispose();
80
+ notice.remove();
81
+ };
82
+ // Dispose before remove(), while the renderer's style resources still exist.
83
+ return dispose;
84
+ }
@@ -4,7 +4,7 @@
4
4
  "sdk": {
5
5
  "package": "@honua/sdk-js",
6
6
  "channel": "release-2026.1",
7
- "version": "0.1.13"
7
+ "version": "0.1.14"
8
8
  },
9
9
  "repository": {
10
10
  "owner": "honua-io",