@ghostly-solutions/auth 0.1.1 → 0.2.2

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 ADDED
@@ -0,0 +1,13 @@
1
+ Proprietary License
2
+
3
+ Copyright (c) Ghostly Solutions.
4
+ All rights reserved.
5
+
6
+ This repository and all source code, configuration, documentation, and related materials
7
+ are proprietary and confidential unless a separate written agreement states otherwise.
8
+
9
+ No permission is granted to use, copy, modify, distribute, sublicense, publish, or sell
10
+ any part of this repository without prior written authorization from Ghostly Solutions.
11
+
12
+ Third-party components included through declared package managers remain subject to their
13
+ own licenses.
package/README.md CHANGED
@@ -1,42 +1,44 @@
1
1
  # @ghostly-solutions/auth
2
2
 
3
+ ## Purpose
4
+
3
5
  Authentication SDK for Ghostly Solutions products.
4
6
 
5
- The SDK implements a fixed Keycloak redirect flow with Ghostly Auth API validation and typed session state.
7
+ This repository contains the npm package that implements a browser-first OAuth redirect flow
8
+ backed by a server-owned cookie session. Client code does not parse callback tokens and does not
9
+ define auth route handlers.
6
10
 
7
- ## Highlights
11
+ Repository type: `lib-repo`.
8
12
 
9
- - Fixed API contract (no runtime endpoint configuration).
10
- - Typed core client with deterministic error codes.
11
- - Dedicated callback flow with immediate token URL cleanup.
12
- - Session state with lazy revalidation.
13
- - Cross-tab synchronization via `BroadcastChannel`.
14
- - React adapter (`AuthProvider`, `useAuth`).
15
- - React callback helpers (`AuthCallbackHandler`, `useAuthCallbackRedirect`).
16
- - React session gate (`AuthSessionGate`).
17
- - Next adapter (server and client guards).
18
- - Next Auth Kit with ready route handlers (`mock` or `proxy`) and server-session helpers.
13
+ ## Architecture
19
14
 
20
- ## Fixed API Endpoints
15
+ Package entrypoints:
21
16
 
22
- - `GET /v1/auth/keycloak/login`
23
- - `POST /v1/auth/keycloak/validate`
24
- - `GET /v1/auth/me`
25
- - `POST /v1/auth/logout`
17
+ - `@ghostly-solutions/auth`: browser/core client
18
+ - `@ghostly-solutions/auth/react`: React provider and session gates
19
+ - `@ghostly-solutions/auth/next`: Next.js server helpers
20
+ - `@ghostly-solutions/auth/extension`: extension-oriented auth helpers
26
21
 
27
- ## Entry Points
22
+ The SDK assumes a fixed Ghostly Auth API surface and keeps token handling server-owned.
28
23
 
29
- - `@ghostly-solutions/auth`
30
- - `@ghostly-solutions/auth/react`
31
- - `@ghostly-solutions/auth/next`
24
+ ## Stack
32
25
 
33
- ## Install
26
+ - TypeScript
27
+ - tsup
28
+ - Vitest
29
+ - Biome
30
+ - npm
31
+
32
+ ## Build
33
+
34
+ Install and validate:
34
35
 
35
36
  ```bash
36
- npm install @ghostly-solutions/auth
37
+ npm ci
38
+ npm run check
37
39
  ```
38
40
 
39
- ## Development
41
+ Expanded commands:
40
42
 
41
43
  ```bash
42
44
  npm run lint
@@ -45,65 +47,204 @@ npm run test
45
47
  npm run build
46
48
  ```
47
49
 
48
- All CI and official workflows are npm-first.
50
+ Pack verification:
49
51
 
50
- Bun is optional for local use through aliases in `bun.json`.
52
+ ```bash
53
+ npm pack --dry-run
54
+ ```
51
55
 
52
- ## Quick Start
56
+ ## Run
53
57
 
