@bardioc/create-bardioc-app 0.5.6 → 0.6.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.
Files changed (65) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/templates/_base/README.md +1 -1
  4. package/templates/_base/public/app-manifest.json +1 -2
  5. package/templates/angular/.env.example +4 -1
  6. package/templates/angular/package.json +2 -2
  7. package/templates/angular/scripts/dev-env.mjs +62 -0
  8. package/templates/angular/scripts/dev.mjs +56 -0
  9. package/templates/angular/scripts/sync-runtime-env.mjs +2 -28
  10. package/templates/angular/src/app/app.component.ts +44 -26
  11. package/templates/angular/src/app/bardioc.token.ts +2 -2
  12. package/templates/angular/src/main.ts +6 -8
  13. package/templates/angular/src/styles.css +4 -0
  14. package/templates/nextjs/.env.example +4 -1
  15. package/templates/nextjs/app/page.tsx +18 -15
  16. package/templates/nextjs/next.config.ts +1 -1
  17. package/templates/nextjs/package.json +3 -3
  18. package/templates/nextjs/scripts/dev-env.mjs +62 -0
  19. package/templates/nextjs/scripts/dev.mjs +56 -0
  20. package/templates/preact/.env.example +3 -0
  21. package/templates/preact/package.json +2 -2
  22. package/templates/preact/src/App.tsx +10 -10
  23. package/templates/preact/src/main.tsx +3 -3
  24. package/templates/preact/vite.config.ts +4 -1
  25. package/templates/solid/.env.example +3 -0
  26. package/templates/solid/package.json +2 -2
  27. package/templates/solid/src/App.tsx +10 -10
  28. package/templates/solid/src/bardioc-sdk.tsx +11 -23
  29. package/templates/solid/src/main.tsx +5 -3
  30. package/templates/solid/vite.config.ts +4 -1
  31. package/templates/svelte/.env.example +3 -0
  32. package/templates/svelte/package.json +2 -2
  33. package/templates/svelte/src/App.svelte +12 -12
  34. package/templates/svelte/src/main.ts +5 -5
  35. package/templates/svelte/vite.config.ts +4 -1
  36. package/templates/vite/.env.example +3 -0
  37. package/templates/vite/CLAUDE.md +34 -7
  38. package/templates/vite/package.json +3 -3
  39. package/templates/vite/public/app-manifest.json +0 -1
  40. package/templates/vite/src/auth/onboarding.tsx +7 -5
  41. package/templates/vite/src/climate/conditions-chart.tsx +2 -2
  42. package/templates/vite/src/climate/overview-view.tsx +1 -1
  43. package/templates/vite/src/climate/stations-view.tsx +3 -10
  44. package/templates/vite/src/climate/use-climate.ts +8 -8
  45. package/templates/vite/src/events/live-events-view.tsx +8 -10
  46. package/templates/vite/src/graph/explorer-view.tsx +7 -14
  47. package/templates/vite/src/graph/requests.ts +16 -19
  48. package/templates/vite/src/locales/de.json +7 -8
  49. package/templates/vite/src/locales/en.json +45 -46
  50. package/templates/vite/src/main.tsx +3 -3
  51. package/templates/vite/src/profile/profile-view.tsx +5 -12
  52. package/templates/vite/src/profile/use-profile.ts +3 -3
  53. package/templates/vite/src/shell/about-dialog.tsx +5 -11
  54. package/templates/vite/src/shell/app-shell.tsx +63 -22
  55. package/templates/vite/src/shell/header.tsx +24 -24
  56. package/templates/vite/vite.config.ts +4 -1
  57. package/templates/vue/.env.example +3 -0
  58. package/templates/vue/package.json +2 -2
  59. package/templates/vue/src/App.vue +12 -12
  60. package/templates/vue/src/bardioc-sdk.ts +6 -15
  61. package/templates/vue/src/main.ts +5 -4
  62. package/templates/vue/vite.config.ts +4 -1
  63. package/templates/angular/scripts/dev-auth-proxy.mjs +0 -17
  64. package/templates/angular/src/app/bardioc-bridge.ts +0 -5
  65. package/templates/nextjs/scripts/dev-auth-proxy.mjs +0 -17
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createDevAuthProxyHandler } from '@bardioc/app-sdk/dev-proxy';
4
+ import { spawn } from 'node:child_process';
5
+ import { createServer } from 'node:http';
6
+ import { dirname, resolve } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { PROXY_PORT_OFFSET, readDevAuthEnv, resolveAppPort } from './dev-env.mjs';
9
+
10
+ const PROXY_HOST = '127.0.0.1';
11
+
12
+ const projectDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
13
+ const port = resolveAppPort(projectDir);
14
+
15
+ // `next dev` cannot host the SDK Vite plugin, so the proxy runs beside it.
16
+ const proxy = await startProxy(port + PROXY_PORT_OFFSET);
17
+
18
+ // One command string: shell:true resolves the .cmd shim on Windows, and passing an args array
19
+ // alongside it is deprecated (DEP0190).
20
+ const server = spawn(`next dev --port ${port}`, { stdio: 'inherit', shell: true });
21
+
22
+ for (const signal of ['SIGINT', 'SIGTERM']) {
23
+ process.on(signal, () => server.kill(signal));
24
+ }
25
+
26
+ // Exit only once the dev server has, carrying its exit code.
27
+ server.on('exit', (code, signal) => {
28
+ proxy?.close();
29
+ process.exit(signal ? 1 : (code ?? 0));
30
+ });
31
+
32
+ // Built from the SDK handler rather than startDevAuthProxy, whose own SIGINT handler exits the
33
+ // process before the dev server has shut down. Without DEV_SECRET / API_BASE_URL the dev server
34
+ // runs alone, matching how the SDK Vite plugin disables itself.
35
+ async function startProxy(proxyPort) {
36
+ const env = readDevAuthEnv(projectDir);
37
+ if (!env) {
38
+ console.warn(
39
+ '[bardioc-dev-auth] DEV_SECRET and API_BASE_URL are required for dev auth — proxy disabled'
40
+ );
41
+ return null;
42
+ }
43
+
44
+ const handler = createDevAuthProxyHandler({ ...env, allowOrigin: '*' });
45
+ const proxyServer = createServer((req, res) => void handler(req, res));
46
+
47
+ await new Promise((resolveListen, rejectListen) => {
48
+ proxyServer.once('error', rejectListen);
49
+ proxyServer.listen(proxyPort, PROXY_HOST, resolveListen);
50
+ });
51
+
52
+ console.log(
53
+ `[bardioc-dev-auth] proxying /rest/* → ${env.apiBaseUrl} on http://${PROXY_HOST}:${proxyPort}/rest`
54
+ );
55
+ return proxyServer;
56
+ }
@@ -7,3 +7,6 @@ DEV_SECRET=
7
7
 
