Skip to content

Commit 3b9d30b

Browse files
authored
Merge pull request #104 from brionmario/next-user-components
feat(nextjs): move to a session cookie to give the ability to do route level scope based authorization
2 parents 36b87dc + ee3b7c6 commit 3b9d30b

File tree

24 files changed

+1470
-117
lines changed

24 files changed

+1470
-117
lines changed

.changeset/late-animals-rush.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@asgardeo/javascript': patch
3+
'@asgardeo/nextjs': patch
4+
---
5+
6+
Move to a session cookie to give the ability to do route level scope based authorization.

docs/developer/LOGGER.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Logger Utility
2+
3+
A universal logging utility that works seamlessly in both browser and Node.js environments with beautiful formatting, colors, and flexible configuration.
4+
5+
## Features
6+
7+
- 🌐 **Universal**: Works in both browser and Node.js environments
8+
- 🎨 **Beautiful Output**: Colored terminal output (Node.js) and styled console output (browser)
9+
-**Package-Aware**: Support for package-specific and component-specific loggers
10+
- �📊 **Log Levels**: DEBUG, INFO, WARN, ERROR, SILENT
11+
- 🏷️ **Prefixes**: Customizable prefixes with support for nested component loggers
12+
-**Timestamps**: Optional timestamp inclusion
13+
- 🔧 **Configurable**: Flexible configuration options
14+
- 🎯 **Type Safe**: Full TypeScript support
15+
16+
## Basic Usage
17+
18+
```typescript
19+
import logger, { LogLevel } from '@asgardeo/javascript';
20+
21+
// Basic logging with package-specific prefix
22+
logger.info('Application started');
23+
// Output: 🛡️ Asgardeo - @asgardeo/javascript [INFO] Application started
24+
25+
logger.warn('This is a warning');
26+
logger.error('Something went wrong');
27+
logger.debug('Debug information'); // Only shown if level is DEBUG
28+
29+
// Configure log level
30+
logger.setLevel(LogLevel.DEBUG);
31+
logger.debug('Now debug messages will show');
32+
33+
// Set to production level
34+
logger.setLevel(LogLevel.WARN); // Only WARN and ERROR will show
35+
```
36+
37+
## Named Function Exports
38+
39+
```typescript
40+
import { info, warn, error, debug } from '@asgardeo/javascript';
41+
42+
info('Quick info message');
43+
warn('Quick warning');
44+
error('Quick error');
45+
debug('Quick debug');
46+
```
47+
48+
## Package-Specific Loggers
49+
50+
```typescript
51+
import { createPackageLogger, createPackageComponentLogger } from '@asgardeo/javascript';
52+
53+
// Create logger for specific package
54+
const nextjsLogger = createPackageLogger('@asgardeo/nextjs');
55+
nextjsLogger.info('Next.js package message');
56+
// Output: 🛡️ Asgardeo - @asgardeo/nextjs [INFO] Next.js package message
57+
58+
const reactLogger = createPackageLogger('@asgardeo/react');
59+
reactLogger.error('React package error');
60+
// Output: 🛡️ Asgardeo - @asgardeo/react [ERROR] React package error
61+
62+
// Create logger for package + component
63+
const nextAuthLogger = createPackageComponentLogger('@asgardeo/nextjs', 'Authentication');
64+
nextAuthLogger.info('User signed in');
65+
// Output: 🛡️ Asgardeo - @asgardeo/nextjs - Authentication [INFO] User signed in
66+
```
67+
68+
## Custom Logger Configuration
69+
70+
```typescript
71+
import { createLogger, LogLevel } from '@asgardeo/javascript';
72+
73+
const customLogger = createLogger({
74+
level: LogLevel.DEBUG,
75+
prefix: '🛡️ Asgardeo - MyCustomApp',
76+
timestamps: true,
77+
showLevel: true,
78+
});
79+
80+
customLogger.info('Custom configured message');
81+
// Output: [2025-01-10T10:30:45.123Z] 🛡️ Asgardeo - MyCustomApp [INFO] Custom configured message
82+
```
83+
84+
## Component-Specific Loggers
85+
86+
```typescript
87+
import { createComponentLogger } from '@asgardeo/javascript';
88+
89+
// Create loggers for different components (uses default package prefix)
90+
const authLogger = createComponentLogger('Authentication');
91+
const apiLogger = createComponentLogger('API');
92+
const uiLogger = createComponentLogger('UI');
93+
94+
authLogger.info('User signed in successfully');
95+
// Output: 🛡️ Asgardeo - @asgardeo/javascript - Authentication [INFO] User signed in successfully
96+
97+
apiLogger.error('API request failed');
98+
// Output: 🛡️ Asgardeo - @asgardeo/javascript - API [ERROR] API request failed
99+
100+
uiLogger.debug('Rendering component');
101+
// Output: 🛡️ Asgardeo - @asgardeo/javascript - UI [DEBUG] Rendering component
102+
```
103+
104+
## Real-World Package Examples
105+
106+
### Next.js Package Usage
107+
108+
```typescript
109+
import { createPackageComponentLogger } from '@asgardeo/javascript';
110+
111+
const authLogger = createPackageComponentLogger('@asgardeo/nextjs', 'Authentication');
112+
const sessionLogger = createPackageComponentLogger('@asgardeo/nextjs', 'SessionManager');
113+
114+
export class NextAuthService {
115+
async signIn(credentials: Credentials): Promise<User> {
116+
authLogger.info('Starting Next.js sign-in process', { username: credentials.username });
117+
118+
try {
119+
sessionLogger.debug('Creating session cookie');
120+
const user = await this.performSignIn(credentials);
121+
authLogger.info('Next.js sign-in successful', { userId: user.id });
122+
return user;
123+
} catch (error) {
124+
authLogger.error('Next.js sign-in failed', { error: error.message, username: credentials.username });
125+
throw error;
126+
}
127+
}
128+
}
129+
```
130+
131+
### Multi-Package Application
132+
133+
```typescript
134+
// In @asgardeo/nextjs package
135+
import { createPackageComponentLogger } from '@asgardeo/javascript';
136+
const nextLogger = createPackageComponentLogger('@asgardeo/nextjs', 'Provider');
137+
138+
// In @asgardeo/react package
139+
import { createPackageComponentLogger } from '@asgardeo/javascript';
140+
const reactLogger = createPackageComponentLogger('@asgardeo/react', 'Hook');
141+
142+
// In @asgardeo/node package
143+
import { createPackageComponentLogger } from '@asgardeo/javascript';
144+
const nodeLogger = createPackageComponentLogger('@asgardeo/node', 'Client');
145+
146+
// Each will have distinct, identifiable output:
147+
// 🛡️ Asgardeo - @asgardeo/nextjs - Provider [INFO] ...
148+
// 🛡️ Asgardeo - @asgardeo/react - Hook [INFO] ...
149+
// 🛡️ Asgardeo - @asgardeo/node - Client [INFO] ...
150+
```