54
- ```ts
55
- import { createAuthClient } from "@ghostly-solutions/auth";
58
+ This repository does not start a long-running application by default.
59
+
60
+ For local manual exploration:
61
+
62
+ ```bash
63
+ npm run demo
64
+ ```
65
+
66
+ Bun is optional for local demo shortcuts only.
67
+
68
+ ## Config
69
+
70
+ This package is configured by the consuming application at runtime, not by repository-level
71
+ environment files.
72
+
73
+ Core client configuration typically includes:
74
+
75
+ - `apiOrigin`
76
+ - `application`
77
+ - browser callback destination or extension auth hooks, depending on entrypoint
56
78
 
57
- const authClient = createAuthClient();
79
+ ## Dependencies
58
80
 
59
- // Start login flow
60
- authClient.login();
81
+ - browser login/logout against Ghostly Auth API
82
+ - session bootstrap for React and Next.js apps
83
+ - server-side session access for Next.js
84
+ - extension auth helpers for tab-based or custom auth flows
61
85
 
62
- // In /auth/callback route
63
- await authClient.completeCallbackRedirect();
86
+ Peer dependencies:
87
+
88
+ - `react >= 18`
89
+ - `react-dom >= 18`
90
+
91
+ Package artifacts are built from `src/` and published to npm. `dist/` and tarballs must not be
92
+ committed as release storage.
93
+
94
+ ## CI
95
+
96
+ GitLab CI validates this repository through `.gitlab-ci.yml`.
97
+
98
+ Current pipeline contract:
99
+
100
+ - `validate`: lint + typecheck
101
+ - `test`: unit tests
102
+ - `build`: bundle build + pack verification
103
+ - `release`: tag-driven npm publish gate
104
+
105
+ Green pipeline means:
106
+
107
+ - `npm run lint`
108
+ - `npm run typecheck`
109
+ - `npm run test`
110
+ - `npm run build`
111
+ - `npm pack --dry-run`
112
+
113
+ ## Release
114
+
115
+ The release artifact is the npm package `@ghostly-solutions/auth`.
116
+
117
+ Release path:
118
+
119
+ 1. merge with green CI
120
+ 2. create a semver tag
121
+ 3. let GitLab CI publish through the tag-gated release job
122
+
123
+ Current published version can be verified with:
124
+
125
+ ```bash
126
+ npm view @ghostly-solutions/auth version dist-tags --json
64
127
  ```
65
128
 
66
- ## Next.js "No-Glue" Integration
129
+ ## Troubleshooting
130
+
131
+ - auth contract mismatch: verify the backend exposes the required `/oauth/*` routes
132
+ - session fetch fails in Next.js: confirm headers are forwarded into `requireNextServerSession`
133
+ - package publish blocked: verify npm auth token and protected branch/tag permissions in GitLab
134
+ - local bundle drift: run `npm run check && npm pack --dry-run`
135
+
136
+ ## Ownership
137
+
138
+ - Repo owners: @kirill
67
139
 
68
- Use the high-level Next adapter in `@ghostly-solutions/auth/next`:
140
+ ## License
69
141
 
70
- - `getNextServerSession()`
71
- - `requireNextServerSession()`
72
- - `createNextAuthRouteHandlers({ mode: "mock" | "proxy" })`
142
+ See [LICENSE](/home/winicred/ghostly-solutions/@ghostly-solutions__auth/LICENSE). Public package availability does not override repository license terms unless Ghostly Solutions publishes separate licensing terms.
73
143
 
74
- This removes custom auth boilerplate from application code and keeps app-level integration thin.
144
+ ## Runtime Contract
75
145
 
76
- ## Callback Page Helper
146
+ The SDK assumes a fixed auth surface on your auth gateway:
147
+
148
+ - `GET /oauth/authorize`
149
+ - `GET /oauth/callback/provider`
150
+ - `GET /oauth/session`
151
+ - `POST /oauth/refresh`
152
+ - `POST /oauth/logout`
153
+
154
+ If your backend does not expose this contract, the SDK is not a drop-in fit.
155
+
156
+ ## Install
157
+
158
+ ```bash
159
+ npm install @ghostly-solutions/auth
160
+ ```
161
+
162
+ Peer dependencies:
163
+
164
+ - `react >= 18`
165
+ - `react-dom >= 18`
166
+
167
+ ## Core Usage
168
+
169
+ ```ts
170
+ import { createAuthClient } from "@ghostly-solutions/auth";
171
+
172
+ const auth = createAuthClient({
173
+ apiOrigin: "https://api.ghostlysolutions.com",
174
+ application: "admin",
175
+ });
176
+
177
+ await auth.init();
178
+ const session = await auth.getSession();
179
+
180
+ if (!session) {
181
+ auth.login({ returnTo: window.location.pathname });
182
+ }
183
+ ```
184
+
185
+ ## React Usage
77
186
 
78
187
  ```tsx
79
- import { AuthCallbackHandler } from "@ghostly-solutions/auth/react";
188
+ import { AuthProvider, AuthSessionGate } from "@ghostly-solutions/auth/react";
80
189
 
81
- export default function AuthCallbackPage() {
190
+ export function App() {
82
191
  return (
83
- <AuthCallbackHandler
84
- processing={<div>Signing you in...</div>}
85
- renderError={() => <div>Could not complete sign in.</div>}
86
- />
192
+ <AuthProvider
193
+ apiOrigin="https://api.ghostlysolutions.com"
194
+ application="admin"
195
+ >
196
+ <AuthSessionGate
197
+ loading={<div>Loading...</div>}
198
+ unauthorized={({ login }) => (
199
+ <button onClick={() => login({ returnTo: "/" })}>Sign in</button>
200
+ )}
201
+ authorized={(session) => <div>{session.email}</div>}
202
+ />
203
+ </AuthProvider>
87
204
  );
88
205
  }
89
206
  ```
90
207
 
91
- ## Error Handling
208
+ ## Next.js Usage
209
+
210
+ Use the server helpers to resolve the current session from request headers.
92
211
 
93
212
  ```ts
94
- import { AuthSdkError } from "@ghostly-solutions/auth";
95
-
96
- try {
97
- await authClient.requireSession();
98
- } catch (error) {
99
- if (error instanceof AuthSdkError) {
100
- if (error.code === "unauthorized") {
101
- authClient.login();
102
- }
103
- }
213
+ import { requireNextServerSession } from "@ghostly-solutions/auth/next";
214
+
215
+ export async function getServerData(headers: Headers) {
216
+ const session = await requireNextServerSession({
217
+ headers,
218
+ apiOrigin: "https://api.ghostlysolutions.com",
219
+ });
220
+
221
+ return { actorId: session.id };
104
222
  }
105
223
  ```
106
224
 
225
+ No Next.js route handlers are required.
226
+
227
+ ## Extension Usage
228
+
229
+ ```ts
230
+ import { createExtensionAuthClient } from "@ghostly-solutions/auth/extension";
231
+
232
+ const auth = createExtensionAuthClient({
233
+ apiOrigin: "https://api.ghostlysolutions.com",
234
+ application: "ghostguard-extension",
235
+ openAuthorizePage: async ({ authorizeUrl }) => {
236
+ await chrome.tabs.create({ url: authorizeUrl });
237
+ },
238
+ launchWebAuthFlow: async ({ authorizeUrl }) => {
239
+ await openAuthWindow(authorizeUrl);
240
+ },
241
+ });
242
+
243
+ await auth.loginWithTabFlow({
244
+ returnTo: "/oauth/complete",
245
+ });
246
+ ```
247
+
107
248
  ## Documentation
108
249
 
109
250
  - [Docs Index](./docs/index.md)
@@ -112,16 +253,4 @@ try {
112
253
  - [Integration Guide](./docs/integration-guide.md)
113
254
  - [Architecture](./docs/architecture.md)
114
255
  - [Development and CI](./docs/development-and-ci.md)
115
-
116
- ## Interactive Demo
117
-
118
- Run the simulated authentication page in this repository:
119
-
120
- ```bash
121
- npm run demo
122
- ```
123
-
124
- Then open `http://localhost:4100/` to test login, callback processing, session retrieval,
125
- and logout.
126
-
127
- Detailed demo docs: [demo/README.md](./demo/README.md).
256
+ - [Demo](./demo/README.md)
@@ -8,25 +8,33 @@ interface GhostlySession {
8
8
  permissions: string[];
9
9
  }
10
10
 
11
- interface ProcessCallbackResult {
12
- redirectTo: string;
13
- session: GhostlySession;
11
+ interface AuthClientOptions {
12
+ apiOrigin?: string;
13
+ application?: string;
14
+ }
15
+ interface AuthInitOptions {
16
+ forceRefresh?: boolean;
17
+ }
18
+ interface AuthInitResult {
19
+ session: GhostlySession | null;
20
+ status: "authenticated" | "unauthenticated";
14
21
  }
15
22
  interface LoginOptions {
16
23
  returnTo?: string;
24
+ application?: string;
17
25
  }
18
26
  interface SessionRequestOptions {
19
27
  forceRefresh?: boolean;
20
28
  }
21
29
  type SessionListener = (session: GhostlySession | null) => void;
22
30
  interface AuthClient {
23
- completeCallbackRedirect(): Promise<never>;
31
+ init(options?: AuthInitOptions): Promise<AuthInitResult>;
24
32
  getSession(options?: SessionRequestOptions): Promise<GhostlySession | null>;
25
33
  login(options?: LoginOptions): void;
26
34
  logout(): Promise<void>;
27
- processCallback(): Promise<ProcessCallbackResult>;
35
+ refresh(): Promise<GhostlySession | null>;
28
36
  requireSession(): Promise<GhostlySession>;
29
37
  subscribe(listener: SessionListener): () => void;
30
38
  }
31
39
 
32
- export type { AuthClient as A, GhostlySession as G, LoginOptions as L, ProcessCallbackResult as P, SessionListener as S, SessionRequestOptions as a };
40
+ export type { AuthClient as A, GhostlySession as G, LoginOptions as L, SessionListener as S, AuthClientOptions as a, AuthInitOptions as b, AuthInitResult as c, SessionRequestOptions as d };
@@ -1,7 +1,4 @@
1
1
  declare const authErrorCode: {
2
- readonly callbackMissingToken: "callback_missing_token";
3
- readonly callbackInvalidToken: "callback_invalid_token";
4
- readonly callbackValidationFailed: "callback_validation_failed";
5
2
  readonly unauthorized: "unauthorized";
6
3
  readonly networkError: "network_error";
7
4
  readonly apiError: "api_error";
@@ -0,0 +1,49 @@
1
+ import { G as GhostlySession, A as AuthClient, L as LoginOptions } from './auth-client-Cdkp07ii.js';
2
+
3
+ interface LaunchWebAuthFlowPayload {
4
+ authorizeUrl: string;
5
+ }
6
+ interface OpenAuthorizePagePayload {
7
+ authorizeUrl: string;
8
+ }
9
+ type PersistAccessToken = (token: ExtensionStoredAccessToken | null) => Promise<void> | void;
10
+ type ResolveSessionId = () => Promise<string | null>;
11
+ type RestoreAccessToken = (() => Promise<ExtensionStoredAccessToken | null>) | (() => ExtensionStoredAccessToken | null);
12
+ interface ExtensionAccessToken {
13
+ accessToken: string;
14
+ application: string;
15
+ expiresAt: string | null;
16
+ session: GhostlySession | null;
17
+ tokenType: string;
18
+ }
19
+ interface ExtensionAccessTokenRequestOptions {
20
+ forceRefresh?: boolean;
21
+ }
22
+ interface ExtensionStoredAccessToken extends ExtensionAccessToken {
23
+ }
24
+ interface ExtensionAuthClientOptions {
25
+ apiOrigin: string;
26
+ application?: string;
27
+ clearSessionId?: () => Promise<void> | void;
28
+ launchWebAuthFlow?: (payload: LaunchWebAuthFlowPayload) => Promise<void>;
29
+ openAuthorizePage?: (payload: OpenAuthorizePagePayload) => Promise<void>;
30
+ persistAccessToken?: PersistAccessToken;
31
+ resolveSessionId?: ResolveSessionId;
32
+ restoreAccessToken?: RestoreAccessToken;
33
+ }
34
+ interface ExtensionAuthClient extends AuthClient {
35
+ getAccessToken(options?: ExtensionAccessTokenRequestOptions): Promise<ExtensionAccessToken | null>;
36
+ loginWithTabFlow(options?: LoginOptions): Promise<void>;
37
+ loginWithWebAuthFlow(options?: LoginOptions): Promise<void>;
38
+ }
39
+ declare function createExtensionAuthClient(options: ExtensionAuthClientOptions): ExtensionAuthClient;
40
+
41
+ interface ChromeExtensionAuthClientOptions extends Omit<ExtensionAuthClientOptions, "clearSessionId" | "openAuthorizePage" | "persistAccessToken" | "resolveSessionId" | "restoreAccessToken"> {
42
+ accessTokenStorageKey?: string;
43
+ sessionCookieName?: string;
44
+ sessionStorageKey?: string;
45
+ tokenExpiresAtStorageKey?: string;
46
+ }
47
+ declare function createChromeExtensionAuthClient(options: ChromeExtensionAuthClientOptions): ExtensionAuthClient;
48
+
49
+ export { type ChromeExtensionAuthClientOptions, type ExtensionAccessToken, type ExtensionAccessTokenRequestOptions, type ExtensionAuthClient, type ExtensionAuthClientOptions, type ExtensionStoredAccessToken, createChromeExtensionAuthClient, createExtensionAuthClient };