@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
package/agents/AGENTS.md
CHANGED
|
@@ -1,192 +1,192 @@
|
|
|
1
|
-
# __NAME__ (`__SLUG__`): a Hawk App
|
|
2
|
-
|
|
3
|
-
A Hawk App is a static web app that runs in an iframe inside the HawkSearch dashboard (and later Spark), for one
|
|
4
|
-
client at a time. It gets its context and all of its data through the bridge,
|
|
5
|
-
`@bridgeline-digital/hawk-app-bridge`. It's deployed with the CLI,
|
|
6
|
-
`@bridgeline-digital/hawk-app-cli` (`npx hawk-app`).
|
|
7
|
-
|
|
8
|
-
## Rules
|
|
9
|
-
|
|
10
|
-
- **No secrets in the app.** Everything in the build is public. Never add API keys, AWS credentials, database
|
|
11
|
-
connection strings or HawkSearch keys. The platform adds credentials server-side, and it takes the client from the
|
|
12
|
-
signed app token, so the app can only reach the current client's data. A third-party key goes in a function secret
|
|
13
|
-
(`npx hawk-app secrets set NAME`) and is used in a function, never in the browser.
|
|
14
|
-
- **Settings that change without a deploy go in `config`.** Non-secret values (notification recipients, thresholds,
|
|
15
|
-
switches) are declared in `config` in `hawk-app.json` (type, label, default) and read with `app.config.get(key)`
|
|
16
|
-
(`ctx.config` in a function). Their values are set with `npx hawk-app config set` or in the Hawk Analytics portal,
|
|
17
|
-
never hard-coded. They reach the browser, so never put a key or password there.
|
|
18
|
-
- **All data goes through the bridge.** Don't call HawkSearch, the analytics API, Athena or AWS directly from the
|
|
19
|
-
app. Use `app.analytics`, `app.dashboard`, `app.data`, `app.functions` and the others below.
|
|
20
|
-
- **Static files only.** The build is plain HTML, JS and CSS: no SSR, API routes or middleware. Server code goes in
|
|
21
|
-
`functions/`.
|
|
22
|
-
- **Every asset URL is under the version's base path.** Each deploy is served from `/<slug>/v<n>/`. `hawk-app deploy`
|
|
23
|
-
builds with `HAWK_APP_BASE_PATH=/__SLUG__/v<n>`; the build must use it (or only relative URLs). An absolute
|
|
24
|
-
`/assets/...` URL loads nothing once deployed.
|
|
25
|
-
- **No cookies, no `localStorage` for auth.** The app runs in a cross-site iframe where browsers block cookies. For a
|
|
26
|
-
backend of your own, send `await app.getToken()` as a Bearer header.
|
|
27
|
-
- **Ask for the fewest scopes.** Each one is in `hawk-app.json` and reviewed; elevated scopes are never auto-approved.
|
|
28
|
-
- **List outside origins.** `externalOrigins` in `hawk-app.json` should list every https origin the app loads from or
|
|
29
|
-
calls (`[]` when none). The default `["*"]` fails review. To show images from hosts you can't list (a client's
|
|
30
|
-
product images), use `"img:*"`: images only, from any https origin, and it passes review.
|
|
31
|
-
- **Handle a client without analytics.** When `app.context.tenant.analyticsProvisioned === false`, show a message
|
|
32
|
-
instead of calling `app.analytics` or `app.data`.
|
|
33
|
-
- Don't add a page heading: the host shows the app's name above the frame.
|
|
34
|
-
- Don't edit `hawk-app.json`'s `slug` (it can't change) and don't add `status`, `clients` or `excludeClients` (set in
|
|
35
|
-
HawkSearch and with `npx hawk-app clients`).
|
|
36
|
-
|
|
37
|
-
## The bridge
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
import { createApp } from '@bridgeline-digital/hawk-app-bridge/client';
|
|
41
|
-
|
|
42
|
-
const app = await createApp({ autoResize: true }); // rejects with code 'not_embedded' when opened outside a host
|
|
43
|
-
render(app.context);
|
|
44
|
-
app.onContextChange(render); // the user switched client, engine or dates
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
`app.context`: `tenant.clientId`, `tenant.analyticsProvisioned`, `engine { id, name }`, `site`,
|
|
48
|
-
`dateRange { from, to, timeZone }`, `user { id, email, roles }`, `locale`, `theme`, `app.slug`.
|
|
49
|
-
|
|
50
|
-
| Call | Scope |
|
|
51
|
-
| --- | --- |
|
|
52
|
-
| `app.analytics.report('queries', { limit, startDate, endDate, filters })` | `reports:read` |
|
|
53
|
-
| `app.dashboard.get('Synonym')`: HawkSearch dashboard API, no API version in the path | `hawksearch:read` |
|
|
54
|
-
| `app.dashboard.post/put/delete(path, body)`: merchandising and relevancy resources only, never retried | `hawksearch:write` |
|
|
55
|
-
| `app.hawksearch.search(...)`, `app.hawksearch.autocomplete(...)` on the user's engine | `hawksearch:search` |
|
|
56
|
-
| `app.data.query('name', params)`: your SQL in `queries/<name>.sql` + `.json` | `data:read` |
|
|
57
|
-
| `app.functions.call('name', input)`, `.start/.wait/.job` for jobs: `functions/<name>.ts` exporting `handler` | `functions:invoke` |
|
|
58
|
-
| `app.email.send(...)` | `email:send` |
|
|
59
|
-
| `app.storage.get/put/delete/list/batch/usage`: the app's own JSON data per client (350 KB a value, `ttlDays`, `ifVersion`); `app.storage.files.upload/url/download/list/delete`: its files (100 MB each) | `storage` |
|
|
60
|
-
| `app.hawksearch.systemParameters.list/get/set`: names listed in `systemParameters` | `hawksearch:sysparams:write` |
|
|
61
|
-
| `app.hawksearch.features.list/set/setFacet` | `hawksearch:features:write` |
|
|
62
|
-
| `app.hawksearch.index.rebuild()`, `.status(id?)`, `.wait(id)`: rebuild the engine's index from its feed (needs the engine's `EnableRebuildIndex` on; one at a time); `.indexes()`, `.current()` | `hawksearch:index` |
|
|
63
|
-
| `app.hawksearch.index.items.upsert/update/delete(...)`: items in the engine's indexes, live at once (125 a call) | `hawksearch:index:items` |
|
|
64
|
-
| `app.hawksearch.index.create/setCurrent/deleteIndex/rebuildAll(...)`, `.call('hierarchy/upsert', …)` and other management | `hawksearch:index:manage` |
|
|
65
|
-
| `app.hawksearch.recommendations({ widgetUids: [{ widgetGuid, uniqueId? }] })`: recommendation widgets, untracked | `hawksearch:recommendations` |
|
|
66
|
-
| `app.ai.generate/stream/info` | `ai:invoke` |
|
|
67
|
-
| `app.lambdas.invoke('name', input)`: names listed in `lambdas`, allowed by Engineering | `lambdas:invoke` |
|
|
68
|
-
| `app.config.get('key')`, `app.config.all()`: keys declared in `config`, the client's value, else the global one, else the default (null when none); not secret | none |
|
|
69
|
-
| `app.assistant.ask('question')`, `app.assistant.setContext({ ...what's on screen })` (null clears): the host's assistant (Hawk Assistant) answers in its chat, as the user; only from a click, and only while `context.features?.assistant` is true (it can load after the app: `app.onContextChange`) | `assistant` |
|
|
70
|
-
|
|
71
|
-
Also: `app.reportError(error)` for errors the app catches and handles (uncaught ones are reported on their own; see
|
|
72
|
-
them with `hawk-app errors`), `app.setTitle`, `app.toast(message, 'info'|'success'|'warning'|'error')`,
|
|
73
|
-
`app.navigate({ intent: 'app'|'report'|'settings'|'external', ... })` (intents, never URLs), `app.getToken()`,
|
|
74
|
-
`app.api.get('me')` (`internal: true` for Bridgeline staff, from the signed token: use it for staff-only screens).
|
|
75
|
-
Failed data calls throw `HawkApiError` (`status`, `code`); host requests throw `HawkBridgeError` (`code`). A 403
|
|
76
|
-
`scope_missing` means the scope is missing from `hawk-app.json` or the app wasn't deployed again after adding it
|
|
77
|
-
(`validate` and `deploy` warn about bridge calls whose scope is missing).
|
|
78
|
-
Look: every template uses the Hawk Apps UI kit (`@bridgeline-digital/hawk-app-ui`) for Spark's look in the
|
|
79
|
-
host's colors and mode: React + MUI apps (next-mui) its provider and components, every other app its stylesheet
|
|
80
|
-
(`/css`) and elements (`/elements`); see this app's section below. Don't restyle it or add another font. For your own
|
|
81
|
-
styles use its `--hawk-ui-*` variables (or the host's `--hawk-*` ones with your own fallbacks).
|
|
82
|
-
Accessibility: approvers see an axe-core check of the built pages (critical issues fail it): label form fields, give
|
|
83
|
-
images `alt`, keep one `<main>` and headings in order. `validate --build` shows the issues.
|
|
84
|
-
Dialogs: any `[role="dialog"]` (every MUI Dialog) covers the host's whole page on its own, even from a small frame;
|
|
85
|
-
center dialogs in the visible part of the frame (`--hawk-visible-top`, `--hawk-visible-height`, as the templates'
|
|
86
|
-
theme does), and use in-page dialogs, never `window.confirm`/`alert` (blocked in the sandbox).
|
|
87
|
-
|
|
88
|
-
Before using a call, read its section in the bridge README for the exact options, limits and error codes: the
|
|
89
|
-
`hawk-apps` MCP server's `docs` tool (below), or
|
|
90
|
-
`node_modules/@bridgeline-digital/hawk-app-bridge/README.md` when the bridge is installed, otherwise
|
|
91
|
-
https://www.npmjs.com/package/@bridgeline-digital/hawk-app-bridge. Its TypeScript types are in the same package.
|
|
92
|
-
|
|
93
|
-
## MCP server
|
|
94
|
-
|
|
95
|
-
`.mcp.json` (Claude Code) and `.vscode/mcp.json` (VS Code) start the CLI's MCP server, `hawk-apps`, from
|
|
96
|
-
`node_modules` (`npm install` first). Its tools: `docs` (the bridge, UI kit, CLI, `hawk-app.json` schema and the
|
|
97
|
-
showcase app, which has working code for every feature), `ui_components` (the UI kit's components for this app's
|
|
98
|
-
template: use them before writing your own), `validate`, `status` (with the review checks approvers will see),
|
|
99
|
-
`analytics_reports` (every report `app.analytics.report()` can call, with its columns and filters),
|
|
100
|
-
`hawksearch_api` (HawkSearch's dashboard, search, recommendation and indexing operations: fields, the bridge call, its scope),
|
|
101
|
-
`data_tables` and `data_describe` (names and columns, never data), `logs`, `init`, `upgrade`,
|
|
102
|
-
`deploy` (with `alias`, and `dryRun` to only show what hawk-app.json would change), `versions`, `why` (what a client sees, and why), `doctor` (what's wrong with the setup), `errors`, `usage`, and `clients` and `clients_add`, which only ever use the dev platform. Prefer them to guessing. When the
|
|
103
|
-
user names a client ("deploy to OTC"), call `clients_add` with their words: it shows them a form to pick the exact
|
|
104
|
-
client. With `alias` (`hawk-app clients add <id> --alias review`) the client gets that alias's version: on a version that
|
|
105
|
-
isn't approved, only Bridgeline staff in it see the app. Only approvers change what a client whose users see the app
|
|
106
|
-
gets. `hawk-app deploy out --alias staging` deploys off the main line: the version carries this hawk-app.json, `staging`
|
|
107
|
-
points at it, and the version under review isn't touched. A plain `hawk-app deploy` sends hawk-app.json first, so scope
|
|
108
|
-
changes go with the deploy. Client names aren't shared with you; don't ask for them in the chat. Its prompts (`check-before-submit`, `add-feature`,
|
|
109
|
-
`explain-app`, `deploy-to-client`; in Claude Code `/mcp__hawk-apps__<name>`) are ready-made tasks that use them.
|
|
110
|
-
|
|
111
|
-
## Icon
|
|
112
|
-
|
|
113
|
-
`icon` in `hawk-app.json` is the app's icon file, next to it: `icon.svg` by default, which `create` and `init` add.
|
|
114
|
-
- **An .svg** is drawn in the host's own color (HawkSearch, Spark; light and dark): only its shape counts, so draw it in
|
|
115
|
-
one color, on a square `viewBox` (e.g. `0 0 24 24`), at most 32 KB.
|
|
116
|
-
- **A .png** is shown as is, for a full-color logo: square, 64 to 1024 px (256 is a good size), at most 256 KB.
|
|
117
|
-
- `hawk-app validate` and `deploy` check it; `deploy` uploads it with each version, so an icon change is reviewed like
|
|
118
|
-
other settings. Leave `icon` out for the hosts' default icon. Names from HawkSearch's icon set are no longer used.
|
|
119
|
-
|
|
120
|
-
## Views
|
|
121
|
-
|
|
122
|
-
`views` in `hawk-app.json` declares pages of the build that hosts show inside other pages:
|
|
123
|
-
- **`preview`:** shown live on the Apps page's cards, under the description.
|
|
124
|
-
- **`"embeddable": true`:** Bridgeline users can place the view in app slots of HawkSearch pages (per engine or for
|
|
125
|
-
every client), with values for its `params`.
|
|
126
|
-
|
|
127
|
-
Each view is a route, e.g. `src/app/views/preview/page.tsx` for `"path": "views/preview"`. It reads
|
|
128
|
-
`app.context.view` (`{ name, params, embedded, maxHeight }`). In a view:
|
|
129
|
-
- Keep it small and fast: read stored results, not reports. Many views can share a page.
|
|
130
|
-
- The page background is transparent (the host's shows through) and the height fits the content: never set
|
|
131
|
-
`html, body { height: 100% }`, or it can't shrink.
|
|
132
|
-
- Toasts and title changes are ignored; `app.navigate({ intent: 'app', slug })` opens the full app.
|
|
133
|
-
- `"cacheMinutes": n` (0–1440) on a view caches its reads (data queries, reports, `dashboard.get`, search,
|
|
134
|
-
recommendations) on the platform for n minutes, per client and engine. A `preview` caches 60 minutes by default
|
|
135
|
-
(`0` turns it off); other views don't unless they say so. Pass
|
|
136
|
-
`{ cache: 'no-store' }` on a call that writes (e.g. an analytics report that records something), or
|
|
137
|
-
`{ cache: 'reload' }` to refresh. The full app page is never cached.
|
|
138
|
-
|
|
139
|
-
A slot can also hold the **entire app** (its own page, with no `view` in the context): it then runs inside another
|
|
140
|
-
page, at the slot's height, so don't rely on the full window either.
|
|
141
|
-
|
|
142
|
-
## Queries and functions
|
|
143
|
-
|
|
144
|
-
- **Queries** (`queries/<name>.sql` + `<name>.json`, next to `hawk-app.json`): one `SELECT`/`WITH`, `?` for each
|
|
145
|
-
parameter in order, plain table names. Every query with a date range needs `{{partitions(from, to)}}`, names its
|
|
146
|
-
columns (no `SELECT *`) and has a `LIMIT` on lists; review flags any that don't. `npx hawk-app data tables` and
|
|
147
|
-
`npx hawk-app data describe <table>` show the tables and columns.
|
|
148
|
-
- **Functions** (`functions/<name>.ts`, settings under `functions` in `hawk-app.json`): Node 22 Lambda,
|
|
149
|
-
`export const handler: HawkFunction<In, Out> = async (input, ctx) => ...` with `HawkFunction` from
|
|
150
|
-
`@bridgeline-digital/hawk-app-bridge/server`. Use `ctx.platform` (same APIs as `app`), `ctx.secrets.NAME`,
|
|
151
|
-
`ctx.client.id`, `ctx.user`. Stateless; 25 s, or 900 s for a job (`"job": true`). Engineering enables functions per
|
|
152
|
-
app.
|
|
153
|
-
|
|
154
|
-
## Project
|
|
155
|
-
|
|
156
|
-
__PROJECT__
|
|
157
|
-
|
|
158
|
-
## Commands
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
npx hawk-app doctor # check the setup (Node, login, hawk-app.json, scopes the code uses) and what to fix
|
|
162
|
-
npm run app:dev # run the app locally in a stand-in for HawkSearch (asks which client the first time)
|
|
163
|
-
npx hawk-app validate # check hawk-app.json, queries/ and functions/ (--build also checks the build's URLs)
|
|
164
|
-
npm run app:audit # npm audit of the production dependencies: fix high and critical before deploying
|
|
165
|
-
npm run app:deploy # build and upload a new version, with hawk-app.json (dev unless --env prod)
|
|
166
|
-
npx hawk-app deploy --dry-run # what hawk-app.json would change, without a version
|
|
167
|
-
npx hawk-app status # released and newest versions, the request, the aliases
|
|
168
|
-
npx hawk-app versions # every version with its status and aliases
|
|
169
|
-
npx hawk-app open # the app's page in HawkSearch (review, submit for approval)
|
|
170
|
-
npx hawk-app logs <function> # a function's logs
|
|
171
|
-
npx hawk-app config list # config values (config set <key> <value> [--client <id>], config unset <key>)
|
|
172
|
-
npx hawk-app errors # errors in the app's pages (deployed versions), the most frequent first
|
|
173
|
-
npx hawk-app usage # opens, users and clients per day
|
|
174
|
-
npx hawk-app upgrade # bring the app (and this file) up to the CLI's current template
|
|
175
|
-
npx hawk-app upgrade --channel latest # a dev app (bridge/CLI on the `dev` tag) to the released versions
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
Deploy only when asked to. Never use `--env prod` unless asked to. If the bridge or CLI is on the
|
|
179
|
-
`dev` tag (a dev app), its features may only exist on the dev platform: don't move it to `latest` or to prod unless
|
|
180
|
-
asked to.
|
|
181
|
-
|
|
182
|
-
## Review
|
|
183
|
-
|
|
184
|
-
A new app is a draft that only Bridgeline staff see. Members of Hawk-App-Developers submit it (and each later version
|
|
185
|
-
or settings change) for approval in HawkSearch; Hawk-App-Approvers approve it. The approve dialog runs automated
|
|
186
|
-
checks, and a failed check forces the approver to override it:
|
|
187
|
-
|
|
188
|
-
- **Bundle:** over 20 MB in total, any file over 5 MB, or 50% (and 1 MB) bigger than the released version.
|
|
189
|
-
- **Dependencies:** high or critical `npm audit` findings in the production dependencies, or no audit.
|
|
190
|
-
- **Outside origins:** `externalOrigins` is `["*"]`.
|
|
191
|
-
- **Queries:** a query without `{{partitions(...)}}`; `SELECT *` and a missing `LIMIT` are flagged too.
|
|
192
|
-
- Functions, external Lambdas and new outside origins are shown to the approver.
|
|
1
|
+
# __NAME__ (`__SLUG__`): a Hawk App
|
|
2
|
+
|
|
3
|
+
A Hawk App is a static web app that runs in an iframe inside the HawkSearch dashboard (and later Spark), for one
|
|
4
|
+
client at a time. It gets its context and all of its data through the bridge,
|
|
5
|
+
`@bridgeline-digital/hawk-app-bridge`. It's deployed with the CLI,
|
|
6
|
+
`@bridgeline-digital/hawk-app-cli` (`npx hawk-app`).
|
|
7
|
+
|
|
8
|
+
## Rules
|
|
9
|
+
|
|
10
|
+
- **No secrets in the app.** Everything in the build is public. Never add API keys, AWS credentials, database
|
|
11
|
+
connection strings or HawkSearch keys. The platform adds credentials server-side, and it takes the client from the
|
|
12
|
+
signed app token, so the app can only reach the current client's data. A third-party key goes in a function secret
|
|
13
|
+
(`npx hawk-app secrets set NAME`) and is used in a function, never in the browser.
|
|
14
|
+
- **Settings that change without a deploy go in `config`.** Non-secret values (notification recipients, thresholds,
|
|
15
|
+
switches) are declared in `config` in `hawk-app.json` (type, label, default) and read with `app.config.get(key)`
|
|
16
|
+
(`ctx.config` in a function). Their values are set with `npx hawk-app config set` or in the Hawk Analytics portal,
|
|
17
|
+
never hard-coded. They reach the browser, so never put a key or password there.
|
|
18
|
+
- **All data goes through the bridge.** Don't call HawkSearch, the analytics API, Athena or AWS directly from the
|
|
19
|
+
app. Use `app.analytics`, `app.dashboard`, `app.data`, `app.functions` and the others below.
|
|
20
|
+
- **Static files only.** The build is plain HTML, JS and CSS: no SSR, API routes or middleware. Server code goes in
|
|
21
|
+
`functions/`.
|
|
22
|
+
- **Every asset URL is under the version's base path.** Each deploy is served from `/<slug>/v<n>/`. `hawk-app deploy`
|
|
23
|
+
builds with `HAWK_APP_BASE_PATH=/__SLUG__/v<n>`; the build must use it (or only relative URLs). An absolute
|
|
24
|
+
`/assets/...` URL loads nothing once deployed.
|
|
25
|
+
- **No cookies, no `localStorage` for auth.** The app runs in a cross-site iframe where browsers block cookies. For a
|
|
26
|
+
backend of your own, send `await app.getToken()` as a Bearer header.
|
|
27
|
+
- **Ask for the fewest scopes.** Each one is in `hawk-app.json` and reviewed; elevated scopes are never auto-approved.
|
|
28
|
+
- **List outside origins.** `externalOrigins` in `hawk-app.json` should list every https origin the app loads from or
|
|
29
|
+
calls (`[]` when none). The default `["*"]` fails review. To show images from hosts you can't list (a client's
|
|
30
|
+
product images), use `"img:*"`: images only, from any https origin, and it passes review.
|
|
31
|
+
- **Handle a client without analytics.** When `app.context.tenant.analyticsProvisioned === false`, show a message
|
|
32
|
+
instead of calling `app.analytics` or `app.data`.
|
|
33
|
+
- Don't add a page heading: the host shows the app's name above the frame.
|
|
34
|
+
- Don't edit `hawk-app.json`'s `slug` (it can't change) and don't add `status`, `clients` or `excludeClients` (set in
|
|
35
|
+
HawkSearch and with `npx hawk-app clients`).
|
|
36
|
+
|
|
37
|
+
## The bridge
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { createApp } from '@bridgeline-digital/hawk-app-bridge/client';
|
|
41
|
+
|
|
42
|
+
const app = await createApp({ autoResize: true }); // rejects with code 'not_embedded' when opened outside a host
|
|
43
|
+
render(app.context);
|
|
44
|
+
app.onContextChange(render); // the user switched client, engine or dates
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`app.context`: `tenant.clientId`, `tenant.analyticsProvisioned`, `engine { id, name }`, `site`,
|
|
48
|
+
`dateRange { from, to, timeZone }`, `user { id, email, roles }`, `locale`, `theme`, `app.slug`.
|
|
49
|
+
|
|
50
|
+
| Call | Scope |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `app.analytics.report('queries', { limit, startDate, endDate, filters })` | `reports:read` |
|
|
53
|
+
| `app.dashboard.get('Synonym')`: HawkSearch dashboard API, no API version in the path | `hawksearch:read` |
|
|
54
|
+
| `app.dashboard.post/put/delete(path, body)`: merchandising and relevancy resources only, never retried | `hawksearch:write` |
|
|
55
|
+
| `app.hawksearch.search(...)`, `app.hawksearch.autocomplete(...)` on the user's engine | `hawksearch:search` |
|
|
56
|
+
| `app.data.query('name', params)`: your SQL in `queries/<name>.sql` + `.json` | `data:read` |
|
|
57
|
+
| `app.functions.call('name', input)`, `.start/.wait/.job` for jobs: `functions/<name>.ts` exporting `handler` | `functions:invoke` |
|
|
58
|
+
| `app.email.send(...)` | `email:send` |
|
|
59
|
+
| `app.storage.get/put/delete/list/batch/usage`: the app's own JSON data per client (350 KB a value, `ttlDays`, `ifVersion`); `app.storage.files.upload/url/download/list/delete`: its files (100 MB each) | `storage` |
|
|
60
|
+
| `app.hawksearch.systemParameters.list/get/set`: names listed in `systemParameters` | `hawksearch:sysparams:write` |
|
|
61
|
+
| `app.hawksearch.features.list/set/setFacet` | `hawksearch:features:write` |
|
|
62
|
+
| `app.hawksearch.index.rebuild()`, `.status(id?)`, `.wait(id)`: rebuild the engine's index from its feed (needs the engine's `EnableRebuildIndex` on; one at a time); `.indexes()`, `.current()` | `hawksearch:index` |
|
|
63
|
+
| `app.hawksearch.index.items.upsert/update/delete(...)`: items in the engine's indexes, live at once (125 a call) | `hawksearch:index:items` |
|
|
64
|
+
| `app.hawksearch.index.create/setCurrent/deleteIndex/rebuildAll(...)`, `.call('hierarchy/upsert', …)` and other management | `hawksearch:index:manage` |
|
|
65
|
+
| `app.hawksearch.recommendations({ widgetUids: [{ widgetGuid, uniqueId? }] })`: recommendation widgets, untracked | `hawksearch:recommendations` |
|
|
66
|
+
| `app.ai.generate/stream/info` | `ai:invoke` |
|
|
67
|
+
| `app.lambdas.invoke('name', input)`: names listed in `lambdas`, allowed by Engineering | `lambdas:invoke` |
|
|
68
|
+
| `app.config.get('key')`, `app.config.all()`: keys declared in `config`, the client's value, else the global one, else the default (null when none); not secret | none |
|
|
69
|
+
| `app.assistant.ask('question')`, `app.assistant.setContext({ ...what's on screen })` (null clears): the host's assistant (Hawk Assistant) answers in its chat, as the user; only from a click, and only while `context.features?.assistant` is true (it can load after the app: `app.onContextChange`) | `assistant` |
|
|
70
|
+
|
|
71
|
+
Also: `app.reportError(error)` for errors the app catches and handles (uncaught ones are reported on their own; see
|
|
72
|
+
them with `hawk-app errors`), `app.setTitle`, `app.toast(message, 'info'|'success'|'warning'|'error')`,
|
|
73
|
+
`app.navigate({ intent: 'app'|'report'|'settings'|'external', ... })` (intents, never URLs), `app.getToken()`,
|
|
74
|
+
`app.api.get('me')` (`internal: true` for Bridgeline staff, from the signed token: use it for staff-only screens).
|
|
75
|
+
Failed data calls throw `HawkApiError` (`status`, `code`); host requests throw `HawkBridgeError` (`code`). A 403
|
|
76
|
+
`scope_missing` means the scope is missing from `hawk-app.json` or the app wasn't deployed again after adding it
|
|
77
|
+
(`validate` and `deploy` warn about bridge calls whose scope is missing).
|
|
78
|
+
Look: every template uses the Hawk Apps UI kit (`@bridgeline-digital/hawk-app-ui`) for Spark's look in the
|
|
79
|
+
host's colors and mode: React + MUI apps (next-mui) its provider and components, every other app its stylesheet
|
|
80
|
+
(`/css`) and elements (`/elements`); see this app's section below. Don't restyle it or add another font. For your own
|
|
81
|
+
styles use its `--hawk-ui-*` variables (or the host's `--hawk-*` ones with your own fallbacks).
|
|
82
|
+
Accessibility: approvers see an axe-core check of the built pages (critical issues fail it): label form fields, give
|
|
83
|
+
images `alt`, keep one `<main>` and headings in order. `validate --build` shows the issues.
|
|
84
|
+
Dialogs: any `[role="dialog"]` (every MUI Dialog) covers the host's whole page on its own, even from a small frame;
|
|
85
|
+
center dialogs in the visible part of the frame (`--hawk-visible-top`, `--hawk-visible-height`, as the templates'
|
|
86
|
+
theme does), and use in-page dialogs, never `window.confirm`/`alert` (blocked in the sandbox).
|
|
87
|
+
|
|
88
|
+
Before using a call, read its section in the bridge README for the exact options, limits and error codes: the
|
|
89
|
+
`hawk-apps` MCP server's `docs` tool (below), or
|
|
90
|
+
`node_modules/@bridgeline-digital/hawk-app-bridge/README.md` when the bridge is installed, otherwise
|
|
91
|
+
https://www.npmjs.com/package/@bridgeline-digital/hawk-app-bridge. Its TypeScript types are in the same package.
|
|
92
|
+
|
|
93
|
+
## MCP server
|
|
94
|
+
|
|
95
|
+
`.mcp.json` (Claude Code) and `.vscode/mcp.json` (VS Code) start the CLI's MCP server, `hawk-apps`, from
|
|
96
|
+
`node_modules` (`npm install` first). Its tools: `docs` (the bridge, UI kit, CLI, `hawk-app.json` schema and the
|
|
97
|
+
showcase app, which has working code for every feature), `ui_components` (the UI kit's components for this app's
|
|
98
|
+
template: use them before writing your own), `validate`, `status` (with the review checks approvers will see),
|
|
99
|
+
`analytics_reports` (every report `app.analytics.report()` can call, with its columns and filters),
|
|
100
|
+
`hawksearch_api` (HawkSearch's dashboard, search, recommendation and indexing operations: fields, the bridge call, its scope),
|
|
101
|
+
`data_tables` and `data_describe` (names and columns, never data), `logs`, `init`, `upgrade`,
|
|
102
|
+
`deploy` (with `alias`, and `dryRun` to only show what hawk-app.json would change), `versions`, `why` (what a client sees, and why), `doctor` (what's wrong with the setup), `errors`, `usage`, and `clients` and `clients_add`, which only ever use the dev platform. Prefer them to guessing. When the
|
|
103
|
+
user names a client ("deploy to OTC"), call `clients_add` with their words: it shows them a form to pick the exact
|
|
104
|
+
client. With `alias` (`hawk-app clients add <id> --alias review`) the client gets that alias's version: on a version that
|
|
105
|
+
isn't approved, only Bridgeline staff in it see the app. Only approvers change what a client whose users see the app
|
|
106
|
+
gets. `hawk-app deploy out --alias staging` deploys off the main line: the version carries this hawk-app.json, `staging`
|
|
107
|
+
points at it, and the version under review isn't touched. A plain `hawk-app deploy` sends hawk-app.json first, so scope
|
|
108
|
+
changes go with the deploy. Client names aren't shared with you; don't ask for them in the chat. Its prompts (`check-before-submit`, `add-feature`,
|
|
109
|
+
`explain-app`, `deploy-to-client`; in Claude Code `/mcp__hawk-apps__<name>`) are ready-made tasks that use them.
|
|
110
|
+
|
|
111
|
+
## Icon
|
|
112
|
+
|
|
113
|
+
`icon` in `hawk-app.json` is the app's icon file, next to it: `icon.svg` by default, which `create` and `init` add.
|
|
114
|
+
- **An .svg** is drawn in the host's own color (HawkSearch, Spark; light and dark): only its shape counts, so draw it in
|
|
115
|
+
one color, on a square `viewBox` (e.g. `0 0 24 24`), at most 32 KB.
|
|
116
|
+
- **A .png** is shown as is, for a full-color logo: square, 64 to 1024 px (256 is a good size), at most 256 KB.
|
|
117
|
+
- `hawk-app validate` and `deploy` check it; `deploy` uploads it with each version, so an icon change is reviewed like
|
|
118
|
+
other settings. Leave `icon` out for the hosts' default icon. Names from HawkSearch's icon set are no longer used.
|
|
119
|
+
|
|
120
|
+
## Views
|
|
121
|
+
|
|
122
|
+
`views` in `hawk-app.json` declares pages of the build that hosts show inside other pages:
|
|
123
|
+
- **`preview`:** shown live on the Apps page's cards, under the description.
|
|
124
|
+
- **`"embeddable": true`:** Bridgeline users can place the view in app slots of HawkSearch pages (per engine or for
|
|
125
|
+
every client), with values for its `params`.
|
|
126
|
+
|
|
127
|
+
Each view is a route, e.g. `src/app/views/preview/page.tsx` for `"path": "views/preview"`. It reads
|
|
128
|
+
`app.context.view` (`{ name, params, embedded, maxHeight }`). In a view:
|
|
129
|
+
- Keep it small and fast: read stored results, not reports. Many views can share a page.
|
|
130
|
+
- The page background is transparent (the host's shows through) and the height fits the content: never set
|
|
131
|
+
`html, body { height: 100% }`, or it can't shrink.
|
|
132
|
+
- Toasts and title changes are ignored; `app.navigate({ intent: 'app', slug })` opens the full app.
|
|
133
|
+
- `"cacheMinutes": n` (0–1440) on a view caches its reads (data queries, reports, `dashboard.get`, search,
|
|
134
|
+
recommendations) on the platform for n minutes, per client and engine. A `preview` caches 60 minutes by default
|
|
135
|
+
(`0` turns it off); other views don't unless they say so. Pass
|
|
136
|
+
`{ cache: 'no-store' }` on a call that writes (e.g. an analytics report that records something), or
|
|
137
|
+
`{ cache: 'reload' }` to refresh. The full app page is never cached.
|
|
138
|
+
|
|
139
|
+
A slot can also hold the **entire app** (its own page, with no `view` in the context): it then runs inside another
|
|
140
|
+
page, at the slot's height, so don't rely on the full window either.
|
|
141
|
+
|
|
142
|
+
## Queries and functions
|
|
143
|
+
|
|
144
|
+
- **Queries** (`queries/<name>.sql` + `<name>.json`, next to `hawk-app.json`): one `SELECT`/`WITH`, `?` for each
|
|
145
|
+
parameter in order, plain table names. Every query with a date range needs `{{partitions(from, to)}}`, names its
|
|
146
|
+
columns (no `SELECT *`) and has a `LIMIT` on lists; review flags any that don't. `npx hawk-app data tables` and
|
|
147
|
+
`npx hawk-app data describe <table>` show the tables and columns.
|
|
148
|
+
- **Functions** (`functions/<name>.ts`, settings under `functions` in `hawk-app.json`): Node 22 Lambda,
|
|
149
|
+
`export const handler: HawkFunction<In, Out> = async (input, ctx) => ...` with `HawkFunction` from
|
|
150
|
+
`@bridgeline-digital/hawk-app-bridge/server`. Use `ctx.platform` (same APIs as `app`), `ctx.secrets.NAME`,
|
|
151
|
+
`ctx.client.id`, `ctx.user`. Stateless; 25 s, or 900 s for a job (`"job": true`). Engineering enables functions per
|
|
152
|
+
app.
|
|
153
|
+
|
|
154
|
+
## Project
|
|
155
|
+
|
|
156
|
+
__PROJECT__
|
|
157
|
+
|
|
158
|
+
## Commands
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
npx hawk-app doctor # check the setup (Node, login, hawk-app.json, scopes the code uses) and what to fix
|
|
162
|
+
npm run app:dev # run the app locally in a stand-in for HawkSearch (asks which client the first time)
|
|
163
|
+
npx hawk-app validate # check hawk-app.json, queries/ and functions/ (--build also checks the build's URLs)
|
|
164
|
+
npm run app:audit # npm audit of the production dependencies: fix high and critical before deploying
|
|
165
|
+
npm run app:deploy # build and upload a new version, with hawk-app.json (dev unless --env prod)
|
|
166
|
+
npx hawk-app deploy --dry-run # what hawk-app.json would change, without a version
|
|
167
|
+
npx hawk-app status # released and newest versions, the request, the aliases
|
|
168
|
+
npx hawk-app versions # every version with its status and aliases
|
|
169
|
+
npx hawk-app open # the app's page in HawkSearch (review, submit for approval)
|
|
170
|
+
npx hawk-app logs <function> # a function's logs
|
|
171
|
+
npx hawk-app config list # config values (config set <key> <value> [--client <id>], config unset <key>)
|
|
172
|
+
npx hawk-app errors # errors in the app's pages (deployed versions), the most frequent first
|
|
173
|
+
npx hawk-app usage # opens, users and clients per day
|
|
174
|
+
npx hawk-app upgrade # bring the app (and this file) up to the CLI's current template
|
|
175
|
+
npx hawk-app upgrade --channel latest # a dev app (bridge/CLI on the `dev` tag) to the released versions
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Deploy only when asked to. Never use `--env prod` unless asked to. If the bridge or CLI is on the
|
|
179
|
+
`dev` tag (a dev app), its features may only exist on the dev platform: don't move it to `latest` or to prod unless
|
|
180
|
+
asked to.
|
|
181
|
+
|
|
182
|
+
## Review
|
|
183
|
+
|
|
184
|
+
A new app is a draft that only Bridgeline staff see. Members of Hawk-App-Developers submit it (and each later version
|
|
185
|
+
or settings change) for approval in HawkSearch; Hawk-App-Approvers approve it. The approve dialog runs automated
|
|
186
|
+
checks, and a failed check forces the approver to override it:
|
|
187
|
+
|
|
188
|
+
- **Bundle:** over 20 MB in total, any file over 5 MB, or 50% (and 1 MB) bigger than the released version.
|
|
189
|
+
- **Dependencies:** high or critical `npm audit` findings in the production dependencies, or no audit.
|
|
190
|
+
- **Outside origins:** `externalOrigins` is `["*"]`.
|
|
191
|
+
- **Queries:** a query without `{{partitions(...)}}`; `SELECT *` and a missing `LIMIT` are flagged too.
|
|
192
|
+
- Functions, external Lambdas and new outside origins are shown to the approver.
|
package/agents/project/custom.md
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
This app doesn't use one of the CLI's templates (it was set up with `npx hawk-app init`), so the project itself has to
|
|
2
|
-
do what a template would:
|
|
3
|
-
|
|
4
|
-
- **Bridge.** Install `@bridgeline-digital/hawk-app-bridge` and import `createApp` from
|
|
5
|
-
`@bridgeline-digital/hawk-app-bridge/client`. Without a bundler, import it from the CDN pinned to a minor
|
|
6
|
-
version: `https://cdn.jsdelivr.net/npm/@bridgeline-digital/hawk-app-bridge@<major.minor>/dist/client/index.js`.
|
|
7
|
-
Connect once (`createApp`), keep the context in state, and show "Open this app from the Apps page in HawkSearch"
|
|
8
|
-
when it rejects with `not_embedded`.
|
|
9
|
-
- **Base path.** `hawk-app deploy` runs `npm run build` with `HAWK_APP_BASE_PATH=/__SLUG__/v<n>`. Read it in the build
|
|
10
|
-
config, e.g. Vite `base: (process.env.HAWK_APP_BASE_PATH ?? '/__SLUG__') + '/'`, Next.js
|
|
11
|
-
`basePath: process.env.HAWK_APP_BASE_PATH ?? '/__SLUG__'` with `output: 'export'`, or emit only relative URLs. `npx hawk-app validate --build` checks the output.
|
|
12
|
-
- **Static output.** The build writes plain files to one folder (e.g. `dist/`), deployed with
|
|
13
|
-
`npx hawk-app deploy <folder>` (it builds when package.json has a `build` script; without one it uploads the folder
|
|
14
|
-
as it is, so use relative URLs only).
|
|
15
|
-
- **Dev server** on `http://localhost:3100` (the dev platform accepts calls from ports 3100-3103), opened in HawkSearch
|
|
16
|
-
with `<HawkSearch>/admin/apps/__SLUG__?devUrl=<the dev server's URL for the app>`.
|
|
17
|
-
- **Look.** Use the Hawk Apps UI kit (`@bridgeline-digital/hawk-app-ui`) for Spark's look: React + MUI apps
|
|
18
|
-
its `<HawkAppProvider>` and components, any other app its stylesheet (`/css`, or from the CDN
|
|
19
|
-
`…/hawk-app-ui@<major.minor>/dist/css/hawk.css`) and elements (`/elements`). See the kit's README.
|
|
20
|
-
- **Scripts.** Add `"app:dev": "hawk-app dev"`, `"app:deploy": "hawk-app deploy <folder>"` and
|
|
21
|
-
`"app:audit": "npm audit --omit=dev --audit-level=high"` to `package.json`, with the CLI as a dev dependency.
|
|
1
|
+
This app doesn't use one of the CLI's templates (it was set up with `npx hawk-app init`), so the project itself has to
|
|
2
|
+
do what a template would:
|
|
3
|
+
|
|
4
|
+
- **Bridge.** Install `@bridgeline-digital/hawk-app-bridge` and import `createApp` from
|
|
5
|
+
`@bridgeline-digital/hawk-app-bridge/client`. Without a bundler, import it from the CDN pinned to a minor
|
|
6
|
+
version: `https://cdn.jsdelivr.net/npm/@bridgeline-digital/hawk-app-bridge@<major.minor>/dist/client/index.js`.
|
|
7
|
+
Connect once (`createApp`), keep the context in state, and show "Open this app from the Apps page in HawkSearch"
|
|
8
|
+
when it rejects with `not_embedded`.
|
|
9
|
+
- **Base path.** `hawk-app deploy` runs `npm run build` with `HAWK_APP_BASE_PATH=/__SLUG__/v<n>`. Read it in the build
|
|
10
|
+
config, e.g. Vite `base: (process.env.HAWK_APP_BASE_PATH ?? '/__SLUG__') + '/'`, Next.js
|
|
11
|
+
`basePath: process.env.HAWK_APP_BASE_PATH ?? '/__SLUG__'` with `output: 'export'`, or emit only relative URLs. `npx hawk-app validate --build` checks the output.
|
|
12
|
+
- **Static output.** The build writes plain files to one folder (e.g. `dist/`), deployed with
|
|
13
|
+
`npx hawk-app deploy <folder>` (it builds when package.json has a `build` script; without one it uploads the folder
|
|
14
|
+
as it is, so use relative URLs only).
|
|
15
|
+
- **Dev server** on `http://localhost:3100` (the dev platform accepts calls from ports 3100-3103), opened in HawkSearch
|
|
16
|
+
with `<HawkSearch>/admin/apps/__SLUG__?devUrl=<the dev server's URL for the app>`.
|
|
17
|
+
- **Look.** Use the Hawk Apps UI kit (`@bridgeline-digital/hawk-app-ui`) for Spark's look: React + MUI apps
|
|
18
|
+
its `<HawkAppProvider>` and components, any other app its stylesheet (`/css`, or from the CDN
|
|
19
|
+
`…/hawk-app-ui@<major.minor>/dist/css/hawk.css`) and elements (`/elements`). See the kit's README.
|
|
20
|
+
- **Scripts.** Add `"app:dev": "hawk-app dev"`, `"app:deploy": "hawk-app deploy <folder>"` and
|
|
21
|
+
`"app:audit": "npm audit --omit=dev --audit-level=high"` to `package.json`, with the CLI as a dev dependency.
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
Created from the CLI's `next-mui` template (Next.js static export + Material UI 9 + the Hawk Apps UI kit,
|
|
2
|
-
`@bridgeline-digital/hawk-app-ui`). `npx hawk-app upgrade` keeps it in step.
|
|
3
|
-
|
|
4
|
-
- `src/app/providers.tsx` renders `<HawkAppProvider>`: it connects to the host and shows the app in Spark's theme, in
|
|
5
|
-
the host's colors and mode. Read the app and its context with `useHawk()` (`{ app, context }`, always connected).
|
|
6
|
-
Components that use hooks are client components (`'use client'`). `src/app/layout.tsx` imports
|
|
7
|
-
`@bridgeline-digital/hawk-app-ui/fonts` (Montserrat): keep it.
|
|
8
|
-
- Build screens from the kit before writing your own: `Section`, `KpiTile`/`KpiRow`, `DataTable` (sortable, totals,
|
|
9
|
-
CSV download), `EmptyState`, `LoadingSection`, `Notice` (with `onRetry`), `ConfirmDialog`, `SideDrawer`; charts from
|
|
10
|
-
`@bridgeline-digital/hawk-app-ui/charts` (`BarList`, `ColumnChart`, `StackedColumnChart`, `Sparkline`);
|
|
11
|
-
`DataGrid` from `/data-grid` (add `@mui/x-data-grid@^9`) for thousands of rows. Format with `useFormat()` (the
|
|
12
|
-
host's locale) and toast with `useToast()`, not hand-rolled helpers or a local Snackbar.
|
|
13
|
-
- Don't restyle Spark's theme or add another font: the kit's theme is Spark's. App-specific additions go in
|
|
14
|
-
`<HawkAppProvider theme={{ … }}>`.
|
|
15
|
-
- `next.config.ts` has `output: 'export'`, `basePath` from `HAWK_APP_BASE_PATH` (local dev: `/__SLUG__`) and
|
|
16
|
-
`trailingSlash`. Keep them. No server features: no `getServerSideProps`, route handlers, server actions,
|
|
17
|
-
middleware or `next/image` optimization.
|
|
18
|
-
- Develop: `npm run dev` (port 3100), then open
|
|
19
|
-
`<HawkSearch>/admin/apps/__SLUG__?devUrl=http://localhost:3100/__SLUG__/` (dev mode
|
|
20
|
-
allows ports 3100-3103).
|
|
21
|
-
- Build output: `out/` (`npm run app:deploy` builds and deploys it).
|
|
1
|
+
Created from the CLI's `next-mui` template (Next.js static export + Material UI 9 + the Hawk Apps UI kit,
|
|
2
|
+
`@bridgeline-digital/hawk-app-ui`). `npx hawk-app upgrade` keeps it in step.
|
|
3
|
+
|
|
4
|
+
- `src/app/providers.tsx` renders `<HawkAppProvider>`: it connects to the host and shows the app in Spark's theme, in
|
|
5
|
+
the host's colors and mode. Read the app and its context with `useHawk()` (`{ app, context }`, always connected).
|
|
6
|
+
Components that use hooks are client components (`'use client'`). `src/app/layout.tsx` imports
|
|
7
|
+
`@bridgeline-digital/hawk-app-ui/fonts` (Montserrat): keep it.
|
|
8
|
+
- Build screens from the kit before writing your own: `Section`, `KpiTile`/`KpiRow`, `DataTable` (sortable, totals,
|
|
9
|
+
CSV download), `EmptyState`, `LoadingSection`, `Notice` (with `onRetry`), `ConfirmDialog`, `SideDrawer`; charts from
|
|
10
|
+
`@bridgeline-digital/hawk-app-ui/charts` (`BarList`, `ColumnChart`, `StackedColumnChart`, `Sparkline`);
|
|
11
|
+
`DataGrid` from `/data-grid` (add `@mui/x-data-grid@^9`) for thousands of rows. Format with `useFormat()` (the
|
|
12
|
+
host's locale) and toast with `useToast()`, not hand-rolled helpers or a local Snackbar.
|
|
13
|
+
- Don't restyle Spark's theme or add another font: the kit's theme is Spark's. App-specific additions go in
|
|
14
|
+
`<HawkAppProvider theme={{ … }}>`.
|
|
15
|
+
- `next.config.ts` has `output: 'export'`, `basePath` from `HAWK_APP_BASE_PATH` (local dev: `/__SLUG__`) and
|
|
16
|
+
`trailingSlash`. Keep them. No server features: no `getServerSideProps`, route handlers, server actions,
|
|
17
|
+
middleware or `next/image` optimization.
|
|
18
|
+
- Develop: `npm run dev` (port 3100), then open
|
|
19
|
+
`<HawkSearch>/admin/apps/__SLUG__?devUrl=http://localhost:3100/__SLUG__/` (dev mode
|
|
20
|
+
allows ports 3100-3103).
|
|
21
|
+
- Build output: `out/` (`npm run app:deploy` builds and deploys it).
|
package/agents/project/next.md
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
Created from the CLI's `__TEMPLATE__` template (Next.js static export + TypeScript). `npx hawk-app upgrade` keeps
|
|
2
|
-
it in step.
|
|
3
|
-
|
|
4
|
-
- `src/lib/useHawkApp.ts` connects to the host once and keeps the context current; build screens on it. Components
|
|
5
|
-
that use it are client components (`'use client'`).
|
|
6
|
-
- Spark's look comes from the Hawk Apps UI kit (`@bridgeline-digital/hawk-app-ui`): its stylesheet (`/css`,
|
|
7
|
-
imported in `src/app/layout.tsx`: Montserrat, the host's colors and light or dark mode) and its elements
|
|
8
|
-
(`/elements`, imported in the client page; safe to import on the server). Build screens from them before writing
|
|
9
|
-
your own: classes `hawk-section` (with `hawk-section-header`, `hawk-section-title`, `hawk-section-subtitle`),
|
|
10
|
-
`hawk-kpi-row`, `hawk-stack`, `hawk-button` (`is-outlined`, `is-small`), `hawk-notice` (`is-error`, `is-warning`,
|
|
11
|
-
`is-success`), `hawk-input`, `hawk-select`, `hawk-chip`, `hawk-empty`, `hawk-spinner`, `hawk-muted`; elements
|
|
12
|
-
`<hawk-kpi label value hint change good-when highlight loading>`, `<hawk-data-table>` (properties `columns`, `rows`,
|
|
13
|
-
`totals`; attributes `download`, `max-height`, `clickable`; sortable, CSV download), `<hawk-bar-list>` (`items`,
|
|
14
|
-
`selectable`: `hawk-select` events) and `<hawk-column-chart>` (`columns`). Data goes in as properties, settings as
|
|
15
|
-
attributes; `src/hawk-elements.d.ts` types them in JSX. Format numbers and dates with `createFormat(context.locale)`
|
|
16
|
-
from `/elements`. Don't add another font or restyle the kit; your own styles go in `src/app/globals.css`, using the
|
|
17
|
-
`--hawk-ui-*` variables.
|
|
18
|
-
- `next.config.ts` has `output: 'export'`, `basePath` from `HAWK_APP_BASE_PATH` (local dev: `/__SLUG__`) and
|
|
19
|
-
`trailingSlash`. Keep them. No server features: no `getServerSideProps`, route handlers, server actions,
|
|
20
|
-
middleware or `next/image` optimization.
|
|
21
|
-
- Develop: `npm run dev` (port 3100), then open
|
|
22
|
-
`<HawkSearch>/admin/apps/__SLUG__?devUrl=http://localhost:3100/__SLUG__/` (dev mode
|
|
23
|
-
allows ports 3100-3103).
|
|
24
|
-
- Build output: `out/` (`npm run app:deploy` builds and deploys it).
|
|
1
|
+
Created from the CLI's `__TEMPLATE__` template (Next.js static export + TypeScript). `npx hawk-app upgrade` keeps
|
|
2
|
+
it in step.
|
|
3
|
+
|
|
4
|
+
- `src/lib/useHawkApp.ts` connects to the host once and keeps the context current; build screens on it. Components
|
|
5
|
+
that use it are client components (`'use client'`).
|
|
6
|
+
- Spark's look comes from the Hawk Apps UI kit (`@bridgeline-digital/hawk-app-ui`): its stylesheet (`/css`,
|
|
7
|
+
imported in `src/app/layout.tsx`: Montserrat, the host's colors and light or dark mode) and its elements
|
|
8
|
+
(`/elements`, imported in the client page; safe to import on the server). Build screens from them before writing
|
|
9
|
+
your own: classes `hawk-section` (with `hawk-section-header`, `hawk-section-title`, `hawk-section-subtitle`),
|
|
10
|
+
`hawk-kpi-row`, `hawk-stack`, `hawk-button` (`is-outlined`, `is-small`), `hawk-notice` (`is-error`, `is-warning`,
|
|
11
|
+
`is-success`), `hawk-input`, `hawk-select`, `hawk-chip`, `hawk-empty`, `hawk-spinner`, `hawk-muted`; elements
|
|
12
|
+
`<hawk-kpi label value hint change good-when highlight loading>`, `<hawk-data-table>` (properties `columns`, `rows`,
|
|
13
|
+
`totals`; attributes `download`, `max-height`, `clickable`; sortable, CSV download), `<hawk-bar-list>` (`items`,
|
|
14
|
+
`selectable`: `hawk-select` events) and `<hawk-column-chart>` (`columns`). Data goes in as properties, settings as
|
|
15
|
+
attributes; `src/hawk-elements.d.ts` types them in JSX. Format numbers and dates with `createFormat(context.locale)`
|
|
16
|
+
from `/elements`. Don't add another font or restyle the kit; your own styles go in `src/app/globals.css`, using the
|
|
17
|
+
`--hawk-ui-*` variables.
|
|
18
|
+
- `next.config.ts` has `output: 'export'`, `basePath` from `HAWK_APP_BASE_PATH` (local dev: `/__SLUG__`) and
|
|
19
|
+
`trailingSlash`. Keep them. No server features: no `getServerSideProps`, route handlers, server actions,
|
|
20
|
+
middleware or `next/image` optimization.
|
|
21
|
+
- Develop: `npm run dev` (port 3100), then open
|
|
22
|
+
`<HawkSearch>/admin/apps/__SLUG__?devUrl=http://localhost:3100/__SLUG__/` (dev mode
|
|
23
|
+
allows ports 3100-3103).
|
|
24
|
+
- Build output: `out/` (`npm run app:deploy` builds and deploys it).
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
Created from the CLI's `vanilla` template (plain HTML and JavaScript, no build step). `npx hawk-app upgrade` keeps
|
|
2
|
-
it in step.
|
|
3
|
-
|
|
4
|
-
- Everything deployed is in `public/` (`npm run app:deploy` uploads it as it is: no build step).
|
|
5
|
-
- `public/app.js` imports the bridge from the CDN, pinned to a minor version
|
|
6
|
-
(`https://cdn.jsdelivr.net/npm/@bridgeline-digital/hawk-app-bridge@<major.minor>/dist/client/index.js`), and
|
|
7
|
-
the Hawk Apps UI kit's elements at the same version (`…/hawk-app-ui@<major.minor>/dist/elements/index.js`);
|
|
8
|
-
`public/index.html` links the kit's stylesheet (`…/hawk-app-ui@<major.minor>/dist/css/hawk.css`: Spark's look,
|
|
9
|
-
Montserrat, the host's colors and light or dark mode). Keep all three on the same version: `npx hawk-app upgrade`
|
|
10
|
-
raises them together.
|
|
11
|
-
- Build screens from the kit before writing your own: classes `hawk-section` (with `hawk-section-header`,
|
|
12
|
-
`hawk-section-title`, `hawk-section-subtitle`), `hawk-kpi-row`, `hawk-stack`, `hawk-button` (`is-outlined`,
|
|
13
|
-
`is-small`), `hawk-notice` (`is-error`, `is-warning`, `is-success`), `hawk-input`, `hawk-select`, `hawk-chip`,
|
|
14
|
-
`hawk-empty`, `hawk-spinner`, `hawk-muted`; elements `<hawk-kpi label value hint change good-when highlight loading>`,
|
|
15
|
-
`<hawk-data-table>` (properties `columns`, `rows`, `totals`; attributes `download`, `max-height`, `clickable`;
|
|
16
|
-
sortable, CSV download), `<hawk-bar-list>` (`items`, `selectable`: `hawk-select` events) and `<hawk-column-chart>`
|
|
17
|
-
(`columns`). Data goes in as properties (`el.rows = [...]`), settings as attributes. Format numbers and dates with
|
|
18
|
-
`createFormat(context.locale)` from the elements module. Your own styles go in `public/styles.css`, using the
|
|
19
|
-
`--hawk-ui-*` variables. `hawk-app.json` keeps `https://cdn.jsdelivr.net` in `externalOrigins` (the CDN).
|
|
20
|
-
- Use only relative URLs (`app.js`, `styles.css`), never `/app.js`: the files are served from `/__SLUG__/v<n>/`.
|
|
21
|
-
- Develop: `npm run app:dev` (serves `public/` on port 3100 inside a local stand-in for HawkSearch), or `npm run dev`
|
|
22
|
-
and open `<HawkSearch>/admin/apps/__SLUG__?devUrl=http://localhost:3100/` (the dev mode allows ports 3100-3103).
|
|
1
|
+
Created from the CLI's `vanilla` template (plain HTML and JavaScript, no build step). `npx hawk-app upgrade` keeps
|
|
2
|
+
it in step.
|
|
3
|
+
|
|
4
|
+
- Everything deployed is in `public/` (`npm run app:deploy` uploads it as it is: no build step).
|
|
5
|
+
- `public/app.js` imports the bridge from the CDN, pinned to a minor version
|
|
6
|
+
(`https://cdn.jsdelivr.net/npm/@bridgeline-digital/hawk-app-bridge@<major.minor>/dist/client/index.js`), and
|
|
7
|
+
the Hawk Apps UI kit's elements at the same version (`…/hawk-app-ui@<major.minor>/dist/elements/index.js`);
|
|
8
|
+
`public/index.html` links the kit's stylesheet (`…/hawk-app-ui@<major.minor>/dist/css/hawk.css`: Spark's look,
|
|
9
|
+
Montserrat, the host's colors and light or dark mode). Keep all three on the same version: `npx hawk-app upgrade`
|
|
10
|
+
raises them together.
|
|
11
|
+
- Build screens from the kit before writing your own: classes `hawk-section` (with `hawk-section-header`,
|
|
12
|
+
`hawk-section-title`, `hawk-section-subtitle`), `hawk-kpi-row`, `hawk-stack`, `hawk-button` (`is-outlined`,
|
|
13
|
+
`is-small`), `hawk-notice` (`is-error`, `is-warning`, `is-success`), `hawk-input`, `hawk-select`, `hawk-chip`,
|
|
14
|
+
`hawk-empty`, `hawk-spinner`, `hawk-muted`; elements `<hawk-kpi label value hint change good-when highlight loading>`,
|
|
15
|
+
`<hawk-data-table>` (properties `columns`, `rows`, `totals`; attributes `download`, `max-height`, `clickable`;
|
|
16
|
+
sortable, CSV download), `<hawk-bar-list>` (`items`, `selectable`: `hawk-select` events) and `<hawk-column-chart>`
|
|
17
|
+
(`columns`). Data goes in as properties (`el.rows = [...]`), settings as attributes. Format numbers and dates with
|
|
18
|
+
`createFormat(context.locale)` from the elements module. Your own styles go in `public/styles.css`, using the
|
|
19
|
+
`--hawk-ui-*` variables. `hawk-app.json` keeps `https://cdn.jsdelivr.net` in `externalOrigins` (the CDN).
|
|
20
|
+
- Use only relative URLs (`app.js`, `styles.css`), never `/app.js`: the files are served from `/__SLUG__/v<n>/`.
|
|
21
|
+
- Develop: `npm run app:dev` (serves `public/` on port 3100 inside a local stand-in for HawkSearch), or `npm run dev`
|
|
22
|
+
and open `<HawkSearch>/admin/apps/__SLUG__?devUrl=http://localhost:3100/` (the dev mode allows ports 3100-3103).
|