@neog-cloud/neog-api-client 0.1.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/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # Neog Auth Client
2
+
3
+ Pacote TypeScript reutilizável para autenticação e consumo da API da plataforma neog.
4
+
5
+ ## Instalação
6
+
7
+ ```bash
8
+ npm install @neog-cloud/neog-api-client
9
+ ```
10
+
11
+ ## Configuração
12
+
13
+ ```ts
14
+ import { createNeogAuth } from "@neog-cloud/neog-api-client";
15
+
16
+ const { AuthProvider, useAuth, createNeogClient } = createNeogAuth({
17
+ baseUrl: "https://api_neog",
18
+ authBaseUrl: "https://iam_neog",
19
+ authRealm: "__REALM__",
20
+ authEndpoint: "/realms/{realm}/protocol/openid-connect/token",
21
+ authRequestFormat: "form",
22
+ authGrantType: "password",
23
+ authScope: "openid profile email",
24
+ clientId: "app-id",
25
+ clientSecret: "secret"
26
+ });
27
+ ```
28
+
29
+ ## Variáveis de ambiente (exemplo local)
30
+
31
+ No app de exemplo (Vite), os valores sensíveis são lidos de um arquivo local de ambiente. Crie um arquivo `.env.local` na pasta do app e preencha as variáveis abaixo (o arquivo fica ignorado por padrão pelo `.gitignore` via `*.local`).
32
+
33
+ ```dotenv
34
+ VITE_NEOG_BASE_URL=
35
+ VITE_NEOG_AUTH_BASE_URL=
36
+ VITE_NEOG_AUTH_REALM=
37
+ VITE_NEOG_AUTH_ENDPOINT=/realms/{realm}/protocol/openid-connect/token
38
+ VITE_NEOG_AUTH_REQUEST_FORMAT=form
39
+ VITE_NEOG_AUTH_GRANT_TYPE=password
40
+ VITE_NEOG_AUTH_SCOPE=openid profile email
41
+ VITE_NEOG_CLIENT_ID=
42
+ VITE_NEOG_CLIENT_SECRET=
43
+ ```
44
+
45
+ No exemplo, o `createNeogAuth` usa essas variáveis, evitando valores fixos no repositório.
46
+
47
+ ## AuthProvider e useAuth
48
+
49
+ ```tsx
50
+ function App() {
51
+ return (
52
+ <AuthProvider>
53
+ <Routes />
54
+ </AuthProvider>
55
+ );
56
+ }
57
+
58
+ function LoginButton() {
59
+ const { login, logout, isAuthenticated, loading } = useAuth();
60
+ return (
61
+ <div>
62
+ <button disabled={loading} onClick={() => login("user", "pass")}>Login</button>
63
+ <button onClick={logout}>Logout</button>
64
+ <span>{isAuthenticated ? "ok" : "off"}</span>
65
+ </div>
66
+ );
67
+ }
68
+ ```
69
+
70
+ ## NeogClient.post
71
+
72
+ ```ts
73
+ const client = createNeogClient();
74
+
75
+ const response = await client.get<{ id: string }>("/status");
76
+
77
+ ```
78
+
79
+ ## Guia de migração (resumido)
80
+
81
+ 1. Instale o pacote:
82
+ ```bash
83
+ npm install @neog-cloud/neog-api-client
84
+ ```
85
+ 2. Crie a instância:
86
+ ```ts
87
+ import { createNeogAuth } from "@neog-cloud/neog-api-client";
88
+
89
+ const { AuthProvider, useAuth, createNeogClient } = createNeogAuth({
90
+ baseUrl: "https://api_neog",
91
+ authBaseUrl: "https://iam_neog",
92
+ authRealm: "__REALM__",
93
+ authEndpoint: "/realms/{realm}/protocol/openid-connect/token",
94
+ authRequestFormat: "form",
95
+ authGrantType: "password",
96
+ authScope: "openid profile email",
97
+ clientId: "app-id",
98
+ clientSecret: "secret",
99
+ });
100
+ ```
101
+ 3. Substitua o AuthProvider local:
102
+ ```tsx
103
+ function App() {
104
+ return (
105
+ <AuthProvider>
106
+ <Routes />
107
+ </AuthProvider>
108
+ );
109
+ }
110
+ ```
111
+ 4. Substitua os imports de `useAuth` locais pelos do pacote (mesmos campos).
112
+ 5. Substitua as chamadas HTTP por `createNeogClient().post(...)`.
113
+
114
+ ## Persistência e refresh
115
+
116
+ - Tokens são persistidos em `localStorage` na chave configurável (default: `neog_auth`).
117
+ - Em caso de `401`, o cliente tenta refresh com `tokenRefreshEndpoint`.
118
+ - Se a API não fornecer refresh token, um `401` exige novo login.
119
+
120
+ ## Segurança
121
+
122
+ O uso de `clientSecret` no frontend expõe o segredo no bundle. Esta configuração deve ser usada apenas em ambientes controlados e/ou temporariamente, até a adoção de um fluxo mais seguro (ex: BFF ou PKCE).
123
+
124
+ ## Desenvolvimento
125
+
126
+ ```bash
127
+ npm run build
128
+ npm test
129
+ ```
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import { AuthContextType, AuthState } from "./types";
3
+ import { NeogAuthOptions } from "./options";
4
+ export type AuthProviderFactory = {
5
+ AuthProvider: React.FC<{
6
+ children: React.ReactNode;
7
+ }>;
8
+ useAuth: () => AuthContextType;
9
+ getToken: () => string | null;
10
+ setToken: (token: string | null, refreshToken?: string | null, user?: AuthState["user"]) => void;
11
+ logout: () => void;
12
+ refreshAccessToken: () => Promise<string | null>;
13
+ };
14
+ export declare const createAuthProvider: (options: NeogAuthOptions) => AuthProviderFactory;
@@ -0,0 +1,27 @@
1
+ export type NeogAuthOptions = {
2
+ baseUrl: string;
3
+ authBaseUrl?: string;
4
+ authRealm?: string;
5
+ authEndpoint: string;
6
+ authRequestFormat?: "json" | "form";
7
+ authGrantType?: string;
8
+ authScope?: string;
9
+ clientId: string;
10
+ clientSecret?: string;
11
+ storageKey?: string;
12
+ tokenRefreshEndpoint?: string;
13
+ requestTimeoutMs?: number;
14
+ onRequestLog?: (info: {
15
+ url: string;
16
+ method: string;
17
+ }) => void;
18
+ onResponseLog?: (info: {
19
+ url: string;
20
+ status: number;
21
+ }) => void;
22
+ onErrorLog?: (info: {
23
+ url: string;
24
+ status?: number;
25
+ message: string;
26
+ }) => void;
27
+ };
@@ -0,0 +1,13 @@
1
+ export interface StoredAuthState {
2
+ accessToken: string | null;
3
+ refreshToken?: string | null;
4
+ expiresAt?: number | null;
5
+ user?: {
6
+ id: string;
7
+ name?: string;
8
+ email?: string;
9
+ } | null;
10
+ }
11
+ export declare const saveAuthState: (storageKey: string, state: StoredAuthState) => void;
12
+ export declare const loadAuthState: (storageKey: string) => StoredAuthState | null;
13
+ export declare const clearAuthState: (storageKey: string) => void;
@@ -0,0 +1,37 @@
1
+ export interface AuthContextType {
2
+ token: string | null;
3
+ refreshToken?: string | null;
4
+ user?: {
5
+ id: string;
6
+ name?: string;
7
+ email?: string;
8
+ } | null;
9
+ isAuthenticated: boolean;
10
+ loading: boolean;
11
+ error?: string | null;
12
+ login: (username: string, password: string) => Promise<void>;
13
+ logout: () => void;
14
+ getToken: () => string | null;
15
+ setToken?: (token: string, refreshToken?: string) => void;
16
+ }
17
+ export type AuthState = {
18
+ token: string | null;
19
+ refreshToken?: string | null;
20
+ user?: {
21
+ id: string;
22
+ name?: string;
23
+ email?: string;
24
+ } | null;
25
+ isAuthenticated: boolean;
26
+ };
27
+ export type TokenResponse = {
28
+ access_token: string;
29
+ refresh_token?: string;
30
+ expires_in?: number;
31
+ expires_at?: number;
32
+ user?: {
33
+ id: string;
34
+ name?: string;
35
+ email?: string;
36
+ } | null;
37
+ };
@@ -0,0 +1,2 @@
1
+ import { AuthContextType } from "./types";
2
+ export type UseAuthHook = () => AuthContextType;
@@ -0,0 +1,29 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { ClientOptions, NeogClient } from "./types";
3
+ export type RefreshTokenHandler = () => Promise<string | null>;
4
+ export type GetTokenHandler = () => string | null;
5
+ export type LogoutHandler = () => void;
6
+ export type CreateClientDeps = {
7
+ baseUrl: string;
8
+ getToken: GetTokenHandler;
9
+ refreshToken: RefreshTokenHandler;
10
+ logout: LogoutHandler;
11
+ requestTimeoutMs?: number;
12
+ defaultHeaders?: Record<string, string>;
13
+ onRequestLog?: (info: {
14
+ url: string;
15
+ method: string;
16
+ }) => void;
17
+ onResponseLog?: (info: {
18
+ url: string;
19
+ status: number;
20
+ }) => void;
21
+ onErrorLog?: (info: {
22
+ url: string;
23
+ status?: number;
24
+ message: string;
25
+ }) => void;
26
+ };
27
+ export declare const createNeogClient: (deps: CreateClientDeps, opts?: ClientOptions) => NeogClient & {
28
+ __axios?: AxiosInstance;
29
+ };
@@ -0,0 +1,40 @@
1
+ export interface Response<T> {
2
+ status: "success" | "error" | "valid" | "unchecked" | "warning";
3
+ message?: string;
4
+ tecnicalMessage?: string;
5
+ count: number;
6
+ page: number;
7
+ version: string;
8
+ objects: T[];
9
+ }
10
+ export type Operator = ">" | "<" | "=" | ">=" | "<=" | "like" | "is null" | "is not null" | "" | "in" | "eq" | "ne" | "gt" | "ge" | "lt" | "le" | "notLike" | "notIn" | "isNull" | "isNotNull" | "between" | "notBetween";
11
+ export interface FilterField {
12
+ column: string;
13
+ type?: string;
14
+ value?: any;
15
+ operator: Operator;
16
+ caption?: string;
17
+ }
18
+ export interface OrderField {
19
+ column: string;
20
+ direction: "asc" | "desc";
21
+ }
22
+ export interface Request<T> {
23
+ compRefid?: string;
24
+ branchRefid?: string;
25
+ version: string;
26
+ message?: string;
27
+ objects?: T[];
28
+ filters?: FilterField[];
29
+ orderBy?: OrderField[];
30
+ params?: FilterField[];
31
+ }
32
+ export type ClientOptions = {
33
+ timeoutMs?: number;
34
+ headers?: Record<string, string>;
35
+ };
36
+ export interface NeogClient {
37
+ post<TRequest, TResponse>(methodPath: string, body: Request<TRequest>): Promise<Response<TResponse>>;
38
+ setAuthHeader(token: string | null): void;
39
+ get<TResponse>(path: string, params?: any): Promise<TResponse>;
40
+ }