@cortejojicoy/admin-kit 0.1.8
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 +21 -0
- package/README.md +347 -0
- package/dist/client.cjs +950 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +334 -0
- package/dist/client.d.ts +334 -0
- package/dist/client.js +900 -0
- package/dist/client.js.map +1 -0
- package/dist/index.cjs +47 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.cjs +117 -0
- package/dist/middleware.cjs.map +1 -0
- package/dist/middleware.d.cts +28 -0
- package/dist/middleware.d.ts +28 -0
- package/dist/middleware.js +115 -0
- package/dist/middleware.js.map +1 -0
- package/dist/server.cjs +128 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +56 -0
- package/dist/server.d.ts +56 -0
- package/dist/server.js +122 -0
- package/dist/server.js.map +1 -0
- package/dist/types-N0f4k4Ie.d.cts +210 -0
- package/dist/types-N0f4k4Ie.d.ts +210 -0
- package/package.json +106 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kukux
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# @cortejojicoy/admin-kit
|
|
2
|
+
|
|
3
|
+
A pluggable Next.js 16 admin panel kit. Drop in a config, get an authenticated dashboard with a customizable sidebar, JWT/OAuth/custom auth, and modules.
|
|
4
|
+
|
|
5
|
+
- **Next.js 16 / React 19** — Works with both App Router and Pages Router.
|
|
6
|
+
- **Pluggable auth** — JWT by default; switch to OAuth or supply a custom provider.
|
|
7
|
+
- **Config-driven sidebar** — Sections, items, badges, roles, and per-user filtering.
|
|
8
|
+
- **Modules** — Self-contained feature packs that contribute nav, providers, and dashboard widgets.
|
|
9
|
+
- **Edge-safe middleware** — Token verification at the edge via Web Crypto.
|
|
10
|
+
- **Theme tokens** — Override colors and radii via CSS variables.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add @cortejojicoy/admin-kit
|
|
16
|
+
# or
|
|
17
|
+
npm install @cortejojicoy/admin-kit
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Peer deps (must be installed in the consumer): `next@>=16`, `react@>=19`, `react-dom@>=19`.
|
|
21
|
+
|
|
22
|
+
## 1. Define your config
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// admin.config.ts
|
|
26
|
+
import { defineAdminConfig } from '@cortejojicoy/admin-kit'
|
|
27
|
+
|
|
28
|
+
export const adminConfig = defineAdminConfig({
|
|
29
|
+
app: { name: 'Acme Admin' },
|
|
30
|
+
auth: {
|
|
31
|
+
provider: 'jwt',
|
|
32
|
+
jwt: {
|
|
33
|
+
endpoints: {
|
|
34
|
+
login: '/api/auth/login',
|
|
35
|
+
me: '/api/auth/me',
|
|
36
|
+
logout: '/api/auth/logout',
|
|
37
|
+
},
|
|
38
|
+
secret: process.env.JWT_SECRET, // only read on the server / in middleware
|
|
39
|
+
cookieName: 'acme_token',
|
|
40
|
+
},
|
|
41
|
+
loginPage: { path: '/login', title: 'Sign in to Acme' },
|
|
42
|
+
publicRoutes: ['/login', '/api/auth'],
|
|
43
|
+
},
|
|
44
|
+
navigation: {
|
|
45
|
+
sections: [
|
|
46
|
+
{
|
|
47
|
+
label: 'Workspace',
|
|
48
|
+
items: [
|
|
49
|
+
{ label: 'Dashboard', href: '/' },
|
|
50
|
+
{ label: 'Users', href: '/users', roles: ['admin'] },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 2. App Router
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
// app/layout.tsx
|
|
62
|
+
import { AdminProvider, AdminLayout, AppLink, useAppPathname } from '@cortejojicoy/admin-kit/client'
|
|
63
|
+
import { adminConfig } from '@/admin.config'
|
|
64
|
+
import { resolveConfig } from '@cortejojicoy/admin-kit'
|
|
65
|
+
|
|
66
|
+
const resolved = resolveConfig(adminConfig)
|
|
67
|
+
|
|
68
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
69
|
+
return (
|
|
70
|
+
<html>
|
|
71
|
+
<body>
|
|
72
|
+
<AdminProvider config={adminConfig}>
|
|
73
|
+
<Shell>{children}</Shell>
|
|
74
|
+
</AdminProvider>
|
|
75
|
+
</body>
|
|
76
|
+
</html>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function Shell({ children }: { children: React.ReactNode }) {
|
|
81
|
+
const pathname = useAppPathname()
|
|
82
|
+
return (
|
|
83
|
+
<AdminLayout config={resolved} Link={AppLink} currentPath={pathname}>
|
|
84
|
+
{children}
|
|
85
|
+
</AdminLayout>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 3. Pages Router
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
// pages/_app.tsx
|
|
94
|
+
import { AdminProvider } from '@cortejojicoy/admin-kit/client'
|
|
95
|
+
import { adminConfig } from '@/admin.config'
|
|
96
|
+
|
|
97
|
+
export default function App({ Component, pageProps }) {
|
|
98
|
+
return (
|
|
99
|
+
<AdminProvider config={adminConfig}>
|
|
100
|
+
<Component {...pageProps} />
|
|
101
|
+
</AdminProvider>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// pages/dashboard.tsx
|
|
106
|
+
import { withAdminLayout } from '@cortejojicoy/admin-kit/client'
|
|
107
|
+
import { resolveConfig } from '@cortejojicoy/admin-kit'
|
|
108
|
+
import { adminConfig } from '@/admin.config'
|
|
109
|
+
|
|
110
|
+
function DashboardPage() { return <div>Hello</div> }
|
|
111
|
+
export default withAdminLayout(DashboardPage, { config: resolveConfig(adminConfig), title: 'Dashboard' })
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 4. Edge middleware
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// middleware.ts (consumer root)
|
|
118
|
+
import { createAdminMiddleware } from '@cortejojicoy/admin-kit/middleware'
|
|
119
|
+
import { adminConfig } from './admin.config'
|
|
120
|
+
|
|
121
|
+
export default createAdminMiddleware(adminConfig)
|
|
122
|
+
export const config = { matcher: ['/((?!_next|api/auth|favicon).*)'] }
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 5. Server-side session
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
// app/api/me/route.ts
|
|
129
|
+
import { getServerSession } from '@cortejojicoy/admin-kit/server'
|
|
130
|
+
import { adminConfig } from '@/admin.config'
|
|
131
|
+
|
|
132
|
+
export async function GET(req: Request) {
|
|
133
|
+
const session = await getServerSession(adminConfig, req)
|
|
134
|
+
return Response.json({ user: session?.user ?? null })
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Sub-path exports
|
|
139
|
+
|
|
140
|
+
| Sub-path | Purpose |
|
|
141
|
+
| --------------------------------- | ------------------------------------------------------ |
|
|
142
|
+
| `@cortejojicoy/admin-kit` | Config helpers + types (safe everywhere) |
|
|
143
|
+
| `@cortejojicoy/admin-kit/client` | React components & hooks (client components) |
|
|
144
|
+
| `@cortejojicoy/admin-kit/server` | `getServerSession`, `verifyJWT`, cookie helpers |
|
|
145
|
+
| `@cortejojicoy/admin-kit/middleware` | `createAdminMiddleware` (edge-safe) |
|
|
146
|
+
|
|
147
|
+
## Modules
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import type { AdminModule } from '@cortejojicoy/admin-kit'
|
|
151
|
+
|
|
152
|
+
export const billingModule: AdminModule = {
|
|
153
|
+
id: 'billing',
|
|
154
|
+
navSections: [{
|
|
155
|
+
label: 'Billing',
|
|
156
|
+
items: [{ label: 'Invoices', href: '/billing/invoices' }],
|
|
157
|
+
}],
|
|
158
|
+
enabled: ({ user }) => user?.roles?.includes('admin') ?? false,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// then add to config.modules
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Versioning
|
|
165
|
+
|
|
166
|
+
We follow [Semantic Versioning](https://semver.org/) — the `MAJOR.MINOR.PATCH` triplet:
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
1.4.2
|
|
170
|
+
│ │ └── PATCH — bug fix, no API change (consumers auto-update safely)
|
|
171
|
+
│ └──── MINOR — new feature, backwards compat (consumers auto-update safely)
|
|
172
|
+
└────── MAJOR — breaking change (consumers must opt in)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
What counts as which:
|
|
176
|
+
|
|
177
|
+
| Change | Bump |
|
|
178
|
+
| ------------------------------------------------------- | ------- |
|
|
179
|
+
| Fix a sidebar render bug, JWT cookie parsing fix | PATCH |
|
|
180
|
+
| Add a new optional prop, add a new module slot | MINOR |
|
|
181
|
+
| Add a new sub-path export (no behavior change) | MINOR |
|
|
182
|
+
| Rename a public prop, remove an export, drop Next 16 | MAJOR |
|
|
183
|
+
| Change the shape of `AdminConfig.auth` | MAJOR |
|
|
184
|
+
| Change a default that consumers depended on | MAJOR |
|
|
185
|
+
|
|
186
|
+
Document every change in `CHANGELOG.md` under `## [Unreleased]` before
|
|
187
|
+
cutting a release — the release script promotes that section to the new
|
|
188
|
+
version automatically.
|
|
189
|
+
|
|
190
|
+
## Releasing
|
|
191
|
+
|
|
192
|
+
The recommended release path is GitHub Actions Trusted Publishing. Local
|
|
193
|
+
commands create and push the release commit/tag; CI performs the npm publish
|
|
194
|
+
without a long-lived `NPM_TOKEN` or local 2FA prompt.
|
|
195
|
+
|
|
196
|
+
**Option A — guarded script (recommended):**
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
./scripts/release.sh patch # 0.1.0 -> 0.1.1
|
|
200
|
+
./scripts/release.sh minor # 0.1.0 -> 0.2.0
|
|
201
|
+
./scripts/release.sh major # 0.1.0 -> 1.0.0
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
It refuses to release from a dirty tree or a non-`main` branch, runs
|
|
205
|
+
typecheck + build, bumps the version, updates the CHANGELOG, commits,
|
|
206
|
+
tags, pushes, then the pushed tag is published by CI.
|
|
207
|
+
|
|
208
|
+
**Option B — raw npm scripts + CI publish:**
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
npm run release:patch
|
|
212
|
+
npm run release:minor
|
|
213
|
+
npm run release:major
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
These wire into npm's `version` lifecycle:
|
|
217
|
+
|
|
218
|
+
| Hook | What runs |
|
|
219
|
+
| --------------- | ------------------------------------------------ |
|
|
220
|
+
| `preversion` | typecheck + build |
|
|
221
|
+
| `version` | promote `[Unreleased]` → new version in CHANGELOG |
|
|
222
|
+
| `postversion` | `git push --follow-tags` |
|
|
223
|
+
| `prepublishOnly` | clean + build before `npm publish` |
|
|
224
|
+
|
|
225
|
+
## Publishing to npm
|
|
226
|
+
|
|
227
|
+
`@cortejojicoy/admin-kit` is a **scoped** package, so publishes use
|
|
228
|
+
`--access public`. The normal path is CI Trusted Publishing:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# local release
|
|
232
|
+
./scripts/release.sh patch
|
|
233
|
+
|
|
234
|
+
# CI then runs
|
|
235
|
+
npm publish --access public --provenance
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
For a one-off local publish, npm accounts with publish 2FA need an OTP:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
NPM_OTP=<current-6-digit-code> npm run publish:npm:local
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
> "packagist" is the PHP/Composer registry — not relevant here. The JavaScript
|
|
245
|
+
> ecosystem publishes to **npm** (https://www.npmjs.com). The same tarball
|
|
246
|
+
> can also be mirrored to GitHub Packages by changing `publishConfig.registry`.
|
|
247
|
+
|
|
248
|
+
### CI/CD (GitHub Actions)
|
|
249
|
+
|
|
250
|
+
The workflow lives at [.github/workflows/ci.yml](.github/workflows/ci.yml). It's **push-driven**: every commit to `main` auto-publishes a new version.
|
|
251
|
+
|
|
252
|
+
| Trigger | What happens |
|
|
253
|
+
| ------------------------------------------------ | ----------------------------------------------------------- |
|
|
254
|
+
| `push` to `main` (normal commit) | `verify` + `release-on-push` → bump + tag + publish to npm |
|
|
255
|
+
| `push` to `main` (release commit, has `[skip ci]`) | nothing — loop guard |
|
|
256
|
+
| `pull_request` to `main` | `verify` only — never publishes |
|
|
257
|
+
| `push` of a `v*.*.*` tag | `verify` + `publish-on-tag` → publish that tag's version |
|
|
258
|
+
| `workflow_dispatch` (manual) | `verify` + `release-on-push` with chosen bump |
|
|
259
|
+
|
|
260
|
+
**Setup (one-time):**
|
|
261
|
+
|
|
262
|
+
1. **npmjs.com → Trusted Publishers** (under your org `@cortejojicoy` or directly on the package settings once it exists).
|
|
263
|
+
Add a new GitHub Actions trusted publisher:
|
|
264
|
+
|
|
265
|
+
| Field | Value |
|
|
266
|
+
| --- | --- |
|
|
267
|
+
| Package | `@cortejojicoy/admin-kit` |
|
|
268
|
+
| Organization/user | (your GitHub username/org owning the repo) |
|
|
269
|
+
| Repository | `admin-kit` |
|
|
270
|
+
| Workflow filename | `ci.yml` |
|
|
271
|
+
| Environment | (leave blank) |
|
|
272
|
+
|
|
273
|
+
This replaces the long-lived `NPM_TOKEN` — the workflow gets a short-lived OIDC token at publish time. No secret in GitHub needed.
|
|
274
|
+
|
|
275
|
+
2. **GitHub repo → Settings → Actions → General → Workflow permissions** → enable **Read and write** (so CI can push the bump commit and tag).
|
|
276
|
+
|
|
277
|
+
That's it. No `NPM_TOKEN` secret, no 2FA bypass. The package will publish with a **verified provenance attestation** (the green "Verified" badge on the npm page), proving it was built from the exact commit shown.
|
|
278
|
+
|
|
279
|
+
### How the bump size is chosen
|
|
280
|
+
|
|
281
|
+
For each push to `main`, CI reads the head commit message and picks a bump level. Precedence (first match wins):
|
|
282
|
+
|
|
283
|
+
1. **`workflow_dispatch` input** — the dropdown you pick in the UI overrides everything.
|
|
284
|
+
2. **Explicit tag in the message:** `[major]`, `[minor]`, or `[patch]` anywhere in the commit.
|
|
285
|
+
3. **Conventional commits:**
|
|
286
|
+
- `feat!: ...` or contains `BREAKING CHANGE` → **major**
|
|
287
|
+
- `feat: ...` / `feat(scope): ...` → **minor**
|
|
288
|
+
4. **Default** → **patch**
|
|
289
|
+
|
|
290
|
+
Examples:
|
|
291
|
+
|
|
292
|
+
| Commit message | Bump |
|
|
293
|
+
| ------------------------------------------- | ------ |
|
|
294
|
+
| `fix: race in sidebar collapse` | patch |
|
|
295
|
+
| `chore: bump deps` | patch |
|
|
296
|
+
| `feat: add OAuth callback handler` | minor |
|
|
297
|
+
| `feat(auth): GitHub provider` | minor |
|
|
298
|
+
| `feat!: drop AdminProvider props` | major |
|
|
299
|
+
| `refactor: rewrite layout [minor]` | minor (override) |
|
|
300
|
+
| `docs: tweak readme [skip release]` | **no release** |
|
|
301
|
+
|
|
302
|
+
### Opting out per-commit
|
|
303
|
+
|
|
304
|
+
Include `[skip release]` anywhere in the commit message and that push won't publish. Use it for README/docs/CI tweaks that shouldn't mint a version.
|
|
305
|
+
|
|
306
|
+
### The other two paths (kept as escape hatches)
|
|
307
|
+
|
|
308
|
+
- **Manual tag** — `git tag v0.2.0 && git push origin v0.2.0`. CI syncs `package.json` to the tag and publishes. Useful if you bumped locally with [`./scripts/release.sh`](scripts/release.sh) or want to ship an exact version.
|
|
309
|
+
- **Manual dispatch** — Actions tab → `ci` → **Run workflow** → pick the bump. Has a `dry_run` toggle for rehearsals.
|
|
310
|
+
|
|
311
|
+
In all three paths the **git tag is the source of truth**; `package.json` version in `main` can lag behind the latest npm version when CI publishes from a tag without committing back.
|
|
312
|
+
|
|
313
|
+
### Loop prevention
|
|
314
|
+
|
|
315
|
+
CI's release commit message is `chore(release): vX.Y.Z [skip ci]`. GitHub honors `[skip ci]` and won't re-trigger the workflow. As a belt-and-suspenders measure, the `release-on-push` job also has an `if:` that skips messages starting with `chore(release):` — so even if `[skip ci]` is stripped somehow, the loop still can't form.
|
|
316
|
+
|
|
317
|
+
## What gets pushed where
|
|
318
|
+
|
|
319
|
+
Two separate allowlists control this — don't conflate them.
|
|
320
|
+
|
|
321
|
+
**Git (`.gitignore`)** — what we *commit* to the repo:
|
|
322
|
+
|
|
323
|
+
| Tracked in git | Ignored in git |
|
|
324
|
+
| --------------------------- | --------------------------------------------------- |
|
|
325
|
+
| `src/**` | `node_modules/`, `dist/`, `.next/`, `.cache/` |
|
|
326
|
+
| `package.json`, `tsconfig.json`, `tsup.config.ts` | `*.log`, `.env`, `.env.*` (except `.env.example`) |
|
|
327
|
+
| `scripts/**`, `examples/**` (source only) | `examples/*/node_modules`, `examples/*/.next` |
|
|
328
|
+
| `README.md`, `CHANGELOG.md`, `LICENSE` | `coverage/`, `.eslintcache`, `*.tsbuildinfo` |
|
|
329
|
+
|
|
330
|
+
`dist/` is intentionally **not** committed — it's built fresh in CI and shipped
|
|
331
|
+
to npm only.
|
|
332
|
+
|
|
333
|
+
**npm (`files` in `package.json`)** — what we *publish* to the registry:
|
|
334
|
+
|
|
335
|
+
```json
|
|
336
|
+
"files": ["dist", "README.md", "LICENSE"]
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
That's a whitelist, so consumers only download `dist/`, the README, and the
|
|
340
|
+
LICENSE. Source `.ts` files, tests, scripts, and configs **never** go to npm.
|
|
341
|
+
We don't use `.npmignore` (the `files` field is single-source-of-truth — using
|
|
342
|
+
both invites drift). Run `npm pack --dry-run` to preview the exact tarball
|
|
343
|
+
contents before publishing.
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
MIT
|