@cobaltcore-dev/aurora 0.6.0 → 0.7.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/README.md CHANGED
@@ -52,19 +52,65 @@ export function App() {
52
52
 
53
53
  ### `createServer(config)`
54
54
 
55
- | Option | Type | Required | Default | Description |
56
- | --------------------------------- | --------- | -------- | -------------------------- | ---------------------------------------------------------------- |
57
- | `identityEndpoint` | `string` | yes | — | OpenStack Keystone v3 URL |
58
- | `policyDir` | `string` | yes | — | Absolute path to a directory of OpenStack policy YAML files |
59
- | `bffEndpoint` | `string` | no | `"/polaris-bff"` | URL prefix for all tRPC routes |
60
- | `viteRoot` | `string` | no | — | Directory that contains `dist/client/` in production |
61
- | `defaultEndpointInterface` | `string` | no | `"public"` | OpenStack service catalog interface |
62
- | `proxyUrl` | `string` | no | — | HTTP proxy for OpenStack calls (dev only, ignored in production) |
63
- | `cephRegion` | `string` | no | — | Ceph RGW region for S3 operations |
64
- | `imageMetadataExcludedProperties` | `string` | no | — | Comma-separated image metadata keys to hide in the UI |
65
- | `cookieName` | `string` | no | `"dashboard-session-auth"` | Override the session cookie name |
66
- | `crossDomainCookie` | `boolean` | no | `true` | Share cookie across subdomains |
67
- | `insecureCookies` | `boolean` | no | `false` | Disable `Secure` flag — only for HTTP-only local dev |
55
+ | Option | Type | Required | Default | Description |
56
+ | --------------------------------- | ------------- | -------- | -------------------------- | ---------------------------------------------------------------- |
57
+ | `identityEndpoint` | `string` | yes | — | OpenStack Keystone v3 URL |
58
+ | `policyDir` | `string` | yes | — | Absolute path to a directory of OpenStack policy YAML files |
59
+ | `bffEndpoint` | `string` | no | `"/polaris-bff"` | URL prefix for all tRPC routes |
60
+ | `viteRoot` | `string` | no | — | Directory that contains `dist/client/` in production |
61
+ | `defaultEndpointInterface` | `string` | no | `"public"` | OpenStack service catalog interface |
62
+ | `proxyUrl` | `string` | no | — | HTTP proxy for OpenStack calls (dev only, ignored in production) |
63
+ | `cephRegion` | `string` | no | — | Ceph RGW region for S3 operations |
64
+ | `imageMetadataExcludedProperties` | `string` | no | — | Comma-separated image metadata keys to hide in the UI |
65
+ | `cookieName` | `string` | no | `"dashboard-session-auth"` | Override the session cookie name |
66
+ | `crossDomainCookie` | `boolean` | no | `true` | Share cookie across subdomains |
67
+ | `insecureCookies` | `boolean` | no | `false` | Disable `Secure` flag — only for HTTP-only local dev |
68
+ | `routers` | `AnyRouter[]` | no | `[]` | Additional tRPC routers — see [Custom routers](#custom-routers) |
69
+
70
+ ## Custom routers
71
+
72
+ `createServer` accepts a `routers` option so consumers can add their own tRPC procedures that run alongside the built-in Aurora routes, sharing the same Fastify request context (session, cookies, OpenStack client).
73
+
74
+ ### Requirements
75
+
76
+ Routers passed via `routers` **must** be created with the `auroraRouter` function exported from `@cobaltcore-dev/aurora/server`. Using a different `initTRPC` instance produces an incompatible context type and will cause runtime failures when procedures access `ctx.openstack`, `ctx.validateSession`, etc.
77
+
78
+ For the full list of exported procedure builders and router utilities, see [`src/server/index.ts`](./src/server/index.ts).
79
+
80
+ ### Example
81
+
82
+ ```ts
83
+ import { z } from "zod"
84
+ import { auroraRouter, protectedProcedure, createServer } from "@cobaltcore-dev/aurora/server"
85
+
86
+ const customRouter = auroraRouter({
87
+ feedback: protectedProcedure.input(z.object({ message: z.string() })).mutation(async ({ input }) => {
88
+ // ctx.validateSession(), ctx.openstack — all available here
89
+ return { status: "received" }
90
+ }),
91
+ })
92
+
93
+ const server = await createServer({
94
+ identityEndpoint: "https://keystone.example.com/v3/",
95
+ policyDir: path.resolve(__dirname, "../policies"),
96
+ routers: [customRouter],
97
+ })
98
+ ```
99
+
100
+ The procedure above is reachable at `POST <bffEndpoint>/feedback` via the tRPC client.
101
+
102
+ ### Registering additional Fastify plugins
103
+
104
+ `createServer` returns the `FastifyInstance` before `.listen()` is called. You can register any Fastify plugin — metrics, tracing, custom middleware — on the returned instance before starting the server:
105
+
106
+ ```ts
107
+ const server = await createServer({ ... })
108
+
109
+ server.register(MyPlugin, { ... })
110
+ server.get("/healthz", async () => ({ ok: true }))
111
+
112
+ await server.listen({ host: "0.0.0.0", port: 4000 })
113
+ ```
68
114
 
69
115
  ### `<AuroraApp />`
70
116
 
@@ -1 +1 @@
1
- {"version":3,"file":"_auth-DXJkv9QO.mjs","names":["Outlet","useAuth","RouteComponent","component"],"sources":["../../src/client/routes/_auth.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, Outlet, redirect } from \"@tanstack/react-router\"\nimport { useAuth } from \"../store/AuthProvider\"\n\nexport const Route = createFileRoute(\"/_auth\")({\n component: RouteComponent,\n beforeLoad: async ({ context, location }) => {\n if (!context.auth?.isAuthenticated) {\n const token = await context.trpcClient?.auth.getCurrentUserSession.query()\n if (!token) {\n const redirectPath = location.pathname ? location.pathname : \"\"\n\n throw redirect({\n to: \"/\",\n search: { redirect: redirectPath },\n })\n }\n context.auth?.login(token.user, token.expires_at)\n }\n },\n})\n\nfunction RouteComponent() {\n useAuth()\n\n return <Outlet />\n}\n"],"mappings":";;;;AAqBA,SAASE,IAAAA;CAGP,OAFAD,EAAAA,GAEO,gBAAC,GAAA,CAAA,CAAA;AACV"}
1
+ {"version":3,"file":"_auth-DXJkv9QO.mjs","names":["Outlet","useAuth","RouteComponent","component"],"sources":["../../src/client/routes/_auth.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, Outlet, redirect } from \"@tanstack/react-router\"\nimport { useAuth } from \"../store/AuthProvider\"\n\nexport const Route = createFileRoute(\"/_auth\")({\n component: RouteComponent,\n beforeLoad: async ({ context, location }) => {\n // Always validate cookie first, even if client state says authenticated\n // This prevents race condition where cookie exists (e.g., from legacy dashboard)\n // but client state hasn't been initialized yet\n if (!context.auth?.isAuthenticated) {\n const token = await context.trpcClient?.auth.getCurrentUserSession.query()\n if (token) {\n // Update client state immediately when cookie is valid\n context.auth?.login(token.user, token.expires_at)\n return // Continue to route\n }\n }\n\n // Only redirect if still not authenticated after cookie validation\n if (!context.auth?.isAuthenticated) {\n const redirectPath = location.pathname ? location.pathname : \"\"\n\n throw redirect({\n to: \"/\",\n search: { redirect: redirectPath },\n })\n }\n },\n})\n\nfunction RouteComponent() {\n useAuth()\n\n return <Outlet />\n}\n"],"mappings":";;;;AA8BA,SAASE,IAAAA;CAGP,OAFAD,EAAAA,GAEO,gBAAC,GAAA,CAAA,CAAA;AACV"}
@@ -290,13 +290,16 @@ var Ue = j("/about")({ component: M(() => import("./about-Bo9vxGHy.mjs"), "compo
290
290
  component: M(() => import("./_auth-DXJkv9QO.mjs"), "component"),
291
291
  beforeLoad: async ({ context: e, location: t }) => {
292
292
  if (!e.auth?.isAuthenticated) {
293
- let n = await e.trpcClient?.auth.getCurrentUserSession.query();
294
- if (!n) throw N({
295
- to: "/",
296
- search: { redirect: t.pathname ? t.pathname : "" }
297
- });
298
- e.auth?.login(n.user, n.expires_at);
293
+ let t = await e.trpcClient?.auth.getCurrentUserSession.query();
294
+ if (t) {
295
+ e.auth?.login(t.user, t.expires_at);
296
+ return;
297
+ }
299
298
  }
299
+ if (!e.auth?.isAuthenticated) throw N({
300
+ to: "/",
301
+ search: { redirect: t.pathname ? t.pathname : "" }
302
+ });
300
303
  }
301
304
  });
302
305
  //#endregion