@bardioc/app-sdk 0.4.7 → 0.4.10
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 +33 -4
- package/dist/dev-auth-env.d.ts +15 -0
- package/dist/dev-auth-env.js +33 -0
- package/dist/dev-proxy.d.ts +23 -2
- package/dist/dev-proxy.js +69 -10
- package/dist/index.d.ts +1 -2
- package/dist/index.js +0 -1
- package/dist/transports/graph-transport.d.ts +26 -9
- package/dist/transports/graph-transport.js +53 -21
- package/dist/types.d.ts +15 -1
- package/dist/vite.js +13 -131
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ export default defineConfig({
|
|
|
105
105
|
});
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
Handles dev base path, port config, host session proxy routes,
|
|
108
|
+
Handles dev base path, port config, host session proxy routes, platform fonts, and manifest validation on build.
|
|
109
109
|
|
|
110
110
|
### Platform fonts
|
|
111
111
|
|
|
@@ -118,7 +118,7 @@ The Bardioc platform guarantees a stable font endpoint wherever an app runs —
|
|
|
118
118
|
It provides `Nunito Sans Variable` (normal + italic) and `Geist Mono Variable` as variable fonts (latin subset), matching the `--font-nunito-sans` / `--font-geist-mono` theme variables that `@bardioc/ui` resolves by default.
|
|
119
119
|
|
|
120
120
|
- **Embedded in the OS** the URL resolves same-origin against the host, which serves it with immutable caching — one download shared by the host and every app.
|
|
121
|
-
- **Standalone dev
|
|
121
|
+
- **Standalone dev** the `bardiocApp()` plugin serves the same files from assets shipped inside this package (dev server only — they are never added to your bundle). This applies to Vite-based apps; the angular and nextjs templates run their own dev servers, where the link is a harmless 404 standalone and resolves normally embedded in the OS.
|
|
122
122
|
|
|
123
123
|
New apps scaffolded with `create-bardioc-app` include the `<link>` already.
|
|
124
124
|
|
|
@@ -131,7 +131,16 @@ Standalone local development is host-backed only.
|
|
|
131
131
|
|
|
132
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.
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
Dev servers that cannot host the Vite plugin (angular, nextjs) run the same proxy as a standalone server:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
import { startDevAuthProxy } from '@bardioc/app-sdk/dev-proxy';
|
|
138
|
+
|
|
139
|
+
// Reads DEV_SECRET / API_BASE_URL from the project's .env files; resolves to null when unset.
|
|
140
|
+
await startDevAuthProxy({ projectDir: process.cwd(), port: 3105 });
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Point the app at it with `installDevBridge({ apiBaseUrl: 'http://127.0.0.1:3105/rest' })`.
|
|
135
144
|
|
|
136
145
|
## React hooks
|
|
137
146
|
|
|
@@ -199,14 +208,34 @@ await sdk.transport.graph.connect(fromId, toId, 'ogit/relates');
|
|
|
199
208
|
// Delete node
|
|
200
209
|
await sdk.transport.graph.delete('node-id');
|
|
201
210
|
|
|
211
|
+
// Combined query: Elasticsearch picks the start vertices, Gremlin traverses from them
|
|
212
|
+
const speeches = await sdk.transport.graph.combined(
|
|
213
|
+
'+(ogit\\/_type: "ogit/Politics/AgendaItem")',
|
|
214
|
+
"inE().outV().has('ogit/_type', 'ogit/Politics/Discussion')",
|
|
215
|
+
{ limit: 1000 }
|
|
216
|
+
);
|
|
217
|
+
|
|
202
218
|
// Time series
|
|
203
219
|
const values = await sdk.transport.graph.timeseries.get('ts-id', {
|
|
204
220
|
from: '2026-01-01',
|
|
205
221
|
to: '2026-01-31',
|
|
206
222
|
});
|
|
223
|
+
|
|
224
|
+
// Several series in one request, averaged per timestamp
|
|
225
|
+
const merged = await sdk.transport.graph.timeseries.get('ts-id', {
|
|
226
|
+
from: '2026-01-01',
|
|
227
|
+
to: '2026-01-31',
|
|
228
|
+
withIds: ['ts-id-2', 'ts-id-3'],
|
|
229
|
+
aggregate: 'avg',
|
|
230
|
+
});
|
|
207
231
|
```
|
|
208
232
|
|
|
209
|
-
Available methods: `get`, `getMany`, `getByXid`, `query`, `gremlin`, `combined`, `create`, `update`, `delete`, `connect`, `history`, `batch.delete`, `timeseries.get`, `timeseries.add`, `timeseries.query`, `content.set`, `content.get`.
|
|
233
|
+
Available methods: `get`, `getMany`, `getByXid`, `query`, `gremlin`, `combined`, `create`, `update`, `delete`, `connect`, `history`, `batch.delete`, `timeseries.get`, `timeseries.add`, `timeseries.query`, `timeseries.history`, `content.set`, `content.get`.
|
|
234
|
+
|
|
235
|
+
`combined` and multi-ID time series reads both return one flat result set: a combined query carries
|
|
236
|
+
no marker for which start vertex a row came from (label and `select()` in the traversal when you need
|
|
237
|
+
it), and time series entries carry only `timestamp` and `value` (read one ID per request when values
|
|
238
|
+
must stay attributable).
|
|
210
239
|
|
|
211
240
|
All graph request option types accept optional `scopeId` when a request must target a specific scope.
|
|
212
241
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface DevAuthEnv {
|
|
2
|
+
devSecret?: string;
|
|
3
|
+
apiBaseUrl?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ResolveDevAuthEnvOptions {
|
|
6
|
+
/** Directory holding the `.env` files (Vite's `envDir`, or the app root). */
|
|
7
|
+
envDir: string;
|
|
8
|
+
/** Vite mode, when the mode-specific files should be read too. */
|
|
9
|
+
mode?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the standalone dev-auth contract (`DEV_SECRET` + `API_BASE_URL`) the same way
|
|
13
|
+
* Vite loads env: dotenv files first, `process.env` last so a shell value always wins.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveDevAuthEnv(options: ResolveDevAuthEnvOptions): DevAuthEnv;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { readDotEnvFile } from './dot-env.js';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the standalone dev-auth contract (`DEV_SECRET` + `API_BASE_URL`) the same way
|
|
6
|
+
* Vite loads env: dotenv files first, `process.env` last so a shell value always wins.
|
|
7
|
+
*/
|
|
8
|
+
export function resolveDevAuthEnv(options) {
|
|
9
|
+
const mode = options.mode?.trim();
|
|
10
|
+
const env = {};
|
|
11
|
+
for (const fileName of [
|
|
12
|
+
'.env',
|
|
13
|
+
'.env.local',
|
|
14
|
+
mode ? `.env.${mode}` : null,
|
|
15
|
+
mode ? `.env.${mode}.local` : null,
|
|
16
|
+
]) {
|
|
17
|
+
if (!fileName)
|
|
18
|
+
continue;
|
|
19
|
+
const filePath = resolve(options.envDir, fileName);
|
|
20
|
+
if (existsSync(filePath)) {
|
|
21
|
+
Object.assign(env, readDotEnvFile(filePath));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
25
|
+
if (typeof value === 'string') {
|
|
26
|
+
env[key] = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
devSecret: env.DEV_SECRET?.trim(),
|
|
31
|
+
apiBaseUrl: env.API_BASE_URL?.trim().replace(/\/$/, ''),
|
|
32
|
+
};
|
|
33
|
+
}
|
package/dist/dev-proxy.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type IncomingMessage, type Server, type ServerResponse } from 'node:http';
|
|
2
2
|
export interface DevAuthProxyOptions {
|
|
3
3
|
/** Upstream BFF base URL (e.g. `https://your-bff-host`). */
|
|
4
4
|
apiBaseUrl: string;
|
|
@@ -9,9 +9,30 @@ export interface DevAuthProxyOptions {
|
|
|
9
9
|
}
|
|
10
10
|
interface SendJsonOptions {
|
|
11
11
|
allowOrigin?: string;
|
|
12
|
+
requestOrigin?: string;
|
|
12
13
|
}
|
|
13
14
|
export declare function readRequestBody(req: IncomingMessage): Promise<Buffer>;
|
|
14
|
-
export declare function applyCors(res: ServerResponse, allowOrigin?: string): void;
|
|
15
|
+
export declare function applyCors(res: ServerResponse, allowOrigin?: string, requestOrigin?: string): void;
|
|
15
16
|
export declare function sendJson(res: ServerResponse, status: number, body: unknown, options?: SendJsonOptions): void;
|
|
16
17
|
export declare function createDevAuthProxyHandler(options: DevAuthProxyOptions): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
18
|
+
export interface StartDevAuthProxyOptions {
|
|
19
|
+
/** Port the proxy listens on. Templates use the app port + 100. */
|
|
20
|
+
port: number;
|
|
21
|
+
/** Directory the `.env` files are read from. Defaults to `process.cwd()`. */
|
|
22
|
+
projectDir?: string;
|
|
23
|
+
/** Interface to bind. Defaults to `127.0.0.1`. */
|
|
24
|
+
host?: string;
|
|
25
|
+
/** CORS origin for the app dev server. Defaults to `*` (echoed back per request). */
|
|
26
|
+
allowOrigin?: string;
|
|
27
|
+
/** Explicit upstream, skips env resolution when both this and `devSecret` are given. */
|
|
28
|
+
apiBaseUrl?: string;
|
|
29
|
+
devSecret?: string;
|
|
30
|
+
/** Mode-specific `.env.<mode>` files to include. */
|
|
31
|
+
mode?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Starts a standalone dev-auth proxy for dev servers that cannot use the Vite plugin
|
|
35
|
+
* (angular, nextjs). Resolves to `null` when `DEV_SECRET` / `API_BASE_URL` are missing.
|
|
36
|
+
*/
|
|
37
|
+
export declare function startDevAuthProxy(options: StartDevAuthProxyOptions): Promise<Server | null>;
|
|
17
38
|
export {};
|
package/dist/dev-proxy.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { resolveDevAuthEnv } from './dev-auth-env.js';
|
|
1
3
|
export async function readRequestBody(req) {
|
|
2
4
|
return new Promise((resolve, reject) => {
|
|
3
5
|
const chunks = [];
|
|
@@ -6,16 +8,23 @@ export async function readRequestBody(req) {
|
|
|
6
8
|
req.on('error', reject);
|
|
7
9
|
});
|
|
8
10
|
}
|
|
9
|
-
export function applyCors(res, allowOrigin) {
|
|
11
|
+
export function applyCors(res, allowOrigin, requestOrigin) {
|
|
10
12
|
if (!allowOrigin) {
|
|
11
13
|
return;
|
|
12
14
|
}
|
|
13
|
-
|
|
15
|
+
// The dev bridge fetches with `credentials: 'include'`, which a browser refuses to pair
|
|
16
|
+
// with a wildcard origin — echo the caller's origin instead and allow credentials.
|
|
17
|
+
const credentialed = allowOrigin === '*' && !!requestOrigin;
|
|
18
|
+
res.setHeader('Access-Control-Allow-Origin', credentialed ? requestOrigin : allowOrigin);
|
|
19
|
+
if (credentialed) {
|
|
20
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
21
|
+
res.setHeader('Vary', 'Origin');
|
|
22
|
+
}
|
|
14
23
|
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');
|
|
15
24
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Scope-ID, X-Requested-With');
|
|
16
25
|
}
|
|
17
26
|
export function sendJson(res, status, body, options = {}) {
|
|
18
|
-
applyCors(res, options.allowOrigin);
|
|
27
|
+
applyCors(res, options.allowOrigin, options.requestOrigin);
|
|
19
28
|
res.statusCode = status;
|
|
20
29
|
res.setHeader('Content-Type', 'application/json');
|
|
21
30
|
res.setHeader('Cache-Control', 'no-store');
|
|
@@ -31,26 +40,37 @@ function addDevSecretHeader(req, headers, devSecret) {
|
|
|
31
40
|
}
|
|
32
41
|
return headers;
|
|
33
42
|
}
|
|
43
|
+
// The BFF answers a bare 403 for any Origin outside its CORS allow-list, which no
|
|
44
|
+
// localhost dev server is in. Dropping Origin makes it a non-CORS request, and the
|
|
45
|
+
// dev-secret check then still passes via its Referer localhost fallback.
|
|
46
|
+
function dropOriginKeepReferer(headers) {
|
|
47
|
+
const origin = headers.get('Origin');
|
|
48
|
+
if (origin && !headers.has('Referer')) {
|
|
49
|
+
headers.set('Referer', `${origin}/`);
|
|
50
|
+
}
|
|
51
|
+
headers.delete('Origin');
|
|
52
|
+
}
|
|
34
53
|
export function createDevAuthProxyHandler(options) {
|
|
35
54
|
const apiBaseUrl = normalizeApiBaseUrl(options.apiBaseUrl);
|
|
36
55
|
const { devSecret, allowOrigin } = options;
|
|
37
56
|
return async (req, res) => {
|
|
38
57
|
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
58
|
+
const requestOrigin = typeof req.headers.origin === 'string' ? req.headers.origin : undefined;
|
|
39
59
|
if (req.method === 'OPTIONS') {
|
|
40
|
-
applyCors(res, allowOrigin);
|
|
60
|
+
applyCors(res, allowOrigin, requestOrigin);
|
|
41
61
|
res.statusCode = 204;
|
|
42
62
|
res.end();
|
|
43
63
|
return;
|
|
44
64
|
}
|
|
45
65
|
if (!url.pathname.startsWith('/rest/')) {
|
|
46
|
-
sendJson(res, 404, { error: 'not_found' }, { allowOrigin });
|
|
66
|
+
sendJson(res, 404, { error: 'not_found' }, { allowOrigin, requestOrigin });
|
|
47
67
|
return;
|
|
48
68
|
}
|
|
49
69
|
const upstreamPath = url.pathname.slice('/rest'.length) + url.search;
|
|
50
70
|
const upstreamUrl = `${apiBaseUrl}${upstreamPath}`;
|
|
51
71
|
const headers = new Headers();
|
|
52
|
-
// Forward headers from the browser so the BFF sees the same request the host would
|
|
53
|
-
// (cookies,
|
|
72
|
+
// Forward headers from the browser so the BFF sees the same request the host would
|
|
73
|
+
// relay (cookies, referer, etc.). Skip hop-by-hop headers; fetch sets Host from the URL.
|
|
54
74
|
const skipHeaders = new Set([
|
|
55
75
|
'connection',
|
|
56
76
|
'content-length',
|
|
@@ -74,6 +94,7 @@ export function createDevAuthProxyHandler(options) {
|
|
|
74
94
|
}
|
|
75
95
|
}
|
|
76
96
|
addDevSecretHeader(req, headers, devSecret);
|
|
97
|
+
dropOriginKeepReferer(headers);
|
|
77
98
|
// Dev auth is dev-secret only: never forward X-App-Id, so the BFF app-token
|
|
78
99
|
// exchange (which would also demand X-Scope-ID) can never be triggered here.
|
|
79
100
|
headers.delete('X-App-Id');
|
|
@@ -84,7 +105,7 @@ export function createDevAuthProxyHandler(options) {
|
|
|
84
105
|
body = await readRequestBody(req);
|
|
85
106
|
}
|
|
86
107
|
catch {
|
|
87
|
-
sendJson(res, 400, { error: 'invalid_body' }, { allowOrigin });
|
|
108
|
+
sendJson(res, 400, { error: 'invalid_body' }, { allowOrigin, requestOrigin });
|
|
88
109
|
return;
|
|
89
110
|
}
|
|
90
111
|
try {
|
|
@@ -94,7 +115,7 @@ export function createDevAuthProxyHandler(options) {
|
|
|
94
115
|
body: body.length > 0 ? new Uint8Array(body) : undefined,
|
|
95
116
|
cache: 'no-store',
|
|
96
117
|
});
|
|
97
|
-
applyCors(res, allowOrigin);
|
|
118
|
+
applyCors(res, allowOrigin, requestOrigin);
|
|
98
119
|
res.statusCode = upstreamRes.status;
|
|
99
120
|
res.setHeader('Cache-Control', 'no-store');
|
|
100
121
|
const upstreamContentType = upstreamRes.headers.get('content-type');
|
|
@@ -105,7 +126,45 @@ export function createDevAuthProxyHandler(options) {
|
|
|
105
126
|
res.end(responseBody);
|
|
106
127
|
}
|
|
107
128
|
catch {
|
|
108
|
-
sendJson(res, 502, { error: 'upstream_unavailable' }, { allowOrigin });
|
|
129
|
+
sendJson(res, 502, { error: 'upstream_unavailable' }, { allowOrigin, requestOrigin });
|
|
109
130
|
}
|
|
110
131
|
};
|
|
111
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Starts a standalone dev-auth proxy for dev servers that cannot use the Vite plugin
|
|
135
|
+
* (angular, nextjs). Resolves to `null` when `DEV_SECRET` / `API_BASE_URL` are missing.
|
|
136
|
+
*/
|
|
137
|
+
export async function startDevAuthProxy(options) {
|
|
138
|
+
const { port, host = '127.0.0.1', allowOrigin = '*' } = options;
|
|
139
|
+
const env = options.apiBaseUrl && options.devSecret
|
|
140
|
+
? { apiBaseUrl: options.apiBaseUrl, devSecret: options.devSecret }
|
|
141
|
+
: resolveDevAuthEnv({ envDir: options.projectDir ?? process.cwd(), mode: options.mode });
|
|
142
|
+
if (!env.apiBaseUrl || !env.devSecret) {
|
|
143
|
+
process.stderr.write('[bardioc-dev-auth] DEV_SECRET and API_BASE_URL are required for dev auth — proxy disabled\n');
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const handler = createDevAuthProxyHandler({
|
|
147
|
+
apiBaseUrl: env.apiBaseUrl,
|
|
148
|
+
devSecret: env.devSecret,
|
|
149
|
+
allowOrigin,
|
|
150
|
+
});
|
|
151
|
+
const server = createServer((req, res) => {
|
|
152
|
+
void handler(req, res);
|
|
153
|
+
});
|
|
154
|
+
await new Promise((resolve, reject) => {
|
|
155
|
+
server.once('error', reject);
|
|
156
|
+
server.listen(port, host, () => {
|
|
157
|
+
server.off('error', reject);
|
|
158
|
+
resolve();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
const address = server.address();
|
|
162
|
+
const boundPort = typeof address === 'object' && address ? address.port : port;
|
|
163
|
+
process.stdout.write(`[bardioc-dev-auth] proxying /rest/* → ${env.apiBaseUrl} on http://${host}:${boundPort}/rest\n`);
|
|
164
|
+
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
165
|
+
process.once(signal, () => {
|
|
166
|
+
server.close(() => process.exit(0));
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return server;
|
|
170
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export { createHostBridge } from './host-bridge.js';
|
|
2
2
|
export { DEFAULT_WINDOW_SIZE, MANIFEST_FILENAME, WINDOW_SIZES, validateManifest, } from './manifest.js';
|
|
3
3
|
export type { AppManifest, AppManifestPermission, AppManifestWindowConfig, CustomWindowSize, WindowSizePreset, } from './manifest.js';
|
|
4
|
-
export { useGraphEvents, useOsConfig } from './react.js';
|
|
5
4
|
export { SDK_CONTRACT_MATRIX, getRequiredPermissionForSdkMessage } from './contract-matrix.js';
|
|
6
5
|
export { ALLOWED_KERNEL_MESSAGES, SDK_MSG } from './protocol.js';
|
|
7
6
|
export type { SdkMessageType } from './protocol.js';
|
|
8
7
|
export { EntityNotFoundError, NetworkError, PermissionError, SdkError, TimeoutError, ValidationError, } from './errors.js';
|
|
9
|
-
export type { Application, BatchResult, Configuration, CreateMemberInput, CreateUnitInput, DeleteOptions, EventSubscribeRequest, EventSubscribeResponse, EventUnsubscribeRequest, EventsApi, FileEntry, GetNodeOptions, GraphEdgeRaw, GraphEvent, GraphEventPushPayload, GraphEventType, GraphNodeRaw, GraphTransport, GremlinOptions, HistoryEntry, HistoryOptions, HostBridge, HostBridgeConfig, InstanceList, MutationOptions, NotifyLevel, OrgMember, OrgStructure, OrgUnit, OsConfig, OsRequestOptions, OsTransport, QueryOptions, SdkCommandDefinition, SdkCommandHandler, SdkCommandInvokePayload, SdkIdbDeletePayload, SdkIdbEntry, SdkIdbGetPayload, SdkIdbPutPayload, SdkIdbQueryPayload, SdkIdbStore, SdkInitResponse, SdkKernelProxyPayload, SdkMenuItem, SdkMenuRoot, SdkMessage, SdkNotifyPayload, SdkResponse, SdkSetActiveTabPayload, SdkSetCommandsPayload, SdkSetMenuPayload, SdkShortcutEventPayload, SdkStorage, SdkStorageDeletePayload, SdkStorageGetPayload, SdkStorageSetPayload, SdkTransport, SdkTransportPayload, TimeseriesOptions, TimeseriesQueryOptions, TimeseriesValue, TransportScopeOptions, UpdateMemberInput, UpdateUnitInput, UserProfile, } from './types.js';
|
|
8
|
+
export type { Application, BatchResult, CombinedQueryOptions, Configuration, CreateMemberInput, CreateUnitInput, DeleteOptions, EventSubscribeRequest, EventSubscribeResponse, EventUnsubscribeRequest, EventsApi, FileEntry, GetNodeOptions, GraphEdgeRaw, GraphEvent, GraphEventPushPayload, GraphEventType, GraphNodeRaw, GraphTransport, GremlinOptions, HistoryEntry, HistoryOptions, HostBridge, HostBridgeConfig, InstanceList, MutationOptions, NotifyLevel, OrgMember, OrgStructure, OrgUnit, OsConfig, OsRequestOptions, OsTransport, QueryOptions, SdkCommandDefinition, SdkCommandHandler, SdkCommandInvokePayload, SdkIdbDeletePayload, SdkIdbEntry, SdkIdbGetPayload, SdkIdbPutPayload, SdkIdbQueryPayload, SdkIdbStore, SdkInitResponse, SdkKernelProxyPayload, SdkMenuItem, SdkMenuRoot, SdkMessage, SdkNotifyPayload, SdkResponse, SdkSetActiveTabPayload, SdkSetCommandsPayload, SdkSetMenuPayload, SdkShortcutEventPayload, SdkStorage, SdkStorageDeletePayload, SdkStorageGetPayload, SdkStorageSetPayload, SdkTransport, SdkTransportPayload, TimeseriesAggregate, TimeseriesHistory, TimeseriesHistoryOptions, TimeseriesOptions, TimeseriesQueryOptions, TimeseriesValue, TransportScopeOptions, UpdateMemberInput, UpdateUnitInput, UserProfile, } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { createHostBridge } from './host-bridge.js';
|
|
2
2
|
export { DEFAULT_WINDOW_SIZE, MANIFEST_FILENAME, WINDOW_SIZES, validateManifest, } from './manifest.js';
|
|
3
|
-
export { useGraphEvents, useOsConfig } from './react.js';
|
|
4
3
|
export { SDK_CONTRACT_MATRIX, getRequiredPermissionForSdkMessage } from './contract-matrix.js';
|
|
5
4
|
export { ALLOWED_KERNEL_MESSAGES, SDK_MSG } from './protocol.js';
|
|
6
5
|
export { EntityNotFoundError, NetworkError, PermissionError, SdkError, TimeoutError, ValidationError, } from './errors.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BatchResult, DeleteOptions, GetNodeOptions, GraphEdgeRaw, GraphNodeRaw, GremlinOptions, HistoryEntry, HistoryOptions, MutationOptions, QueryOptions, SdkTransportPayload, TimeseriesOptions, TimeseriesQueryOptions, TimeseriesValue, TransportScopeOptions } from '../types.js';
|
|
1
|
+
import type { BatchResult, CombinedQueryOptions, DeleteOptions, GetNodeOptions, GraphEdgeRaw, GraphNodeRaw, GremlinOptions, HistoryEntry, HistoryOptions, MutationOptions, QueryOptions, SdkTransportPayload, TimeseriesHistory, TimeseriesHistoryOptions, TimeseriesOptions, TimeseriesQueryOptions, TimeseriesValue, TransportScopeOptions } from '../types.js';
|
|
2
2
|
/** Graph transport class providing graph database operations */
|
|
3
3
|
export declare class GraphTransport {
|
|
4
4
|
private _request;
|
|
@@ -64,20 +64,24 @@ export declare class GraphTransport {
|
|
|
64
64
|
*/
|
|
65
65
|
gremlin<T = unknown>(rootId: string, query: string, options?: GremlinOptions): Promise<T[]>;
|
|
66
66
|
/**
|
|
67
|
-
* Execute combined query
|
|
68
|
-
* Returns raw results (structure varies by
|
|
67
|
+
* Execute combined query: Elasticsearch selects the start vertices, the Gremlin traversal
|
|
68
|
+
* runs from their IDs. Returns raw results (structure varies by the traversal).
|
|
69
|
+
*
|
|
70
|
+
* The result is one flat set for all start vertices — it carries no marker for which start
|
|
71
|
+
* vertex a row came from. Label and select in the traversal when attribution is needed.
|
|
69
72
|
*
|
|
70
73
|
* @example
|
|
71
|
-
* const
|
|
72
|
-
* 'ogit
|
|
73
|
-
*
|
|
74
|
+
* const speeches = await graph.combined(
|
|
75
|
+
* '+(ogit\\/_type: "ogit/Politics/AgendaItem")',
|
|
76
|
+
* "inE().outV().has('ogit/_type', 'ogit/Politics/Discussion')",
|
|
77
|
+
* { limit: 1000 }
|
|
74
78
|
* );
|
|
75
79
|
*
|
|
76
|
-
* @throws {ValidationError} if query
|
|
80
|
+
* @throws {ValidationError} if either query is invalid
|
|
77
81
|
* @throws {NetworkError} on HTTP errors
|
|
78
82
|
* @throws {TimeoutError} on request timeout
|
|
79
83
|
*/
|
|
80
|
-
combined<T = unknown>(
|
|
84
|
+
combined<T = unknown>(elasticsearchQuery: string, gremlinQuery: string, options?: CombinedQueryOptions): Promise<T[]>;
|
|
81
85
|
/**
|
|
82
86
|
* Create new graph node
|
|
83
87
|
*
|
|
@@ -165,7 +169,11 @@ export declare class GraphTransport {
|
|
|
165
169
|
*/
|
|
166
170
|
timeseries: {
|
|
167
171
|
/**
|
|
168
|
-
* Get time series values
|
|
172
|
+
* Get time series values.
|
|
173
|
+
*
|
|
174
|
+
* `withIds` pulls further time series into the same request and `aggregate` combines the
|
|
175
|
+
* values sharing a timestamp. Entries carry only timestamp and value, so a multi-ID request
|
|
176
|
+
* yields one merged series — read a single ID per request when values must stay attributable.
|
|
169
177
|
*
|
|
170
178
|
* @throws {EntityNotFoundError} if time series doesn't exist
|
|
171
179
|
* @throws {NetworkError} on HTTP errors
|
|
@@ -189,6 +197,15 @@ export declare class GraphTransport {
|
|
|
189
197
|
* @throws {TimeoutError} on request timeout
|
|
190
198
|
*/
|
|
191
199
|
query: (options: TimeseriesQueryOptions) => Promise<TimeseriesValue[]>;
|
|
200
|
+
/**
|
|
201
|
+
* Get every value ever written for one timestamp of a time series.
|
|
202
|
+
* Keyed by timestamp, so a single-timestamp request returns a single-entry map.
|
|
203
|
+
*
|
|
204
|
+
* @throws {EntityNotFoundError} if time series doesn't exist
|
|
205
|
+
* @throws {NetworkError} on HTTP errors
|
|
206
|
+
* @throws {TimeoutError} on request timeout
|
|
207
|
+
*/
|
|
208
|
+
history: (id: string, timestamp: number, options?: TimeseriesHistoryOptions) => Promise<TimeseriesHistory>;
|
|
192
209
|
};
|
|
193
210
|
/**
|
|
194
211
|
* Content/blob operations
|
|
@@ -232,38 +232,40 @@ export class GraphTransport {
|
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
/**
|
|
235
|
-
* Execute combined query
|
|
236
|
-
* Returns raw results (structure varies by
|
|
235
|
+
* Execute combined query: Elasticsearch selects the start vertices, the Gremlin traversal
|
|
236
|
+
* runs from their IDs. Returns raw results (structure varies by the traversal).
|
|
237
|
+
*
|
|
238
|
+
* The result is one flat set for all start vertices — it carries no marker for which start
|
|
239
|
+
* vertex a row came from. Label and select in the traversal when attribution is needed.
|
|
237
240
|
*
|
|
238
241
|
* @example
|
|
239
|
-
* const
|
|
240
|
-
* 'ogit
|
|
241
|
-
*
|
|
242
|
+
* const speeches = await graph.combined(
|
|
243
|
+
* '+(ogit\\/_type: "ogit/Politics/AgendaItem")',
|
|
244
|
+
* "inE().outV().has('ogit/_type', 'ogit/Politics/Discussion')",
|
|
245
|
+
* { limit: 1000 }
|
|
242
246
|
* );
|
|
243
247
|
*
|
|
244
|
-
* @throws {ValidationError} if query
|
|
248
|
+
* @throws {ValidationError} if either query is invalid
|
|
245
249
|
* @throws {NetworkError} on HTTP errors
|
|
246
250
|
* @throws {TimeoutError} on request timeout
|
|
247
251
|
*/
|
|
248
|
-
async combined(
|
|
252
|
+
async combined(elasticsearchQuery, gremlinQuery, options) {
|
|
249
253
|
try {
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
limit: options?.limit,
|
|
253
|
-
offset: options?.offset,
|
|
254
|
-
fields: options?.fields,
|
|
255
|
-
includeDeleted: options?.includeDeleted,
|
|
256
|
-
listMeta: options?.listMeta,
|
|
257
|
-
order: options?.order,
|
|
258
|
-
});
|
|
259
|
-
this.log('combined', { path: `${GRAPH_BASE}/query/combined${qs}`, query });
|
|
254
|
+
const path = `${GRAPH_BASE}/query/combined`;
|
|
255
|
+
this.log('combined', { path, elasticsearchQuery, gremlinQuery, limit: options?.limit });
|
|
260
256
|
return await this._request(this.withScope({
|
|
261
|
-
path
|
|
262
|
-
method: '
|
|
257
|
+
path,
|
|
258
|
+
method: 'POST',
|
|
259
|
+
body: {
|
|
260
|
+
elasticsearch_query: elasticsearchQuery,
|
|
261
|
+
gremlin_query: gremlinQuery,
|
|
262
|
+
...(options?.limit === undefined ? {} : { limit: options.limit }),
|
|
263
|
+
},
|
|
264
|
+
contentType: 'application/json',
|
|
263
265
|
}, options));
|
|
264
266
|
}
|
|
265
267
|
catch (error) {
|
|
266
|
-
throw parseError(error, 'graph.combined', {
|
|
268
|
+
throw parseError(error, 'graph.combined', { elasticsearchQuery, gremlinQuery, ...options });
|
|
267
269
|
}
|
|
268
270
|
}
|
|
269
271
|
/**
|
|
@@ -450,7 +452,11 @@ export class GraphTransport {
|
|
|
450
452
|
*/
|
|
451
453
|
timeseries = {
|
|
452
454
|
/**
|
|
453
|
-
* Get time series values
|
|
455
|
+
* Get time series values.
|
|
456
|
+
*
|
|
457
|
+
* `withIds` pulls further time series into the same request and `aggregate` combines the
|
|
458
|
+
* values sharing a timestamp. Entries carry only timestamp and value, so a multi-ID request
|
|
459
|
+
* yields one merged series — read a single ID per request when values must stay attributable.
|
|
454
460
|
*
|
|
455
461
|
* @throws {EntityNotFoundError} if time series doesn't exist
|
|
456
462
|
* @throws {NetworkError} on HTTP errors
|
|
@@ -463,6 +469,9 @@ export class GraphTransport {
|
|
|
463
469
|
to: options?.to,
|
|
464
470
|
limit: options?.limit,
|
|
465
471
|
order: options?.order,
|
|
472
|
+
with: options?.withIds?.join(','),
|
|
473
|
+
aggregate: options?.aggregate,
|
|
474
|
+
includeDeleted: options?.includeDeleted,
|
|
466
475
|
});
|
|
467
476
|
return await this._request(this.withScope({
|
|
468
477
|
path: `${GRAPH_BASE}/${encodeURIComponent(id)}/values${qs}`,
|
|
@@ -520,6 +529,29 @@ export class GraphTransport {
|
|
|
520
529
|
throw parseError(error, 'graph.timeseries.query', { ...options });
|
|
521
530
|
}
|
|
522
531
|
},
|
|
532
|
+
/**
|
|
533
|
+
* Get every value ever written for one timestamp of a time series.
|
|
534
|
+
* Keyed by timestamp, so a single-timestamp request returns a single-entry map.
|
|
535
|
+
*
|
|
536
|
+
* @throws {EntityNotFoundError} if time series doesn't exist
|
|
537
|
+
* @throws {NetworkError} on HTTP errors
|
|
538
|
+
* @throws {TimeoutError} on request timeout
|
|
539
|
+
*/
|
|
540
|
+
history: async (id, timestamp, options) => {
|
|
541
|
+
try {
|
|
542
|
+
const qs = buildQueryString({
|
|
543
|
+
timestamp,
|
|
544
|
+
includeDeleted: options?.includeDeleted,
|
|
545
|
+
});
|
|
546
|
+
return await this._request(this.withScope({
|
|
547
|
+
path: `${GRAPH_BASE}/${encodeURIComponent(id)}/values/history${qs}`,
|
|
548
|
+
method: 'GET',
|
|
549
|
+
}, options));
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
throw parseError(error, 'graph.timeseries.history', { id, timestamp, ...options });
|
|
553
|
+
}
|
|
554
|
+
},
|
|
523
555
|
};
|
|
524
556
|
/**
|
|
525
557
|
* Content/blob operations
|
package/dist/types.d.ts
CHANGED
|
@@ -231,6 +231,10 @@ export interface QueryOptions extends TransportScopeOptions {
|
|
|
231
231
|
listMeta?: boolean;
|
|
232
232
|
order?: string;
|
|
233
233
|
}
|
|
234
|
+
export interface CombinedQueryOptions extends TransportScopeOptions {
|
|
235
|
+
/** Cap on the vertices the Elasticsearch stage feeds into the traversal. */
|
|
236
|
+
limit?: number;
|
|
237
|
+
}
|
|
234
238
|
export interface GremlinOptions extends TransportScopeOptions {
|
|
235
239
|
fields?: string;
|
|
236
240
|
includeDeleted?: boolean;
|
|
@@ -259,16 +263,26 @@ export interface TimeseriesValue {
|
|
|
259
263
|
timestamp: number;
|
|
260
264
|
value: unknown;
|
|
261
265
|
}
|
|
266
|
+
export type TimeseriesAggregate = 'avg' | 'min' | 'max' | 'sum' | 'none';
|
|
262
267
|
export interface TimeseriesOptions extends TransportScopeOptions {
|
|
263
268
|
from?: number | string;
|
|
264
269
|
to?: number | string;
|
|
265
270
|
limit?: number;
|
|
266
271
|
order?: 'asc' | 'desc';
|
|
272
|
+
/** Further time series merged into the same request (sent as `with`). */
|
|
273
|
+
withIds?: string[];
|
|
274
|
+
/** How values sharing a timestamp are combined across the requested series. */
|
|
275
|
+
aggregate?: TimeseriesAggregate;
|
|
276
|
+
includeDeleted?: boolean;
|
|
267
277
|
}
|
|
268
278
|
export interface TimeseriesQueryOptions extends TimeseriesOptions {
|
|
269
279
|
ids?: string[];
|
|
270
|
-
aggregate?: string;
|
|
271
280
|
}
|
|
281
|
+
export interface TimeseriesHistoryOptions extends TransportScopeOptions {
|
|
282
|
+
includeDeleted?: boolean;
|
|
283
|
+
}
|
|
284
|
+
/** Values ever written for a timestamp, keyed by that timestamp in ms. */
|
|
285
|
+
export type TimeseriesHistory = Record<string, unknown>;
|
|
272
286
|
export interface BatchResult {
|
|
273
287
|
succeeded: string[];
|
|
274
288
|
failed: Array<{
|
package/dist/vite.js
CHANGED
|
@@ -1,95 +1,17 @@
|
|
|
1
1
|
/** Vite plugin for Bardioc iframe apps. Usage: `bardiocApp({ appName, port })` */
|
|
2
|
-
import { execSync, spawn } from 'node:child_process';
|
|
3
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
4
3
|
import { resolve, sep } from 'node:path';
|
|
5
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { resolveDevAuthEnv } from './dev-auth-env.js';
|
|
6
6
|
import { createDevAuthProxyHandler } from './dev-proxy.js';
|
|
7
|
-
import { readDotEnvFile } from './dot-env.js';
|
|
8
7
|
import { MANIFEST_FILENAME, validateManifest } from './manifest.js';
|
|
9
|
-
function hasCommand(cmd) {
|
|
10
|
-
try {
|
|
11
|
-
execSync(`which ${cmd}`, { stdio: 'ignore' });
|
|
12
|
-
return true;
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function startTunnel(port) {
|
|
19
|
-
return new Promise((resolve, reject) => {
|
|
20
|
-
if (!hasCommand('cloudflared')) {
|
|
21
|
-
reject(new Error('cloudflared is not installed.\n' +
|
|
22
|
-
' macOS: brew install cloudflared\n' +
|
|
23
|
-
' Linux: apt install cloudflared\n' +
|
|
24
|
-
' Other: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/'));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const proc = spawn('cloudflared', ['tunnel', '--url', `http://localhost:${port}`], {
|
|
28
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
29
|
-
});
|
|
30
|
-
let found = false;
|
|
31
|
-
const timeout = setTimeout(() => {
|
|
32
|
-
if (!found) {
|
|
33
|
-
proc.kill();
|
|
34
|
-
reject(new Error('Tunnel timed out waiting for URL'));
|
|
35
|
-
}
|
|
36
|
-
}, 30_000);
|
|
37
|
-
function onData(data) {
|
|
38
|
-
const text = data.toString();
|
|
39
|
-
const match = text.match(/(https:\/\/[a-z0-9-]+\.trycloudflare\.com)/);
|
|
40
|
-
if (match?.[1] && !found) {
|
|
41
|
-
found = true;
|
|
42
|
-
clearTimeout(timeout);
|
|
43
|
-
resolve({ url: match[1], process: proc });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
proc.stdout?.on('data', onData);
|
|
47
|
-
proc.stderr?.on('data', onData);
|
|
48
|
-
proc.on('close', code => {
|
|
49
|
-
if (!found) {
|
|
50
|
-
clearTimeout(timeout);
|
|
51
|
-
reject(new Error(`cloudflared exited with code ${code} before providing a URL`));
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
8
|
function devProxy(opts) {
|
|
57
9
|
const { port } = opts;
|
|
58
|
-
const wantTunnel = !!process.env.BARDIOC_TUNNEL;
|
|
59
|
-
let tunnelProcess = null;
|
|
60
|
-
let tunnelHost = null;
|
|
61
|
-
let tunnelReady = null;
|
|
62
10
|
return {
|
|
63
11
|
name: 'bardioc-dev-proxy',
|
|
64
12
|
apply: 'serve',
|
|
65
13
|
configureServer(server) {
|
|
66
|
-
|
|
67
|
-
tunnelReady = (async () => {
|
|
68
|
-
try {
|
|
69
|
-
const manifestPath = resolve(process.cwd(), 'public', MANIFEST_FILENAME);
|
|
70
|
-
let manifestId = opts.appName;
|
|
71
|
-
if (existsSync(manifestPath)) {
|
|
72
|
-
try {
|
|
73
|
-
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
|
74
|
-
manifestId = manifest.id || manifestId;
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
// ignore
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
console.log(`[bardioc] Starting tunnel for "${manifestId}" on port ${port}...`);
|
|
81
|
-
const tunnel = await startTunnel(port);
|
|
82
|
-
tunnelProcess = tunnel.process;
|
|
83
|
-
tunnelHost = new URL(tunnel.url).host;
|
|
84
|
-
console.log(`[bardioc] Tunnel ready: ${tunnel.url}`);
|
|
85
|
-
}
|
|
86
|
-
catch (err) {
|
|
87
|
-
console.error(`[bardioc] Tunnel failed: ${err.message}`);
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
})();
|
|
91
|
-
}
|
|
92
|
-
server.httpServer?.on('listening', async () => {
|
|
14
|
+
server.httpServer?.on('listening', () => {
|
|
93
15
|
const manifestPath = resolve(process.cwd(), 'public', MANIFEST_FILENAME);
|
|
94
16
|
if (!existsSync(manifestPath)) {
|
|
95
17
|
console.warn(`[bardioc] public/${MANIFEST_FILENAME} not found`);
|
|
@@ -103,26 +25,10 @@ function devProxy(opts) {
|
|
|
103
25
|
console.error(`[bardioc] Failed to read manifest: ${err}`);
|
|
104
26
|
return;
|
|
105
27
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
console.error(`[bardioc] Tunnel was requested but failed to start`);
|
|
111
|
-
process.exit(1);
|
|
112
|
-
}
|
|
113
|
-
console.log(`[bardioc] Use this live URL in the host App Store app configuration:`);
|
|
114
|
-
console.log(`[bardioc] App Name: ${manifestId}`);
|
|
115
|
-
console.log(`[bardioc] Live URL: https://${tunnelHost}`);
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
console.log(`[bardioc] Dev server ready: http://localhost:${port}`);
|
|
119
|
-
console.log(`[bardioc] For standalone dev auth, set DEV_SECRET and API_BASE_URL in .env.`);
|
|
120
|
-
console.log(`[bardioc] App Name: ${manifestId}`);
|
|
121
|
-
console.log(`[bardioc] URL: http://localhost:${port}`);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
server.httpServer?.on('close', () => {
|
|
125
|
-
tunnelProcess?.kill();
|
|
28
|
+
console.log(`[bardioc] Dev server ready: http://localhost:${port}`);
|
|
29
|
+
console.log(`[bardioc] For standalone dev auth, set DEV_SECRET and API_BASE_URL in .env.`);
|
|
30
|
+
console.log(`[bardioc] App Name: ${opts.appName || manifest.id}`);
|
|
31
|
+
console.log(`[bardioc] URL: http://localhost:${port}`);
|
|
126
32
|
});
|
|
127
33
|
},
|
|
128
34
|
};
|
|
@@ -217,33 +123,6 @@ function manifestCheck() {
|
|
|
217
123
|
},
|
|
218
124
|
};
|
|
219
125
|
}
|
|
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
126
|
export function bardiocDevAuth(options) {
|
|
248
127
|
let proxyOptions = options.proxy ?? null;
|
|
249
128
|
return {
|
|
@@ -252,14 +131,17 @@ export function bardiocDevAuth(options) {
|
|
|
252
131
|
enforce: 'pre',
|
|
253
132
|
configureServer(server) {
|
|
254
133
|
if (!proxyOptions) {
|
|
255
|
-
const env =
|
|
256
|
-
|
|
134
|
+
const env = resolveDevAuthEnv({
|
|
135
|
+
envDir: server.config.envDir ?? server.config.root,
|
|
136
|
+
mode: server.config.mode,
|
|
137
|
+
});
|
|
138
|
+
if (!env.devSecret || !env.apiBaseUrl) {
|
|
257
139
|
server.config.logger.warn(`[bardioc-dev-auth] DEV_SECRET and API_BASE_URL are required for dev auth — disabled for appName="${options.appName}".`);
|
|
258
140
|
return;
|
|
259
141
|
}
|
|
260
142
|
proxyOptions = {
|
|
261
|
-
apiBaseUrl: env.
|
|
262
|
-
devSecret: env.
|
|
143
|
+
apiBaseUrl: env.apiBaseUrl,
|
|
144
|
+
devSecret: env.devSecret,
|
|
263
145
|
};
|
|
264
146
|
}
|
|
265
147
|
const handler = createDevAuthProxyHandler(proxyOptions);
|