8
8
  # Base URL of the Bardioc BFF / backend-for-frontend (e.g. https://your-host).
9
9
  API_BASE_URL=
10
+
11
+ # By default, the app will start on port {{PORT}}. Feel free to uncomment the following variable and change it to match your local setup preferences.
12
+ #LOCALHOST_PORT={{PORT}}
@@ -18,11 +18,11 @@
18
18
  "release:publish": "changeset publish"
19
19
  },
20
20
  "dependencies": {
21
- "@bardioc/app-sdk": "^0.4.9",
21
+ "@bardioc/app-sdk": "^1.0.0",
22
22
  "preact": "^10.26.7"
23
23
  },
24
24
  "devDependencies": {
25
- "@bardioc/configs": "^0.2.1",
25
+ "@bardioc/configs": "0.2.1",
26
26
  "@changesets/cli": "^2.31.0",
27
27
  "@preact/preset-vite": "^2.10.6",
28
28
  "@tailwindcss/vite": "^4.3.0",
@@ -9,7 +9,7 @@ type ResultState =
9
9
  | { status: 'error'; request: string; message: string };
10
10
 
11
11
  function SdkDemo() {
12
- const bridge = useSdk();
12
+ const bardioc = useSdk();
13
13
  const notify = useNotify();
14
14
  const [result, setResult] = useState<ResultState>({ status: 'idle' });
15
15
  const [running, setRunning] = useState(false);
@@ -18,17 +18,17 @@ function SdkDemo() {
18
18
  if (running) return;
19
19
  setRunning(true);
20
20
 
21
- const request = 'transport.os.profile.get()';
21
+ const request = 'os.profile.get()';
22
22
  setResult({ status: 'loading', request });
23
23
 
24
24
  const startTime = Date.now();
25
- notify('Getting user profile', 'info');
25
+ notify('Getting user profile…', 'info');
26
26
 
27
27
  try {
28
- const data = await bridge.transport.os.profile.get();
28
+ const data = await bardioc.os.profile.get();
29
29
 
30
30
  const duration = Date.now() - startTime;
31
- notify(`Profile loaded (${duration}ms)`, 'success');
31
+ notify(`Profile loaded (${duration}ms).`, 'success');
32
32
  setResult({ status: 'success', request, data });
33
33
  } catch (err) {
34
34
  const message = err instanceof Error ? err.message : String(err);
@@ -40,10 +40,10 @@ function SdkDemo() {
40
40
  }
41
41
 
42
42
  function handleNotify() {
43
- notify('Hello from {{DISPLAY_NAME}}', 'info');
43
+ notify('Hello from {{DISPLAY_NAME}}.', 'info');
44
44
  setResult({
45
45
  status: 'success',
46
- request: 'SDK_NOTIFY',
46
+ request: 'ui.notify',
47
47
  data: { ok: true, message: 'Notification sent to OS' },
48
48
  });
49
49
  }
@@ -99,7 +99,7 @@ function SdkDemo() {
99
99
  <div className="text-muted-foreground border-border border-b pb-2 font-mono text-xs">
100
100
  {result.request}
101
101
  </div>
102
- <div className="text-destructive break-all whitespace-pre-wrap">{result.message}</div>
102
+ <div className="text-destructive whitespace-pre-wrap break-all">{result.message}</div>
103
103
  </div>
104
104
  )}
105
105
  {result.status === 'success' && (
@@ -121,14 +121,14 @@ export function App() {
121
121
  const showSdkDemo = isInsideIframe() || isDevStandalone();
122
122
 
123
123
  return (
124
- <div className="bg-background text-foreground min-h-screen">
124
+ <div className="bg-background text-foreground @container/app min-h-screen">
125
125
  {showSdkDemo ? (
126
126
  <SdkDemo />
127
127
  ) : (
128
128
  <div className="mx-auto flex min-h-screen w-full max-w-3xl flex-col gap-4 p-4">
129
129
  <h1 className="m-0 text-2xl font-semibold">Hello Bardioc App</h1>
130
130
  <p className="text-muted-foreground m-0 max-w-2xl text-xs leading-5">
131
- Open this app inside Bardioc OS to use transport requests and send host notifications.
131
+ Open this app inside Bardioc to use transport requests and send host notifications.
132
132
  </p>
133
133
  <div className="border-border bg-muted/20 rounded-xl border p-3 text-xs leading-5">
134
134
  Outside the host iframe this page is only a local preview shell.
@@ -1,4 +1,4 @@
1
- import { installDevBridge, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
1
+ import { installDevHost, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
2
2
  import { AppSdkProvider } from '@bardioc/app-sdk/react';
3
3
  import { render } from 'preact';
4
4
  import { App } from './App';
@@ -15,12 +15,12 @@ const devStandalone = isDevStandalone();
15
15
  const useSdkProvider = insideIframe || devStandalone;
16
16
 
17
17
  if (devStandalone) {
18
- installDevBridge({ debug: false });
18
+ installDevHost({ appId: APP_NAME });
19
19
  }
20
20
 
21
21
  render(
22
22
  useSdkProvider ? (
23
- <AppSdkProvider appId={APP_NAME}>
23
+ <AppSdkProvider>
24
24
  <App />
25
25
  </AppSdkProvider>
26
26
  ) : (
@@ -3,9 +3,12 @@ import preact from '@preact/preset-vite';
3
3
  import tailwindcss from '@tailwindcss/vite';
4
4
  import { defineConfig, loadEnv } from 'vite';
5
5
 
6
+ const DEFAULT_PORT = {{PORT}};
7
+
6
8
  export default defineConfig(({ mode }) => {
7
9
  const env = loadEnv(mode, __dirname, '');
8
10
  const appName = env.VITE_APP_NAME?.trim();
11
+ const port = Number(env.LOCALHOST_PORT) || DEFAULT_PORT;
9
12
 
10
13
  if (!appName) {
11
14
  throw new Error('Missing VITE_APP_NAME for Vite config');
@@ -15,7 +18,7 @@ export default defineConfig(({ mode }) => {
15
18
  plugins: [
16
19
  bardiocDevAuth({ appName }),
17
20
  preact(),
18
- bardiocApp({ appName, port: {{PORT}} }),
21
+ bardiocApp({ appName, port }),
19
22
  tailwindcss(),
20
23
  ],
21
24
  };
@@ -7,3 +7,6 @@ DEV_SECRET=
7
7
 
8
8
  # Base URL of the Bardioc BFF / backend-for-frontend (e.g. https://your-host).
9
9
  API_BASE_URL=
10
+
11
+ # By default, the app will start on port {{PORT}}. Feel free to uncomment the following variable and change it to match your local setup preferences.
12
+ #LOCALHOST_PORT={{PORT}}
@@ -18,11 +18,11 @@
18
18
  "release:publish": "changeset publish"
19
19
  },
20
20
  "dependencies": {
21
- "@bardioc/app-sdk": "^0.4.9",
21
+ "@bardioc/app-sdk": "^1.0.0",
22
22
  "solid-js": "^1.9.7"
23
23
  },
24
24
  "devDependencies": {
25
- "@bardioc/configs": "^0.2.1",
25
+ "@bardioc/configs": "0.2.1",
26
26
  "@changesets/cli": "^2.31.0",
27
27
  "@tailwindcss/vite": "^4.3.0",
28
28
  "@types/node": "^22.19.19",
@@ -9,7 +9,7 @@ type ResultState =
9
9
  | { status: 'error'; request: string; message: string };
10
10
 
11
11
  function SdkDemo() {
12
- const bridge = useSdk();
12
+ const bardioc = useSdk();
13
13
  const notify = useNotify();
14
14
  const [result, setResult] = createSignal<ResultState>({ status: 'idle' });
15
15
  const [running, setRunning] = createSignal(false);
@@ -18,17 +18,17 @@ function SdkDemo() {
18
18
  if (running()) return;
19
19
  setRunning(true);
20
20
 
21
- const request = 'transport.os.profile.get()';
21
+ const request = 'os.profile.get()';
22
22
  setResult({ status: 'loading', request });
23
23
 
24
24
  const startTime = Date.now();
25
- notify('Getting user profile', 'info');
25
+ notify('Getting user profile…', 'info');
26
26
 
27
27
  try {
28
- const data = await bridge.transport.os.profile.get();
28
+ const data = await bardioc.os.profile.get();
29
29
 
30
30
  const duration = Date.now() - startTime;
31
- notify(`Profile loaded (${duration}ms)`, 'success');
31
+ notify(`Profile loaded (${duration}ms).`, 'success');
32
32
  setResult({ status: 'success', request, data });
33
33
  } catch (err) {
34
34
  const message = err instanceof Error ? err.message : String(err);
@@ -40,10 +40,10 @@ function SdkDemo() {
40
40
  }
41
41
 
42
42
  function handleNotify() {
43
- notify('Hello from {{DISPLAY_NAME}}', 'info');
43
+ notify('Hello from {{DISPLAY_NAME}}.', 'info');
44
44
  setResult({
45
45
  status: 'success',
46
- request: 'SDK_NOTIFY',
46
+ request: 'ui.notify',
47
47
  data: { ok: true, message: 'Notification sent to OS' },
48
48
  });
49
49
  }
@@ -106,7 +106,7 @@ function SdkDemo() {
106
106
  <div class="text-muted-foreground border-border border-b pb-2 font-mono text-xs">
107
107
  {r.request}
108
108
  </div>
109
- <div class="text-destructive break-all whitespace-pre-wrap">{r.message}</div>
109
+ <div class="text-destructive whitespace-pre-wrap break-all">{r.message}</div>
110
110
  </div>
111
111
  );
112
112
  }
@@ -132,14 +132,14 @@ export function App() {
132
132
  const showSdkDemo = isInsideIframe() || isDevStandalone();
133
133
 
134
134
  return (
135
- <div class="bg-background text-foreground min-h-screen">
135
+ <div class="bg-background text-foreground @container/app min-h-screen">
136
136
  {showSdkDemo ? (
137
137
  <SdkDemo />
138
138
  ) : (
139
139
  <div class="mx-auto flex min-h-screen w-full max-w-3xl flex-col gap-4 p-4">
140
140
  <h1 class="m-0 text-2xl font-semibold">Hello Bardioc App</h1>
141
141
  <p class="text-muted-foreground m-0 max-w-2xl text-xs leading-5">
142
- Open this app inside Bardioc OS to use transport requests and send host notifications.
142
+ Open this app inside Bardioc to use transport requests and send host notifications.
143
143
  </p>
144
144
  <div class="border-border bg-muted/20 rounded-xl border p-3 text-xs leading-5">
145
145
  Outside the host iframe this page is only a local preview shell.
@@ -1,33 +1,21 @@
1
- import { createHostBridge, type HostBridge, type NotifyLevel } from '@bardioc/app-sdk';
2
- import { createContext, onCleanup, onMount, useContext, type JSX } from 'solid-js';
1
+ import type { Bardioc, NotifyLevel } from '@bardioc/app-sdk';
2
+ import { createContext, useContext, type JSX } from 'solid-js';
3
3
 
4
- const BardiocContext = createContext<HostBridge>();
4
+ const BardiocContext = createContext<Bardioc>();
5
5
 
6
- export function AppSdkProvider(props: { appId: string; children: JSX.Element }) {
7
- const bridge = createHostBridge({ appId: props.appId });
8
-
9
- onMount(() => {
10
- void bridge.connect();
11
- });
12
-
13
- onCleanup(() => {
14
- bridge.destroy();
15
- });
16
-
17
- return <BardiocContext.Provider value={bridge}>{props.children}</BardiocContext.Provider>;
6
+ export function AppSdkProvider(props: { bardioc: Bardioc; children: JSX.Element }) {
7
+ return <BardiocContext.Provider value={props.bardioc}>{props.children}</BardiocContext.Provider>;
18
8
  }
19
9
 
20
- export function useSdk(): HostBridge {
21
- const bridge = useContext(BardiocContext);
22
- if (!bridge) {
23
- throw new Error('useSdk() must be used inside AppSdkProvider');
24
- }
25
- return bridge;
10
+ export function useSdk(): Bardioc {
11
+ const bardioc = useContext(BardiocContext);
12
+ if (!bardioc) throw new Error('useSdk() must be used inside AppSdkProvider');
13
+ return bardioc;
26
14
  }
27
15
 
28
16
  export function useNotify() {
29
- const bridge = useSdk();
17
+ const { ui } = useSdk();
30
18
  return (message: string, level?: NotifyLevel) => {
31
- bridge.notify(message, level);
19
+ ui.notify(message, level).catch(console.error);
32
20
  };
33
21
  }
@@ -1,4 +1,5 @@
1
- import { installDevBridge, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
1
+ import { connect } from '@bardioc/app-sdk';
2
+ import { installDevHost, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
2
3
  import { render } from 'solid-js/web';
3
4
  import { App } from './App';
4
5
  import { AppSdkProvider } from './bardioc-sdk';
@@ -15,15 +16,16 @@ const devStandalone = isDevStandalone();
15
16
  const useSdkProvider = insideIframe || devStandalone;
16
17
 
17
18
  if (devStandalone) {
18
- installDevBridge({ debug: false });
19
+ installDevHost({ appId: APP_NAME });
19
20
  }
20
21
 
21
22
  const root = document.getElementById('root')!;
22
23
 
23
24
  if (useSdkProvider) {
25
+ const bardioc = await connect();
24
26
  render(
25
27
  () => (
26
- <AppSdkProvider appId={APP_NAME}>
28
+ <AppSdkProvider bardioc={bardioc}>
27
29
  <App />
28
30
  </AppSdkProvider>
29
31
  ),
@@ -3,9 +3,12 @@ import tailwindcss from '@tailwindcss/vite';
3
3
  import { defineConfig, loadEnv } from 'vite';
4
4
  import solid from 'vite-plugin-solid';
5
5
 
6
+ const DEFAULT_PORT = {{PORT}};
7
+
6
8
  export default defineConfig(({ mode }) => {
7
9
  const env = loadEnv(mode, __dirname, '');
8
10
  const appName = env.VITE_APP_NAME?.trim();
11
+ const port = Number(env.LOCALHOST_PORT) || DEFAULT_PORT;
9
12
 
10
13
  if (!appName) {
11
14
  throw new Error('Missing VITE_APP_NAME for Vite config');
@@ -15,7 +18,7 @@ export default defineConfig(({ mode }) => {
15
18
  plugins: [
16
19
  bardiocDevAuth({ appName }),
17
20
  solid(),
18
- bardiocApp({ appName, port: {{PORT}} }),
21
+ bardiocApp({ appName, port }),
19
22
  tailwindcss(),
20
23
  ],
21
24
  };
@@ -7,3 +7,6 @@ DEV_SECRET=
7
7
 
8
8
  # Base URL of the Bardioc BFF / backend-for-frontend (e.g. https://your-host).
9
9
  API_BASE_URL=
10
+
11
+ # By default, the app will start on port {{PORT}}. Feel free to uncomment the following variable and change it to match your local setup preferences.
12
+ #LOCALHOST_PORT={{PORT}}
@@ -18,11 +18,11 @@
18
18
  "release:publish": "changeset publish"
19
19
  },
20
20
  "dependencies": {
21
- "@bardioc/app-sdk": "^0.4.9",
21
+ "@bardioc/app-sdk": "^1.0.0",
22
22
  "svelte": "^5.33.14"
23
23
  },
24
24
  "devDependencies": {
25
- "@bardioc/configs": "^0.2.1",
25
+ "@bardioc/configs": "0.2.1",
26
26
  "@changesets/cli": "^2.31.0",
27
27
  "@sveltejs/vite-plugin-svelte": "^7.2.0",
28
28
  "@tailwindcss/vite": "^4.3.0",
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import type { HostBridge, NotifyLevel } from '@bardioc/app-sdk';
2
+ import type { Bardioc, NotifyLevel } from '@bardioc/app-sdk';
3
3
  import { isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
4
4
  import { type Snippet } from 'svelte';
5
5
  import './index.css';
@@ -10,7 +10,7 @@
10
10
  | { status: 'success'; request: string; data: unknown }
11
11
  | { status: 'error'; request: string; message: string };
12
12
 
13
- let { bridge = null, children }: { bridge?: HostBridge | null; children?: Snippet } = $props();
13
+ let { bardioc = null, children }: { bardioc?: Bardioc | null; children?: Snippet } = $props();
14
14
 
15
15
  const showSdkDemo = isInsideIframe() || isDevStandalone();
16
16
 
@@ -18,24 +18,24 @@
18
18
  let running = $state(false);
19
19
 
20
20
  function notify(message: string, level?: NotifyLevel) {
21
- bridge?.notify(message, level);
21
+ bardioc?.ui.notify(message, level).catch(console.error);
22
22
  }
23
23
 
24
24
  async function runGetProfile() {
25
- if (running || !bridge) return;
25
+ if (running || !bardioc) return;
26
26
  running = true;
27
27
 
28
- const request = 'transport.os.profile.get()';
28
+ const request = 'os.profile.get()';
29
29
  result = { status: 'loading', request };
30
30
 
31
31
  const startTime = Date.now();
32
- notify('Getting user profile', 'info');
32
+ notify('Getting user profile…', 'info');
33
33
 
34
34
  try {
35
- const data = await bridge.transport.os.profile.get();
35
+ const data = await bardioc.os.profile.get();
36
36
 
37
37
  const duration = Date.now() - startTime;
38
- notify(`Profile loaded (${duration}ms)`, 'success');
38
+ notify(`Profile loaded (${duration}ms).`, 'success');
39
39
  result = { status: 'success', request, data };
40
40
  } catch (err) {
41
41
  const message = err instanceof Error ? err.message : String(err);
@@ -47,10 +47,10 @@
47
47
  }
48
48
 
49
49
  function handleNotify() {
50
- notify('Hello from {{DISPLAY_NAME}}', 'info');
50
+ notify('Hello from {{DISPLAY_NAME}}.', 'info');
51
51
  result = {
52
52
  status: 'success',
53
- request: 'SDK_NOTIFY',
53
+ request: 'ui.notify',
54
54
  data: { ok: true, message: 'Notification sent to OS' },
55
55
  };
56
56
  }
@@ -60,7 +60,7 @@
60
60
  }
61
61
  </script>
62
62
 
63
- <div class="bg-background text-foreground min-h-screen">
63
+ <div class="bg-background text-foreground @container/app min-h-screen">
64
64
  {#if showSdkDemo}
65
65
  <div class="mx-auto flex min-h-screen w-full max-w-3xl flex-col gap-3 p-4">
66
66
  <div class="flex flex-col gap-1">
@@ -125,7 +125,7 @@
125
125
  <div class="mx-auto flex min-h-screen w-full max-w-3xl flex-col gap-4 p-4">
126
126
  <h1 class="m-0 text-2xl font-semibold">Hello Bardioc App</h1>
127
127
  <p class="text-muted-foreground m-0 max-w-2xl text-xs leading-5">
128
- Open this app inside Bardioc OS to use transport requests and send host notifications.
128
+ Open this app inside Bardioc to use transport requests and send host notifications.
129
129
  </p>
130
130
  <div class="border-border bg-muted/20 rounded-xl border p-3 text-xs leading-5">
131
131
  Outside the host iframe this page is only a local preview shell.
@@ -1,5 +1,5 @@
1
- import { createHostBridge } from '@bardioc/app-sdk';
2
- import { installDevBridge, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
1
+ import { connect } from '@bardioc/app-sdk';
2
+ import { installDevHost, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
3
3
  import { mount } from 'svelte';
4
4
  import App from './App.svelte';
5
5
  import './index.css';
@@ -15,12 +15,12 @@ const devStandalone = isDevStandalone();
15
15
  const useSdkProvider = insideIframe || devStandalone;
16
16
 
17
17
  if (devStandalone) {
18
- installDevBridge({ debug: false });
18
+ installDevHost({ appId: APP_NAME });
19
19
  }
20
20
 
21
- const bridge = useSdkProvider ? createHostBridge({ appId: APP_NAME }) : null;
21
+ const bardioc = useSdkProvider ? await connect() : null;
22
22
 
23
23
  mount(App, {
24
24
  target: document.getElementById('app')!,
25
- props: { bridge },
25
+ props: { bardioc },
26
26
  });
@@ -3,9 +3,12 @@ import { svelte } from '@sveltejs/vite-plugin-svelte';
3
3
  import tailwindcss from '@tailwindcss/vite';
4
4
  import { defineConfig, loadEnv } from 'vite';
5
5
 
6
+ const DEFAULT_PORT = {{PORT}};
7
+
6
8
  export default defineConfig(({ mode }) => {
7
9
  const env = loadEnv(mode, __dirname, '');
8
10
  const appName = env.VITE_APP_NAME?.trim();
11
+ const port = Number(env.LOCALHOST_PORT) || DEFAULT_PORT;
9
12
 
10
13
  if (!appName) {
11
14
  throw new Error('Missing VITE_APP_NAME for Vite config');
@@ -15,7 +18,7 @@ export default defineConfig(({ mode }) => {
15
18
  plugins: [
16
19
  bardiocDevAuth({ appName }),
17
20
  svelte(),
18
- bardiocApp({ appName, port: {{PORT}} }),
21
+ bardiocApp({ appName, port }),
19
22
  tailwindcss(),
20
23
  ],
21
24
  };
@@ -7,3 +7,6 @@ DEV_SECRET=
7
7
 
8
8
  # Base URL of the Bardioc BFF / backend-for-frontend (e.g. https://your-host).
9
9
  API_BASE_URL=
10
+
11
+ # By default, the app will start on port {{PORT}}. Feel free to uncomment the following variable and change it to match your local setup preferences.
12
+ #LOCALHOST_PORT={{PORT}}
@@ -35,9 +35,9 @@ src/
35
35
  auth/
36
36
  onboarding.tsx # Empty full-page screen with the DEV_SECRET dev-auth steps
37
37
  shell/
38
- app-shell.tsx # Sidebar + view routing + Toaster + OS top-menu integration (useCommandMenu)
38
+ app-shell.tsx # Sidebar + Page + view routing + Toaster + OS top-menu (useCommandMenu)
39
39
  about-dialog.tsx # "About" Dialog — reads public/app-manifest.json at runtime (manifest example)
40
- header.tsx # location combobox + language switcher + sync
40
+ header.tsx # Page actions: location combobox + language switcher + sync
41
41
  climate/
42
42
  types.ts # Station/ClimateState + METRICS config (icon, unit, color)
43
43
  climate-data.ts # demo-data generator (replace with your real source)
@@ -87,9 +87,10 @@ live SDK data comes only when the app is opened inside the host, or when `DEV_SE
87
87
 
88
88
  ## UI — `@bardioc/ui`
89
89
 
90
- Tailwind v4 + the Bardioc design system. **Never restyle with raw hex/oklch** — use the theme
91
- tokens (`bg-background`, `text-foreground`, `text-muted-foreground`, `bg-card`, `border-border`,
92
- `bg-primary`, and chart tokens `var(--chart-1..5)`). Theme is wired in `src/index.css`:
90
+ Tailwind v4 + the Bardioc design system. **Before writing any UI, read
91
+ `node_modules/@bardioc/ui/docs/INDEX.md`** — component choice, design tokens, layout and spacing
92
+ patterns, and copy rules ship with the installed package, so they match its version. Theme is wired
93
+ in `src/index.css`:
93
94
 
94
95
  ```css
95
96
  @import 'tailwindcss';
@@ -113,6 +114,7 @@ import {
113
114
  Empty,
114
115
  FilterDropdown,
115
116
  Kbd,
117
+ Page,
116
118
  SidebarBasic,
117
119
  SidebarContainedProvider,
118
120
  SortableColumnHeader,
@@ -126,10 +128,33 @@ import type { ChartConfig } from '@bardioc/ui/shadcn/chart';
126
128
  import type { TReactTable } from '@bardioc/ui/types'; // TReactTable.ColumnDef<Row>
127
129
  ```
128
130
 
129
- Prefer a Bardioc component over a raw HTML element. Icons come from `lucide-react`. The
130
- sidebar uses `SidebarBasic` inside a `SidebarContainedProvider` (the contained variant for
131
+ The sidebar uses `SidebarBasic` inside a `SidebarContainedProvider` (the contained variant for
131
132
  OS windows); the language switcher is `ConnectedLanguageSwitcher useI18n={useI18n}`.
132
133
 
134
+ ### Layout — the container contract
135
+
136
+ The app root opens `@container/app`; `Page` opens its own `@container/page` inside it. Keep both:
137
+ sizing that should follow the whole app reads `@container/app`, and anything inside the page column
138
+ — the page header included — reads `@container/page`, so it responds to the column rather than the
139
+ window.
140
+
141
+ `Page` is the scrolling column, a **sibling of the sidebar** — it owns the header, the scroller and
142
+ the padding that lines them up. Don't compose a header and a `ScrollArea` by hand, and don't wrap
143
+ the sidebar in it:
144
+
145
+ ```tsx
146
+ <div className="bg-background text-foreground @container/app flex h-full min-h-0">
147
+ <SidebarBasic … />
148
+ <Page title={pageTitle} actions={<Header />} actionsClassName="gap-2" sticky className="min-w-0">
149
+ <ViewContent view={view} />
150
+ </Page>
151
+ </div>
152
+ ```
153
+
154
+ Collapse your own `actions` against the same container (e.g. `@3xl/page:hidden`) so both sides agree
155
+ on what "wide enough" means. `sticky` keeps the header at the top while the body scrolls under it,
156
+ compacting once it does; drop it if you want the header to scroll away instead.
157
+
133
158
  ---
134
159
 
135
160
  ## i18n — `@bardioc/i18n-core`
@@ -150,6 +175,8 @@ t('overview.updated', { fallback: 'Updated {time}', params: { time } });
150
175
  - Always pass a `fallback` so a missing key degrades gracefully.
151
176
  - `@bardioc/ui` component strings ship with the `@bardioc/ui` package itself — the app only
152
177
  carries its own `en/de.json`.
178
+ - Copy style (Title Case labels, sentence-case messages, American English):
179
+ `node_modules/@bardioc/ui/docs/copy.md`.
153
180
 
154
181
  ---
155
182
 
@@ -18,15 +18,15 @@
18
18
  "release:publish": "changeset publish"
19
19
  },
20
20
  "dependencies": {
21
- "@bardioc/app-sdk": "^0.4.9",
21
+ "@bardioc/app-sdk": "^1.0.0",
22
22
  "@bardioc/i18n-core": "^0.1.1",
23
- "@bardioc/ui": "^0.3.1",
23
+ "@bardioc/ui": "^0.7.29",
24
24
  "lucide-react": "^0.544.0",
25
25
  "react": "19.2.6",
26
26
  "react-dom": "19.2.6"
27
27
  },
28
28
  "devDependencies": {
29
- "@bardioc/configs": "^0.2.1",
29
+ "@bardioc/configs": "0.2.1",
30
30
  "@changesets/cli": "^2.31.0",
31
31
  "@tailwindcss/vite": "^4.3.0",
32
32
  "@types/node": "^22.19.19",
@@ -8,7 +8,6 @@
8
8
  "icon": "icon.svg",
9
9
  "author": { "name": "{{DISPLAY_NAME}} Team" },
10
10
  "categories": ["productivity"],
11
- "permissions": ["notify", "transport", "indexdb", "events"],
12
11
  "showInDock": true,
13
12
  "showInDockAppsMenu": true,
14
13
  "window": {