@bardioc/create-bardioc-app 0.4.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 (108) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +105 -0
  3. package/bin/create.mjs +76 -0
  4. package/package.json +45 -0
  5. package/src/scaffold.d.ts +50 -0
  6. package/src/scaffold.js +379 -0
  7. package/templates/_base/.changeset/README.md +17 -0
  8. package/templates/_base/.changeset/config.json +12 -0
  9. package/templates/_base/.claude/commands/changeset-app.md +104 -0
  10. package/templates/_base/.claude/commands/refresh-bundle.md +101 -0
  11. package/templates/_base/README.md +89 -0
  12. package/templates/_base/public/app-manifest.json +10 -0
  13. package/templates/_base/scripts/stamp-manifest.mjs +17 -0
  14. package/templates/_opt-link/_npmrc +2 -0
  15. package/templates/_opt-link/pnpm-workspace.yaml +3 -0
  16. package/templates/_opt-link/scripts/link-source.mjs +188 -0
  17. package/templates/_opt-pipeline/bitbucket-pipelines.yml +100 -0
  18. package/templates/angular/.env.example +5 -0
  19. package/templates/angular/_gitignore +7 -0
  20. package/templates/angular/angular.json +64 -0
  21. package/templates/angular/package.json +49 -0
  22. package/templates/angular/postcss.config.mjs +5 -0
  23. package/templates/angular/public/icon.svg +1 -0
  24. package/templates/angular/public/runtime-env.js +1 -0
  25. package/templates/angular/scripts/dev-auth-proxy.mjs +92 -0
  26. package/templates/angular/scripts/sync-runtime-env.mjs +89 -0
  27. package/templates/angular/src/app/app.component.ts +181 -0
  28. package/templates/angular/src/app/bardioc-bridge.ts +5 -0
  29. package/templates/angular/src/app/bardioc.token.ts +4 -0
  30. package/templates/angular/src/index.html +15 -0
  31. package/templates/angular/src/main.ts +82 -0
  32. package/templates/angular/src/runtime-env.ts +17 -0
  33. package/templates/angular/src/styles.css +258 -0
  34. package/templates/angular/src/vite-env.d.ts +10 -0
  35. package/templates/angular/tsconfig.json +27 -0
  36. package/templates/manifest.json +13 -0
  37. package/templates/nextjs/.env.example +8 -0
  38. package/templates/nextjs/_gitignore +7 -0
  39. package/templates/nextjs/app/globals.css +75 -0
  40. package/templates/nextjs/app/layout.tsx +17 -0
  41. package/templates/nextjs/app/page.tsx +222 -0
  42. package/templates/nextjs/app/proxy/route.ts +85 -0
  43. package/templates/nextjs/global.d.ts +1 -0
  44. package/templates/nextjs/next-env.d.ts +5 -0
  45. package/templates/nextjs/next.config.ts +21 -0
  46. package/templates/nextjs/package.json +32 -0
  47. package/templates/nextjs/postcss.config.mjs +5 -0
  48. package/templates/nextjs/public/icon.svg +1 -0
  49. package/templates/nextjs/tailwind.config.ts +10 -0
  50. package/templates/nextjs/tsconfig.json +27 -0
  51. package/templates/preact/.env.example +13 -0
  52. package/templates/preact/_gitignore +9 -0
  53. package/templates/preact/index.html +13 -0
  54. package/templates/preact/package.json +32 -0
  55. package/templates/preact/public/icon.svg +1 -0
  56. package/templates/preact/src/App.tsx +139 -0
  57. package/templates/preact/src/index.css +76 -0
  58. package/templates/preact/src/main.tsx +46 -0
  59. package/templates/preact/src/vite-env.d.ts +11 -0
  60. package/templates/preact/tsconfig.json +19 -0
  61. package/templates/preact/vite.config.ts +17 -0
  62. package/templates/solid/.env.example +13 -0
  63. package/templates/solid/_gitignore +9 -0
  64. package/templates/solid/index.html +13 -0
  65. package/templates/solid/package.json +32 -0
  66. package/templates/solid/public/icon.svg +1 -0
  67. package/templates/solid/src/App.tsx +150 -0
  68. package/templates/solid/src/bardioc-sdk.tsx +33 -0
  69. package/templates/solid/src/index.css +76 -0
  70. package/templates/solid/src/main.tsx +50 -0
  71. package/templates/solid/src/vite-env.d.ts +11 -0
  72. package/templates/solid/tsconfig.json +20 -0
  73. package/templates/solid/vite.config.ts +17 -0
  74. package/templates/svelte/.env.example +5 -0
  75. package/templates/svelte/_gitignore +6 -0
  76. package/templates/svelte/index.html +13 -0
  77. package/templates/svelte/package.json +32 -0
  78. package/templates/svelte/public/icon.svg +1 -0
  79. package/templates/svelte/src/App.svelte +135 -0
  80. package/templates/svelte/src/index.css +76 -0
  81. package/templates/svelte/src/main.ts +42 -0
  82. package/templates/svelte/src/vite-env.d.ts +11 -0
  83. package/templates/svelte/tsconfig.json +13 -0
  84. package/templates/svelte/vite.config.ts +17 -0
  85. package/templates/vite/.env.example +14 -0
  86. package/templates/vite/CLAUDE.md +114 -0
  87. package/templates/vite/_gitignore +9 -0
  88. package/templates/vite/index.html +13 -0
  89. package/templates/vite/package.json +34 -0
  90. package/templates/vite/public/icon.svg +1 -0
  91. package/templates/vite/src/App.tsx +141 -0
  92. package/templates/vite/src/index.css +76 -0
  93. package/templates/vite/src/main.tsx +44 -0
  94. package/templates/vite/src/vite-env.d.ts +11 -0
  95. package/templates/vite/tsconfig.json +18 -0
  96. package/templates/vite/vite.config.ts +17 -0
  97. package/templates/vue/.env.example +5 -0
  98. package/templates/vue/_gitignore +6 -0
  99. package/templates/vue/index.html +13 -0
  100. package/templates/vue/package.json +32 -0
  101. package/templates/vue/public/icon.svg +1 -0
  102. package/templates/vue/src/App.vue +127 -0
  103. package/templates/vue/src/bardioc-sdk.ts +23 -0
  104. package/templates/vue/src/index.css +76 -0
  105. package/templates/vue/src/main.ts +43 -0
  106. package/templates/vue/src/vite-env.d.ts +17 -0
  107. package/templates/vue/tsconfig.json +26 -0
  108. package/templates/vue/vite.config.ts +17 -0
