@bridgeline-digital/hawk-app-cli 0.1.0-dev.20261020202308 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -7
- package/README.md +770 -770
- package/agents/AGENTS.md +192 -192
- package/agents/project/custom.md +21 -21
- package/agents/project/next-mui.md +21 -21
- package/agents/project/next.md +24 -24
- package/agents/project/vanilla.md +22 -22
- package/agents/project/vite.md +19 -19
- package/bin/hawk-app.mjs +0 -0
- package/docs/bridge/README.md +1315 -1315
- package/docs/showcase/README.md +47 -47
- package/docs/showcase/functions/echo.ts +12 -12
- package/docs/showcase/functions/long-task.ts +31 -31
- package/docs/showcase/functions/showcase.ts +186 -186
- package/docs/showcase/hawk-app.json +73 -73
- package/docs/showcase/queries/assistant-prompts-by-day.json +6 -6
- package/docs/showcase/queries/assistant-prompts-by-day.sql +8 -8
- package/docs/showcase/queries/searches-by-day.json +6 -6
- package/docs/showcase/queries/searches-by-day.sql +7 -7
- package/docs/showcase/src/App.tsx +1436 -1436
- package/docs/showcase/src/main.tsx +10 -10
- package/docs/showcase/src/styles.css +71 -71
- package/docs/showcase/src/useHawkApp.ts +44 -44
- package/docs/showcase/src/vite-env.d.ts +1 -1
- package/docs/ui/README.md +166 -166
- package/package.json +1 -1
- package/schema/hawk-app.schema.json +611 -611
- package/src/accessibility.mjs +105 -105
- package/src/agents.mjs +145 -145
- package/src/aliases.mjs +30 -30
- package/src/app-icon.mjs +82 -82
- package/src/channel.mjs +116 -116
- package/src/cli.mjs +825 -825
- package/src/clients.mjs +221 -221
- package/src/config.mjs +148 -148
- package/src/create.mjs +186 -186
- package/src/credentials.mjs +56 -56
- package/src/data.mjs +169 -169
- package/src/deploy.mjs +349 -349
- package/src/dev.mjs +459 -459
- package/src/doctor.mjs +176 -176
- package/src/env.mjs +140 -140
- package/src/functions.mjs +313 -313
- package/src/login.mjs +166 -166
- package/src/logs.mjs +64 -64
- package/src/manifest.mjs +425 -425
- package/src/mcp-docs.mjs +168 -168
- package/src/mcp-hawksearch.mjs +342 -342
- package/src/mcp-reports.mjs +130 -130
- package/src/mcp-rules.mjs +109 -109
- package/src/mcp.mjs +539 -539
- package/src/platform.mjs +116 -116
- package/src/project-checks.mjs +153 -153
- package/src/queries.mjs +289 -289
- package/src/scope-check.mjs +91 -91
- package/src/secrets.mjs +86 -86
- package/src/slug-guard.mjs +80 -80
- package/src/sso.mjs +182 -182
- package/src/telemetry.mjs +50 -50
- package/src/upgrade.mjs +406 -406
- package/src/versions.mjs +102 -102
- package/templates/next/next.config.ts +13 -13
- package/templates/next/package.json +26 -26
- package/templates/next/src/lib/useHawkApp.ts +46 -46
- package/templates/next-mui/next.config.ts +13 -13
- package/templates/next-mui/package.json +30 -30
- package/templates/next-mui/src/app/layout.tsx +19 -19
- package/templates/next-mui/src/app/page.tsx +78 -78
- package/templates/next-mui/src/app/providers.tsx +10 -10
- package/templates/preact/package.json +26 -26
- package/templates/preact/src/useHawkApp.ts +44 -44
- package/templates/preact/src/vite-env.d.ts +1 -1
- package/templates/preact/tsconfig.json +17 -17
- package/templates/preact/vite.config.ts +11 -11
- package/templates/react/package.json +29 -29
- package/templates/react/src/useHawkApp.ts +44 -44
- package/templates/react/src/vite-env.d.ts +1 -1
- package/templates/react/tsconfig.json +16 -16
- package/templates/react/vite.config.ts +11 -11
- package/templates/vanilla/package.json +15 -15
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { HawkApiError } from '@bridgeline-digital/hawk-app-bridge/client';
|
|
4
|
-
import { KpiRow, KpiTile, LoadingSection, Notice, Section, useFormat, useHawk, useToast } from '@bridgeline-digital/hawk-app-ui';
|
|
5
|
-
import { ColumnChart } from '@bridgeline-digital/hawk-app-ui/charts';
|
|
6
|
-
import Button from '@mui/material/Button';
|
|
7
|
-
import Stack from '@mui/material/Stack';
|
|
8
|
-
import Typography from '@mui/material/Typography';
|
|
9
|
-
import { useEffect, useState } from 'react';
|
|
10
|
-
|
|
11
|
-
interface SearchesRow {
|
|
12
|
-
search_date: string;
|
|
13
|
-
search_count: number | string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Starter screen: the context from the host and one real data call, with the UI kit's components.
|
|
18
|
-
* Replace it with your app. Data comes only through the bridge: no API keys in the app.
|
|
19
|
-
*/
|
|
20
|
-
export default function Page() {
|
|
21
|
-
const { app, context } = useHawk();
|
|
22
|
-
const format = useFormat();
|
|
23
|
-
const toast = useToast();
|
|
24
|
-
const [rows, setRows] = useState<SearchesRow[] | null>(null);
|
|
25
|
-
const [error, setError] = useState<string | null>(null);
|
|
26
|
-
const [attempt, setAttempt] = useState(0);
|
|
27
|
-
|
|
28
|
-
// Reload whenever the user changes the date range or engine in the host.
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
let current = true;
|
|
31
|
-
setRows(null);
|
|
32
|
-
setError(null);
|
|
33
|
-
const filters = context.engine ? [{ member: 'engine_id', operator: 'equals', values: [context.engine.id] }] : undefined;
|
|
34
|
-
app.analytics
|
|
35
|
-
.report<SearchesRow>('searches', { filters, limit: 1000 }) // dates default to the host's date range
|
|
36
|
-
.then((report) => current && setRows(report.data))
|
|
37
|
-
.catch((e: unknown) => current && setError(e instanceof HawkApiError ? `${e.message}${e.code ? ` (${e.code})` : ''}` : String(e)));
|
|
38
|
-
return () => {
|
|
39
|
-
current = false;
|
|
40
|
-
};
|
|
41
|
-
}, [app, context.dateRange?.from, context.dateRange?.to, context.engine?.id, attempt]);
|
|
42
|
-
|
|
43
|
-
const { tenant, engine, dateRange } = context;
|
|
44
|
-
const days = (rows ?? []).map((r) => ({ label: format.date(r.search_date.slice(0, 10), { year: false }), value: Number(r.search_count) || 0 }));
|
|
45
|
-
const total = days.reduce((sum, d) => sum + d.value, 0);
|
|
46
|
-
return (
|
|
47
|
-
<Stack component="main" spacing={2} sx={{ p: 2 }}>
|
|
48
|
-
{/* No page heading: the host already shows the app's name above the frame. */}
|
|
49
|
-
<Typography variant="body2" color="text.secondary">
|
|
50
|
-
Client {tenant.clientId}
|
|
51
|
-
{engine ? ` · ${engine.name ?? `Engine ${engine.id}`}` : ''}
|
|
52
|
-
{dateRange ? ` · ${format.date(dateRange.from.slice(0, 10))} – ${format.date(dateRange.to.slice(0, 10))}` : ''}
|
|
53
|
-
</Typography>
|
|
54
|
-
|
|
55
|
-
{error ? (
|
|
56
|
-
<Notice severity="error" onRetry={() => setAttempt((n) => n + 1)}>
|
|
57
|
-
{error}
|
|
58
|
-
</Notice>
|
|
59
|
-
) : !rows ? (
|
|
60
|
-
<LoadingSection title="Searches" height={160} />
|
|
61
|
-
) : (
|
|
62
|
-
<>
|
|
63
|
-
<KpiRow columns={3}>
|
|
64
|
-
<KpiTile highlight label="Searches" value={format.integer(total)} />
|
|
65
|
-
<KpiTile label="Days" value={format.integer(days.length)} />
|
|
66
|
-
<KpiTile label="Per day" value={format.integer(days.length ? total / days.length : 0)} />
|
|
67
|
-
</KpiRow>
|
|
68
|
-
<Section title="Searches per day">
|
|
69
|
-
<ColumnChart label="Searches per day" columns={days} format={format.integer} />
|
|
70
|
-
</Section>
|
|
71
|
-
</>
|
|
72
|
-
)}
|
|
73
|
-
|
|
74
|
-
<Button variant="contained" onClick={() => toast('Hello from __NAME__!', 'success')}>
|
|
75
|
-
Say hello
|
|
76
|
-
</Button>
|
|
77
|
-
</Stack>
|
|
78
|
-
);
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { HawkApiError } from '@bridgeline-digital/hawk-app-bridge/client';
|
|
4
|
+
import { KpiRow, KpiTile, LoadingSection, Notice, Section, useFormat, useHawk, useToast } from '@bridgeline-digital/hawk-app-ui';
|
|
5
|
+
import { ColumnChart } from '@bridgeline-digital/hawk-app-ui/charts';
|
|
6
|
+
import Button from '@mui/material/Button';
|
|
7
|
+
import Stack from '@mui/material/Stack';
|
|
8
|
+
import Typography from '@mui/material/Typography';
|
|
9
|
+
import { useEffect, useState } from 'react';
|
|
10
|
+
|
|
11
|
+
interface SearchesRow {
|
|
12
|
+
search_date: string;
|
|
13
|
+
search_count: number | string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Starter screen: the context from the host and one real data call, with the UI kit's components.
|
|
18
|
+
* Replace it with your app. Data comes only through the bridge: no API keys in the app.
|
|
19
|
+
*/
|
|
20
|
+
export default function Page() {
|
|
21
|
+
const { app, context } = useHawk();
|
|
22
|
+
const format = useFormat();
|
|
23
|
+
const toast = useToast();
|
|
24
|
+
const [rows, setRows] = useState<SearchesRow[] | null>(null);
|
|
25
|
+
const [error, setError] = useState<string | null>(null);
|
|
26
|
+
const [attempt, setAttempt] = useState(0);
|
|
27
|
+
|
|
28
|
+
// Reload whenever the user changes the date range or engine in the host.
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
let current = true;
|
|
31
|
+
setRows(null);
|
|
32
|
+
setError(null);
|
|
33
|
+
const filters = context.engine ? [{ member: 'engine_id', operator: 'equals', values: [context.engine.id] }] : undefined;
|
|
34
|
+
app.analytics
|
|
35
|
+
.report<SearchesRow>('searches', { filters, limit: 1000 }) // dates default to the host's date range
|
|
36
|
+
.then((report) => current && setRows(report.data))
|
|
37
|
+
.catch((e: unknown) => current && setError(e instanceof HawkApiError ? `${e.message}${e.code ? ` (${e.code})` : ''}` : String(e)));
|
|
38
|
+
return () => {
|
|
39
|
+
current = false;
|
|
40
|
+
};
|
|
41
|
+
}, [app, context.dateRange?.from, context.dateRange?.to, context.engine?.id, attempt]);
|
|
42
|
+
|
|
43
|
+
const { tenant, engine, dateRange } = context;
|
|
44
|
+
const days = (rows ?? []).map((r) => ({ label: format.date(r.search_date.slice(0, 10), { year: false }), value: Number(r.search_count) || 0 }));
|
|
45
|
+
const total = days.reduce((sum, d) => sum + d.value, 0);
|
|
46
|
+
return (
|
|
47
|
+
<Stack component="main" spacing={2} sx={{ p: 2 }}>
|
|
48
|
+
{/* No page heading: the host already shows the app's name above the frame. */}
|
|
49
|
+
<Typography variant="body2" color="text.secondary">
|
|
50
|
+
Client {tenant.clientId}
|
|
51
|
+
{engine ? ` · ${engine.name ?? `Engine ${engine.id}`}` : ''}
|
|
52
|
+
{dateRange ? ` · ${format.date(dateRange.from.slice(0, 10))} – ${format.date(dateRange.to.slice(0, 10))}` : ''}
|
|
53
|
+
</Typography>
|
|
54
|
+
|
|
55
|
+
{error ? (
|
|
56
|
+
<Notice severity="error" onRetry={() => setAttempt((n) => n + 1)}>
|
|
57
|
+
{error}
|
|
58
|
+
</Notice>
|
|
59
|
+
) : !rows ? (
|
|
60
|
+
<LoadingSection title="Searches" height={160} />
|
|
61
|
+
) : (
|
|
62
|
+
<>
|
|
63
|
+
<KpiRow columns={3}>
|
|
64
|
+
<KpiTile highlight label="Searches" value={format.integer(total)} />
|
|
65
|
+
<KpiTile label="Days" value={format.integer(days.length)} />
|
|
66
|
+
<KpiTile label="Per day" value={format.integer(days.length ? total / days.length : 0)} />
|
|
67
|
+
</KpiRow>
|
|
68
|
+
<Section title="Searches per day">
|
|
69
|
+
<ColumnChart label="Searches per day" columns={days} format={format.integer} />
|
|
70
|
+
</Section>
|
|
71
|
+
</>
|
|
72
|
+
)}
|
|
73
|
+
|
|
74
|
+
<Button variant="contained" onClick={() => toast('Hello from __NAME__!', 'success')}>
|
|
75
|
+
Say hello
|
|
76
|
+
</Button>
|
|
77
|
+
</Stack>
|
|
78
|
+
);
|
|
79
79
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { HawkAppProvider } from '@bridgeline-digital/hawk-app-ui';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Connects to the host (HawkSearch or Spark) and shows the app in Spark's theme, in the host's colors and mode. Until it
|
|
7
|
-
* has connected it shows a spinner, and outside a host it says how to open the app. Pages read the app with useHawk().
|
|
8
|
-
*/
|
|
9
|
-
export default function Providers({ children }: Readonly<{ children: React.ReactNode }>) {
|
|
10
|
-
return <HawkAppProvider>{children}</HawkAppProvider>;
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { HawkAppProvider } from '@bridgeline-digital/hawk-app-ui';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Connects to the host (HawkSearch or Spark) and shows the app in Spark's theme, in the host's colors and mode. Until it
|
|
7
|
+
* has connected it shows a spinner, and outside a host it says how to open the app. Pages read the app with useHawk().
|
|
8
|
+
*/
|
|
9
|
+
export default function Providers({ children }: Readonly<{ children: React.ReactNode }>) {
|
|
10
|
+
return <HawkAppProvider>{children}</HawkAppProvider>;
|
|
11
11
|
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "__SLUG__",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"dev": "vite",
|
|
8
|
-
"build": "tsc --noEmit && vite build",
|
|
9
|
-
"preview": "vite preview",
|
|
10
|
-
"app:dev": "hawk-app dev",
|
|
11
|
-
"app:deploy": "hawk-app deploy",
|
|
12
|
-
"app:audit": "npm audit --omit=dev --audit-level=high"
|
|
13
|
-
},
|
|
14
|
-
"dependencies": {
|
|
15
|
-
"@bridgeline-digital/hawk-app-bridge": "^0.1.0",
|
|
16
|
-
"@bridgeline-digital/hawk-app-ui": "^0.1.0",
|
|
17
|
-
"preact": "^11.0.0"
|
|
18
|
-
},
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"@bridgeline-digital/hawk-app-cli": "^__CLI_VERSION__",
|
|
21
|
-
"@types/node": "^20",
|
|
22
|
-
"@preact/preset-vite": "^2.10.6",
|
|
23
|
-
"typescript": "^5.6.0",
|
|
24
|
-
"vite": "^8.0.0"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "__SLUG__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc --noEmit && vite build",
|
|
9
|
+
"preview": "vite preview",
|
|
10
|
+
"app:dev": "hawk-app dev",
|
|
11
|
+
"app:deploy": "hawk-app deploy",
|
|
12
|
+
"app:audit": "npm audit --omit=dev --audit-level=high"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@bridgeline-digital/hawk-app-bridge": "^0.1.0",
|
|
16
|
+
"@bridgeline-digital/hawk-app-ui": "^0.1.0",
|
|
17
|
+
"preact": "^11.0.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@bridgeline-digital/hawk-app-cli": "^__CLI_VERSION__",
|
|
21
|
+
"@types/node": "^20",
|
|
22
|
+
"@preact/preset-vite": "^2.10.6",
|
|
23
|
+
"typescript": "^5.6.0",
|
|
24
|
+
"vite": "^8.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import { createApp, type HawkApp, type HawkAppContext } from '@bridgeline-digital/hawk-app-bridge/client';
|
|
2
|
-
import { useEffect, useState } from 'preact/hooks';
|
|
3
|
-
|
|
4
|
-
/** Shown when the app is opened directly instead of inside a host. */
|
|
5
|
-
function notEmbeddedMessage(): string {
|
|
6
|
-
return `Open this app from the Apps page in HawkSearch. Developing locally? Add ?devUrl=${window.location.href} to the app's address in HawkSearch.`;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type HawkAppState =
|
|
10
|
-
| { status: 'connecting' }
|
|
11
|
-
| { status: 'ready'; app: HawkApp; context: HawkAppContext }
|
|
12
|
-
| { status: 'error'; message: string };
|
|
13
|
-
|
|
14
|
-
/** Connects to the host (the HawkSearch dashboard / Spark) once and keeps the context (client, engine, dates, theme) current. */
|
|
15
|
-
export function useHawkApp(): HawkAppState {
|
|
16
|
-
const [state, setState] = useState<HawkAppState>({ status: 'connecting' });
|
|
17
|
-
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
let app: HawkApp | undefined;
|
|
20
|
-
let cancelled = false;
|
|
21
|
-
|
|
22
|
-
createApp({ autoResize: true })
|
|
23
|
-
.then((connected) => {
|
|
24
|
-
if (cancelled) return connected.destroy();
|
|
25
|
-
app = connected;
|
|
26
|
-
setState({ status: 'ready', app: connected, context: connected.context });
|
|
27
|
-
connected.onContextChange((context) => setState({ status: 'ready', app: connected, context }));
|
|
28
|
-
})
|
|
29
|
-
.catch((error: { code?: string; message?: string }) => {
|
|
30
|
-
if (cancelled) return;
|
|
31
|
-
setState({
|
|
32
|
-
status: 'error',
|
|
33
|
-
message: error.code === 'not_embedded' ? notEmbeddedMessage() : `Could not connect to the host: ${error.message}`,
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
return () => {
|
|
38
|
-
cancelled = true;
|
|
39
|
-
app?.destroy();
|
|
40
|
-
};
|
|
41
|
-
}, []);
|
|
42
|
-
|
|
43
|
-
return state;
|
|
44
|
-
}
|
|
1
|
+
import { createApp, type HawkApp, type HawkAppContext } from '@bridgeline-digital/hawk-app-bridge/client';
|
|
2
|
+
import { useEffect, useState } from 'preact/hooks';
|
|
3
|
+
|
|
4
|
+
/** Shown when the app is opened directly instead of inside a host. */
|
|
5
|
+
function notEmbeddedMessage(): string {
|
|
6
|
+
return `Open this app from the Apps page in HawkSearch. Developing locally? Add ?devUrl=${window.location.href} to the app's address in HawkSearch.`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type HawkAppState =
|
|
10
|
+
| { status: 'connecting' }
|
|
11
|
+
| { status: 'ready'; app: HawkApp; context: HawkAppContext }
|
|
12
|
+
| { status: 'error'; message: string };
|
|
13
|
+
|
|
14
|
+
/** Connects to the host (the HawkSearch dashboard / Spark) once and keeps the context (client, engine, dates, theme) current. */
|
|
15
|
+
export function useHawkApp(): HawkAppState {
|
|
16
|
+
const [state, setState] = useState<HawkAppState>({ status: 'connecting' });
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
let app: HawkApp | undefined;
|
|
20
|
+
let cancelled = false;
|
|
21
|
+
|
|
22
|
+
createApp({ autoResize: true })
|
|
23
|
+
.then((connected) => {
|
|
24
|
+
if (cancelled) return connected.destroy();
|
|
25
|
+
app = connected;
|
|
26
|
+
setState({ status: 'ready', app: connected, context: connected.context });
|
|
27
|
+
connected.onContextChange((context) => setState({ status: 'ready', app: connected, context }));
|
|
28
|
+
})
|
|
29
|
+
.catch((error: { code?: string; message?: string }) => {
|
|
30
|
+
if (cancelled) return;
|
|
31
|
+
setState({
|
|
32
|
+
status: 'error',
|
|
33
|
+
message: error.code === 'not_embedded' ? notEmbeddedMessage() : `Could not connect to the host: ${error.message}`,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return () => {
|
|
38
|
+
cancelled = true;
|
|
39
|
+
app?.destroy();
|
|
40
|
+
};
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
return state;
|
|
44
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
/// <reference types="vite/client" />
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
-
"module": "ESNext",
|
|
6
|
-
"moduleResolution": "Bundler",
|
|
7
|
-
"jsx": "react-jsx",
|
|
8
|
-
"jsxImportSource": "preact",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"noUnusedLocals": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"isolatedModules": true,
|
|
13
|
-
"noEmit": true,
|
|
14
|
-
"types": ["vite/client", "node"]
|
|
15
|
-
},
|
|
16
|
-
"include": ["src", "vite.config.ts"]
|
|
17
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"jsxImportSource": "preact",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"noUnusedLocals": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"types": ["vite/client", "node"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["src", "vite.config.ts"]
|
|
17
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import preact from '@preact/preset-vite';
|
|
2
|
-
import { defineConfig } from 'vite';
|
|
3
|
-
|
|
4
|
-
// Each deploy is served from the apps CDN at /<slug>/v<n>/, so every asset URL needs that prefix.
|
|
5
|
-
// `hawk-app deploy` builds with HAWK_APP_BASE_PATH=/<slug>/v<n>; local dev uses /<slug>/.
|
|
6
|
-
export default defineConfig({
|
|
7
|
-
base: `${process.env.HAWK_APP_BASE_PATH ?? '/__SLUG__'}/`,
|
|
8
|
-
plugins: [preact()],
|
|
9
|
-
// Port 3100: the dev platform accepts data calls from localhost:3100-3103 (HawkSearch dev mode, ?devUrl=).
|
|
10
|
-
server: { port: 3100, strictPort: true },
|
|
11
|
-
});
|
|
1
|
+
import preact from '@preact/preset-vite';
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
|
|
4
|
+
// Each deploy is served from the apps CDN at /<slug>/v<n>/, so every asset URL needs that prefix.
|
|
5
|
+
// `hawk-app deploy` builds with HAWK_APP_BASE_PATH=/<slug>/v<n>; local dev uses /<slug>/.
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
base: `${process.env.HAWK_APP_BASE_PATH ?? '/__SLUG__'}/`,
|
|
8
|
+
plugins: [preact()],
|
|
9
|
+
// Port 3100: the dev platform accepts data calls from localhost:3100-3103 (HawkSearch dev mode, ?devUrl=).
|
|
10
|
+
server: { port: 3100, strictPort: true },
|
|
11
|
+
});
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "__SLUG__",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"dev": "vite",
|
|
8
|
-
"build": "tsc --noEmit && vite build",
|
|
9
|
-
"preview": "vite preview",
|
|
10
|
-
"app:dev": "hawk-app dev",
|
|
11
|
-
"app:deploy": "hawk-app deploy",
|
|
12
|
-
"app:audit": "npm audit --omit=dev --audit-level=high"
|
|
13
|
-
},
|
|
14
|
-
"dependencies": {
|
|
15
|
-
"@bridgeline-digital/hawk-app-bridge": "^0.1.0",
|
|
16
|
-
"@bridgeline-digital/hawk-app-ui": "^0.1.0",
|
|
17
|
-
"react": "^19.1.0",
|
|
18
|
-
"react-dom": "^19.1.0"
|
|
19
|
-
},
|
|
20
|
-
"devDependencies": {
|
|
21
|
-
"@bridgeline-digital/hawk-app-cli": "^__CLI_VERSION__",
|
|
22
|
-
"@types/node": "^20",
|
|
23
|
-
"@types/react": "^19.1.0",
|
|
24
|
-
"@types/react-dom": "^19.1.0",
|
|
25
|
-
"@vitejs/plugin-react": "^6.0.0",
|
|
26
|
-
"typescript": "^5.6.0",
|
|
27
|
-
"vite": "^8.0.0"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "__SLUG__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc --noEmit && vite build",
|
|
9
|
+
"preview": "vite preview",
|
|
10
|
+
"app:dev": "hawk-app dev",
|
|
11
|
+
"app:deploy": "hawk-app deploy",
|
|
12
|
+
"app:audit": "npm audit --omit=dev --audit-level=high"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@bridgeline-digital/hawk-app-bridge": "^0.1.0",
|
|
16
|
+
"@bridgeline-digital/hawk-app-ui": "^0.1.0",
|
|
17
|
+
"react": "^19.1.0",
|
|
18
|
+
"react-dom": "^19.1.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@bridgeline-digital/hawk-app-cli": "^__CLI_VERSION__",
|
|
22
|
+
"@types/node": "^20",
|
|
23
|
+
"@types/react": "^19.1.0",
|
|
24
|
+
"@types/react-dom": "^19.1.0",
|
|
25
|
+
"@vitejs/plugin-react": "^6.0.0",
|
|
26
|
+
"typescript": "^5.6.0",
|
|
27
|
+
"vite": "^8.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import { createApp, type HawkApp, type HawkAppContext } from '@bridgeline-digital/hawk-app-bridge/client';
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
|
|
4
|
-
/** Shown when the app is opened directly instead of inside a host. */
|
|
5
|
-
function notEmbeddedMessage(): string {
|
|
6
|
-
return `Open this app from the Apps page in HawkSearch. Developing locally? Add ?devUrl=${window.location.href} to the app's address in HawkSearch.`;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type HawkAppState =
|
|
10
|
-
| { status: 'connecting' }
|
|
11
|
-
| { status: 'ready'; app: HawkApp; context: HawkAppContext }
|
|
12
|
-
| { status: 'error'; message: string };
|
|
13
|
-
|
|
14
|
-
/** Connects to the host (the HawkSearch dashboard / Spark) once and keeps the context (client, engine, dates, theme) current. */
|
|
15
|
-
export function useHawkApp(): HawkAppState {
|
|
16
|
-
const [state, setState] = useState<HawkAppState>({ status: 'connecting' });
|
|
17
|
-
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
let app: HawkApp | undefined;
|
|
20
|
-
let cancelled = false;
|
|
21
|
-
|
|
22
|
-
createApp({ autoResize: true })
|
|
23
|
-
.then((connected) => {
|
|
24
|
-
if (cancelled) return connected.destroy();
|
|
25
|
-
app = connected;
|
|
26
|
-
setState({ status: 'ready', app: connected, context: connected.context });
|
|
27
|
-
connected.onContextChange((context) => setState({ status: 'ready', app: connected, context }));
|
|
28
|
-
})
|
|
29
|
-
.catch((error: { code?: string; message?: string }) => {
|
|
30
|
-
if (cancelled) return;
|
|
31
|
-
setState({
|
|
32
|
-
status: 'error',
|
|
33
|
-
message: error.code === 'not_embedded' ? notEmbeddedMessage() : `Could not connect to the host: ${error.message}`,
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
return () => {
|
|
38
|
-
cancelled = true;
|
|
39
|
-
app?.destroy();
|
|
40
|
-
};
|
|
41
|
-
}, []);
|
|
42
|
-
|
|
43
|
-
return state;
|
|
44
|
-
}
|
|
1
|
+
import { createApp, type HawkApp, type HawkAppContext } from '@bridgeline-digital/hawk-app-bridge/client';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
/** Shown when the app is opened directly instead of inside a host. */
|
|
5
|
+
function notEmbeddedMessage(): string {
|
|
6
|
+
return `Open this app from the Apps page in HawkSearch. Developing locally? Add ?devUrl=${window.location.href} to the app's address in HawkSearch.`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type HawkAppState =
|
|
10
|
+
| { status: 'connecting' }
|
|
11
|
+
| { status: 'ready'; app: HawkApp; context: HawkAppContext }
|
|
12
|
+
| { status: 'error'; message: string };
|
|
13
|
+
|
|
14
|
+
/** Connects to the host (the HawkSearch dashboard / Spark) once and keeps the context (client, engine, dates, theme) current. */
|
|
15
|
+
export function useHawkApp(): HawkAppState {
|
|
16
|
+
const [state, setState] = useState<HawkAppState>({ status: 'connecting' });
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
let app: HawkApp | undefined;
|
|
20
|
+
let cancelled = false;
|
|
21
|
+
|
|
22
|
+
createApp({ autoResize: true })
|
|
23
|
+
.then((connected) => {
|
|
24
|
+
if (cancelled) return connected.destroy();
|
|
25
|
+
app = connected;
|
|
26
|
+
setState({ status: 'ready', app: connected, context: connected.context });
|
|
27
|
+
connected.onContextChange((context) => setState({ status: 'ready', app: connected, context }));
|
|
28
|
+
})
|
|
29
|
+
.catch((error: { code?: string; message?: string }) => {
|
|
30
|
+
if (cancelled) return;
|
|
31
|
+
setState({
|
|
32
|
+
status: 'error',
|
|
33
|
+
message: error.code === 'not_embedded' ? notEmbeddedMessage() : `Could not connect to the host: ${error.message}`,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return () => {
|
|
38
|
+
cancelled = true;
|
|
39
|
+
app?.destroy();
|
|
40
|
+
};
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
return state;
|
|
44
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
/// <reference types="vite/client" />
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
-
"module": "ESNext",
|
|
6
|
-
"moduleResolution": "Bundler",
|
|
7
|
-
"jsx": "react-jsx",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"noUnusedLocals": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"isolatedModules": true,
|
|
12
|
-
"noEmit": true,
|
|
13
|
-
"types": ["vite/client", "node"]
|
|
14
|
-
},
|
|
15
|
-
"include": ["src", "vite.config.ts"]
|
|
16
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noUnusedLocals": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"types": ["vite/client", "node"]
|
|
14
|
+
},
|
|
15
|
+
"include": ["src", "vite.config.ts"]
|
|
16
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import react from '@vitejs/plugin-react';
|
|
2
|
-
import { defineConfig } from 'vite';
|
|
3
|
-
|
|
4
|
-
// Each deploy is served from the apps CDN at /<slug>/v<n>/, so every asset URL needs that prefix.
|
|
5
|
-
// `hawk-app deploy` builds with HAWK_APP_BASE_PATH=/<slug>/v<n>; local dev uses /<slug>/.
|
|
6
|
-
export default defineConfig({
|
|
7
|
-
base: `${process.env.HAWK_APP_BASE_PATH ?? '/__SLUG__'}/`,
|
|
8
|
-
plugins: [react()],
|
|
9
|
-
// Port 3100: the dev platform accepts data calls from localhost:3100-3103 (HawkSearch dev mode, ?devUrl=).
|
|
10
|
-
server: { port: 3100, strictPort: true },
|
|
11
|
-
});
|
|
1
|
+
import react from '@vitejs/plugin-react';
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
|
|
4
|
+
// Each deploy is served from the apps CDN at /<slug>/v<n>/, so every asset URL needs that prefix.
|
|
5
|
+
// `hawk-app deploy` builds with HAWK_APP_BASE_PATH=/<slug>/v<n>; local dev uses /<slug>/.
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
base: `${process.env.HAWK_APP_BASE_PATH ?? '/__SLUG__'}/`,
|
|
8
|
+
plugins: [react()],
|
|
9
|
+
// Port 3100: the dev platform accepts data calls from localhost:3100-3103 (HawkSearch dev mode, ?devUrl=).
|
|
10
|
+
server: { port: 3100, strictPort: true },
|
|
11
|
+
});
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "__SLUG__",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"dev": "serve public -l 3100",
|
|
7
|
-
"app:dev": "hawk-app dev",
|
|
8
|
-
"app:deploy": "hawk-app deploy",
|
|
9
|
-
"app:audit": "npm audit --omit=dev --audit-level=high"
|
|
10
|
-
},
|
|
11
|
-
"devDependencies": {
|
|
12
|
-
"@bridgeline-digital/hawk-app-cli": "^__CLI_VERSION__",
|
|
13
|
-
"serve": "^14.2.4"
|
|
14
|
-
}
|
|
15
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "__SLUG__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "serve public -l 3100",
|
|
7
|
+
"app:dev": "hawk-app dev",
|
|
8
|
+
"app:deploy": "hawk-app deploy",
|
|
9
|
+
"app:audit": "npm audit --omit=dev --audit-level=high"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@bridgeline-digital/hawk-app-cli": "^__CLI_VERSION__",
|
|
13
|
+
"serve": "^14.2.4"
|
|
14
|
+
}
|
|
15
|
+
}
|