packages/javascript/src/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,19 @@ export {default as processOpenIDScopes} from './utils/processOpenIDScopes';
132132
export {default as withVendorCSSClassPrefix} from './utils/withVendorCSSClassPrefix';
133133
export {default as transformBrandingPreferenceToTheme} from './utils/transformBrandingPreferenceToTheme';
134134

135+
export {
136+
default as logger,
137+
createLogger,
138+
createComponentLogger,
139+
createPackageLogger,
140+
createPackageComponentLogger,
141+
LogLevel,
142+
configure as configureLogger,
143+
debug,
144+
info,
145+
warn,
146+
error,
147+
} from './utils/logger';
148+
export type {LoggerConfig} from './utils/logger';
149+
135150
export {default as StorageManager} from './StorageManager';
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/**
2+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
import logger, {createLogger, createComponentLogger, LogLevel} from '../logger';
20+
21+
describe('Logger', () => {
22+
beforeEach(() => {
23+
// Reset console methods before each test
24+
jest.spyOn(console, 'log').mockImplementation();
25+
jest.spyOn(console, 'info').mockImplementation();
26+
jest.spyOn(console, 'warn').mockImplementation();
27+
jest.spyOn(console, 'error').mockImplementation();
28+
jest.spyOn(console, 'debug').mockImplementation();
29+
});
30+
31+
afterEach(() => {
32+
jest.restoreAllMocks();
33+
});
34+
35+
describe('Basic logging', () => {
36+
it('should log info messages', () => {
37+
logger.info('Test info message');
38+
expect(console.info).toHaveBeenCalled();
39+
});
40+
41+
it('should log warning messages', () => {
42+
logger.warn('Test warning message');
43+
expect(console.warn).toHaveBeenCalled();
44+
});
45+
46+
it('should log error messages', () => {
47+
logger.error('Test error message');
48+
expect(console.error).toHaveBeenCalled();
49+
});
50+
51+
it('should log debug messages when level is DEBUG', () => {
52+
logger.setLevel(LogLevel.DEBUG);
53+
logger.debug('Test debug message');
54+
expect(console.debug).toHaveBeenCalled();
55+
});
56+
57+
it('should not log debug messages when level is INFO', () => {
58+
logger.setLevel(LogLevel.INFO);
59+
logger.debug('Test debug message');
60+
expect(console.debug).not.toHaveBeenCalled();
61+
});
62+
});
63+
64+
describe('Log levels', () => {
65+
it('should respect log level filtering', () => {
66+
logger.setLevel(LogLevel.WARN);
67+
68+
logger.debug('Debug message');
69+
logger.info('Info message');
70+
logger.warn('Warning message');
71+
logger.error('Error message');
72+
73+
expect(console.debug).not.toHaveBeenCalled();
74+
expect(console.info).not.toHaveBeenCalled();
75+
expect(console.warn).toHaveBeenCalled();
76+
expect(console.error).toHaveBeenCalled();
77+
});
78+
79+
it('should silence all logs when level is SILENT', () => {
80+
logger.setLevel(LogLevel.SILENT);
81+
82+
logger.debug('Debug message');
83+
logger.info('Info message');
84+
logger.warn('Warning message');
85+
logger.error('Error message');
86+
87+
expect(console.debug).not.toHaveBeenCalled();
88+
expect(console.info).not.toHaveBeenCalled();
89+
expect(console.warn).not.toHaveBeenCalled();
90+
expect(console.error).not.toHaveBeenCalled();
91+
});
92+
});
93+
94+
describe('Custom loggers', () => {
95+
it('should create logger with custom configuration', () => {
96+
const customLogger = createLogger({
97+
level: LogLevel.DEBUG,
98+
prefix: 'Custom',
99+
timestamps: false,
100+
showLevel: false,
101+
});
102+
103+
expect(customLogger.getLevel()).toBe(LogLevel.DEBUG);
104+
expect(customLogger.getConfig().prefix).toBe('Custom');
105+
expect(customLogger.getConfig().timestamps).toBe(false);
106+
expect(customLogger.getConfig().showLevel).toBe(false);
107+
});
108+
109+
it('should create component logger with nested prefix', () => {
110+
const componentLogger = createComponentLogger('Authentication');
111+
112+
componentLogger.info('Test message');
113+
114+
expect(console.info).toHaveBeenCalled();
115+
// The exact format depends on environment detection
116+
});
117+
118+
it('should create child logger', () => {
119+
const parentLogger = createLogger({prefix: 'Parent'});
120+
const childLogger = parentLogger.child('Child');
121+
122+
expect(childLogger.getConfig().prefix).toBe('Parent - Child');
123+
});
124+
});
125+
126+
describe('Configuration', () => {
127+
it('should update configuration', () => {
128+
const testLogger = createLogger({level: LogLevel.INFO});
129+
130+
testLogger.configure({
131+
level: LogLevel.DEBUG,
132+
prefix: 'Updated',
133+
});
134+
135+
expect(testLogger.getLevel()).toBe(LogLevel.DEBUG);
136+
expect(testLogger.getConfig().prefix).toBe('Updated');
137+
});
138+
});
139+
140+
describe('Custom formatter', () => {
141+
it('should use custom formatter when provided', () => {
142+
const mockFormatter = jest.fn();
143+
const customLogger = createLogger({
144+
formatter: mockFormatter,
145+
});
146+
147+
customLogger.info('Test message', {data: 'test'});
148+
149+
expect(mockFormatter).toHaveBeenCalledWith(LogLevel.INFO, 'Test message', {data: 'test'});
150+
expect(console.info).not.toHaveBeenCalled();
151+
});
152+
});
153+
});

0 commit comments

Comments
 (0)