4bnode 4.1.9 → 4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "4bnode",
3
- "version": "4.1.9",
3
+ "version": "4.2.0",
4
4
  "description": "4bnode is a CLI-powered backend development platform with a built-in visual dashboard to generate, manage, and test Node.js/Express APIs faster.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -15,6 +15,7 @@ export function DiscoveryPage() {
15
15
  const [info, setInfo] = useState(null);
16
16
  const [loading, setLoading] = useState(true);
17
17
  const [saving, setSaving] = useState(false);
18
+ const [toggling, setToggling] = useState(false);
18
19
  const [name, setName] = useState("");
19
20
  const [type, setType] = useState("http");
20
21
  const [enabled, setEnabled] = useState(true);
@@ -41,6 +42,24 @@ export function DiscoveryPage() {
41
42
  loadInfo();
42
43
  }, []);
43
44
 
45
+ // Flip Bonjour on/off immediately — no "Save" step. The dashboard runs in the
46
+ // same process as the advertiser, so the server re-publishes / unpublishes live
47
+ // and persists BONJOUR_ENABLED to .env in one call.
48
+ async function handleToggle(e) {
49
+ const next = e.target.checked;
50
+ setEnabled(next); // optimistic
51
+ setToggling(true);
52
+ try {
53
+ await api("/discovery/config", { method: "POST", body: { enabled: next } });
54
+ toast(next ? "Bonjour enabled" : "Bonjour disabled", "success");
55
+ loadInfo();
56
+ } catch (err) {
57
+ setEnabled(!next); // revert on failure
58
+ toast(err.message, "error");
59
+ }
60
+ setToggling(false);
61
+ }
62
+
44
63
  async function handleSave() {
45
64
  setSaving(true);
46
65
  try {
@@ -114,6 +133,20 @@ export function DiscoveryPage() {
114
133
  </div>
115
134
  </div>`
116
135
  : html`<div>
136
+ <!-- Enable / disable — applies instantly, no restart -->
137
+ <div style=${{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: "12px", padding: "10px 12px", border: "1px solid var(--border)", borderRadius: "8px", marginBottom: "14px" }}>
138
+ <div>
139
+ <div style=${{ fontSize: "13px", fontWeight: 600 }}>Advertise on local network</div>
140
+ <div className="text-muted" style=${{ fontSize: "12px" }}>
141
+ ${enabled ? "On — this app is discoverable via Bonjour/mDNS" : "Off — not broadcasting on the network"}
142
+ </div>
143
+ </div>
144
+ <label className="form-toggle">
145
+ <input type="checkbox" checked=${enabled} disabled=${toggling} onChange=${handleToggle} />
146
+ <span className="slider"></span>
147
+ </label>
148
+ </div>
149
+
117
150
  ${status === "advertising"
118
151
  ? html`<div style=${{ display: "grid", gridTemplateColumns: "90px 1fr", gap: "6px 12px", fontSize: "13px", marginBottom: "12px" }}>
119
152
  <span className="text-muted">Name</span><span>${self.name}</span>
@@ -135,11 +168,7 @@ export function DiscoveryPage() {
135
168
 
136
169
  <div style=${{ borderTop: "1px solid var(--border)", margin: "4px 0 14px" }}></div>
137
170
 
138
- <label className="form-label" style=${{ display: "flex", alignItems: "center", gap: "8px", cursor: "pointer", marginBottom: "12px" }}>
139
- <input type="checkbox" checked=${enabled} onChange=${(e) => setEnabled(e.target.checked)} />
140
- Advertise this app on the local network
141
- </label>
142
- <div className="form-group">
171
+ <div className="form-group" style=${{ opacity: enabled ? 1 : 0.55 }}>
143
172
  <label className="form-label">Service name</label>
144
173
  <input className="form-input" value=${name} placeholder="My App (auto: app + hostname)" onInput=${(e) => setName(e.target.value)} />
145
174
  </div>