@bardioc/app-sdk 0.4.2 → 0.4.4
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 +6 -20
- package/dist/dev-proxy.d.ts +14 -3
- package/dist/dev-proxy.js +88 -22
- package/dist/dev.d.ts +4 -29
- package/dist/dev.js +47 -144
- package/dist/dot-env.d.ts +0 -1
- package/dist/dot-env.js +0 -3
- package/dist/host-bridge.js +0 -5
- package/dist/react.d.ts +0 -3
- package/dist/react.js +6 -9
- package/dist/vite.d.ts +19 -1
- package/dist/vite.js +79 -7
- package/package.json +8 -16
- package/dist/dev-auth-proxy-core.d.ts +0 -24
- package/dist/dev-auth-proxy-core.js +0 -59
- package/dist/dev-auth-vite.d.ts +0 -34
- package/dist/dev-auth-vite.js +0 -221
- package/dist/dev-session-cli.d.ts +0 -34
- package/dist/dev-session-cli.js +0 -125
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ createRoot(document.getElementById('root')!).render(
|
|
|
56
56
|
| --------------------------- | ------------------------------------------- |
|
|
57
57
|
| `@bardioc/app-sdk` | `createHostBridge`, errors, types, manifest |
|
|
58
58
|
| `@bardioc/app-sdk/react` | `AppSdkProvider`, hooks (`useSdk`, etc.) |
|
|
59
|
-
| `@bardioc/app-sdk/dev` |
|
|
59
|
+
| `@bardioc/app-sdk/dev` | standalone dev bridge helpers |
|
|
60
60
|
| `@bardioc/app-sdk/types` | Type-only TypeScript exports |
|
|
61
61
|
| `@bardioc/app-sdk/protocol` | `SDK_MSG` constants, wire format types |
|
|
62
62
|
| `@bardioc/app-sdk/vite` | `bardiocApp()` Vite plugin |
|
|
@@ -86,21 +86,10 @@ import {
|
|
|
86
86
|
} from '@bardioc/app-sdk';
|
|
87
87
|
|
|
88
88
|
// React hooks
|
|
89
|
-
import {
|
|
90
|
-
AppSdkProvider,
|
|
91
|
-
useSdk,
|
|
92
|
-
useNotify,
|
|
93
|
-
useSendToKernel,
|
|
94
|
-
useStandaloneDevLogout,
|
|
95
|
-
} from '@bardioc/app-sdk/react';
|
|
89
|
+
import { AppSdkProvider, useSdk, useNotify, useSendToKernel } from '@bardioc/app-sdk/react';
|
|
96
90
|
|
|
97
91
|
// Standalone dev helpers
|
|
98
|
-
import {
|
|
99
|
-
ensureDevAuthSession,
|
|
100
|
-
installDevBridge,
|
|
101
|
-
isDevStandalone,
|
|
102
|
-
isInsideIframe,
|
|
103
|
-
} from '@bardioc/app-sdk/dev';
|
|
92
|
+
import { installDevBridge, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
|
|
104
93
|
```
|
|
105
94
|
|
|
106
95
|
## Vite plugin
|
|
@@ -137,12 +126,10 @@ New apps scaffolded with `create-bardioc-app` include the `<link>` already.
|
|
|
137
126
|
|
|
138
127
|
Standalone local development is host-backed only.
|
|
139
128
|
|
|
140
|
-
1.
|
|
141
|
-
2.
|
|
142
|
-
3. Paste the snippet into your local `.env`.
|
|
143
|
-
4. Set `VITE_ENABLE_DEV_AUTH=true` and run `pnpm dev`.
|
|
129
|
+
1. Set `DEV_SECRET` and `API_BASE_URL` in your local `.env`.
|
|
130
|
+
2. Run `pnpm dev`.
|
|
144
131
|
|
|
145
|
-
|
|
132
|
+
The Vite plugin proxies `/rest/*` requests to `API_BASE_URL` with the `X-Dev-Secret` header, and `installDevBridge()` handles SDK messages when running in standalone dev.
|
|
146
133
|
|
|
147
134
|
For public testing against a live URL, run `pnpm dev:live` and use the emitted tunnel URL as the app's live URL in the host App Store configuration.
|
|
148
135
|
|
|
@@ -151,7 +138,6 @@ For public testing against a live URL, run `pnpm dev:live` and use the emitted t
|
|
|
151
138
|
- `useSdk()` — raw bridge instance
|
|
152
139
|
- `useNotify()` — fire-and-forget toast
|
|
153
140
|
- `useSendToKernel()` — proxy a whitelisted message to the OS service worker
|
|
154
|
-
- `useStandaloneDevLogout()` — clear standalone dev auth state and reload the page
|
|
155
141
|
|
|
156
142
|
### IndexedDB persistence
|
|
157
143
|
|
package/dist/dev-proxy.d.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
2
|
export interface DevAuthProxyOptions {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/** Upstream BFF base URL (e.g. `https://your-bff-host`). */
|
|
4
|
+
apiBaseUrl: string;
|
|
5
|
+
/** Dev secret copied from the backend. */
|
|
6
|
+
devSecret: string;
|
|
7
|
+
/** App slug stamped as `X-App-ID`, mirroring how the host identifies iframe apps. */
|
|
8
|
+
appId?: string;
|
|
9
|
+
/** Optional CORS origin (e.g. `*`). */
|
|
6
10
|
allowOrigin?: string;
|
|
7
11
|
}
|
|
12
|
+
interface SendJsonOptions {
|
|
13
|
+
allowOrigin?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function readRequestBody(req: IncomingMessage): Promise<Buffer>;
|
|
16
|
+
export declare function applyCors(res: ServerResponse, allowOrigin?: string): void;
|
|
17
|
+
export declare function sendJson(res: ServerResponse, status: number, body: unknown, options?: SendJsonOptions): void;
|
|
8
18
|
export declare function createDevAuthProxyHandler(options: DevAuthProxyOptions): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
19
|
+
export {};
|
package/dist/dev-proxy.js
CHANGED
|
@@ -1,40 +1,106 @@
|
|
|
1
|
-
|
|
1
|
+
export async function readRequestBody(req) {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
const chunks = [];
|
|
4
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
5
|
+
req.on('end', () => resolve(Buffer.concat(chunks)));
|
|
6
|
+
req.on('error', reject);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
export function applyCors(res, allowOrigin) {
|
|
10
|
+
if (!allowOrigin) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
res.setHeader('Access-Control-Allow-Origin', allowOrigin);
|
|
14
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');
|
|
15
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Scope-ID, X-Requested-With');
|
|
16
|
+
}
|
|
17
|
+
export function sendJson(res, status, body, options = {}) {
|
|
18
|
+
applyCors(res, options.allowOrigin);
|
|
19
|
+
res.statusCode = status;
|
|
20
|
+
res.setHeader('Content-Type', 'application/json');
|
|
21
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
22
|
+
res.end(JSON.stringify(body));
|
|
23
|
+
}
|
|
24
|
+
function normalizeApiBaseUrl(value) {
|
|
25
|
+
return value.trim().replace(/\/$/, '');
|
|
26
|
+
}
|
|
27
|
+
function addDevSecretHeader(req, headers, devSecret) {
|
|
28
|
+
const url = req.url ?? '/';
|
|
29
|
+
if (url.startsWith('/rest/') && !url.startsWith('/rest/auth/local-dev-secret')) {
|
|
30
|
+
headers.set('X-Dev-Secret', devSecret);
|
|
31
|
+
}
|
|
32
|
+
return headers;
|
|
33
|
+
}
|
|
2
34
|
export function createDevAuthProxyHandler(options) {
|
|
35
|
+
const apiBaseUrl = normalizeApiBaseUrl(options.apiBaseUrl);
|
|
36
|
+
const { devSecret, allowOrigin, appId } = options;
|
|
3
37
|
return async (req, res) => {
|
|
4
|
-
const
|
|
38
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
5
39
|
if (req.method === 'OPTIONS') {
|
|
6
|
-
applyCors(res,
|
|
40
|
+
applyCors(res, allowOrigin);
|
|
7
41
|
res.statusCode = 204;
|
|
8
42
|
res.end();
|
|
9
43
|
return;
|
|
10
44
|
}
|
|
11
|
-
if (
|
|
12
|
-
sendJson(res, 404, { error: 'not_found' }, { allowOrigin
|
|
45
|
+
if (!url.pathname.startsWith('/rest/')) {
|
|
46
|
+
sendJson(res, 404, { error: 'not_found' }, { allowOrigin });
|
|
13
47
|
return;
|
|
14
48
|
}
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
49
|
+
const upstreamPath = url.pathname.slice('/rest'.length) + url.search;
|
|
50
|
+
const upstreamUrl = `${apiBaseUrl}${upstreamPath}`;
|
|
51
|
+
const headers = new Headers();
|
|
52
|
+
const contentType = req.headers['content-type'];
|
|
53
|
+
if (contentType) {
|
|
54
|
+
headers.set('Content-Type', contentType);
|
|
55
|
+
}
|
|
56
|
+
addDevSecretHeader(req, headers, devSecret);
|
|
57
|
+
// The host stamps X-App-ID from its own registration data, never from the app — the
|
|
58
|
+
// dev proxy does the same with the configured app slug.
|
|
59
|
+
if (appId) {
|
|
60
|
+
headers.set('X-App-ID', appId);
|
|
61
|
+
}
|
|
62
|
+
// BFF rejects /bardioc/ calls without this CSRF marker header; stamp it like the host does.
|
|
63
|
+
headers.set('X-Requested-With', 'XMLHttpRequest');
|
|
64
|
+
// Forward a few useful headers from the browser.
|
|
65
|
+
const forwardedHeaders = ['accept', 'accept-language', 'x-scope-id'];
|
|
66
|
+
for (const name of forwardedHeaders) {
|
|
67
|
+
const value = req.headers[name];
|
|
68
|
+
if (typeof value === 'string') {
|
|
69
|
+
headers.set(name, value);
|
|
70
|
+
}
|
|
71
|
+
else if (Array.isArray(value)) {
|
|
72
|
+
for (const v of value) {
|
|
73
|
+
headers.append(name, v);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
let body;
|
|
78
|
+
try {
|
|
79
|
+
body = await readRequestBody(req);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
sendJson(res, 400, { error: 'invalid_body' }, { allowOrigin });
|
|
18
83
|
return;
|
|
19
84
|
}
|
|
20
85
|
try {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
86
|
+
const upstreamRes = await fetch(upstreamUrl, {
|
|
87
|
+
method: req.method ?? 'GET',
|
|
88
|
+
headers,
|
|
89
|
+
body: body.length > 0 ? new Uint8Array(body) : undefined,
|
|
90
|
+
cache: 'no-store',
|
|
91
|
+
});
|
|
92
|
+
applyCors(res, allowOrigin);
|
|
93
|
+
res.statusCode = upstreamRes.status;
|
|
25
94
|
res.setHeader('Cache-Control', 'no-store');
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
-
res.setHeader('Content-Type',
|
|
95
|
+
const upstreamContentType = upstreamRes.headers.get('content-type');
|
|
96
|
+
if (upstreamContentType) {
|
|
97
|
+
res.setHeader('Content-Type', upstreamContentType);
|
|
29
98
|
}
|
|
30
|
-
|
|
99
|
+
const responseBody = Buffer.from(await upstreamRes.arrayBuffer());
|
|
100
|
+
res.end(responseBody);
|
|
31
101
|
}
|
|
32
|
-
catch
|
|
33
|
-
|
|
34
|
-
sendJson(res, 400, { error: 'missing_dev_session' }, { allowOrigin: options.allowOrigin });
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
sendJson(res, 502, { error: 'host_transport_failed' }, { allowOrigin: options.allowOrigin });
|
|
102
|
+
catch {
|
|
103
|
+
sendJson(res, 502, { error: 'upstream_unavailable' }, { allowOrigin });
|
|
38
104
|
}
|
|
39
105
|
};
|
|
40
106
|
}
|
package/dist/dev.d.ts
CHANGED
|
@@ -1,33 +1,8 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
proxyUrl?: string;
|
|
5
|
-
}
|
|
6
|
-
export interface DevAuthSession {
|
|
7
|
-
sessionKey?: string;
|
|
8
|
-
hostUrl?: string;
|
|
9
|
-
scopeId: string | null;
|
|
10
|
-
}
|
|
11
|
-
export interface DevAuthStorageOptions {
|
|
12
|
-
appId: string;
|
|
13
|
-
appName?: string;
|
|
14
|
-
storageKey?: string;
|
|
15
|
-
}
|
|
16
|
-
export interface EnsureDevAuthSessionOptions extends DevAuthStorageOptions {
|
|
17
|
-
baseUrl?: string;
|
|
18
|
-
loginPath?: string;
|
|
19
|
-
redirect?: (url: string) => void;
|
|
20
|
-
}
|
|
21
|
-
export interface DevBridgeOptions extends DevAuthStorageOptions {
|
|
1
|
+
export interface DevBridgeOptions {
|
|
2
|
+
/** Base URL prepended to SDK transport paths. Defaults to `/rest`. */
|
|
3
|
+
apiBaseUrl?: string;
|
|
22
4
|
debug?: boolean;
|
|
23
|
-
baseUrl?: string;
|
|
24
|
-
proxyPath?: string;
|
|
25
5
|
}
|
|
26
|
-
export declare function getInjectedDevAuthConfig(): InjectedDevAuthConfig | null;
|
|
27
6
|
export declare function isInsideIframe(): boolean;
|
|
28
7
|
export declare function isDevStandalone(): boolean;
|
|
29
|
-
export declare function
|
|
30
|
-
export declare function getDevScopeId(options: DevAuthStorageOptions): string | null;
|
|
31
|
-
export declare function clearDevAuthSession(options: DevAuthStorageOptions): void;
|
|
32
|
-
export declare function ensureDevAuthSession(options: EnsureDevAuthSessionOptions): Promise<void>;
|
|
33
|
-
export declare function installDevBridge(options: DevBridgeOptions): () => void;
|
|
8
|
+
export declare function installDevBridge(options?: DevBridgeOptions): () => void;
|
package/dist/dev.js
CHANGED
|
@@ -1,47 +1,6 @@
|
|
|
1
1
|
import { SDK_MSG } from './protocol.js';
|
|
2
2
|
function getBaseUrl(baseUrl) {
|
|
3
|
-
|
|
4
|
-
return baseUrl ?? metaEnv?.BASE_URL ?? '/';
|
|
5
|
-
}
|
|
6
|
-
function resolveStorageKey(options) {
|
|
7
|
-
return options.storageKey ?? `bardioc.dev.auth.${options.appName ?? options.appId}`;
|
|
8
|
-
}
|
|
9
|
-
function writeDevSession(storageKey, session) {
|
|
10
|
-
localStorage.setItem(storageKey, JSON.stringify(session));
|
|
11
|
-
}
|
|
12
|
-
export function getInjectedDevAuthConfig() {
|
|
13
|
-
const config = globalThis.__BARDIOC_DEV_AUTH__;
|
|
14
|
-
if (!config?.hostUrl || !config?.sessionKey) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
return {
|
|
18
|
-
hostUrl: config.hostUrl,
|
|
19
|
-
sessionKey: config.sessionKey,
|
|
20
|
-
proxyUrl: typeof config.proxyUrl === 'string' ? config.proxyUrl : undefined,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
function readStoredSession(storageKey) {
|
|
24
|
-
const raw = localStorage.getItem(storageKey);
|
|
25
|
-
if (!raw) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const parsed = JSON.parse(raw);
|
|
30
|
-
const hasHostSession = typeof parsed.sessionKey === 'string' && typeof parsed.hostUrl === 'string';
|
|
31
|
-
if (!hasHostSession) {
|
|
32
|
-
localStorage.removeItem(storageKey);
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
return {
|
|
36
|
-
sessionKey: typeof parsed.sessionKey === 'string' ? parsed.sessionKey : undefined,
|
|
37
|
-
hostUrl: typeof parsed.hostUrl === 'string' ? parsed.hostUrl : undefined,
|
|
38
|
-
scopeId: typeof parsed.scopeId === 'string' ? parsed.scopeId : null,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
localStorage.removeItem(storageKey);
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
3
|
+
return baseUrl ?? '/rest';
|
|
45
4
|
}
|
|
46
5
|
export function isInsideIframe() {
|
|
47
6
|
const currentWindow = globalThis;
|
|
@@ -51,57 +10,10 @@ export function isDevStandalone() {
|
|
|
51
10
|
const metaEnv = import.meta.env;
|
|
52
11
|
return Boolean(metaEnv?.DEV) && !isInsideIframe();
|
|
53
12
|
}
|
|
54
|
-
export function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
export function getDevScopeId(options) {
|
|
58
|
-
return getDevSession(options)?.scopeId ?? null;
|
|
59
|
-
}
|
|
60
|
-
export function clearDevAuthSession(options) {
|
|
61
|
-
localStorage.removeItem(resolveStorageKey(options));
|
|
62
|
-
}
|
|
63
|
-
export async function ensureDevAuthSession(options) {
|
|
64
|
-
const storageKey = resolveStorageKey(options);
|
|
65
|
-
const url = new URL(window.location.href);
|
|
66
|
-
const authError = url.searchParams.get('auth_error');
|
|
67
|
-
if (authError) {
|
|
68
|
-
console.error('[dev-auth] Authentication failed:', authError);
|
|
69
|
-
url.searchParams.delete('auth_error');
|
|
70
|
-
window.history.replaceState({}, '', url.toString());
|
|
71
|
-
throw new Error(`Authentication failed: ${authError}`);
|
|
72
|
-
}
|
|
73
|
-
const injectedConfig = getInjectedDevAuthConfig();
|
|
74
|
-
if (injectedConfig) {
|
|
75
|
-
const storedSession = readStoredSession(storageKey);
|
|
76
|
-
if (storedSession?.hostUrl !== injectedConfig.hostUrl ||
|
|
77
|
-
storedSession?.sessionKey !== injectedConfig.sessionKey) {
|
|
78
|
-
writeDevSession(storageKey, {
|
|
79
|
-
hostUrl: injectedConfig.hostUrl,
|
|
80
|
-
sessionKey: injectedConfig.sessionKey,
|
|
81
|
-
scopeId: null,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const session = readStoredSession(storageKey);
|
|
87
|
-
if (session?.sessionKey) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
const loginPath = options.loginPath ?? 'login';
|
|
91
|
-
const loginUrl = new URL(loginPath, window.location.origin + getBaseUrl(options.baseUrl)).toString();
|
|
92
|
-
console.info('[dev-auth] redirecting browser to login', {
|
|
93
|
-
currentUrl: url.toString(),
|
|
94
|
-
baseUrl: getBaseUrl(options.baseUrl),
|
|
95
|
-
loginUrl,
|
|
96
|
-
});
|
|
97
|
-
(options.redirect ?? ((nextUrl) => window.location.replace(nextUrl)))(loginUrl);
|
|
98
|
-
await new Promise(() => { });
|
|
99
|
-
}
|
|
100
|
-
export function installDevBridge(options) {
|
|
101
|
-
const { appId, debug = false } = options;
|
|
13
|
+
export function installDevBridge(options = {}) {
|
|
14
|
+
const apiBaseUrl = getBaseUrl(options.apiBaseUrl);
|
|
15
|
+
const debug = options.debug ?? false;
|
|
102
16
|
const origin = window.location.origin;
|
|
103
|
-
const proxyUrl = new URL(options.proxyPath ?? 'proxy', window.location.origin + getBaseUrl(options.baseUrl)).toString();
|
|
104
|
-
const readSession = () => getDevSession(options);
|
|
105
17
|
const log = (...args) => {
|
|
106
18
|
if (debug) {
|
|
107
19
|
console.log('[bardioc-dev-bridge]', ...args);
|
|
@@ -117,71 +29,62 @@ export function installDevBridge(options) {
|
|
|
117
29
|
window.postMessage({ type: SDK_MSG.INIT_ACK, id, payload }, origin);
|
|
118
30
|
}
|
|
119
31
|
async function handleTransport(payload) {
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
32
|
+
const headers = new Headers();
|
|
33
|
+
const body = payload.body == null
|
|
34
|
+
? undefined
|
|
35
|
+
: payload.contentType === 'application/json'
|
|
36
|
+
? JSON.stringify(payload.body)
|
|
37
|
+
: payload.body;
|
|
38
|
+
if (body && payload.contentType) {
|
|
39
|
+
headers.set('Content-Type', payload.contentType);
|
|
40
|
+
}
|
|
41
|
+
// BFF rejects /bardioc/ calls without this CSRF marker header.
|
|
42
|
+
headers.set('X-Requested-With', 'XMLHttpRequest');
|
|
43
|
+
// Mirror the host bridge: a required scope without an id is rejected locally, and a
|
|
44
|
+
// resolved scope id is always forwarded regardless of policy. Standalone has no
|
|
45
|
+
// instance, so there is no instance-based fallback here.
|
|
46
|
+
const resolvedScopeId = payload.scopeId;
|
|
47
|
+
if (payload.scopePolicy === 'required' && !resolvedScopeId) {
|
|
48
|
+
throw new Error('Scope ID is required');
|
|
49
|
+
}
|
|
50
|
+
if (resolvedScopeId) {
|
|
51
|
+
headers.set('X-Scope-ID', resolvedScopeId);
|
|
123
52
|
}
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
: null;
|
|
128
|
-
console.info('[bardioc-dev-bridge][1/2] sending dev session to local proxy', {
|
|
129
|
-
proxyUrl,
|
|
130
|
-
appId,
|
|
131
|
-
path: payload.path,
|
|
53
|
+
const url = `${apiBaseUrl}${payload.path}`;
|
|
54
|
+
log('[transport]', payload.method ?? 'GET', url);
|
|
55
|
+
const response = await fetch(url, {
|
|
132
56
|
method: payload.method ?? 'GET',
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
nextStep: 'local_proxy_relays_to_host_transport',
|
|
137
|
-
});
|
|
138
|
-
const response = await fetch(proxyUrl, {
|
|
139
|
-
method: 'POST',
|
|
140
|
-
headers: { 'Content-Type': 'application/json' },
|
|
141
|
-
body: JSON.stringify({
|
|
142
|
-
sessionKey: session.sessionKey,
|
|
143
|
-
hostUrl: session.hostUrl,
|
|
144
|
-
scopeId: forwardedScopeId,
|
|
145
|
-
path: payload.path,
|
|
146
|
-
method: payload.method ?? 'GET',
|
|
147
|
-
body: payload.body,
|
|
148
|
-
contentType: payload.contentType,
|
|
149
|
-
scopePolicy: payload.scopePolicy,
|
|
150
|
-
}),
|
|
57
|
+
headers,
|
|
58
|
+
body,
|
|
59
|
+
credentials: 'include',
|
|
151
60
|
cache: 'no-store',
|
|
152
61
|
});
|
|
153
|
-
const
|
|
154
|
-
let data = null;
|
|
155
|
-
if (text) {
|
|
156
|
-
try {
|
|
157
|
-
data = JSON.parse(text);
|
|
158
|
-
}
|
|
159
|
-
catch {
|
|
160
|
-
data = text;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
62
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
163
63
|
if (!response.ok) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
path: payload.path,
|
|
167
|
-
method: payload.method ?? 'GET',
|
|
168
|
-
status: response.status,
|
|
169
|
-
failureStage: response.headers.get('X-Bardioc-Dev-Auth-Stage'),
|
|
170
|
-
responsePayload: data,
|
|
171
|
-
});
|
|
64
|
+
const text = await response.text();
|
|
65
|
+
const responsePayload = contentType.includes('application/json') && text ? JSON.parse(text) : text;
|
|
172
66
|
const err = new Error(`Transport ${payload.path} failed: ${response.status}`);
|
|
173
|
-
Object.assign(err, { status: response.status, responsePayload
|
|
67
|
+
Object.assign(err, { status: response.status, responsePayload });
|
|
174
68
|
throw err;
|
|
175
69
|
}
|
|
176
|
-
|
|
70
|
+
// Same response typing as the host: JSON is parsed, empty/plain text becomes a string,
|
|
71
|
+
// anything binary (zip, octet-stream, images/svg, …) round-trips as a Blob.
|
|
72
|
+
if (contentType.includes('application/json')) {
|
|
73
|
+
const text = await response.text();
|
|
74
|
+
return text ? JSON.parse(text) : null;
|
|
75
|
+
}
|
|
76
|
+
if (contentType === '' || contentType.startsWith('text/')) {
|
|
77
|
+
const text = await response.text();
|
|
78
|
+
return text || null;
|
|
79
|
+
}
|
|
80
|
+
return response.blob();
|
|
177
81
|
}
|
|
178
82
|
async function handleKernelProxy(payload) {
|
|
179
83
|
if (payload.kernelType === 'PING') {
|
|
180
84
|
return { pong: true };
|
|
181
85
|
}
|
|
182
86
|
if (payload.kernelType === 'GET_SESSION_STATE') {
|
|
183
|
-
|
|
184
|
-
return { authenticated: !!session?.sessionKey };
|
|
87
|
+
return { authenticated: true };
|
|
185
88
|
}
|
|
186
89
|
throw new Error(`Kernel message ${payload.kernelType} not supported in dev bridge`);
|
|
187
90
|
}
|
|
@@ -200,7 +103,7 @@ export function installDevBridge(options) {
|
|
|
200
103
|
try {
|
|
201
104
|
switch (data.type) {
|
|
202
105
|
case SDK_MSG.INIT:
|
|
203
|
-
ack(data.id, { appId, instanceId: null });
|
|
106
|
+
ack(data.id, { appId: null, instanceId: null });
|
|
204
107
|
return;
|
|
205
108
|
case SDK_MSG.NOTIFY:
|
|
206
109
|
return;
|
package/dist/dot-env.d.ts
CHANGED
package/dist/dot-env.js
CHANGED
package/dist/host-bridge.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getInjectedDevAuthConfig } from './dev.js';
|
|
2
1
|
import { SDK_MSG } from './protocol.js';
|
|
3
2
|
import { GraphTransport } from './transports/graph-transport.js';
|
|
4
3
|
import { OsTransport } from './transports/os-transport.js';
|
|
@@ -36,10 +35,6 @@ export function createHostBridge(config) {
|
|
|
36
35
|
console.log('[app-sdk]', ...args);
|
|
37
36
|
}
|
|
38
37
|
log('createHostBridge', { appId: hintAppId, targetOrigin, isInsideIframe });
|
|
39
|
-
const standaloneDevAuthActive = !isInsideIframe && !!getInjectedDevAuthConfig();
|
|
40
|
-
if (!isInsideIframe && !standaloneDevAuthActive) {
|
|
41
|
-
console.warn('[app-sdk] NOT inside an iframe — bridge will not work standalone.');
|
|
42
|
-
}
|
|
43
38
|
let _connected = false;
|
|
44
39
|
let _context = null;
|
|
45
40
|
let _destroyed = false;
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
import { type DevAuthStorageOptions } from './dev.js';
|
|
3
2
|
import type { GraphEvent, HostBridge, HostBridgeConfig, NotifyLevel, OsConfig, SdkCommandDefinition, SdkCommandHandler, SdkMenuRoot } from './types.js';
|
|
4
3
|
export interface AppSdkProviderProps extends HostBridgeConfig {
|
|
5
4
|
children: ReactNode;
|
|
@@ -30,5 +29,3 @@ export declare function useOsConfig(): OsConfig | null;
|
|
|
30
29
|
export declare function useGraphEvents(options: {
|
|
31
30
|
types: string[];
|
|
32
31
|
}, handler: (event: GraphEvent) => void, deps?: React.DependencyList): void;
|
|
33
|
-
/** Returns a stable callback that clears standalone dev auth state and reloads the page. */
|
|
34
|
-
export declare function useStandaloneDevLogout(options: DevAuthStorageOptions): () => void;
|
package/dist/react.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useCallback, useContext, useEffect, useRef, useState, } from 'react';
|
|
3
|
-
import { clearDevAuthSession } from './dev.js';
|
|
4
3
|
import { createHostBridge } from './host-bridge.js';
|
|
5
4
|
const SdkContext = createContext(null);
|
|
6
5
|
const SYSTEM_SIZE_CLASS_NAMES = ['text-sm', 'text-base', 'text-lg', 'text-xl'];
|
|
@@ -9,7 +8,12 @@ function applyOsConfigToDocument(osConfig) {
|
|
|
9
8
|
return;
|
|
10
9
|
}
|
|
11
10
|
const root = document.documentElement;
|
|
12
|
-
|
|
11
|
+
const isDark = osConfig.theme === 'dark';
|
|
12
|
+
root.classList.toggle('dark', isDark);
|
|
13
|
+
// Advertise the resolved theme to the UA so externally-referenced SVGs (app icon.svg
|
|
14
|
+
// via <img>, favicons) theme-switch through @media (prefers-color-scheme). Mirrors
|
|
15
|
+
// webos-host (next-themes enableColorScheme) and Storybook's preview decorator.
|
|
16
|
+
root.style.colorScheme = isDark ? 'dark' : 'light';
|
|
13
17
|
if (osConfig.language) {
|
|
14
18
|
root.lang = osConfig.language;
|
|
15
19
|
}
|
|
@@ -215,10 +219,3 @@ export function useGraphEvents(options, handler, deps = []) {
|
|
|
215
219
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
216
220
|
}, [bridge, typesKey, ...deps]);
|
|
217
221
|
}
|
|
218
|
-
/** Returns a stable callback that clears standalone dev auth state and reloads the page. */
|
|
219
|
-
export function useStandaloneDevLogout(options) {
|
|
220
|
-
return useCallback(() => {
|
|
221
|
-
clearDevAuthSession(options);
|
|
222
|
-
window.location.reload();
|
|
223
|
-
}, [options]);
|
|
224
|
-
}
|
package/dist/vite.d.ts
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
/** Vite plugin for Bardioc iframe apps. Usage: `bardiocApp({ appName, port })` */
|
|
2
|
-
|
|
2
|
+
import { type DevAuthProxyOptions } from './dev-proxy.js';
|
|
3
3
|
export interface BardiocAppOptions {
|
|
4
4
|
appName?: string;
|
|
5
5
|
port: number;
|
|
6
6
|
previewPort?: number;
|
|
7
7
|
}
|
|
8
|
+
type VitePlugin = {
|
|
9
|
+
name: string;
|
|
10
|
+
apply?: 'serve' | 'build';
|
|
11
|
+
enforce?: 'pre' | 'post';
|
|
12
|
+
config?: (config: any, env: {
|
|
13
|
+
command: string;
|
|
14
|
+
}) => any;
|
|
15
|
+
configureServer?: (server: any) => void;
|
|
16
|
+
transformIndexHtml?: () => Promise<any[] | undefined> | any[] | undefined;
|
|
17
|
+
closeBundle?: () => void;
|
|
18
|
+
};
|
|
19
|
+
export interface BardiocDevAuthOptions {
|
|
20
|
+
appName: string;
|
|
21
|
+
/** Optional explicit proxy options. If omitted, DEV_SECRET and API_BASE_URL are read from env. */
|
|
22
|
+
proxy?: DevAuthProxyOptions;
|
|
23
|
+
}
|
|
24
|
+
export declare function bardiocDevAuth(options: BardiocDevAuthOptions): VitePlugin;
|
|
8
25
|
/** Returns an array of Vite plugins for a Bardioc iframe app. */
|
|
9
26
|
export declare function bardiocApp(opts: BardiocAppOptions): any[];
|
|
27
|
+
export {};
|
package/dist/vite.js
CHANGED
|
@@ -3,9 +3,9 @@ import { execSync, spawn } from 'node:child_process';
|
|
|
3
3
|
import { existsSync, readFileSync } from 'node:fs';
|
|
4
4
|
import { resolve, sep } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import {
|
|
6
|
+
import { createDevAuthProxyHandler } from './dev-proxy.js';
|
|
7
|
+
import { readDotEnvFile } from './dot-env.js';
|
|
7
8
|
import { MANIFEST_FILENAME, validateManifest } from './manifest.js';
|
|
8
|
-
export { bardiocDevAuth } from './dev-auth-vite.js';
|
|
9
9
|
function hasCommand(cmd) {
|
|
10
10
|
try {
|
|
11
11
|
execSync(`which ${cmd}`, { stdio: 'ignore' });
|
|
@@ -91,8 +91,6 @@ function devProxy(opts) {
|
|
|
91
91
|
}
|
|
92
92
|
server.httpServer?.on('listening', async () => {
|
|
93
93
|
const manifestPath = resolve(process.cwd(), 'public', MANIFEST_FILENAME);
|
|
94
|
-
const envPath = resolve(process.cwd(), '.env');
|
|
95
|
-
const envAppId = existsSync(envPath) ? readDotEnvValue(envPath, 'VITE_APP_ID') : null;
|
|
96
94
|
if (!existsSync(manifestPath)) {
|
|
97
95
|
console.warn(`[bardioc] public/${MANIFEST_FILENAME} not found`);
|
|
98
96
|
return;
|
|
@@ -114,14 +112,12 @@ function devProxy(opts) {
|
|
|
114
112
|
}
|
|
115
113
|
console.log(`[bardioc] Use this live URL in the host App Store app configuration:`);
|
|
116
114
|
console.log(`[bardioc] App Name: ${manifestId}`);
|
|
117
|
-
console.log(`[bardioc] App ID: ${envAppId || '<from .env VITE_APP_ID>'}`);
|
|
118
115
|
console.log(`[bardioc] Live URL: https://${tunnelHost}`);
|
|
119
116
|
}
|
|
120
117
|
else {
|
|
121
118
|
console.log(`[bardioc] Dev server ready: http://localhost:${port}`);
|
|
122
|
-
console.log(`[bardioc] For standalone
|
|
119
|
+
console.log(`[bardioc] For standalone dev auth, set DEV_SECRET and API_BASE_URL in .env.`);
|
|
123
120
|
console.log(`[bardioc] App Name: ${manifestId}`);
|
|
124
|
-
console.log(`[bardioc] App ID: ${envAppId || '<from .env VITE_APP_ID>'}`);
|
|
125
121
|
console.log(`[bardioc] URL: http://localhost:${port}`);
|
|
126
122
|
}
|
|
127
123
|
});
|
|
@@ -221,6 +217,82 @@ function manifestCheck() {
|
|
|
221
217
|
},
|
|
222
218
|
};
|
|
223
219
|
}
|
|
220
|
+
function readRuntimeEnv(server) {
|
|
221
|
+
const envDir = server.config.envDir ?? server.config.root;
|
|
222
|
+
const mode = server.config.mode?.trim();
|
|
223
|
+
const env = {};
|
|
224
|
+
for (const fileName of [
|
|
225
|
+
'.env',
|
|
226
|
+
'.env.local',
|
|
227
|
+
mode ? `.env.${mode}` : null,
|
|
228
|
+
mode ? `.env.${mode}.local` : null,
|
|
229
|
+
]) {
|
|
230
|
+
if (!fileName)
|
|
231
|
+
continue;
|
|
232
|
+
const filePath = resolve(envDir, fileName);
|
|
233
|
+
if (existsSync(filePath)) {
|
|
234
|
+
Object.assign(env, readDotEnvFile(filePath));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
238
|
+
if (typeof value === 'string') {
|
|
239
|
+
env[key] = value;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
DEV_SECRET: env.DEV_SECRET?.trim(),
|
|
244
|
+
API_BASE_URL: env.API_BASE_URL?.trim().replace(/\/$/, ''),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
export function bardiocDevAuth(options) {
|
|
248
|
+
let proxyOptions = options.proxy ?? null;
|
|
249
|
+
return {
|
|
250
|
+
name: 'bardioc-dev-auth',
|
|
251
|
+
apply: 'serve',
|
|
252
|
+
enforce: 'pre',
|
|
253
|
+
configureServer(server) {
|
|
254
|
+
if (!proxyOptions) {
|
|
255
|
+
const env = readRuntimeEnv(server);
|
|
256
|
+
if (!env.DEV_SECRET || !env.API_BASE_URL) {
|
|
257
|
+
server.config.logger.warn(`[bardioc-dev-auth] DEV_SECRET and API_BASE_URL are required for dev auth — disabled for appName="${options.appName}".`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
proxyOptions = {
|
|
261
|
+
apiBaseUrl: env.API_BASE_URL,
|
|
262
|
+
devSecret: env.DEV_SECRET,
|
|
263
|
+
appId: options.appName,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
const handler = createDevAuthProxyHandler(proxyOptions);
|
|
267
|
+
const basePath = server.config.base.endsWith('/')
|
|
268
|
+
? server.config.base.slice(0, -1)
|
|
269
|
+
: server.config.base;
|
|
270
|
+
server.config.logger.info(`[bardioc-dev-auth] proxying /rest/* → ${proxyOptions.apiBaseUrl} for appName="${options.appName}"`);
|
|
271
|
+
server.middlewares.use(async (req, res, next) => {
|
|
272
|
+
const originalUrl = req.url ?? '';
|
|
273
|
+
const parsed = new URL(originalUrl, 'http://localhost');
|
|
274
|
+
const pathname = parsed.pathname;
|
|
275
|
+
const routePath = pathname.startsWith(basePath)
|
|
276
|
+
? pathname.slice(basePath.length) || '/'
|
|
277
|
+
: pathname;
|
|
278
|
+
if (!routePath.startsWith('/rest/')) {
|
|
279
|
+
next();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
req.url = `${routePath}${parsed.search}`;
|
|
284
|
+
await handler(req, res);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
next(error);
|
|
288
|
+
}
|
|
289
|
+
finally {
|
|
290
|
+
req.url = originalUrl;
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
}
|
|
224
296
|
/** Returns an array of Vite plugins for a Bardioc iframe app. */
|
|
225
297
|
export function bardiocApp(opts) {
|
|
226
298
|
const { port, previewPort } = opts;
|
package/package.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bardioc/app-sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "SDK for building apps for the Bardioc OS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
7
7
|
"type": "module",
|
|
8
|
-
"bin": {
|
|
9
|
-
"bardioc-dev-session": "./dist/dev-session-cli.js"
|
|
10
|
-
},
|
|
11
8
|
"publishConfig": {
|
|
12
9
|
"registry": "https://registry.npmjs.org/",
|
|
13
10
|
"access": "public"
|
|
@@ -44,10 +41,6 @@
|
|
|
44
41
|
"types": "./dist/dev-proxy.d.ts",
|
|
45
42
|
"default": "./dist/dev-proxy.js"
|
|
46
43
|
},
|
|
47
|
-
"./dev-session-cli": {
|
|
48
|
-
"types": "./dist/dev-session-cli.d.ts",
|
|
49
|
-
"default": "./dist/dev-session-cli.js"
|
|
50
|
-
},
|
|
51
44
|
"./types": {
|
|
52
45
|
"types": "./dist/types.d.ts"
|
|
53
46
|
}
|
|
@@ -76,16 +69,15 @@
|
|
|
76
69
|
}
|
|
77
70
|
},
|
|
78
71
|
"devDependencies": {
|
|
79
|
-
"@vitest/coverage-v8": "4.1.
|
|
80
|
-
"@types/node": "^25.
|
|
81
|
-
"@types/react": "
|
|
82
|
-
"@testing-library/jest-dom": "6.9.1",
|
|
72
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
73
|
+
"@types/node": "^25.9.1",
|
|
74
|
+
"@types/react": "19.1.16",
|
|
83
75
|
"@testing-library/react": "16.3.2",
|
|
84
76
|
"jsdom": "29.1.0",
|
|
85
|
-
"react": "19.2.
|
|
86
|
-
"react-dom": "19.2.
|
|
87
|
-
"typescript": "
|
|
88
|
-
"vitest": "4.1.
|
|
77
|
+
"react": "19.2.6",
|
|
78
|
+
"react-dom": "19.2.6",
|
|
79
|
+
"typescript": "6.0.3",
|
|
80
|
+
"vitest": "^4.1.8"
|
|
89
81
|
},
|
|
90
82
|
"scripts": {
|
|
91
83
|
"build": "tsc",
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
export type ProxyPayload = {
|
|
3
|
-
sessionKey?: string;
|
|
4
|
-
hostUrl?: string;
|
|
5
|
-
scopeId?: string | null;
|
|
6
|
-
scopePolicy?: 'none' | 'optional' | 'required';
|
|
7
|
-
path: string;
|
|
8
|
-
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
9
|
-
body?: unknown;
|
|
10
|
-
contentType?: string;
|
|
11
|
-
};
|
|
12
|
-
interface ProxyTransportOptions {
|
|
13
|
-
appId: string;
|
|
14
|
-
hostUrl: string;
|
|
15
|
-
devSessionKey: string;
|
|
16
|
-
}
|
|
17
|
-
interface SendJsonOptions {
|
|
18
|
-
allowOrigin?: string;
|
|
19
|
-
}
|
|
20
|
-
export declare function readJsonBody<T = unknown>(req: IncomingMessage): Promise<T | null>;
|
|
21
|
-
export declare function applyCors(res: ServerResponse, allowOrigin?: string): void;
|
|
22
|
-
export declare function sendJson(res: ServerResponse, status: number, body: unknown, options?: SendJsonOptions): void;
|
|
23
|
-
export declare function forwardDevAuthProxyRequest(payload: ProxyPayload, options: ProxyTransportOptions): Promise<Response>;
|
|
24
|
-
export {};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
export async function readJsonBody(req) {
|
|
2
|
-
return new Promise(resolveBody => {
|
|
3
|
-
const chunks = [];
|
|
4
|
-
req.on('data', (chunk) => chunks.push(chunk));
|
|
5
|
-
req.on('end', () => {
|
|
6
|
-
const buffer = Buffer.concat(chunks);
|
|
7
|
-
if (buffer.length === 0) {
|
|
8
|
-
resolveBody(null);
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
try {
|
|
12
|
-
resolveBody(JSON.parse(buffer.toString('utf8')));
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
resolveBody(null);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
req.on('error', () => resolveBody(null));
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
export function applyCors(res, allowOrigin) {
|
|
22
|
-
if (!allowOrigin) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
res.setHeader('Access-Control-Allow-Origin', allowOrigin);
|
|
26
|
-
res.setHeader('Access-Control-Allow-Methods', 'POST,OPTIONS');
|
|
27
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
28
|
-
}
|
|
29
|
-
export function sendJson(res, status, body, options = {}) {
|
|
30
|
-
applyCors(res, options.allowOrigin);
|
|
31
|
-
res.statusCode = status;
|
|
32
|
-
res.setHeader('Content-Type', 'application/json');
|
|
33
|
-
res.setHeader('Cache-Control', 'no-store');
|
|
34
|
-
res.end(JSON.stringify(body));
|
|
35
|
-
}
|
|
36
|
-
export async function forwardDevAuthProxyRequest(payload, options) {
|
|
37
|
-
const hostUrl = payload.hostUrl ?? options.hostUrl;
|
|
38
|
-
const sessionKey = payload.sessionKey ?? options.devSessionKey;
|
|
39
|
-
if (!hostUrl || !sessionKey) {
|
|
40
|
-
throw new Error('missing_dev_session');
|
|
41
|
-
}
|
|
42
|
-
return fetch(`${hostUrl.replace(/\/$/, '')}/api/transport`, {
|
|
43
|
-
method: 'POST',
|
|
44
|
-
headers: {
|
|
45
|
-
'Content-Type': 'application/json',
|
|
46
|
-
'X-Dev-Session-Key': sessionKey,
|
|
47
|
-
},
|
|
48
|
-
body: JSON.stringify({
|
|
49
|
-
appId: options.appId,
|
|
50
|
-
path: payload.path,
|
|
51
|
-
method: payload.method ?? 'GET',
|
|
52
|
-
body: payload.body,
|
|
53
|
-
contentType: payload.contentType,
|
|
54
|
-
scopePolicy: payload.scopePolicy,
|
|
55
|
-
scopeId: payload.scopeId ?? null,
|
|
56
|
-
}),
|
|
57
|
-
cache: 'no-store',
|
|
58
|
-
});
|
|
59
|
-
}
|
package/dist/dev-auth-vite.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
type VitePlugin = {
|
|
3
|
-
name: string;
|
|
4
|
-
apply?: 'serve' | 'build';
|
|
5
|
-
enforce?: 'pre' | 'post';
|
|
6
|
-
configureServer?: (server: ViteDevServerLike) => void;
|
|
7
|
-
transformIndexHtml?: () => Array<{
|
|
8
|
-
tag: string;
|
|
9
|
-
attrs?: Record<string, string>;
|
|
10
|
-
children?: string;
|
|
11
|
-
injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend';
|
|
12
|
-
}> | void;
|
|
13
|
-
};
|
|
14
|
-
interface ViteDevServerLike {
|
|
15
|
-
config: {
|
|
16
|
-
root: string;
|
|
17
|
-
envDir?: string;
|
|
18
|
-
mode?: string;
|
|
19
|
-
base: string;
|
|
20
|
-
logger: {
|
|
21
|
-
warn: (message: string) => void;
|
|
22
|
-
info: (message: string) => void;
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
middlewares: {
|
|
26
|
-
use: (handler: (req: IncomingMessage, res: ServerResponse, next: (error?: unknown) => void) => void) => void;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
export interface BardiocDevAuthOptions {
|
|
30
|
-
appName: string;
|
|
31
|
-
sessionStorageKey?: string;
|
|
32
|
-
}
|
|
33
|
-
export declare function bardiocDevAuth(options: BardiocDevAuthOptions): VitePlugin;
|
|
34
|
-
export {};
|
package/dist/dev-auth-vite.js
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import { forwardDevAuthProxyRequest, readJsonBody, sendJson, } from './dev-auth-proxy-core.js';
|
|
4
|
-
import { readDotEnvFile } from './dot-env.js';
|
|
5
|
-
function resolveSessionStorageKey(options) {
|
|
6
|
-
return options.sessionStorageKey ?? `bardioc.dev.auth.${options.appName}`;
|
|
7
|
-
}
|
|
8
|
-
function readRuntimeEnv(server) {
|
|
9
|
-
const envDir = server.config.envDir ?? server.config.root;
|
|
10
|
-
const mode = server.config.mode?.trim();
|
|
11
|
-
const envFileNames = [
|
|
12
|
-
'.env',
|
|
13
|
-
'.env.local',
|
|
14
|
-
mode ? `.env.${mode}` : null,
|
|
15
|
-
mode ? `.env.${mode}.local` : null,
|
|
16
|
-
];
|
|
17
|
-
const env = {};
|
|
18
|
-
for (const fileName of envFileNames) {
|
|
19
|
-
if (!fileName) {
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
const filePath = resolve(envDir, fileName);
|
|
23
|
-
if (!existsSync(filePath)) {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
Object.assign(env, readDotEnvFile(filePath));
|
|
27
|
-
}
|
|
28
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
29
|
-
if (typeof value === 'string') {
|
|
30
|
-
env[key] = value;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return env;
|
|
34
|
-
}
|
|
35
|
-
function readDevAuthEnv(server, options) {
|
|
36
|
-
const env = readRuntimeEnv(server);
|
|
37
|
-
const hostUrl = env.DEV_AUTH_HOST_URL?.trim().replace(/\/$/, '');
|
|
38
|
-
const devSessionKey = env.DEV_SESSION_KEY?.trim();
|
|
39
|
-
const exchangeAppId = env.VITE_APP_ID?.trim();
|
|
40
|
-
if (!hostUrl || !devSessionKey || !exchangeAppId) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
return {
|
|
44
|
-
exchangeAppId,
|
|
45
|
-
hostUrl,
|
|
46
|
-
devSessionKey,
|
|
47
|
-
sessionStorageKey: resolveSessionStorageKey(options),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function getRequestPathname(req) {
|
|
51
|
-
const originalUrl = req.__bardiocOriginalUrl;
|
|
52
|
-
return new URL(originalUrl ?? req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`)
|
|
53
|
-
.pathname;
|
|
54
|
-
}
|
|
55
|
-
function getBasePath(req, routePath) {
|
|
56
|
-
const pathname = getRequestPathname(req);
|
|
57
|
-
if (pathname.endsWith(routePath)) {
|
|
58
|
-
const basePath = pathname.slice(0, -routePath.length);
|
|
59
|
-
return basePath || '/';
|
|
60
|
-
}
|
|
61
|
-
return '/';
|
|
62
|
-
}
|
|
63
|
-
function buildAppPath(basePath, path) {
|
|
64
|
-
const normalizedBase = basePath === '/' ? '' : basePath.replace(/\/$/, '');
|
|
65
|
-
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
66
|
-
return `${normalizedBase}${normalizedPath}`;
|
|
67
|
-
}
|
|
68
|
-
function sendHtml(res, status, html) {
|
|
69
|
-
res.statusCode = status;
|
|
70
|
-
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
71
|
-
res.setHeader('Cache-Control', 'no-store');
|
|
72
|
-
res.end(html);
|
|
73
|
-
}
|
|
74
|
-
function renderLoginHtml(session, basePath, sessionStorageKey) {
|
|
75
|
-
const payload = JSON.stringify(JSON.stringify(session))
|
|
76
|
-
.replace(/</g, '\\u003c')
|
|
77
|
-
.replace(/>/g, '\\u003e')
|
|
78
|
-
.replace(/&/g, '\\u0026');
|
|
79
|
-
const redirectPath = buildAppPath(basePath, '/');
|
|
80
|
-
return `<!doctype html>
|
|
81
|
-
<html lang="en">
|
|
82
|
-
<head>
|
|
83
|
-
<meta charset="utf-8" />
|
|
84
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
85
|
-
<title>Signing in...</title>
|
|
86
|
-
</head>
|
|
87
|
-
<body>
|
|
88
|
-
<script>
|
|
89
|
-
window.localStorage.removeItem('${sessionStorageKey.replace('bardioc.dev.auth.', '')}.dev.auth');
|
|
90
|
-
window.localStorage.setItem('${sessionStorageKey}', ${payload});
|
|
91
|
-
window.location.replace(${JSON.stringify(redirectPath)});
|
|
92
|
-
</script>
|
|
93
|
-
</body>
|
|
94
|
-
</html>`;
|
|
95
|
-
}
|
|
96
|
-
function createLoginHandler(env) {
|
|
97
|
-
return async (req, res) => {
|
|
98
|
-
const basePath = getBasePath(req, '/login');
|
|
99
|
-
sendHtml(res, 200, renderLoginHtml({
|
|
100
|
-
sessionKey: env.devSessionKey,
|
|
101
|
-
hostUrl: env.hostUrl,
|
|
102
|
-
scopeId: null,
|
|
103
|
-
}, basePath, env.sessionStorageKey));
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function createProxyHandler(options) {
|
|
107
|
-
return async (req, res) => {
|
|
108
|
-
const payload = await readJsonBody(req);
|
|
109
|
-
if (!payload?.path) {
|
|
110
|
-
sendJson(res, 400, { error: 'invalid_payload' });
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
try {
|
|
114
|
-
const transportResponse = await forwardDevAuthProxyRequest(payload, {
|
|
115
|
-
appId: options.appId,
|
|
116
|
-
hostUrl: options.env.hostUrl,
|
|
117
|
-
devSessionKey: options.env.devSessionKey,
|
|
118
|
-
});
|
|
119
|
-
const responseText = await transportResponse.text();
|
|
120
|
-
res.statusCode = transportResponse.status;
|
|
121
|
-
const contentType = transportResponse.headers.get('content-type');
|
|
122
|
-
if (contentType) {
|
|
123
|
-
res.setHeader('Content-Type', contentType);
|
|
124
|
-
}
|
|
125
|
-
res.setHeader('Cache-Control', 'no-store');
|
|
126
|
-
res.end(responseText);
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
if (error instanceof Error && error.message === 'missing_dev_session') {
|
|
130
|
-
sendJson(res, 400, { error: 'missing_dev_session' });
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
sendJson(res, 502, { error: 'host_transport_failed' });
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
function createDevAuthRouter(options) {
|
|
138
|
-
const handleLogin = createLoginHandler(options.env);
|
|
139
|
-
const handleProxy = createProxyHandler(options);
|
|
140
|
-
const handlers = {
|
|
141
|
-
'GET /login': handleLogin,
|
|
142
|
-
'POST /proxy': handleProxy,
|
|
143
|
-
};
|
|
144
|
-
return async (req, res) => {
|
|
145
|
-
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
146
|
-
const key = `${req.method ?? 'GET'} ${url.pathname}`;
|
|
147
|
-
const handler = handlers[key];
|
|
148
|
-
if (!handler) {
|
|
149
|
-
sendJson(res, 404, { error: 'not_found' });
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
await handler(req, res);
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
export function bardiocDevAuth(options) {
|
|
156
|
-
let runtimeConfig = null;
|
|
157
|
-
return {
|
|
158
|
-
name: 'bardioc-dev-auth',
|
|
159
|
-
apply: 'serve',
|
|
160
|
-
enforce: 'pre',
|
|
161
|
-
configureServer(server) {
|
|
162
|
-
runtimeConfig = readDevAuthEnv(server, options);
|
|
163
|
-
if (!runtimeConfig) {
|
|
164
|
-
server.config.logger.warn(`[bardioc-dev-auth] DEV_AUTH_HOST_URL + DEV_SESSION_KEY, plus VITE_APP_ID, are required in env files — dev auth disabled for appName="${options.appName}".`);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
const env = {
|
|
168
|
-
hostUrl: runtimeConfig.hostUrl,
|
|
169
|
-
devSessionKey: runtimeConfig.devSessionKey,
|
|
170
|
-
sessionStorageKey: runtimeConfig.sessionStorageKey,
|
|
171
|
-
};
|
|
172
|
-
const router = createDevAuthRouter({ appId: runtimeConfig.exchangeAppId, env });
|
|
173
|
-
server.config.logger.info(`[bardioc-dev-auth] enabled for appName="${options.appName}" appId="${runtimeConfig.exchangeAppId}" → ${runtimeConfig.hostUrl}/api/transport`);
|
|
174
|
-
const basePath = server.config.base.endsWith('/')
|
|
175
|
-
? server.config.base.slice(0, -1)
|
|
176
|
-
: server.config.base;
|
|
177
|
-
server.middlewares.use(async (req, res, next) => {
|
|
178
|
-
const originalUrl = req.url ?? '';
|
|
179
|
-
const devAuthReq = req;
|
|
180
|
-
const parsed = new URL(originalUrl, 'http://localhost');
|
|
181
|
-
const pathname = parsed.pathname;
|
|
182
|
-
const routePath = pathname.startsWith(basePath)
|
|
183
|
-
? pathname.slice(basePath.length) || '/'
|
|
184
|
-
: pathname;
|
|
185
|
-
const shouldHandle = routePath === '/login' || routePath === '/proxy';
|
|
186
|
-
if (shouldHandle) {
|
|
187
|
-
try {
|
|
188
|
-
devAuthReq.__bardiocOriginalUrl = originalUrl;
|
|
189
|
-
req.url = `${routePath}${parsed.search}`;
|
|
190
|
-
await router(req, res);
|
|
191
|
-
}
|
|
192
|
-
catch (error) {
|
|
193
|
-
next(error);
|
|
194
|
-
}
|
|
195
|
-
finally {
|
|
196
|
-
req.url = originalUrl;
|
|
197
|
-
delete devAuthReq.__bardiocOriginalUrl;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
next();
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
},
|
|
205
|
-
transformIndexHtml() {
|
|
206
|
-
if (!runtimeConfig) {
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
return [
|
|
210
|
-
{
|
|
211
|
-
tag: 'script',
|
|
212
|
-
injectTo: 'head',
|
|
213
|
-
children: `window.__BARDIOC_DEV_AUTH__ = ${JSON.stringify({
|
|
214
|
-
hostUrl: runtimeConfig.hostUrl,
|
|
215
|
-
sessionKey: runtimeConfig.devSessionKey,
|
|
216
|
-
})};`,
|
|
217
|
-
},
|
|
218
|
-
];
|
|
219
|
-
},
|
|
220
|
-
};
|
|
221
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
interface CliConfig {
|
|
3
|
-
hostUrl?: string;
|
|
4
|
-
cliAccessToken?: string;
|
|
5
|
-
cliAccessTokenExpiresAt?: number;
|
|
6
|
-
}
|
|
7
|
-
interface RuntimeEnv {
|
|
8
|
-
VITE_ENABLE_DEV_AUTH?: string;
|
|
9
|
-
VITE_APP_ID?: string;
|
|
10
|
-
DEV_AUTH_HOST_URL?: string;
|
|
11
|
-
}
|
|
12
|
-
interface DevSessionResponse {
|
|
13
|
-
sessionKey: string;
|
|
14
|
-
hostUrl: string;
|
|
15
|
-
appId: string;
|
|
16
|
-
}
|
|
17
|
-
interface CliMainRuntime {
|
|
18
|
-
argv?: string[];
|
|
19
|
-
cwd?: () => string;
|
|
20
|
-
env?: NodeJS.ProcessEnv;
|
|
21
|
-
platform?: NodeJS.Platform;
|
|
22
|
-
spawnCommand?: typeof spawn;
|
|
23
|
-
stdout?: Pick<NodeJS.WriteStream, 'write'>;
|
|
24
|
-
stderr?: Pick<NodeJS.WriteStream, 'write'>;
|
|
25
|
-
exit?: (code: number) => void;
|
|
26
|
-
readCliConfig?: () => CliConfig | null;
|
|
27
|
-
}
|
|
28
|
-
export declare function readLayeredEnv(cwd: string, runtimeEnv?: NodeJS.ProcessEnv): RuntimeEnv;
|
|
29
|
-
export declare function readCliConfigFromFile(configPath: string): CliConfig | null;
|
|
30
|
-
export declare function normalizeHostUrl(hostUrl: string): string;
|
|
31
|
-
export declare function assertCliConfig(config: CliConfig | null, hostUrl: string): asserts config is CliConfig;
|
|
32
|
-
export declare function fetchDevSession(hostUrl: string, cliAccessToken: string, appId: string): Promise<DevSessionResponse>;
|
|
33
|
-
export declare function main(runtime?: CliMainRuntime): Promise<void>;
|
|
34
|
-
export {};
|
package/dist/dev-session-cli.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { resolve } from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { readDotEnvFile } from './dot-env.js';
|
|
7
|
-
export function readLayeredEnv(cwd, runtimeEnv = process.env) {
|
|
8
|
-
const env = {};
|
|
9
|
-
for (const fileName of ['.env', '.env.local']) {
|
|
10
|
-
const filePath = resolve(cwd, fileName);
|
|
11
|
-
if (!existsSync(filePath)) {
|
|
12
|
-
continue;
|
|
13
|
-
}
|
|
14
|
-
Object.assign(env, readDotEnvFile(filePath));
|
|
15
|
-
}
|
|
16
|
-
for (const [key, value] of Object.entries(runtimeEnv)) {
|
|
17
|
-
if (typeof value === 'string') {
|
|
18
|
-
env[key] = value;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return env;
|
|
22
|
-
}
|
|
23
|
-
export function readCliConfigFromFile(configPath) {
|
|
24
|
-
if (!existsSync(configPath)) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
const parsed = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
28
|
-
return parsed;
|
|
29
|
-
}
|
|
30
|
-
function readCliConfig() {
|
|
31
|
-
return readCliConfigFromFile(resolve(homedir(), '.bardioc', 'config.json'));
|
|
32
|
-
}
|
|
33
|
-
export function normalizeHostUrl(hostUrl) {
|
|
34
|
-
return hostUrl.trim().replace(/\/$/, '');
|
|
35
|
-
}
|
|
36
|
-
export function assertCliConfig(config, hostUrl) {
|
|
37
|
-
if (!config?.hostUrl || !config.cliAccessToken) {
|
|
38
|
-
throw new Error('Missing CLI login. Run `bardioc login` first.');
|
|
39
|
-
}
|
|
40
|
-
if (normalizeHostUrl(config.hostUrl) !== normalizeHostUrl(hostUrl)) {
|
|
41
|
-
throw new Error(`CLI login host ${normalizeHostUrl(config.hostUrl)} does not match DEV_AUTH_HOST_URL ${normalizeHostUrl(hostUrl)}.`);
|
|
42
|
-
}
|
|
43
|
-
if (typeof config.cliAccessTokenExpiresAt === 'number' &&
|
|
44
|
-
config.cliAccessTokenExpiresAt > 0 &&
|
|
45
|
-
config.cliAccessTokenExpiresAt * 1000 <= Date.now()) {
|
|
46
|
-
throw new Error('Stored CLI login is expired. Run `bardioc login` again.');
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
export async function fetchDevSession(hostUrl, cliAccessToken, appId) {
|
|
50
|
-
const response = await fetch(`${normalizeHostUrl(hostUrl)}/api/auth/dev-session`, {
|
|
51
|
-
method: 'POST',
|
|
52
|
-
headers: {
|
|
53
|
-
'Content-Type': 'application/json',
|
|
54
|
-
Authorization: `Bearer ${cliAccessToken}`,
|
|
55
|
-
},
|
|
56
|
-
body: JSON.stringify({ appId }),
|
|
57
|
-
cache: 'no-store',
|
|
58
|
-
});
|
|
59
|
-
if (!response.ok) {
|
|
60
|
-
const data = (await response.json().catch(() => ({})));
|
|
61
|
-
throw new Error(data.error ?? `Dev session failed (${response.status})`);
|
|
62
|
-
}
|
|
63
|
-
return (await response.json());
|
|
64
|
-
}
|
|
65
|
-
export async function main(runtime = {}) {
|
|
66
|
-
const argv = runtime.argv ?? process.argv;
|
|
67
|
-
const currentEnv = runtime.env ?? process.env;
|
|
68
|
-
const currentCwd = runtime.cwd ?? (() => process.cwd());
|
|
69
|
-
const spawnCommand = runtime.spawnCommand ?? spawn;
|
|
70
|
-
const stdout = runtime.stdout ?? process.stdout;
|
|
71
|
-
const stderr = runtime.stderr ?? process.stderr;
|
|
72
|
-
const exit = runtime.exit ?? process.exit;
|
|
73
|
-
const separatorIndex = argv.indexOf('--');
|
|
74
|
-
const commandArgs = separatorIndex >= 0 ? argv.slice(separatorIndex + 1) : [];
|
|
75
|
-
if (commandArgs.length === 0) {
|
|
76
|
-
throw new Error('Missing command after `--`. Example: bardioc-dev-session -- vite');
|
|
77
|
-
}
|
|
78
|
-
const cwd = currentCwd();
|
|
79
|
-
const env = readLayeredEnv(cwd, currentEnv);
|
|
80
|
-
const devAuthEnabled = env.VITE_ENABLE_DEV_AUTH === 'true';
|
|
81
|
-
const childEnv = { ...currentEnv };
|
|
82
|
-
const [command, ...commandRestArgs] = commandArgs;
|
|
83
|
-
if (!command) {
|
|
84
|
-
throw new Error('Missing command after `--`. Example: bardioc-dev-session -- vite');
|
|
85
|
-
}
|
|
86
|
-
if (devAuthEnabled) {
|
|
87
|
-
const appId = env.VITE_APP_ID?.trim();
|
|
88
|
-
const hostUrl = env.DEV_AUTH_HOST_URL?.trim();
|
|
89
|
-
if (!appId) {
|
|
90
|
-
throw new Error('Missing VITE_APP_ID for standalone dev auth.');
|
|
91
|
-
}
|
|
92
|
-
if (!hostUrl) {
|
|
93
|
-
throw new Error('Missing DEV_AUTH_HOST_URL for standalone dev auth.');
|
|
94
|
-
}
|
|
95
|
-
const cliConfig = (runtime.readCliConfig ?? readCliConfig)();
|
|
96
|
-
assertCliConfig(cliConfig, hostUrl);
|
|
97
|
-
const devSession = await fetchDevSession(hostUrl, cliConfig.cliAccessToken, appId);
|
|
98
|
-
childEnv.DEV_AUTH_HOST_URL = normalizeHostUrl(devSession.hostUrl);
|
|
99
|
-
childEnv.DEV_SESSION_KEY = devSession.sessionKey;
|
|
100
|
-
stdout.write(`[bardioc-dev-session] Refreshed dev session for appId="${devSession.appId}" via ${childEnv.DEV_AUTH_HOST_URL}\n`);
|
|
101
|
-
}
|
|
102
|
-
const child = spawnCommand(command, commandRestArgs, {
|
|
103
|
-
stdio: 'inherit',
|
|
104
|
-
env: childEnv,
|
|
105
|
-
shell: (runtime.platform ?? process.platform) === 'win32',
|
|
106
|
-
});
|
|
107
|
-
child.on('exit', (code) => {
|
|
108
|
-
exit(code ?? 0);
|
|
109
|
-
});
|
|
110
|
-
child.on('error', (error) => {
|
|
111
|
-
stderr.write(`${error.message}\n`);
|
|
112
|
-
exit(1);
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
const isDirectRun = process.argv[1]
|
|
116
|
-
? realpathSync.native(resolve(process.argv[1])) ===
|
|
117
|
-
realpathSync.native(fileURLToPath(import.meta.url))
|
|
118
|
-
: false;
|
|
119
|
-
if (isDirectRun) {
|
|
120
|
-
void main().catch(error => {
|
|
121
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
122
|
-
process.stderr.write(`[bardioc-dev-session] ${message}\n`);
|
|
123
|
-
process.exit(1);
|
|
124
|
-
});
|
|
125
|
-
}
|