@ogcio/sag-client 0.2.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 +533 -0
- package/dist/auth.d.ts +55 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +154 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +93 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +118 -0
- package/dist/client.js.map +1 -0
- package/dist/fetcher.d.ts +39 -0
- package/dist/fetcher.d.ts.map +1 -0
- package/dist/fetcher.js +141 -0
- package/dist/fetcher.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/onboarding.d.ts +68 -0
- package/dist/onboarding.d.ts.map +1 -0
- package/dist/onboarding.js +67 -0
- package/dist/onboarding.js.map +1 -0
- package/dist/react/index.d.ts +15 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +16 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/provider.d.ts +22 -0
- package/dist/react/provider.d.ts.map +1 -0
- package/dist/react/provider.js +31 -0
- package/dist/react/provider.js.map +1 -0
- package/dist/react/use-auth.d.ts +13 -0
- package/dist/react/use-auth.d.ts.map +1 -0
- package/dist/react/use-auth.js +84 -0
- package/dist/react/use-auth.js.map +1 -0
- package/dist/react/use-gateway-fetch.d.ts +29 -0
- package/dist/react/use-gateway-fetch.d.ts.map +1 -0
- package/dist/react/use-gateway-fetch.js +47 -0
- package/dist/react/use-gateway-fetch.js.map +1 -0
- package/dist/react/use-gateway-mutation.d.ts +32 -0
- package/dist/react/use-gateway-mutation.d.ts.map +1 -0
- package/dist/react/use-gateway-mutation.js +58 -0
- package/dist/react/use-gateway-mutation.js.map +1 -0
- package/dist/react/use-onboarding-guard.d.ts +91 -0
- package/dist/react/use-onboarding-guard.d.ts.map +1 -0
- package/dist/react/use-onboarding-guard.js +140 -0
- package/dist/react/use-onboarding-guard.js.map +1 -0
- package/dist/react/use-public-servant-guard.d.ts +70 -0
- package/dist/react/use-public-servant-guard.d.ts.map +1 -0
- package/dist/react/use-public-servant-guard.js +79 -0
- package/dist/react/use-public-servant-guard.js.map +1 -0
- package/dist/roles.d.ts +67 -0
- package/dist/roles.d.ts.map +1 -0
- package/dist/roles.js +93 -0
- package/dist/roles.js.map +1 -0
- package/dist/types.d.ts +131 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +28 -0
- package/dist/types.js.map +1 -0
- package/package.json +79 -0
package/dist/auth.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone authentication helpers for the Secure API Gateway.
|
|
3
|
+
*
|
|
4
|
+
* These are pure functions — no React, no framework dependency.
|
|
5
|
+
* They accept `gatewayUrl` (and optionally `appName`) so they
|
|
6
|
+
* can be called without a SagClient instance.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Check if the user is authenticated against the gateway.
|
|
10
|
+
*/
|
|
11
|
+
export async function checkAuth(gatewayUrl) {
|
|
12
|
+
try {
|
|
13
|
+
const res = await fetch(`${gatewayUrl}/auth/status`, {
|
|
14
|
+
credentials: "include",
|
|
15
|
+
});
|
|
16
|
+
return (await res.json());
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.error("Error checking auth", error);
|
|
20
|
+
return { authenticated: false };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Check if the authentication service (Logto) is reachable.
|
|
25
|
+
*/
|
|
26
|
+
export async function checkHealth(gatewayUrl) {
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(`${gatewayUrl}/auth/health`, {
|
|
29
|
+
credentials: "include",
|
|
30
|
+
});
|
|
31
|
+
const data = (await res.json());
|
|
32
|
+
return { available: res.ok && data.status === "healthy" };
|
|
33
|
+
}
|
|
34
|
+
catch (_a) {
|
|
35
|
+
return { available: false };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Invalidate the current server session so the next sign-in
|
|
40
|
+
* fetches fresh claims. Used after onboarding completes (the user
|
|
41
|
+
* gains new roles that must appear in the next ID token).
|
|
42
|
+
*/
|
|
43
|
+
export async function invalidateSession(gatewayUrl) {
|
|
44
|
+
await fetch(`${gatewayUrl}/auth/invalidate-session`, {
|
|
45
|
+
method: "POST",
|
|
46
|
+
credentials: "include",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Fetch structured organization data for the authenticated user.
|
|
51
|
+
* Requires an active session. Returns an empty array if not authenticated.
|
|
52
|
+
*/
|
|
53
|
+
export async function fetchOrganizations(gatewayUrl) {
|
|
54
|
+
var _a;
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(`${gatewayUrl}/auth/organizations`, {
|
|
57
|
+
credentials: "include",
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok)
|
|
60
|
+
return [];
|
|
61
|
+
const data = (await res.json());
|
|
62
|
+
return (_a = data.organizations) !== null && _a !== void 0 ? _a : [];
|
|
63
|
+
}
|
|
64
|
+
catch (_b) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Set the user's currently selected organization on the gateway.
|
|
70
|
+
* Persists as a signed cookie.
|
|
71
|
+
*/
|
|
72
|
+
export async function selectOrganization(gatewayUrl, organizationId) {
|
|
73
|
+
try {
|
|
74
|
+
const res = await fetch(`${gatewayUrl}/auth/select-organization`, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
credentials: "include",
|
|
77
|
+
headers: { "Content-Type": "application/json" },
|
|
78
|
+
body: JSON.stringify({ organizationId }),
|
|
79
|
+
});
|
|
80
|
+
return res.ok;
|
|
81
|
+
}
|
|
82
|
+
catch (_a) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get the user's currently selected organization from the gateway.
|
|
88
|
+
*/
|
|
89
|
+
export async function getSelectedOrganization(gatewayUrl) {
|
|
90
|
+
var _a;
|
|
91
|
+
try {
|
|
92
|
+
const res = await fetch(`${gatewayUrl}/auth/selected-organization`, {
|
|
93
|
+
credentials: "include",
|
|
94
|
+
});
|
|
95
|
+
if (!res.ok)
|
|
96
|
+
return null;
|
|
97
|
+
const data = (await res.json());
|
|
98
|
+
return (_a = data.organizationId) !== null && _a !== void 0 ? _a : null;
|
|
99
|
+
}
|
|
100
|
+
catch (_b) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clear the user's organization selection on the gateway.
|
|
106
|
+
*/
|
|
107
|
+
export async function clearSelectedOrganization(gatewayUrl) {
|
|
108
|
+
try {
|
|
109
|
+
const res = await fetch(`${gatewayUrl}/auth/selected-organization`, {
|
|
110
|
+
method: "DELETE",
|
|
111
|
+
credentials: "include",
|
|
112
|
+
});
|
|
113
|
+
return res.ok;
|
|
114
|
+
}
|
|
115
|
+
catch (_a) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Submit a hidden form via POST to trigger a full-page navigation.
|
|
121
|
+
*
|
|
122
|
+
* Using POST (instead of GET via window.location.href) provides CSRF
|
|
123
|
+
* protection: browsers do not send sameSite:"lax" cookies on cross-site
|
|
124
|
+
* POST requests, so an attacker page cannot trigger auth actions.
|
|
125
|
+
*/
|
|
126
|
+
function postNavigate(url) {
|
|
127
|
+
const form = document.createElement("form");
|
|
128
|
+
form.method = "POST";
|
|
129
|
+
form.action = url;
|
|
130
|
+
document.body.appendChild(form);
|
|
131
|
+
form.submit();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Redirect the user to the gateway sign-in endpoint.
|
|
135
|
+
*
|
|
136
|
+
* @param gatewayUrl - Secure API Gateway base URL.
|
|
137
|
+
* @param app - Application name registered in the gateway.
|
|
138
|
+
* @param options - Optional sign-in options (connector, redirectUrl).
|
|
139
|
+
*/
|
|
140
|
+
export function signIn(gatewayUrl, app, options) {
|
|
141
|
+
const params = new URLSearchParams({ app });
|
|
142
|
+
if (options === null || options === void 0 ? void 0 : options.connector)
|
|
143
|
+
params.set("connector", options.connector);
|
|
144
|
+
if (options === null || options === void 0 ? void 0 : options.redirectUrl)
|
|
145
|
+
params.set("redirectUrl", options.redirectUrl);
|
|
146
|
+
postNavigate(`${gatewayUrl}/auth/sign-in?${params.toString()}`);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Redirect the user to the gateway sign-out endpoint.
|
|
150
|
+
*/
|
|
151
|
+
export function signOut(gatewayUrl, app) {
|
|
152
|
+
postNavigate(`${gatewayUrl}/auth/sign-out?app=${encodeURIComponent(app)}`);
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SagClient — framework-agnostic client for the Secure API Gateway.
|
|
3
|
+
*
|
|
4
|
+
* Encapsulates `gatewayUrl` and `appName` so consumers don't have to
|
|
5
|
+
* pass them to every function call.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* const client = new SagClient({ gatewayUrl: "http://localhost:3333", appName: "cars" })
|
|
9
|
+
* const status = await client.checkAuth()
|
|
10
|
+
* const { data } = await client.fetch<Car[]>("/cars")
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
import type { AuthStatus, GatewayFetchOptions, MutationMethod, OrganizationInfo, SagClientConfig, SignInOptions } from "./types";
|
|
14
|
+
export declare class SagClient {
|
|
15
|
+
readonly gatewayUrl: string;
|
|
16
|
+
readonly appName: string;
|
|
17
|
+
private readonly onSessionExpired?;
|
|
18
|
+
constructor(config: SagClientConfig);
|
|
19
|
+
/** Check if the user is authenticated. */
|
|
20
|
+
checkAuth(): Promise<AuthStatus>;
|
|
21
|
+
/** Check if the authentication service (Logto) is reachable. */
|
|
22
|
+
checkHealth(): Promise<{
|
|
23
|
+
available: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Redirect the user to the gateway sign-in endpoint.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Optional sign-in options (connector selection, redirect URL).
|
|
29
|
+
*/
|
|
30
|
+
signIn(options?: SignInOptions): void;
|
|
31
|
+
/** Redirect the user to the gateway sign-out endpoint. */
|
|
32
|
+
signOut(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Invalidate the server session so the next sign-in fetches fresh claims.
|
|
35
|
+
* Use after onboarding or any flow that changes the user's roles.
|
|
36
|
+
*/
|
|
37
|
+
invalidateSession(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Fetch structured organization data for the authenticated user.
|
|
40
|
+
* Requires an active session. Returns an empty array if not authenticated.
|
|
41
|
+
*/
|
|
42
|
+
fetchOrganizations(): Promise<OrganizationInfo[]>;
|
|
43
|
+
/** Set the user's currently selected organization. */
|
|
44
|
+
selectOrganization(organizationId: string): Promise<boolean>;
|
|
45
|
+
/** Get the user's currently selected organization ID. */
|
|
46
|
+
getSelectedOrganization(): Promise<string | null>;
|
|
47
|
+
/** Clear the user's organization selection. */
|
|
48
|
+
clearSelectedOrganization(): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Fetch data from the gateway.
|
|
51
|
+
*
|
|
52
|
+
* @param path - Gateway path (e.g. "/cars", "/weather")
|
|
53
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
54
|
+
*/
|
|
55
|
+
fetch<T>(path: string, options?: GatewayFetchOptions): Promise<{
|
|
56
|
+
data: T;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Create a fetcher function bound to this client's configuration.
|
|
60
|
+
*
|
|
61
|
+
* The returned function accepts an absolute URL and returns
|
|
62
|
+
* `{ data: T }`. Suitable for passing to SWR, TanStack Query,
|
|
63
|
+
* or calling directly.
|
|
64
|
+
*
|
|
65
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
66
|
+
*/
|
|
67
|
+
createFetcher<T>(options?: GatewayFetchOptions): (url: string) => Promise<{
|
|
68
|
+
data: T;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Perform a mutation (POST, PUT, PATCH, DELETE) through the gateway.
|
|
72
|
+
*
|
|
73
|
+
* @param path - Gateway path (e.g. "/profile/api/v1/users/123")
|
|
74
|
+
* @param method - HTTP method
|
|
75
|
+
* @param body - Optional JSON-serializable request body
|
|
76
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
77
|
+
*/
|
|
78
|
+
mutate<T>(path: string, method: MutationMethod, body?: unknown, options?: GatewayFetchOptions): Promise<{
|
|
79
|
+
data: T;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Create a mutator function bound to this client's configuration.
|
|
83
|
+
*
|
|
84
|
+
* The returned function accepts an absolute URL, HTTP method, and
|
|
85
|
+
* optional body. Suitable for imperative mutation calls.
|
|
86
|
+
*
|
|
87
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
88
|
+
*/
|
|
89
|
+
createMutator<T>(options?: GatewayFetchOptions): (url: string, method: MutationMethod, body?: unknown) => Promise<{
|
|
90
|
+
data: T;
|
|
91
|
+
}>;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAcH,OAAO,KAAK,EACV,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACd,MAAM,SAAS,CAAA;AAEhB,qBAAa,SAAS;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAY;gBAElC,MAAM,EAAE,eAAe;IAQnC,0CAA0C;IAC1C,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC;IAIhC,gEAAgE;IAChE,WAAW,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAI9C;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI;IAIrC,0DAA0D;IAC1D,OAAO,IAAI,IAAI;IAIf;;;OAGG;IACH,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlC;;;OAGG;IACH,kBAAkB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAIjD,sDAAsD;IACtD,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5D,yDAAyD;IACzD,uBAAuB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIjD,+CAA+C;IAC/C,yBAAyB,IAAI,OAAO,CAAC,OAAO,CAAC;IAM7C;;;;;OAKG;IACG,KAAK,CAAC,CAAC,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;IAMvB;;;;;;;;OAQG;IACH,aAAa,CAAC,CAAC,EACb,OAAO,CAAC,EAAE,mBAAmB,GAC5B,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;IAWxC;;;;;;;OAOG;IACG,MAAM,CAAC,CAAC,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;IAMvB;;;;;;;OAOG;IACH,aAAa,CAAC,CAAC,EACb,OAAO,CAAC,EAAE,mBAAmB,GAC5B,CACD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,OAAO,KACX,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;CAQ1B"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SagClient — framework-agnostic client for the Secure API Gateway.
|
|
3
|
+
*
|
|
4
|
+
* Encapsulates `gatewayUrl` and `appName` so consumers don't have to
|
|
5
|
+
* pass them to every function call.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* const client = new SagClient({ gatewayUrl: "http://localhost:3333", appName: "cars" })
|
|
9
|
+
* const status = await client.checkAuth()
|
|
10
|
+
* const { data } = await client.fetch<Car[]>("/cars")
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
import { checkAuth as checkAuthFn, checkHealth as checkHealthFn, clearSelectedOrganization as clearSelectedOrgFn, fetchOrganizations as fetchOrganizationsFn, getSelectedOrganization as getSelectedOrgFn, invalidateSession as invalidateSessionFn, selectOrganization as selectOrgFn, signIn as signInFn, signOut as signOutFn, } from "./auth";
|
|
14
|
+
import { createGatewayFetcher, createGatewayMutator } from "./fetcher";
|
|
15
|
+
export class SagClient {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.gatewayUrl = config.gatewayUrl;
|
|
18
|
+
this.appName = config.appName;
|
|
19
|
+
this.onSessionExpired = config.onSessionExpired;
|
|
20
|
+
}
|
|
21
|
+
// ── Auth ─────────────────────────────────────────────────
|
|
22
|
+
/** Check if the user is authenticated. */
|
|
23
|
+
checkAuth() {
|
|
24
|
+
return checkAuthFn(this.gatewayUrl);
|
|
25
|
+
}
|
|
26
|
+
/** Check if the authentication service (Logto) is reachable. */
|
|
27
|
+
checkHealth() {
|
|
28
|
+
return checkHealthFn(this.gatewayUrl);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Redirect the user to the gateway sign-in endpoint.
|
|
32
|
+
*
|
|
33
|
+
* @param options - Optional sign-in options (connector selection, redirect URL).
|
|
34
|
+
*/
|
|
35
|
+
signIn(options) {
|
|
36
|
+
signInFn(this.gatewayUrl, this.appName, options);
|
|
37
|
+
}
|
|
38
|
+
/** Redirect the user to the gateway sign-out endpoint. */
|
|
39
|
+
signOut() {
|
|
40
|
+
signOutFn(this.gatewayUrl, this.appName);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Invalidate the server session so the next sign-in fetches fresh claims.
|
|
44
|
+
* Use after onboarding or any flow that changes the user's roles.
|
|
45
|
+
*/
|
|
46
|
+
invalidateSession() {
|
|
47
|
+
return invalidateSessionFn(this.gatewayUrl);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Fetch structured organization data for the authenticated user.
|
|
51
|
+
* Requires an active session. Returns an empty array if not authenticated.
|
|
52
|
+
*/
|
|
53
|
+
fetchOrganizations() {
|
|
54
|
+
return fetchOrganizationsFn(this.gatewayUrl);
|
|
55
|
+
}
|
|
56
|
+
/** Set the user's currently selected organization. */
|
|
57
|
+
selectOrganization(organizationId) {
|
|
58
|
+
return selectOrgFn(this.gatewayUrl, organizationId);
|
|
59
|
+
}
|
|
60
|
+
/** Get the user's currently selected organization ID. */
|
|
61
|
+
getSelectedOrganization() {
|
|
62
|
+
return getSelectedOrgFn(this.gatewayUrl);
|
|
63
|
+
}
|
|
64
|
+
/** Clear the user's organization selection. */
|
|
65
|
+
clearSelectedOrganization() {
|
|
66
|
+
return clearSelectedOrgFn(this.gatewayUrl);
|
|
67
|
+
}
|
|
68
|
+
// ── Fetching ─────────────────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* Fetch data from the gateway.
|
|
71
|
+
*
|
|
72
|
+
* @param path - Gateway path (e.g. "/cars", "/weather")
|
|
73
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
74
|
+
*/
|
|
75
|
+
async fetch(path, options) {
|
|
76
|
+
const url = `${this.gatewayUrl}${path}`;
|
|
77
|
+
const fetcher = this.createFetcher(options);
|
|
78
|
+
return fetcher(url);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Create a fetcher function bound to this client's configuration.
|
|
82
|
+
*
|
|
83
|
+
* The returned function accepts an absolute URL and returns
|
|
84
|
+
* `{ data: T }`. Suitable for passing to SWR, TanStack Query,
|
|
85
|
+
* or calling directly.
|
|
86
|
+
*
|
|
87
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
88
|
+
*/
|
|
89
|
+
createFetcher(options) {
|
|
90
|
+
return createGatewayFetcher(this.gatewayUrl, this.appName, this.onSessionExpired, options);
|
|
91
|
+
}
|
|
92
|
+
// ── Mutations ───────────────────────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* Perform a mutation (POST, PUT, PATCH, DELETE) through the gateway.
|
|
95
|
+
*
|
|
96
|
+
* @param path - Gateway path (e.g. "/profile/api/v1/users/123")
|
|
97
|
+
* @param method - HTTP method
|
|
98
|
+
* @param body - Optional JSON-serializable request body
|
|
99
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
100
|
+
*/
|
|
101
|
+
async mutate(path, method, body, options) {
|
|
102
|
+
const url = `${this.gatewayUrl}${path}`;
|
|
103
|
+
const mutator = this.createMutator(options);
|
|
104
|
+
return mutator(url, method, body);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Create a mutator function bound to this client's configuration.
|
|
108
|
+
*
|
|
109
|
+
* The returned function accepts an absolute URL, HTTP method, and
|
|
110
|
+
* optional body. Suitable for imperative mutation calls.
|
|
111
|
+
*
|
|
112
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
113
|
+
*/
|
|
114
|
+
createMutator(options) {
|
|
115
|
+
return createGatewayMutator(this.gatewayUrl, this.appName, this.onSessionExpired, options);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic gateway fetcher with error handling.
|
|
3
|
+
*
|
|
4
|
+
* - On 401 (session expired / invalid grant): calls the `onSessionExpired`
|
|
5
|
+
* callback (default: redirect to sign-in).
|
|
6
|
+
* - On non-OK responses: attempts to parse the gateway JSON body for
|
|
7
|
+
* user-friendly error messages (e.g. 503 LOGTO_UNAVAILABLE).
|
|
8
|
+
*/
|
|
9
|
+
import { type GatewayFetchOptions, type MutationMethod } from "./types";
|
|
10
|
+
/**
|
|
11
|
+
* Create a fetcher function bound to a specific gateway + application.
|
|
12
|
+
*
|
|
13
|
+
* The returned function is suitable for passing to SWR, TanStack Query,
|
|
14
|
+
* or calling directly.
|
|
15
|
+
*
|
|
16
|
+
* @param gatewayUrl - Secure API Gateway base URL
|
|
17
|
+
* @param appName - Application name (sent as X-Application header)
|
|
18
|
+
* @param onSessionExpired - Called on 401. Default: redirect to sign-in.
|
|
19
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
20
|
+
*/
|
|
21
|
+
export declare function createGatewayFetcher<T>(gatewayUrl: string, appName: string, onSessionExpired?: () => void, options?: GatewayFetchOptions): (url: string) => Promise<{
|
|
22
|
+
data: T;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Create a mutator function bound to a specific gateway + application.
|
|
26
|
+
*
|
|
27
|
+
* Unlike `createGatewayFetcher` (GET-only / SWR-compatible), this factory
|
|
28
|
+
* returns a function that accepts an HTTP method and optional JSON body,
|
|
29
|
+
* suitable for POST, PUT, PATCH, and DELETE operations.
|
|
30
|
+
*
|
|
31
|
+
* @param gatewayUrl - Secure API Gateway base URL
|
|
32
|
+
* @param appName - Application name (sent as X-Application header)
|
|
33
|
+
* @param onSessionExpired - Called on 401. Default: redirect to sign-in.
|
|
34
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
35
|
+
*/
|
|
36
|
+
export declare function createGatewayMutator<T>(gatewayUrl: string, appName: string, onSessionExpired?: () => void, options?: GatewayFetchOptions): (url: string, method: MutationMethod, body?: unknown) => Promise<{
|
|
37
|
+
data: T;
|
|
38
|
+
}>;
|
|
39
|
+
//# sourceMappingURL=fetcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,cAAc,EAGpB,MAAM,SAAS,CAAA;AAEhB;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,gBAAgB,CAAC,EAAE,MAAM,IAAI,EAC7B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAoDvC;AA6DD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,gBAAgB,CAAC,EAAE,MAAM,IAAI,EAC7B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,CACD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,OAAO,KACX,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAoBxB"}
|
package/dist/fetcher.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic gateway fetcher with error handling.
|
|
3
|
+
*
|
|
4
|
+
* - On 401 (session expired / invalid grant): calls the `onSessionExpired`
|
|
5
|
+
* callback (default: redirect to sign-in).
|
|
6
|
+
* - On non-OK responses: attempts to parse the gateway JSON body for
|
|
7
|
+
* user-friendly error messages (e.g. 503 LOGTO_UNAVAILABLE).
|
|
8
|
+
*/
|
|
9
|
+
import { signIn } from "./auth";
|
|
10
|
+
import { ACTOR_TYPE_HEADER, ORGANIZATION_ID_HEADER, SagFetchError, } from "./types";
|
|
11
|
+
/**
|
|
12
|
+
* Create a fetcher function bound to a specific gateway + application.
|
|
13
|
+
*
|
|
14
|
+
* The returned function is suitable for passing to SWR, TanStack Query,
|
|
15
|
+
* or calling directly.
|
|
16
|
+
*
|
|
17
|
+
* @param gatewayUrl - Secure API Gateway base URL
|
|
18
|
+
* @param appName - Application name (sent as X-Application header)
|
|
19
|
+
* @param onSessionExpired - Called on 401. Default: redirect to sign-in.
|
|
20
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
21
|
+
*/
|
|
22
|
+
export function createGatewayFetcher(gatewayUrl, appName, onSessionExpired, options) {
|
|
23
|
+
return async (url) => {
|
|
24
|
+
const headers = {
|
|
25
|
+
"X-Application": appName,
|
|
26
|
+
};
|
|
27
|
+
if (options === null || options === void 0 ? void 0 : options.actorType) {
|
|
28
|
+
headers[ACTOR_TYPE_HEADER] = options.actorType;
|
|
29
|
+
}
|
|
30
|
+
if (options === null || options === void 0 ? void 0 : options.organizationId) {
|
|
31
|
+
headers[ORGANIZATION_ID_HEADER] = options.organizationId;
|
|
32
|
+
}
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
credentials: "include",
|
|
35
|
+
headers,
|
|
36
|
+
});
|
|
37
|
+
if (response.status === 401) {
|
|
38
|
+
if (onSessionExpired) {
|
|
39
|
+
onSessionExpired();
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
signIn(gatewayUrl, appName);
|
|
43
|
+
}
|
|
44
|
+
throw new SagFetchError("Session expired. Redirecting to sign in\u2026", 401);
|
|
45
|
+
}
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
let message = `HTTP error! status: ${response.status} ${response.statusText}`;
|
|
48
|
+
let code;
|
|
49
|
+
// Use gateway error body when available (503 LOGTO_UNAVAILABLE, etc.)
|
|
50
|
+
try {
|
|
51
|
+
const body = (await response.json());
|
|
52
|
+
if (body.details)
|
|
53
|
+
message = body.details;
|
|
54
|
+
else if (body.error)
|
|
55
|
+
message = body.error;
|
|
56
|
+
if (body.code)
|
|
57
|
+
code = body.code;
|
|
58
|
+
}
|
|
59
|
+
catch (_a) {
|
|
60
|
+
// Non-JSON or empty body — keep default message
|
|
61
|
+
}
|
|
62
|
+
throw new SagFetchError(message, response.status, code);
|
|
63
|
+
}
|
|
64
|
+
return response.json();
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build gateway request headers from options.
|
|
69
|
+
*/
|
|
70
|
+
function buildHeaders(appName, options) {
|
|
71
|
+
const headers = {
|
|
72
|
+
"X-Application": appName,
|
|
73
|
+
};
|
|
74
|
+
if (options === null || options === void 0 ? void 0 : options.actorType) {
|
|
75
|
+
headers[ACTOR_TYPE_HEADER] = options.actorType;
|
|
76
|
+
}
|
|
77
|
+
if (options === null || options === void 0 ? void 0 : options.organizationId) {
|
|
78
|
+
headers[ORGANIZATION_ID_HEADER] = options.organizationId;
|
|
79
|
+
}
|
|
80
|
+
return headers;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Handle non-OK gateway responses consistently.
|
|
84
|
+
*/
|
|
85
|
+
async function handleErrorResponse(response, gatewayUrl, appName, onSessionExpired) {
|
|
86
|
+
if (response.status === 401) {
|
|
87
|
+
if (onSessionExpired) {
|
|
88
|
+
onSessionExpired();
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
signIn(gatewayUrl, appName);
|
|
92
|
+
}
|
|
93
|
+
throw new SagFetchError("Session expired. Redirecting to sign in\u2026", 401);
|
|
94
|
+
}
|
|
95
|
+
let message = `HTTP error! status: ${response.status} ${response.statusText}`;
|
|
96
|
+
let code;
|
|
97
|
+
try {
|
|
98
|
+
const body = (await response.json());
|
|
99
|
+
if (body.details)
|
|
100
|
+
message = body.details;
|
|
101
|
+
else if (body.error)
|
|
102
|
+
message = body.error;
|
|
103
|
+
if (body.code)
|
|
104
|
+
code = body.code;
|
|
105
|
+
}
|
|
106
|
+
catch (_a) {
|
|
107
|
+
// Non-JSON or empty body — keep default message
|
|
108
|
+
}
|
|
109
|
+
throw new SagFetchError(message, response.status, code);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Create a mutator function bound to a specific gateway + application.
|
|
113
|
+
*
|
|
114
|
+
* Unlike `createGatewayFetcher` (GET-only / SWR-compatible), this factory
|
|
115
|
+
* returns a function that accepts an HTTP method and optional JSON body,
|
|
116
|
+
* suitable for POST, PUT, PATCH, and DELETE operations.
|
|
117
|
+
*
|
|
118
|
+
* @param gatewayUrl - Secure API Gateway base URL
|
|
119
|
+
* @param appName - Application name (sent as X-Application header)
|
|
120
|
+
* @param onSessionExpired - Called on 401. Default: redirect to sign-in.
|
|
121
|
+
* @param options - Optional fetch options (e.g. `{ actorType: "m2m" }`)
|
|
122
|
+
*/
|
|
123
|
+
export function createGatewayMutator(gatewayUrl, appName, onSessionExpired, options) {
|
|
124
|
+
return async (url, method, body) => {
|
|
125
|
+
const headers = buildHeaders(appName, options);
|
|
126
|
+
if (body !== undefined) {
|
|
127
|
+
headers["Content-Type"] = "application/json";
|
|
128
|
+
}
|
|
129
|
+
const response = await fetch(url, {
|
|
130
|
+
method,
|
|
131
|
+
credentials: "include",
|
|
132
|
+
headers,
|
|
133
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
134
|
+
});
|
|
135
|
+
if (!response.ok) {
|
|
136
|
+
await handleErrorResponse(response, gatewayUrl, appName, onSessionExpired);
|
|
137
|
+
}
|
|
138
|
+
return response.json();
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=fetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { checkAuth, checkHealth, clearSelectedOrganization, fetchOrganizations, getSelectedOrganization, invalidateSession, selectOrganization, signIn, signOut, } from "./auth";
|
|
2
|
+
export { SagClient } from "./client";
|
|
3
|
+
export { createGatewayFetcher, createGatewayMutator } from "./fetcher";
|
|
4
|
+
export type { OnboardingRedirectParams, WrongLoginMethodParams, } from "./onboarding";
|
|
5
|
+
export { buildOnboardingRedirectUrl, buildWrongLoginMethodRedirect, CLEAR_SESSION_PATH, ONBOARDING_PATH, ONBOARDING_SOURCE_PARAM, WRONG_LOGIN_METHOD_PATH, WRONG_LOGIN_RETURN_URL_PARAM, } from "./onboarding";
|
|
6
|
+
export { ALLOWED_SIGNIN_METHODS, CONNECTOR_ENTRAID, CONNECTOR_MYGOVID, DEFAULT_PUBLIC_SERVANT_ROLES, INACTIVE_PS_ORG_ROLE, isCitizen, isCitizenOnboarded, isInactivePublicServant, isPublicServant, ORG_ROLE_ADMIN, ORG_ROLE_MEMBER, ROLE_NAME_ONBOARDED_CITIZEN, } from "./roles";
|
|
7
|
+
export type { ActorType, AuthClaims, AuthStatus, AuthUser, GatewayFetchOptions, GatewayMutationOptions, MutationMethod, OrganizationInfo, SagClientConfig, SignInOptions, UseAuthResult, } from "./types";
|
|
8
|
+
export { ACTOR_TYPE_HEADER, ORGANIZATION_ID_HEADER, SagFetchError, } from "./types";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,SAAS,EACT,WAAW,EACX,yBAAyB,EACzB,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,EACN,OAAO,GACR,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGpC,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AACtE,YAAY,EACV,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,4BAA4B,EAC5B,oBAAoB,EACpB,SAAS,EACT,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,EACf,cAAc,EACd,eAAe,EACf,2BAA2B,GAC5B,MAAM,SAAS,CAAA;AAGhB,YAAY,EACV,SAAS,EACT,UAAU,EACV,UAAU,EACV,QAAQ,EACR,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,aAAa,GACd,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,GACd,MAAM,SAAS,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// ── Client ───────────────────────────────────────────────────
|
|
2
|
+
// ── Standalone auth functions ────────────────────────────────
|
|
3
|
+
export { checkAuth, checkHealth, clearSelectedOrganization, fetchOrganizations, getSelectedOrganization, invalidateSession, selectOrganization, signIn, signOut, } from "./auth";
|
|
4
|
+
export { SagClient } from "./client";
|
|
5
|
+
// ── Fetcher / Mutator factories ─────────────────────────────
|
|
6
|
+
export { createGatewayFetcher, createGatewayMutator } from "./fetcher";
|
|
7
|
+
// ── Onboarding helpers ──────────────────────────────────────
|
|
8
|
+
export { buildOnboardingRedirectUrl, buildWrongLoginMethodRedirect, CLEAR_SESSION_PATH, ONBOARDING_PATH, ONBOARDING_SOURCE_PARAM, WRONG_LOGIN_METHOD_PATH, WRONG_LOGIN_RETURN_URL_PARAM, } from "./onboarding";
|
|
9
|
+
// ── Role detection utilities ────────────────────────────────
|
|
10
|
+
export { ALLOWED_SIGNIN_METHODS, CONNECTOR_ENTRAID, CONNECTOR_MYGOVID, DEFAULT_PUBLIC_SERVANT_ROLES, INACTIVE_PS_ORG_ROLE, isCitizen, isCitizenOnboarded, isInactivePublicServant, isPublicServant, ORG_ROLE_ADMIN, ORG_ROLE_MEMBER, ROLE_NAME_ONBOARDED_CITIZEN, } from "./roles";
|
|
11
|
+
export { ACTOR_TYPE_HEADER, ORGANIZATION_ID_HEADER, SagFetchError, } from "./types";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAEhE,gEAAgE;AAChE,OAAO,EACL,SAAS,EACT,WAAW,EACX,yBAAyB,EACzB,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,EACN,OAAO,GACR,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEpC,+DAA+D;AAC/D,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAMtE,+DAA+D;AAC/D,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,cAAc,CAAA;AACrB,+DAA+D;AAC/D,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,4BAA4B,EAC5B,oBAAoB,EACpB,SAAS,EACT,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,EACf,cAAc,EACd,eAAe,EACf,2BAA2B,GAC5B,MAAM,SAAS,CAAA;AAgBhB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,GACd,MAAM,SAAS,CAAA"}
|