@@ -0,0 +1,64 @@
1
+ {
2
+ "$schema": "https://schemas.angular.io/schematics/angular",
3
+ "version": 1,
4
+ "newProjectRoot": "projects",
5
+ "projects": {
6
+ "{{APP_NAME}}": {
7
+ "projectType": "application",
8
+ "root": "",
9
+ "sourceRoot": "src",
10
+ "prefix": "app",
11
+ "architect": {
12
+ "build": {
13
+ "builder": "@angular-devkit/build-angular:application",
14
+ "options": {
15
+ "outputPath": "dist/{{APP_NAME}}",
16
+ "index": "src/index.html",
17
+ "browser": "src/main.ts",
18
+ "polyfills": ["zone.js"],
19
+ "tsConfig": "tsconfig.json",
20
+ "assets": [{ "glob": "**/*", "input": "public" }],
21
+ "styles": ["src/styles.css"],
22
+ "scripts": [],
23
+ "outputMode": "static"
24
+ },
25
+ "configurations": {
26
+ "production": {
27
+ "budgets": [
28
+ {
29
+ "type": "initial",
30
+ "maximumWarning": "1MB",
31
+ "maximumError": "2MB"
32
+ },
33
+ {
34
+ "type": "anyComponentStyle",
35
+ "maximumWarning": "4kB",
36
+ "maximumError": "8kB"
37
+ }
38
+ ],
39
+ "outputHashing": "all"
40
+ },
41
+ "development": {
42
+ "optimization": false,
43
+ "extractLicenses": false,
44
+ "sourceMap": true
45
+ }
46
+ },
47
+ "defaultConfiguration": "production"
48
+ },
49
+ "serve": {
50
+ "builder": "@angular-devkit/build-angular:dev-server",
51
+ "configurations": {
52
+ "production": {
53
+ "buildTarget": "{{APP_NAME}}:build:production"
54
+ },
55
+ "development": {
56
+ "buildTarget": "{{APP_NAME}}:build:development"
57
+ }
58
+ },
59
+ "defaultConfiguration": "development"
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "{{APP_NAME}}",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "scripts": {
6
+ "sync:runtime-env": "node ./scripts/sync-runtime-env.mjs",
7
+ "ng": "ng",
8
+ "predev": "pnpm sync:runtime-env",
9
+ "dev": "node ./scripts/dev-auth-proxy.mjs --app-port {{PORT}} & PROXY_PID=$!; ng serve --port {{PORT}}; EXIT_CODE=$?; kill $PROXY_PID; exit $EXIT_CODE",
10
+ "predev:live": "pnpm sync:runtime-env",
11
+ "dev:live": "node ./scripts/dev-auth-proxy.mjs --app-port {{PORT}} & PROXY_PID=$!; BARDIOC_TUNNEL=1 ng serve --port {{PORT}}; EXIT_CODE=$?; kill $PROXY_PID; exit $EXIT_CODE",
12
+ "prebuild": "pnpm sync:runtime-env",
13
+ "build": "ng build && node scripts/stamp-manifest.mjs dist/{{APP_NAME}}/browser",
14
+ "bundle": "ng build && node scripts/stamp-manifest.mjs dist/{{APP_NAME}}/browser && cd dist/{{APP_NAME}}/browser && zip -r ../../../{{APP_NAME}}.zip .",
15
+ "prewatch": "pnpm sync:runtime-env",
16
+ "watch": "ng build --watch --configuration development",
17
+ "precheck-types": "pnpm sync:runtime-env",
18
+ "check-types": "ng build --configuration development",
19
+ "changeset": "changeset",
20
+ "release:status": "changeset status --verbose",
21
+ "release:version": "changeset version && pnpm install --lockfile-only",
22
+ "release:publish": "changeset publish"
23
+ },
24
+ "dependencies": {
25
+ "@angular/animations": "^19.2.12",
26
+ "@angular/common": "^19.2.12",
27
+ "@angular/compiler": "^19.2.12",
28
+ "@angular/core": "^19.2.12",
29
+ "@angular/forms": "^19.2.12",
30
+ "@angular/platform-browser": "^19.2.12",
31
+ "@angular/platform-browser-dynamic": "^19.2.12",
32
+ "@angular/router": "^19.2.12",
33
+ "@bardioc/app-sdk": "latest",
34
+ "rxjs": "~7.8.2",
35
+ "tslib": "^2.8.1",
36
+ "zone.js": "~0.15.1"
37
+ },
38
+ "devDependencies": {
39
+ "@angular-devkit/build-angular": "^19.2.13",
40
+ "@angular/cli": "^19.2.13",
41
+ "@angular/compiler-cli": "^19.2.12",
42
+ "@changesets/cli": "^2.31.0",
43
+ "@tailwindcss/postcss": "^4.2.4",
44
+ "autoprefixer": "^10.4.21",
45
+ "postcss": "^8.5.4",
46
+ "tailwindcss": "^4.2.4",
47
+ "typescript": "~5.8.3"
48
+ }
49
+ }
@@ -0,0 +1,5 @@
1
+ import tailwindcss from '@tailwindcss/postcss';
2
+
3
+ export default {
4
+ plugins: [tailwindcss()],
5
+ };
@@ -0,0 +1 @@
1
+ <svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="15.3012" x2="-2.25993" y1="1.77049" y2="12.9254"><stop offset=".4898" stop-color="#c084fc"/><stop offset="1" stop-color="#9333ea"/></linearGradient><path d="m14.3984 3.35791c1.9618.00013 3.5514 1.59021 3.5518 3.55176v8.08593c0 1.9602-1.5896 3.5507-3.5518 3.5508h-8.84567c-1.96194-.0002-3.55273-1.5909-3.55273-3.5527v-8.08403c.00042-1.96151 1.59105-3.55156 3.55273-3.55176zm4.5186 12.18069c.0121-.1019.0221-.2048.0273-.3086.004-.0776.0059-.1559.0059-.2344v-8.08593c0-.18616-.0124-.36951-.0342-.54981.0218.18056.0352.36435.0352.55078v8.08496c0 .1837-.013.3649-.0342.543zm-17.8672.1318c-.03282-.2205-.0498-.4471-.0498-.6767 0 .2298.01694.456.0498.6767zm.00098-9.44042c-.03187.21266-.0494.43015-.05078.65137.00138-.22122.01891-.43871.05078-.65137zm3.60254-3.7832c.0723-.01449.14526-.02707.21875-.03809-.07349.01102-.14645.0236-.21875.03809zm.66504-.08301c-.14548.00737-.2891.02225-.43066.04297.14156-.02072.28518-.0356.43066-.04297zm9.31444 0c.1368.00693.272.02032.4053.03906-.1332-.01872-.2686-.03213-.4053-.03906zm-9.76171 17.13183c-.06758-.0101-.1346-.0221-.20117-.0352.06658.0131.13359.0251.20117.0352zm-2.92578-1.7256c-.0288-.0374-.0573-.075-.08496-.1133.02766.0383.05616.0759.08496.1133zm16.82719-12.11912c.0144.05023.0292.10044.042.15137-.0128-.05093-.0276-.10114-.042-.15137zm.0449.16504c.0166.06713.0313.13485.0449.20312-.0135-.06826-.0284-.13599-.0449-.20312zm.0644.31152c.006.03443.0124.06883.0176.10352-.0052-.03469-.0116-.06909-.0176-.10352zm-17.81246 9.65526c-.00653-.0373-.01393-.0746-.01954-.1123.00561.0377.01301.075.01954.1123zm17.57126-10.5244c.0165.04237.0326.08495.0479.12793-.0153-.04298-.0314-.08556-.0479-.12793zm-14.12888-2.78027c.04696-.01099.09409-.02174.1416-.03125-.04751.00952-.09464.02026-.1416.03125z" fill="url(#a)"/><g opacity=".31"><path d="m3.24438 5.75049v7.11941c0 1.4408.99919 2.6095 2.23108 2.6095h9.00044c1.2319 0 2.231-1.1687 2.231-2.6095v-7.11941z" fill="#fff" fill-opacity=".6"/></g><rect x="6" y="7" width="8" height="1.5" rx="0.75" fill="#eddcff"/><rect x="6" y="10" width="8" height="1.5" rx="0.75" fill="#eddcff"/><rect x="6" y="13" width="5" height="1.5" rx="0.75" fill="#eddcff"/></svg>
@@ -0,0 +1 @@
1
+ window.__BARDIOC_RUNTIME_ENV__ = {};
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'node:fs';
4
+ import { createServer } from 'node:http';
5
+ import { dirname, join, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { createDevAuthProxyHandler } from '@bardioc/app-sdk/dev-proxy';
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const projectRoot = resolve(__dirname, '..');
11
+ const appPort = readAppPort();
12
+ const proxyPort = appPort + 100;
13
+ const env = loadEnv(projectRoot);
14
+
15
+ if (!env.VITE_APP_ID || !env.DEV_AUTH_HOST_URL || !env.DEV_SESSION_KEY) {
16
+ process.stderr.write('[bardioc-dev-auth-proxy] missing env, proxy disabled\n');
17
+ await new Promise(() => {});
18
+ }
19
+
20
+ const handler = createDevAuthProxyHandler({
21
+ appId: env.VITE_APP_ID,
22
+ hostUrl: env.DEV_AUTH_HOST_URL,
23
+ devSessionKey: env.DEV_SESSION_KEY,
24
+ allowOrigin: '*',
25
+ });
26
+
27
+ const server = createServer((req, res) => {
28
+ void handler(req, res);
29
+ });
30
+
31
+ server.listen(proxyPort, '127.0.0.1', () => {
32
+ process.stdout.write(`[bardioc-dev-auth-proxy] listening on http://127.0.0.1:${proxyPort}/proxy\n`);
33
+ });
34
+
35
+ for (const signal of ['SIGINT', 'SIGTERM']) {
36
+ process.on(signal, () => {
37
+ server.close(() => process.exit(0));
38
+ });
39
+ }
40
+
41
+ function readAppPort() {
42
+ const flagIndex = process.argv.indexOf('--app-port');
43
+ const raw = flagIndex >= 0 ? process.argv[flagIndex + 1] : undefined;
44
+ const parsed = Number.parseInt(raw ?? '{{PORT}}', 10);
45
+ return Number.isFinite(parsed) ? parsed : {{PORT}};
46
+ }
47
+
48
+ function loadEnv(projectDir) {
49
+ const result = {};
50
+
51
+ for (const fileName of ['.env', '.env.local']) {
52
+ const filePath = join(projectDir, fileName);
53
+
54
+ try {
55
+ Object.assign(result, parseEnv(readFileSync(filePath, 'utf8')));
56
+ } catch {
57
+ // Ignore missing env files.
58
+ }
59
+ }
60
+
61
+ return result;
62
+ }
63
+
64
+ function parseEnv(source) {
65
+ const result = {};
66
+
67
+ for (const rawLine of source.split(/\r?\n/)) {
68
+ const line = rawLine.trim();
69
+ if (!line || line.startsWith('#')) {
70
+ continue;
71
+ }
72
+
73
+ const equalsIndex = line.indexOf('=');
74
+ if (equalsIndex <= 0) {
75
+ continue;
76
+ }
77
+
78
+ const key = line.slice(0, equalsIndex).trim();
79
+ let value = line.slice(equalsIndex + 1).trim();
80
+
81
+ if (
82
+ (value.startsWith('"') && value.endsWith('"')) ||
83
+ (value.startsWith("'") && value.endsWith("'"))
84
+ ) {
85
+ value = value.slice(1, -1);
86
+ }
87
+
88
+ result[key] = value;
89
+ }
90
+
91
+ return result;
92
+ }
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const projectRoot = resolve(__dirname, '..');
9
+ const env = loadEnv(projectRoot);
10
+ const appPort = readAppPort();
11
+ const proxyPort = appPort + 100;
12
+
13
+ const runtimeEnv = {
14
+ VITE_APP_NAME: env.VITE_APP_NAME,
15
+ VITE_APP_ID: env.VITE_APP_ID,
16
+ VITE_ENABLE_DEV_AUTH: env.VITE_ENABLE_DEV_AUTH,
17
+ DEV_AUTH_HOST_URL: env.DEV_AUTH_HOST_URL,
18
+ DEV_SESSION_KEY: env.DEV_SESSION_KEY,
19
+ };
20
+
21
+ const injectedDevAuth =
22
+ env.DEV_AUTH_HOST_URL && env.DEV_SESSION_KEY
23
+ ? {
24
+ hostUrl: env.DEV_AUTH_HOST_URL,
25
+ sessionKey: env.DEV_SESSION_KEY,
26
+ proxyUrl: `http://127.0.0.1:${proxyPort}/proxy`,
27
+ }
28
+ : null;
29
+
30
+ const outputPath = join(projectRoot, 'public', 'runtime-env.js');
31
+ mkdirSync(dirname(outputPath), { recursive: true });
32
+ writeFileSync(
33
+ outputPath,
34
+ `window.__BARDIOC_RUNTIME_ENV__ = ${JSON.stringify(runtimeEnv, null, 2)};\nwindow.__BARDIOC_DEV_AUTH__ = ${JSON.stringify(injectedDevAuth, null, 2)};\n`,
35
+ 'utf8'
36
+ );
37
+
38
+ function readAppPort() {
39
+ const flagIndex = process.argv.indexOf('--app-port');
40
+ const raw = flagIndex >= 0 ? process.argv[flagIndex + 1] : undefined;
41
+ const parsed = Number.parseInt(raw ?? '{{PORT}}', 10);
42
+ return Number.isFinite(parsed) ? parsed : {{PORT}};
43
+ }
44
+
45
+ function loadEnv(projectDir) {
46
+ const result = {};
47
+
48
+ for (const fileName of ['.env', '.env.local']) {
49
+ const filePath = join(projectDir, fileName);
50
+
51
+ try {
52
+ Object.assign(result, parseEnv(readFileSync(filePath, 'utf8')));
53
+ } catch {
54
+ // Ignore missing env files.
55
+ }
56
+ }
57
+
58
+ return result;
59
+ }
60
+
61
+ function parseEnv(source) {
62
+ const result = {};
63
+
64
+ for (const rawLine of source.split(/\r?\n/)) {
65
+ const line = rawLine.trim();
66
+ if (!line || line.startsWith('#')) {
67
+ continue;
68
+ }
69
+
70
+ const equalsIndex = line.indexOf('=');
71
+ if (equalsIndex <= 0) {
72
+ continue;
73
+ }
74
+
75
+ const key = line.slice(0, equalsIndex).trim();
76
+ let value = line.slice(equalsIndex + 1).trim();
77
+
78
+ if (
79
+ (value.startsWith('"') && value.endsWith('"')) ||
80
+ (value.startsWith("'") && value.endsWith("'"))
81
+ ) {
82
+ value = value.slice(1, -1);
83
+ }
84
+
85
+ result[key] = value;
86
+ }
87
+
88
+ return result;
89
+ }
@@ -0,0 +1,181 @@
1
+ import { isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
2
+ import { JsonPipe } from '@angular/common';
3
+ import { Component, inject, signal } from '@angular/core';
4
+ import { BARDIOC_BRIDGE } from './bardioc.token';
5
+ import type { HostBridge } from '@bardioc/app-sdk';
6
+ import { readRuntimeEnv } from '../runtime-env';
7
+
8
+ type InjectedDevAuthConfig = {
9
+ hostUrl?: string;
10
+ sessionKey?: string;
11
+ };
12
+
13
+ function readInjectedDevAuthConfig(): InjectedDevAuthConfig | null {
14
+ const config = (globalThis as typeof globalThis & {
15
+ __BARDIOC_DEV_AUTH__?: InjectedDevAuthConfig;
16
+ }).__BARDIOC_DEV_AUTH__;
17
+
18
+ if (!config?.hostUrl || !config?.sessionKey) {
19
+ return null;
20
+ }
21
+
22
+ return {
23
+ hostUrl: config.hostUrl,
24
+ sessionKey: config.sessionKey,
25
+ };
26
+ }
27
+
28
+ type ResultState =
29
+ | { status: 'idle' }
30
+ | { status: 'loading'; request: string }
31
+ | { status: 'success'; request: string; data: unknown }
32
+ | { status: 'error'; request: string; message: string };
33
+
34
+ @Component({
35
+ selector: 'app-root',
36
+ standalone: true,
37
+ imports: [JsonPipe],
38
+ template: `
39
+ <div class="bg-background text-foreground min-h-screen">
40
+ @if (showSdkDemo) {
41
+ <div class="mx-auto flex min-h-screen w-full max-w-3xl flex-col gap-3 p-4">
42
+ <div class="flex flex-col gap-1">
43
+ <h1 class="m-0 text-2xl font-semibold">Hello Bardioc App</h1>
44
+ <p class="text-muted-foreground m-0 text-xs leading-5">
45
+ Minimal hosted-app demo for API transport and SDK APIs.
46
+ </p>
47
+ </div>
48
+
49
+ <div class="flex flex-wrap gap-2">
50
+ <button
51
+ class="bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 rounded px-3 py-1 text-xs font-medium disabled:cursor-not-allowed"
52
+ (click)="runGetProfile()"
53
+ [disabled]="running()">
54
+ Get Profile
55
+ </button>
56
+ <button
57
+ class="bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 rounded px-3 py-1 text-xs font-medium disabled:cursor-not-allowed"
58
+ (click)="handleNotify()"
59
+ [disabled]="running()">
60
+ Send Notification OS
61
+ </button>
62
+ <button
63
+ class="border-border text-muted-foreground hover:text-foreground rounded border px-3 py-1 text-xs"
64
+ (click)="clearResult()"
65
+ [disabled]="running()">
66
+ Clear
67
+ </button>
68
+ </div>
69
+
70
+ <div class="border-border bg-background flex min-h-0 flex-1 flex-col overflow-hidden rounded border">
71
+ @switch (result().status) {
72
+ @case ('idle') {
73
+ <div class="text-muted-foreground flex h-full items-center justify-center p-3 text-center text-xs leading-5">
74
+ Run a query to see results. If the host session is missing, the transport route will return 401.
75
+ </div>
76
+ }
77
+ @case ('loading') {
78
+ <div class="flex h-full flex-col items-center justify-center gap-2 p-3">
79
+ <div class="text-muted-foreground font-mono text-xs">{{ resultRequest() }}</div>
80
+ <div class="text-muted-foreground text-xs">Loading…</div>
81
+ </div>
82
+ }
83
+ @case ('error') {
84
+ <div class="flex h-full flex-col gap-2 p-3 text-xs">
85
+ <div class="text-muted-foreground border-border border-b pb-2 font-mono text-xs">
86
+ {{ resultRequest() }}
87
+ </div>
88
+ <div class="text-destructive whitespace-pre-wrap break-all">{{ resultMessage() }}</div>
89
+ </div>
90
+ }
91
+ @case ('success') {
92
+ <div class="flex h-full flex-col gap-0 overflow-hidden">
93
+ <div class="border-border text-muted-foreground shrink-0 border-b px-3 py-1 font-mono text-xs">
94
+ {{ resultRequest() }}
95
+ </div>
96
+ <pre class="text-foreground flex-1 overflow-auto p-3 text-[11px] leading-5">{{ resultData() | json }}</pre>
97
+ </div>
98
+ }
99
+ }
100
+ </div>
101
+ </div>
102
+ } @else {
103
+ <div class="mx-auto flex min-h-screen w-full max-w-3xl flex-col gap-4 p-4">
104
+ <h1 class="m-0 text-2xl font-semibold">Hello Bardioc App</h1>
105
+ <p class="text-muted-foreground m-0 max-w-2xl text-xs leading-5">
106
+ Open this app inside Bardioc OS to use transport requests and send host notifications.
107
+ </p>
108
+ <div class="border-border bg-muted/20 rounded-xl border p-3 text-xs leading-5">
109
+ Outside the host iframe this page is only a local preview shell.
110
+ </div>
111
+ </div>
112
+ }
113
+ </div>
114
+ `,
115
+ })
116
+ export class AppComponent {
117
+ private bridge = inject(BARDIOC_BRIDGE, { optional: true }) as HostBridge | null;
118
+ private injectedDevAuth = readInjectedDevAuthConfig();
119
+
120
+ showSdkDemo =
121
+ isInsideIframe() ||
122
+ (readRuntimeEnv('VITE_ENABLE_DEV_AUTH') === 'true' &&
123
+ !!this.injectedDevAuth?.hostUrl &&
124
+ !!this.injectedDevAuth?.sessionKey &&
125
+ isDevStandalone());
126
+ result = signal<ResultState>({ status: 'idle' });
127
+ running = signal(false);
128
+
129
+ async runGetProfile(): Promise<void> {
130
+ if (this.running() || !this.bridge) return;
131
+ this.running.set(true);
132
+
133
+ const request = 'transport.os.profile.get()';
134
+ this.result.set({ status: 'loading', request });
135
+
136
+ const startTime = Date.now();
137
+ this.bridge.notify('Getting user profile', 'info');
138
+
139
+ try {
140
+ const data = await this.bridge.transport.os.profile.get();
141
+ const duration = Date.now() - startTime;
142
+ this.bridge.notify(`Profile loaded (${duration}ms)`, 'success');
143
+ this.result.set({ status: 'success', request, data });
144
+ } catch (err) {
145
+ const message = err instanceof Error ? err.message : String(err);
146
+ this.bridge.notify(`Failed: ${message}`, 'error');
147
+ this.result.set({ status: 'error', request, message });
148
+ }
149
+
150
+ this.running.set(false);
151
+ }
152
+
153
+ handleNotify(): void {
154
+ if (!this.bridge) return;
155
+ this.bridge.notify('Hello from {{DISPLAY_NAME}}', 'info');
156
+ this.result.set({
157
+ status: 'success',
158
+ request: 'SDK_NOTIFY',
159
+ data: { ok: true, message: 'Notification sent to OS' },
160
+ });
161
+ }
162
+
163
+ clearResult(): void {
164
+ this.result.set({ status: 'idle' });
165
+ }
166
+
167
+ resultRequest(): string {
168
+ const state = this.result();
169
+ return 'request' in state ? state.request : '';
170
+ }
171
+
172
+ resultMessage(): string {
173
+ const state = this.result();
174
+ return 'message' in state ? state.message : '';
175
+ }
176
+
177
+ resultData(): unknown {
178
+ const state = this.result();
179
+ return 'data' in state ? state.data : null;
180
+ }
181
+ }
@@ -0,0 +1,5 @@
1
+ import { createHostBridge, type HostBridge } from '@bardioc/app-sdk';
2
+
3
+ export function createBardiocBridge(appId: string): HostBridge {
4
+ return createHostBridge({ appId });
5
+ }
@@ -0,0 +1,4 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import type { HostBridge } from '@bardioc/app-sdk';
3
+
4
+ export const BARDIOC_BRIDGE = new InjectionToken<HostBridge>('BARDIOC_BRIDGE');
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="dark" style="height: 100%; margin: 0">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>{{DISPLAY_NAME}}</title>
6
+ <base href="/" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+ <link rel="icon" type="image/x-icon" href="favicon.ico" />
9
+ <link rel="stylesheet" href="/fonts/bardioc-fonts.css" />
10
+ </head>
11
+ <body style="height: 100%; margin: 0">
12
+ <script src="runtime-env.js"></script>
13
+ <app-root style="height: 100%"></app-root>
14
+ </body>
15
+ </html>
@@ -0,0 +1,82 @@
1
+ import {
2
+ ensureDevAuthSession,
3
+ installDevBridge,
4
+ isDevStandalone,
5
+ isInsideIframe,
6
+ } from '@bardioc/app-sdk/dev';
7
+ import { bootstrapApplication } from '@angular/platform-browser';
8
+ import { provideHttpClient } from '@angular/common/http';
9
+ import { isDevMode, type EnvironmentProviders, type Provider } from '@angular/core';
10
+ import { AppComponent } from './app/app.component';
11
+ import { createBardiocBridge } from './app/bardioc-bridge';
12
+ import { BARDIOC_BRIDGE } from './app/bardioc.token';
13
+ import { readRuntimeEnv } from './runtime-env';
14
+ import './styles.css';
15
+
16
+ type InjectedDevAuthConfig = {
17
+ hostUrl?: string;
18
+ sessionKey?: string;
19
+ proxyUrl?: string;
20
+ };
21
+
22
+ function readInjectedDevAuthConfig(): InjectedDevAuthConfig | null {
23
+ const config = (globalThis as typeof globalThis & {
24
+ __BARDIOC_DEV_AUTH__?: InjectedDevAuthConfig;
25
+ }).__BARDIOC_DEV_AUTH__;
26
+
27
+ if (!config?.hostUrl || !config?.sessionKey) {
28
+ return null;
29
+ }
30
+
31
+ return {
32
+ hostUrl: config.hostUrl,
33
+ sessionKey: config.sessionKey,
34
+ proxyUrl: typeof config.proxyUrl === 'string' ? config.proxyUrl : undefined,
35
+ };
36
+ }
37
+
38
+ const APP_NAME = (readRuntimeEnv('VITE_APP_NAME') ?? document.title.trim()) || 'Bardioc App';
39
+ const APP_ID = readRuntimeEnv('VITE_APP_ID');
40
+ const injectedDevAuth = readInjectedDevAuthConfig();
41
+ const standaloneDevAuthEnabled =
42
+ isDevMode() &&
43
+ readRuntimeEnv('VITE_ENABLE_DEV_AUTH') === 'true' &&
44
+ !!injectedDevAuth?.hostUrl &&
45
+ !!injectedDevAuth?.sessionKey;
46
+
47
+ const insideIframe = isInsideIframe();
48
+ const devStandalone = standaloneDevAuthEnabled && isDevStandalone();
49
+ const useSdkProvider = insideIframe || devStandalone;
50
+
51
+ if (useSdkProvider && !APP_ID) {
52
+ throw new Error('Missing VITE_APP_ID for SDK runtime');
53
+ }
54
+
55
+ async function bootstrap() {
56
+ if (devStandalone) {
57
+ await ensureDevAuthSession({ appId: APP_ID!, appName: APP_NAME });
58
+ installDevBridge({
59
+ appId: APP_ID!,
60
+ appName: APP_NAME,
61
+ debug: false,
62
+ proxyPath: injectedDevAuth?.proxyUrl,
63
+ });
64
+ }
65
+
66
+ const providers: Array<Provider | EnvironmentProviders> = [
67
+ provideHttpClient(),
68
+ ];
69
+
70
+ if (useSdkProvider) {
71
+ providers.push({
72
+ provide: BARDIOC_BRIDGE,
73
+ useValue: createBardiocBridge(APP_ID!),
74
+ });
75
+ }
76
+
77
+ bootstrapApplication(AppComponent, {
78
+ providers,
79
+ });
80
+ }
81
+
82
+ bootstrap();
@@ -0,0 +1,17 @@
1
+ type RuntimeEnv = Record<string, string | undefined>;
2
+
3
+ declare global {
4
+ interface Window {
5
+ __BARDIOC_RUNTIME_ENV__?: RuntimeEnv;
6
+ }
7
+ }
8
+
9
+ export function readRuntimeEnv(name: string): string | undefined {
10
+ const value = window.__BARDIOC_RUNTIME_ENV__?.[name];
11
+ if (typeof value !== 'string') {
12
+ return undefined;
13
+ }
14
+
15
+ const trimmed = value.trim();
16
+ return trimmed.length > 0 ? trimmed : undefined;
17
+ }