@carlonicora/nextjs-jsonapi 1.24.3 → 1.25.1
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/dist/{BlockNoteEditor-OFSTXGZX.js → BlockNoteEditor-7WAWEZVW.js} +13 -13
- package/dist/{BlockNoteEditor-OFSTXGZX.js.map → BlockNoteEditor-7WAWEZVW.js.map} +1 -1
- package/dist/{BlockNoteEditor-TJNLCNIP.mjs → BlockNoteEditor-UNVKGZ2G.mjs} +3 -3
- package/dist/billing/index.js +342 -342
- package/dist/billing/index.mjs +2 -2
- package/dist/{chunk-H5JZ5E7M.mjs → chunk-6BDOZDZ3.mjs} +1247 -54
- package/dist/chunk-6BDOZDZ3.mjs.map +1 -0
- package/dist/{chunk-EJALOG7L.js → chunk-JI6BDV7L.js} +1598 -405
- package/dist/chunk-JI6BDV7L.js.map +1 -0
- package/dist/{chunk-5U4NJJOF.mjs → chunk-LNBT2YPZ.mjs} +289 -2
- package/dist/chunk-LNBT2YPZ.mjs.map +1 -0
- package/dist/{chunk-NQVPCNRS.js → chunk-O3LLMGP7.js} +290 -3
- package/dist/chunk-O3LLMGP7.js.map +1 -0
- package/dist/client/index.d.mts +96 -1
- package/dist/client/index.d.ts +96 -1
- package/dist/client/index.js +9 -3
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +8 -2
- package/dist/components/index.d.mts +225 -1
- package/dist/components/index.d.ts +225 -1
- package/dist/components/index.js +25 -3
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +24 -2
- package/dist/contexts/index.js +3 -3
- package/dist/contexts/index.mjs +2 -2
- package/dist/core/index.d.mts +108 -1
- package/dist/core/index.d.ts +108 -1
- package/dist/core/index.js +14 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +13 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -1
- package/dist/oauth.interface-DsZ5ecSX.d.mts +119 -0
- package/dist/oauth.interface-vL7za9Bz.d.ts +119 -0
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +1 -1
- package/package.json +3 -2
- package/src/client/index.ts +1 -0
- package/src/components/index.ts +1 -0
- package/src/core/index.ts +3 -0
- package/src/core/registry/ModuleRegistry.ts +2 -0
- package/src/features/index.ts +1 -0
- package/src/features/oauth/atoms/index.ts +1 -0
- package/src/features/oauth/atoms/oauth.atoms.ts +131 -0
- package/src/features/oauth/components/OAuthClientCard.tsx +105 -0
- package/src/features/oauth/components/OAuthClientDetail.tsx +269 -0
- package/src/features/oauth/components/OAuthClientForm.tsx +212 -0
- package/src/features/oauth/components/OAuthClientList.tsx +127 -0
- package/src/features/oauth/components/OAuthClientSecretDisplay.tsx +127 -0
- package/src/features/oauth/components/OAuthRedirectUriInput.tsx +152 -0
- package/src/features/oauth/components/OAuthScopeSelector.tsx +123 -0
- package/src/features/oauth/components/consent/OAuthConsentActions.tsx +41 -0
- package/src/features/oauth/components/consent/OAuthConsentHeader.tsx +51 -0
- package/src/features/oauth/components/consent/OAuthConsentScreen.tsx +142 -0
- package/src/features/oauth/components/consent/OAuthScopeList.tsx +72 -0
- package/src/features/oauth/components/consent/index.ts +4 -0
- package/src/features/oauth/components/index.ts +8 -0
- package/src/features/oauth/data/index.ts +2 -0
- package/src/features/oauth/data/oauth.service.ts +191 -0
- package/src/features/oauth/data/oauth.ts +87 -0
- package/src/features/oauth/hooks/index.ts +3 -0
- package/src/features/oauth/hooks/useOAuthClient.ts +161 -0
- package/src/features/oauth/hooks/useOAuthClients.ts +111 -0
- package/src/features/oauth/hooks/useOAuthConsent.ts +125 -0
- package/src/features/oauth/index.ts +6 -0
- package/src/features/oauth/interfaces/index.ts +1 -0
- package/src/features/oauth/interfaces/oauth.interface.ts +175 -0
- package/src/features/oauth/oauth.module.ts +9 -0
- package/dist/chunk-5U4NJJOF.mjs.map +0 -1
- package/dist/chunk-EJALOG7L.js.map +0 -1
- package/dist/chunk-H5JZ5E7M.mjs.map +0 -1
- package/dist/chunk-NQVPCNRS.js.map +0 -1
- /package/dist/{BlockNoteEditor-TJNLCNIP.mjs.map → BlockNoteEditor-UNVKGZ2G.mjs.map} +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
import { OAuthConsentInfo, OAuthConsentRequest } from "../interfaces/oauth.interface";
|
|
5
|
+
import { OAuthService } from "../data/oauth.service";
|
|
6
|
+
|
|
7
|
+
export interface UseOAuthConsentReturn {
|
|
8
|
+
/** Client and scope info for consent display */
|
|
9
|
+
clientInfo: OAuthConsentInfo | null;
|
|
10
|
+
/** Whether consent info is being loaded */
|
|
11
|
+
isLoading: boolean;
|
|
12
|
+
/** Error from consent flow */
|
|
13
|
+
error: Error | null;
|
|
14
|
+
/** Approve the authorization request */
|
|
15
|
+
approve: () => Promise<void>;
|
|
16
|
+
/** Deny the authorization request */
|
|
17
|
+
deny: () => Promise<void>;
|
|
18
|
+
/** Whether approve/deny is in progress */
|
|
19
|
+
isSubmitting: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Hook for managing the OAuth consent flow
|
|
24
|
+
*
|
|
25
|
+
* @param params - OAuth authorization parameters from URL
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* const { clientInfo, isLoading, approve, deny } = useOAuthConsent({
|
|
30
|
+
* clientId: searchParams.client_id,
|
|
31
|
+
* redirectUri: searchParams.redirect_uri,
|
|
32
|
+
* scope: searchParams.scope,
|
|
33
|
+
* state: searchParams.state,
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Render consent screen with clientInfo
|
|
37
|
+
* // On button click: approve() or deny()
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function useOAuthConsent(params: OAuthConsentRequest): UseOAuthConsentReturn {
|
|
41
|
+
const [clientInfo, setClientInfo] = useState<OAuthConsentInfo | null>(null);
|
|
42
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
43
|
+
const [error, setError] = useState<Error | null>(null);
|
|
44
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
45
|
+
|
|
46
|
+
// Fetch client info on mount
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const fetchInfo = async () => {
|
|
49
|
+
if (!params.clientId || !params.redirectUri || !params.scope) {
|
|
50
|
+
setError(new Error("Missing required authorization parameters"));
|
|
51
|
+
setIsLoading(false);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setIsLoading(true);
|
|
56
|
+
setError(null);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const info = await OAuthService.getAuthorizationInfo(params);
|
|
60
|
+
setClientInfo(info);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error("[useOAuthConsent] Failed to fetch authorization info:", err);
|
|
63
|
+
setError(err instanceof Error ? err : new Error("Failed to load authorization info"));
|
|
64
|
+
} finally {
|
|
65
|
+
setIsLoading(false);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
fetchInfo();
|
|
70
|
+
}, [
|
|
71
|
+
params.clientId,
|
|
72
|
+
params.redirectUri,
|
|
73
|
+
params.scope,
|
|
74
|
+
params.state,
|
|
75
|
+
params.codeChallenge,
|
|
76
|
+
params.codeChallengeMethod,
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
const approve = useCallback(async (): Promise<void> => {
|
|
80
|
+
setIsSubmitting(true);
|
|
81
|
+
setError(null);
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const result = await OAuthService.approveAuthorization(params);
|
|
85
|
+
|
|
86
|
+
// Redirect to client with authorization code
|
|
87
|
+
if (result.redirectUrl) {
|
|
88
|
+
window.location.href = result.redirectUrl;
|
|
89
|
+
}
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.error("[useOAuthConsent] Failed to approve authorization:", err);
|
|
92
|
+
setError(err instanceof Error ? err : new Error("Failed to approve authorization"));
|
|
93
|
+
setIsSubmitting(false);
|
|
94
|
+
}
|
|
95
|
+
// Note: Don't set isSubmitting to false on success - we're redirecting
|
|
96
|
+
}, [params]);
|
|
97
|
+
|
|
98
|
+
const deny = useCallback(async (): Promise<void> => {
|
|
99
|
+
setIsSubmitting(true);
|
|
100
|
+
setError(null);
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const result = await OAuthService.denyAuthorization(params);
|
|
104
|
+
|
|
105
|
+
// Redirect to client with error
|
|
106
|
+
if (result.redirectUrl) {
|
|
107
|
+
window.location.href = result.redirectUrl;
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error("[useOAuthConsent] Failed to deny authorization:", err);
|
|
111
|
+
setError(err instanceof Error ? err : new Error("Failed to deny authorization"));
|
|
112
|
+
setIsSubmitting(false);
|
|
113
|
+
}
|
|
114
|
+
// Note: Don't set isSubmitting to false on success - we're redirecting
|
|
115
|
+
}, [params]);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
clientInfo,
|
|
119
|
+
isLoading,
|
|
120
|
+
error,
|
|
121
|
+
approve,
|
|
122
|
+
deny,
|
|
123
|
+
isSubmitting,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./oauth.interface";
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { ApiDataInterface } from "../../../core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* OAuth client application interface
|
|
5
|
+
* Represents a registered OAuth application that can request access tokens
|
|
6
|
+
*/
|
|
7
|
+
export interface OAuthClientInterface extends ApiDataInterface {
|
|
8
|
+
/** The public client identifier (UUID format) */
|
|
9
|
+
get clientId(): string;
|
|
10
|
+
/** Human-readable application name */
|
|
11
|
+
get name(): string;
|
|
12
|
+
/** Optional description of the application */
|
|
13
|
+
get description(): string | undefined;
|
|
14
|
+
/** Array of allowed redirect URIs (exact match validation) */
|
|
15
|
+
get redirectUris(): string[];
|
|
16
|
+
/** Array of scopes this client can request */
|
|
17
|
+
get allowedScopes(): string[];
|
|
18
|
+
/** Supported grant types (authorization_code, client_credentials, refresh_token) */
|
|
19
|
+
get allowedGrantTypes(): string[];
|
|
20
|
+
/** True for server-side apps (can keep secret secure), false for mobile/desktop apps */
|
|
21
|
+
get isConfidential(): boolean;
|
|
22
|
+
/** Whether the client is currently active */
|
|
23
|
+
get isActive(): boolean;
|
|
24
|
+
/** When the client was created */
|
|
25
|
+
get createdAt(): Date;
|
|
26
|
+
/** When the client was last updated */
|
|
27
|
+
get updatedAt(): Date;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Input type for OAuth client CRUD operations
|
|
32
|
+
*/
|
|
33
|
+
export type OAuthClientInput = {
|
|
34
|
+
id?: string;
|
|
35
|
+
name?: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
redirectUris?: string[];
|
|
38
|
+
allowedScopes?: string[];
|
|
39
|
+
allowedGrantTypes?: string[];
|
|
40
|
+
isConfidential?: boolean;
|
|
41
|
+
isActive?: boolean;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Request body for creating a new OAuth client
|
|
46
|
+
*/
|
|
47
|
+
export interface OAuthClientCreateRequest {
|
|
48
|
+
/** Required: Human-readable application name */
|
|
49
|
+
name: string;
|
|
50
|
+
/** Optional: Description of the application */
|
|
51
|
+
description?: string;
|
|
52
|
+
/** Required: At least one redirect URI */
|
|
53
|
+
redirectUris: string[];
|
|
54
|
+
/** Required: Array of scopes the client needs */
|
|
55
|
+
allowedScopes: string[];
|
|
56
|
+
/** Optional: Grant types (defaults to authorization_code + refresh_token) */
|
|
57
|
+
allowedGrantTypes?: string[];
|
|
58
|
+
/** Required: Whether this is a confidential client */
|
|
59
|
+
isConfidential: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Response when creating a client (includes one-time secret)
|
|
64
|
+
*/
|
|
65
|
+
export interface OAuthClientCreateResponse {
|
|
66
|
+
client: OAuthClientInterface;
|
|
67
|
+
/** Only returned on creation - must be saved immediately */
|
|
68
|
+
clientSecret?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parameters for the OAuth authorization consent flow
|
|
73
|
+
* Passed via URL query parameters to the consent page
|
|
74
|
+
*/
|
|
75
|
+
export interface OAuthConsentRequest {
|
|
76
|
+
/** The client_id requesting authorization */
|
|
77
|
+
clientId: string;
|
|
78
|
+
/** Where to redirect after authorization */
|
|
79
|
+
redirectUri: string;
|
|
80
|
+
/** Space-separated list of requested scopes */
|
|
81
|
+
scope: string;
|
|
82
|
+
/** CSRF protection token (passed back on redirect) */
|
|
83
|
+
state?: string;
|
|
84
|
+
/** PKCE code challenge (required for public clients) */
|
|
85
|
+
codeChallenge?: string;
|
|
86
|
+
/** PKCE method: 'S256' (recommended) or 'plain' */
|
|
87
|
+
codeChallengeMethod?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Scope information for display in consent screen
|
|
92
|
+
*/
|
|
93
|
+
export interface OAuthScopeInfo {
|
|
94
|
+
/** The scope identifier (e.g., 'photographs:read') */
|
|
95
|
+
scope: string;
|
|
96
|
+
/** Human-readable scope name */
|
|
97
|
+
name: string;
|
|
98
|
+
/** Description of what this scope allows */
|
|
99
|
+
description: string;
|
|
100
|
+
/** Optional icon identifier */
|
|
101
|
+
icon?: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Client info returned for consent screen display
|
|
106
|
+
*/
|
|
107
|
+
export interface OAuthConsentInfo {
|
|
108
|
+
client: OAuthClientInterface;
|
|
109
|
+
scopes: OAuthScopeInfo[];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Default scope display configuration
|
|
114
|
+
* Maps scope identifiers to human-readable info
|
|
115
|
+
*/
|
|
116
|
+
export const OAUTH_SCOPE_DISPLAY: Record<string, OAuthScopeInfo> = {
|
|
117
|
+
read: {
|
|
118
|
+
scope: "read",
|
|
119
|
+
name: "Read Access",
|
|
120
|
+
description: "Read access to your data",
|
|
121
|
+
icon: "eye",
|
|
122
|
+
},
|
|
123
|
+
write: {
|
|
124
|
+
scope: "write",
|
|
125
|
+
name: "Write Access",
|
|
126
|
+
description: "Write access to your data",
|
|
127
|
+
icon: "pencil",
|
|
128
|
+
},
|
|
129
|
+
"photographs:read": {
|
|
130
|
+
scope: "photographs:read",
|
|
131
|
+
name: "View Photographs",
|
|
132
|
+
description: "Access and download your photo library",
|
|
133
|
+
icon: "image",
|
|
134
|
+
},
|
|
135
|
+
"photographs:write": {
|
|
136
|
+
scope: "photographs:write",
|
|
137
|
+
name: "Upload Photographs",
|
|
138
|
+
description: "Add new photos to your rolls",
|
|
139
|
+
icon: "upload",
|
|
140
|
+
},
|
|
141
|
+
"rolls:read": {
|
|
142
|
+
scope: "rolls:read",
|
|
143
|
+
name: "View Rolls",
|
|
144
|
+
description: "See your film rolls and collections",
|
|
145
|
+
icon: "film",
|
|
146
|
+
},
|
|
147
|
+
"rolls:write": {
|
|
148
|
+
scope: "rolls:write",
|
|
149
|
+
name: "Manage Rolls",
|
|
150
|
+
description: "Create and modify film rolls",
|
|
151
|
+
icon: "folder-plus",
|
|
152
|
+
},
|
|
153
|
+
profile: {
|
|
154
|
+
scope: "profile",
|
|
155
|
+
name: "View Profile",
|
|
156
|
+
description: "Access your name and email",
|
|
157
|
+
icon: "user",
|
|
158
|
+
},
|
|
159
|
+
admin: {
|
|
160
|
+
scope: "admin",
|
|
161
|
+
name: "Administrative Access",
|
|
162
|
+
description: "Full administrative access to your account",
|
|
163
|
+
icon: "shield",
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Available scopes list for the scope selector
|
|
169
|
+
*/
|
|
170
|
+
export const AVAILABLE_OAUTH_SCOPES: OAuthScopeInfo[] = Object.values(OAUTH_SCOPE_DISPLAY);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Default grant types for new clients
|
|
174
|
+
*/
|
|
175
|
+
export const DEFAULT_GRANT_TYPES = ["authorization_code", "refresh_token"];
|