@brendanbank/atrium-host-types 0.15.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/LICENCE.md +25 -0
- package/README.md +81 -0
- package/dist/index.d.ts +197 -0
- package/dist/index.js +3 -0
- package/package.json +40 -0
package/LICENCE.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Brendan Bank
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
9
|
+
this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
18
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
19
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
20
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
21
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
22
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
23
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
24
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
25
|
+
POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# `@brendanbank/atrium-host-types`
|
|
2
|
+
|
|
3
|
+
TypeScript declarations for the [atrium](https://github.com/brendanbank/atrium)
|
|
4
|
+
host-extension contract.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import type {
|
|
8
|
+
AtriumRegistry,
|
|
9
|
+
AtriumNotification,
|
|
10
|
+
AtriumEvent,
|
|
11
|
+
UserContext,
|
|
12
|
+
AdminUserRow,
|
|
13
|
+
} from '@brendanbank/atrium-host-types';
|
|
14
|
+
|
|
15
|
+
const reg = window.__ATRIUM_REGISTRY__ as AtriumRegistry;
|
|
16
|
+
reg.registerHomeWidget({ key: 'my-card', render: () => /* ... */ });
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The package is **types-only** — no runtime, no JS payload at runtime.
|
|
20
|
+
Bundlers strip it from the production output.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
The package is published on **GitHub Packages**, not the public npm
|
|
25
|
+
registry. Add an `.npmrc` to your host project that points the
|
|
26
|
+
`@brendanbank` scope at GitHub Packages:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
# .npmrc
|
|
30
|
+
@brendanbank:registry=https://npm.pkg.github.com
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
GitHub Packages requires an authenticated install even for public
|
|
34
|
+
packages — give npm a token with at least the `read:packages` scope:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
In CI, `GITHUB_TOKEN` is provided automatically by Actions; locally,
|
|
41
|
+
generate a [classic PAT](https://github.com/settings/tokens) with
|
|
42
|
+
`read:packages` and export it. Then:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add -D @brendanbank/atrium-host-types
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Versioning
|
|
49
|
+
|
|
50
|
+
The package version tracks atrium's image version. Pin `^0.15` for
|
|
51
|
+
"compatible with atrium 0.15.x"; bump together with the atrium image
|
|
52
|
+
to pick up new registry slots. New slots land as **optional** members
|
|
53
|
+
on `AtriumRegistry` first so a host that hasn't bumped yet still
|
|
54
|
+
type-checks.
|
|
55
|
+
|
|
56
|
+
## What ships
|
|
57
|
+
|
|
58
|
+
- `AtriumRegistry` — every `register*` slot atrium exposes plus
|
|
59
|
+
`subscribeEvent`.
|
|
60
|
+
- `UserContext` — `/users/me/context` shape.
|
|
61
|
+
- `AdminUserRow` — `/admin/users` row shape.
|
|
62
|
+
- `AtriumNotification` — notification row body.
|
|
63
|
+
- `AtriumEvent` / `AtriumEventHandler` — SSE typed event shape.
|
|
64
|
+
- Per-slot option-bag types: `HomeWidget`, `RouteEntry`, `NavItem`,
|
|
65
|
+
`AdminTab`, `ProfileItem`, `NotificationKindRenderer`,
|
|
66
|
+
`LocaleOverlay`.
|
|
67
|
+
- `ProfileSlot`, `HomeWidgetWidth` — string unions.
|
|
68
|
+
- A `declare global` block that types `window.React`,
|
|
69
|
+
`window.__ATRIUM_VERSION__`, and `window.__ATRIUM_REGISTRY__`.
|
|
70
|
+
|
|
71
|
+
## See also
|
|
72
|
+
|
|
73
|
+
- [`@brendanbank/atrium-host-bundle-utils`](../host-bundle-utils/) —
|
|
74
|
+
runtime helpers, Vite preset, and React hooks. Re-exports the types
|
|
75
|
+
from this package, so a host adding only one dep still gets the
|
|
76
|
+
declarations.
|
|
77
|
+
- [`docs/published-images.md`](../../docs/published-images.md) — the
|
|
78
|
+
full host-extension contract (image catalogue, loader behaviour,
|
|
79
|
+
registry semantics).
|
|
80
|
+
- [`docs/compat-matrix.md`](../../docs/compat-matrix.md) — which
|
|
81
|
+
atrium release added which slot.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source-of-truth TypeScript declarations for the atrium host-extension
|
|
3
|
+
* contract. A host bundle imports these types so its registration calls
|
|
4
|
+
* are checked against the same shapes atrium's own consumer components
|
|
5
|
+
* read.
|
|
6
|
+
*
|
|
7
|
+
* The package version tracks atrium's image version (`^0.14` of this
|
|
8
|
+
* package implies "compatible with atrium 0.14.x"). New registry slots
|
|
9
|
+
* land here when they ship in atrium; bumping the package picks them
|
|
10
|
+
* up. A host that calls a method missing on the pinned major gets a
|
|
11
|
+
* TypeScript error before runtime — the runtime Proxy on
|
|
12
|
+
* `window.__ATRIUM_REGISTRY__` is a belt-and-braces fallback for
|
|
13
|
+
* version skew, not a substitute for typing.
|
|
14
|
+
*/
|
|
15
|
+
import type { ReactElement } from 'react';
|
|
16
|
+
/** Shape of `GET /users/me/context` — the atrium-owned RBAC view of the
|
|
17
|
+
* signed-in user. The bundled hook in `@brendanbank/atrium-host-bundle-utils/react`
|
|
18
|
+
* returns this exact shape. */
|
|
19
|
+
export interface UserContext {
|
|
20
|
+
id: number;
|
|
21
|
+
email: string;
|
|
22
|
+
full_name: string;
|
|
23
|
+
is_active: boolean;
|
|
24
|
+
roles: string[];
|
|
25
|
+
permissions: string[];
|
|
26
|
+
impersonating_from: {
|
|
27
|
+
id: number;
|
|
28
|
+
email: string;
|
|
29
|
+
full_name: string;
|
|
30
|
+
} | null;
|
|
31
|
+
}
|
|
32
|
+
/** Shape of `GET /admin/users` rows (and `/admin/users/{id}` responses).
|
|
33
|
+
* Hosts that render their own admin UIs against atrium's user list
|
|
34
|
+
* read this shape. The patch endpoint accepts `role_ids`; the read
|
|
35
|
+
* shape carries both `role_ids` and the human-readable `roles` codes. */
|
|
36
|
+
export interface AdminUserRow {
|
|
37
|
+
id: number;
|
|
38
|
+
email: string;
|
|
39
|
+
is_active: boolean;
|
|
40
|
+
is_verified: boolean;
|
|
41
|
+
full_name: string;
|
|
42
|
+
phone: string | null;
|
|
43
|
+
preferred_language: 'en' | 'nl';
|
|
44
|
+
role_ids: number[];
|
|
45
|
+
roles: string[];
|
|
46
|
+
}
|
|
47
|
+
/** A single notification row as the SPA sees it. `kind` is host-defined;
|
|
48
|
+
* `payload` is opaque JSON. `read_at` is null until the user clears the
|
|
49
|
+
* bell; `created_at` is the server-side timestamp. */
|
|
50
|
+
export interface AtriumNotification {
|
|
51
|
+
id: number;
|
|
52
|
+
kind: string;
|
|
53
|
+
payload: Record<string, unknown>;
|
|
54
|
+
read_at: string | null;
|
|
55
|
+
created_at: string;
|
|
56
|
+
}
|
|
57
|
+
/** SSE `notification` event published by `app.services.notifications.notify_user`.
|
|
58
|
+
* Same wire shape as the row's body — `kind` matches what
|
|
59
|
+
* `registerNotificationKind` listens on. */
|
|
60
|
+
export interface AtriumEvent {
|
|
61
|
+
kind: string;
|
|
62
|
+
payload: Record<string, unknown>;
|
|
63
|
+
}
|
|
64
|
+
export type AtriumEventHandler = (event: AtriumEvent) => void;
|
|
65
|
+
/** Layout width for a home-page widget. `narrow` matches atrium's default
|
|
66
|
+
* 680px column; `wide` extends to a comfortable dashboard column; `full`
|
|
67
|
+
* takes the whole panel inside `AppShell.Main`. Default `narrow`. */
|
|
68
|
+
export type HomeWidgetWidth = 'narrow' | 'wide' | 'full';
|
|
69
|
+
export interface HomeWidget {
|
|
70
|
+
key: string;
|
|
71
|
+
render: () => ReactElement;
|
|
72
|
+
width?: HomeWidgetWidth;
|
|
73
|
+
}
|
|
74
|
+
export interface RouteEntry {
|
|
75
|
+
key: string;
|
|
76
|
+
path: string;
|
|
77
|
+
/** Returns a fresh element each time the route mounts. Strongly
|
|
78
|
+
* preferred — see the host-bundle wrapper-element rationale in
|
|
79
|
+
* `docs/published-images.md`. Exactly one of `render` / `element`
|
|
80
|
+
* must be supplied. */
|
|
81
|
+
render?: () => ReactElement;
|
|
82
|
+
/** @deprecated Pass `render: () => element` instead. Captured
|
|
83
|
+
* elements share the same DOM node across navigations and can carry
|
|
84
|
+
* stale state. Kept for back-compat with hosts built against
|
|
85
|
+
* pre-0.12 atrium. */
|
|
86
|
+
element?: ReactElement;
|
|
87
|
+
/** Default `true`. Set false for public routes (e.g. host landing pages). */
|
|
88
|
+
requireAuth?: boolean;
|
|
89
|
+
/** Default `'shell'`. `'bare'` skips atrium's AppLayout wrapper. */
|
|
90
|
+
layout?: 'shell' | 'bare';
|
|
91
|
+
}
|
|
92
|
+
export interface NavItem {
|
|
93
|
+
key: string;
|
|
94
|
+
label: string;
|
|
95
|
+
to: string;
|
|
96
|
+
icon?: ReactElement;
|
|
97
|
+
/** Optional visibility predicate. Default: always visible. `me` is
|
|
98
|
+
* null until the SPA's auth probe resolves. */
|
|
99
|
+
condition?: (ctx: {
|
|
100
|
+
me: UserContext | null;
|
|
101
|
+
}) => boolean;
|
|
102
|
+
}
|
|
103
|
+
export interface AdminTab {
|
|
104
|
+
key: string;
|
|
105
|
+
label: string;
|
|
106
|
+
icon?: ReactElement;
|
|
107
|
+
/** Permission code; the tab is hidden for users without it. Omit to
|
|
108
|
+
* show the tab to every viewer with admin access. */
|
|
109
|
+
perm?: string;
|
|
110
|
+
/** Returns a fresh element each time the tab is selected. Strongly
|
|
111
|
+
* preferred — see `RouteEntry.render`. Exactly one of `render` /
|
|
112
|
+
* `element` must be supplied. */
|
|
113
|
+
render?: () => ReactElement;
|
|
114
|
+
/** @deprecated Pass `render: () => element` instead. */
|
|
115
|
+
element?: ReactElement;
|
|
116
|
+
}
|
|
117
|
+
/** Insertion slot inside `ProfilePage`'s vertical card stack. Default
|
|
118
|
+
* `'after-roles'` — the natural place for extra preferences. */
|
|
119
|
+
export type ProfileSlot = 'after-profile' | 'after-password' | 'after-2fa' | 'after-roles' | 'after-sessions' | 'before-delete';
|
|
120
|
+
export interface ProfileItem {
|
|
121
|
+
key: string;
|
|
122
|
+
/** Insertion slot. Default `'after-roles'`. */
|
|
123
|
+
slot?: ProfileSlot;
|
|
124
|
+
/** Optional visibility predicate. The profile page early-returns on a
|
|
125
|
+
* missing user, so `me` is never null when this fires. */
|
|
126
|
+
condition?: (ctx: {
|
|
127
|
+
me: UserContext;
|
|
128
|
+
}) => boolean;
|
|
129
|
+
render: () => ReactElement;
|
|
130
|
+
}
|
|
131
|
+
/** Per-kind renderer for a notification row. Atrium emits `{kind,
|
|
132
|
+
* payload}` rows but ships no built-in formatting — host apps register
|
|
133
|
+
* one renderer per kind they care about. */
|
|
134
|
+
export interface NotificationKindRenderer {
|
|
135
|
+
/** Notification `kind` string this renderer handles. Match is exact;
|
|
136
|
+
* no glob / prefix matching. Duplicate registrations for the same
|
|
137
|
+
* kind warn and last-write-wins. */
|
|
138
|
+
kind: string;
|
|
139
|
+
/** Detail-modal body. Receives the full row. */
|
|
140
|
+
render: (n: AtriumNotification) => ReactElement;
|
|
141
|
+
/** Compact summary for the bell + inbox row line and the modal title. */
|
|
142
|
+
title?: (n: AtriumNotification) => string;
|
|
143
|
+
/** App-internal href. When set, the row click navigates instead of
|
|
144
|
+
* opening the detail modal. */
|
|
145
|
+
href?: (n: AtriumNotification) => string;
|
|
146
|
+
}
|
|
147
|
+
/** Locale overlay registered by a host. `strings` is a flat
|
|
148
|
+
* i18next-style bundle (dot-paths or nested object — both accepted).
|
|
149
|
+
* Layered on top of atrium's shipped locale + admin overrides;
|
|
150
|
+
* precedence is shipped < admin overrides < host overlay. */
|
|
151
|
+
export interface LocaleOverlay {
|
|
152
|
+
locale: string;
|
|
153
|
+
strings: Record<string, unknown>;
|
|
154
|
+
}
|
|
155
|
+
/** The runtime-discovered registry exposed at `window.__ATRIUM_REGISTRY__`.
|
|
156
|
+
*
|
|
157
|
+
* Optional methods are slots that landed in a later atrium release
|
|
158
|
+
* than the one that introduced this type — type-narrow before calling
|
|
159
|
+
* if you intend to support older images, or use the runtime
|
|
160
|
+
* `__ATRIUM_VERSION__` global for explicit gating. The Proxy on the
|
|
161
|
+
* registry already turns calls to missing methods into a console
|
|
162
|
+
* warning + no-op; this is for clean TypeScript checking on top of
|
|
163
|
+
* that runtime safety net.
|
|
164
|
+
*
|
|
165
|
+
* When atrium adds a new slot, this type bumps and the slot becomes
|
|
166
|
+
* optional first; once a release window has passed and `^0.X` no
|
|
167
|
+
* longer covers the pre-slot images, the slot becomes required. */
|
|
168
|
+
export interface AtriumRegistry {
|
|
169
|
+
registerHomeWidget: (widget: HomeWidget) => void;
|
|
170
|
+
registerRoute: (route: RouteEntry) => void;
|
|
171
|
+
registerNavItem: (item: NavItem) => void;
|
|
172
|
+
registerAdminTab: (tab: AdminTab) => void;
|
|
173
|
+
registerProfileItem: (item: ProfileItem) => void;
|
|
174
|
+
registerNotificationKind: (renderer: NotificationKindRenderer) => void;
|
|
175
|
+
registerLocale: (overlay: LocaleOverlay) => void;
|
|
176
|
+
subscribeEvent: (kind: string, handler: AtriumEventHandler) => () => void;
|
|
177
|
+
}
|
|
178
|
+
declare global {
|
|
179
|
+
interface Window {
|
|
180
|
+
/** atrium's React instance. Host bundles read this so their
|
|
181
|
+
* wrapper elements can call `React.createElement(...)` without
|
|
182
|
+
* bundling a second React copy that atrium's reconciler would
|
|
183
|
+
* refuse to render. Available since the host-bundle pattern
|
|
184
|
+
* shipped (atrium 0.10+). */
|
|
185
|
+
React?: typeof import('react');
|
|
186
|
+
/** Backend version string (e.g. "0.14.0") mirrored from
|
|
187
|
+
* `GET /app-config` before the host bundle is imported, so
|
|
188
|
+
* import-time code can branch on it. Available since atrium
|
|
189
|
+
* 0.14.0; treat as best-effort on older images. */
|
|
190
|
+
__ATRIUM_VERSION__?: string;
|
|
191
|
+
/** The registry. Populated by atrium before the host bundle
|
|
192
|
+
* imports; host bundles read it and call its `register*` methods
|
|
193
|
+
* at module init. */
|
|
194
|
+
__ATRIUM_REGISTRY__?: AtriumRegistry;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
export {};
|
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@brendanbank/atrium-host-types",
|
|
3
|
+
"version": "0.15.0",
|
|
4
|
+
"description": "TypeScript declarations for the atrium host-extension contract: AtriumRegistry, UserContext, AdminUserRow, AtriumNotification, AtriumEvent. Source-of-truth shapes a host bundle types against, kept in sync with atrium's published image major.minor.",
|
|
5
|
+
"license": "BSD-2-Clause",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/react": "^19.2.14",
|
|
24
|
+
"react": "^19.2.5",
|
|
25
|
+
"typescript": "^6.0.3"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/brendanbank/atrium.git",
|
|
33
|
+
"directory": "packages/host-types"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.json",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
38
|
+
"clean": "rm -rf dist"
|
|
39
|
+
}
|
|
40
|
+
}
|