@smartsides/oracle-ebs-sdk 1.0.7 → 1.0.10

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 CHANGED
@@ -5,7 +5,8 @@ TypeScript SDK for Oracle EBS API - Optimized for Next.js 15+
5
5
  ## Features
6
6
 
7
7
  - ✅ **Full TypeScript Support** - Complete type safety with autocomplete
8
- - ✅ **All API Endpoints** - 9 modules covering all Oracle EBS functionality
8
+ - ✅ **All API Endpoints** - 10 modules covering all Oracle EBS functionality
9
+ - ✅ **AI Assistant** - ChatGPT-style chat with voice support ⭐ NEW
9
10
  - ✅ **Auto User Context** - Stores full user object from login automatically
10
11
  - ✅ **Smart Defaults** - Employee number auto-extracted for payslip/leave requests
11
12
  - ✅ **Error Handling** - Typed errors with automatic retry logic
@@ -178,22 +179,67 @@ const preview = await client.sitRequests.saveAndPreview(data);
178
179
  const result = await client.sitRequests.submit(data);
179
180
  ```
180
181
 
182
+ ### Segments
183
+
184
+ ```typescript
185
+ // Get SIT segments metadata
186
+ const segments = await client.segments.getSitSegments({
187
+ idFlexNum: '50496'
188
+ });
189
+
190
+ // Returns array of segment metadata:
191
+ // - segmentNumber, segmentName, segmentPrompt
192
+ // - applicationColumnName, requiredFlag
193
+ // - defaultValue, valueSetName, validationType
194
+ // - enabledFlag, displayedFlag, executionStatus
195
+ ```
196
+
197
+
181
198
  ### Notifications
182
199
 
183
200
  ```typescript
184
- // Get notifications
201
+ // Get notification list (USER_ID auto-extracted from login)
185
202
  const notifications = await client.notifications.getList();
186
203
 
187
- // Get details
188
- const details = await client.notifications.getDetails({ notificationId: '123' });
204
+ // Get notification details
205
+ const details = await client.notifications.getDetails({
206
+ notificationId: '9341634'
207
+ });
189
208
 
190
- // Process approval
209
+ // Get all details (SSHR_SIT_REQDTLS)
210
+ const allDetails = await client.notifications.getAllDetails({
211
+ notificationId: '9288875',
212
+ itemKey: '756840',
213
+ analysisCriteriaId: '3643761',
214
+ idFlexNum: '50310'
215
+ });
216
+
217
+ // Get absence details (for FYI notifications)
218
+ const absenceDetails = await client.notifications.getAbsenceDetails({
219
+ itemKey: '760206'
220
+ });
221
+
222
+ // Get action history
223
+ const history = await client.notifications.getActionHistory({
224
+ notificationId: '9330566'
225
+ });
226
+
227
+ // Process approval (APPROVE or DECLINE)
191
228
  await client.notifications.processApproval({
192
- notificationId: '123',
229
+ notificationId: '9341634',
193
230
  action: 'APPROVE',
231
+ comments: 'Approved for processing',
232
+ responderUserName: 'optional'
233
+ });
234
+
235
+ // Close FYI notification (USER_ID auto-extracted)
236
+ await client.notifications.closeFyi({
237
+ notificationId: '9336582'
194
238
  });
195
239
  ```
196
240
 
241
+ **Auto User ID**: Notification methods automatically use USER_ID from the logged-in user where needed.
242
+
197
243
  ### Payslip
198
244
 
199
245
  ```typescript
@@ -264,6 +310,101 @@ const health = await client.health.check();
264
310
  const message = await client.health.ping();
265
311
  ```
266
312
 
313
+ ### AI Assistant 🆕
314
+
315
+ The AI module provides ChatGPT-style conversational AI with persistent chat history.
316
+
317
+ ```typescript
318
+ import { MessageRole } from '@smartsides/oracle-ebs-sdk';
319
+
320
+ // Send a chat message
321
+ const response = await client.ai.sendMessage({
322
+ message: 'Show my latest payslip',
323
+ language: 'en',
324
+ history: [
325
+ { role: MessageRole.USER, content: 'Hello' },
326
+ { role: MessageRole.ASSISTANT, content: 'Hi! How can I help?' }
327
+ ],
328
+ threadId: 'optional-thread-id' // For continuing existing conversation
329
+ });
330
+
331
+ // Response includes:
332
+ // - message: AI response text
333
+ // - ctas: Call-to-action buttons (if any)
334
+ // - metadata: Intent, tokens used, etc.
335
+ // - threadId: Thread ID for conversation persistence
336
+
337
+ // Voice message with thread continuity ⭐ NEW
338
+ // First voice message - creates new thread
339
+ const voiceResponse1 = await client.ai.sendVoice(audioBlob, {
340
+ language: 'en'
341
+ });
342
+ const threadId = voiceResponse1.response.threadId;
343
+
344
+ // Second voice message - continues same thread
345
+ const voiceResponse2 = await client.ai.sendVoice(audioBlob, {
346
+ language: 'en',
347
+ threadId: threadId // Maintains conversation context!
348
+ });
349
+
350
+ // Arabic voice with thread continuity
351
+ const arabicResponse = await client.ai.sendVoice(audioBlob, {
352
+ language: 'ar',
353
+ threadId: threadId // Works with Arabic too!
354
+ });
355
+
356
+ // Thread management
357
+ const threads = await client.ai.getChatThreads();
358
+ const messages = await client.ai.getThreadMessages(threadId);
359
+ await client.ai.deleteThread(threadId);
360
+ ```
361
+
362
+ **Voice Thread Continuity Benefits:**
363
+ - ✅ Multi-turn voice conversations (request → confirmation → submission)
364
+ - ✅ Maintains full conversation context across voice messages
365
+ - ✅ Works with both English and Arabic
366
+ - ✅ Automatic leave type mapping and date extraction
367
+ - ✅ Seamless voice-based leave request submission
368
+
369
+ // Transcribe voice to text
370
+ const transcription = await client.ai.transcribeVoice(audioBlob);
371
+
372
+ // Get all chat threads for current user
373
+ const threads = await client.ai.getChatThreads();
374
+ // Returns: Array of ChatThread objects with id, title, messageCount, etc.
375
+
376
+ // Get messages for a specific thread
377
+ const { thread, messages } = await client.ai.getThreadMessages(threadId);
378
+ // Returns: Thread metadata + array of ThreadMessage objects
379
+
380
+ // Create a new chat thread
381
+ const newThread = await client.ai.createThread();
382
+ // Returns: ChatThread object with new thread ID
383
+
384
+ // Delete a chat thread
385
+ await client.ai.deleteThread(threadId);
386
+ // Deletes thread and all associated messages
387
+ ```
388
+
389
+ **Chat History Features:**
390
+ - ✅ **Persistent Threads**: All conversations saved to PostgreSQL
391
+ - ✅ **Auto-Title Generation**: Thread titles generated from first message
392
+ - ✅ **Message History**: Complete conversation history with timestamps
393
+ - ✅ **User-Scoped**: Each user only sees their own threads
394
+ - ✅ **Secure**: JWT authentication + ownership validation
395
+
396
+ **Available Types:**
397
+ ```typescript
398
+ import {
399
+ MessageRole, // USER | ASSISTANT
400
+ ActionType, // Enum for action types
401
+ UserIntent, // Enum for user intents
402
+ ChatThread, // Thread metadata type
403
+ ThreadMessage, // Message type
404
+ CallToAction, // CTA button type
405
+ } from '@smartsides/oracle-ebs-sdk';
406
+ ```
407
+
267
408
  ## Error Handling
268
409
 
269
410
  ```typescript
@@ -311,6 +452,69 @@ const client = new OracleEBSClient({
311
452
  });
312
453
  ```
313
454
 
455
+ ## 🔒 Security Best Practices
456
+
457
+ ### CRITICAL: Never Decode JWT Tokens
458
+
459
+ **❌ NEVER do this in your application:**
460
+
461
+ ```typescript
462
+ // DON'T decode JWT on the client side
463
+ const token = localStorage.getItem('token');
464
+ const payload = JSON.parse(atob(token.split('.')[1]));
465
+ const employeeNumber = payload.EMPLOYEE_NUMBER;
466
+
467
+ // DON'T pass user context to SDK methods
468
+ await client.payslip.getHeader({ periodName, employeeNumber });
469
+ ```
470
+
471
+ **✅ ALWAYS do this instead:**
472
+
473
+ ```typescript
474
+ // Just set the token and pass business parameters
475
+ client.setToken(token);
476
+ await client.payslip.getHeader({ periodName });
477
+ // Backend extracts employeeNumber from JWT automatically
478
+ ```
479
+
480
+ ### Why This Matters
481
+
482
+ 1. **Security**: JWT payload is base64 encoded, NOT encrypted - anyone can read it
483
+ 2. **Single Source of Truth**: Backend validates and extracts user context
484
+ 3. **Prevents Tampering**: Users cannot access other users' data
485
+ 4. **Maintainability**: JWT structure changes don't affect your code
486
+ 5. **Consistency**: All endpoints follow the same pattern
487
+
488
+ ### How It Works
489
+
490
+ The SDK sends the JWT token in the Authorization header. The backend:
491
+ 1. Validates the token signature
492
+ 2. Checks token expiration
493
+ 3. Extracts user context (employeeNumber, userId, personId, etc.)
494
+ 4. Uses this context to fetch user-specific data
495
+
496
+ ### Affected Methods
497
+
498
+ All user-specific methods automatically use JWT context:
499
+ - ✅ `payslip.getHeader()` - Uses EMPLOYEE_NUMBER from JWT
500
+ - ✅ `payslip.getDetails()` - Uses EMPLOYEE_NUMBER from JWT
501
+ - ✅ `leaves.getRestrictedTypes()` - Uses USER_ID, PERSON_ID from JWT
502
+ - ✅ `leaves.createRequest()` - Uses PERSON_ID, USER_ID from JWT
503
+ - ✅ `notifications.getList()` - Uses USER_ID from JWT
504
+ - ✅ `notifications.closeFyi()` - Uses USER_ID from JWT
505
+ - ✅ `employee.getPersonalInfo()` - Uses context from JWT
506
+ - ✅ `accrualBalances.getBalances()` - Uses context from JWT
507
+
508
+ **You only pass business parameters** (periodName, dates, etc.) - never user context.
509
+
510
+ ### Reference
511
+
512
+ For complete security documentation, see:
513
+ - [Backend JWT Security Pattern](../docs/JWT_SECURITY_PATTERN.md)
514
+ - [Backend Documentation](../docs/index.md#-core-security-principles)
515
+
516
+ ---
517
+
314
518
  ## React Query Hooks
315
519
 
316
520
  All hooks are available from `@smartsides/oracle-ebs-sdk/hooks`:
@@ -173,16 +173,16 @@ declare class LeavesModule extends BaseClient {
173
173
  createRequest(input: CreateLeaveRequestInput): Promise<CreateLeaveRequestResponse>;
174
174
  }
175
175
 
176
- interface SitSegment {
176
+ interface SitSegment$1 {
177
177
  segmentName: string;
178
178
  segmentValue: string;
179
179
  displayValue?: string;
180
180
  }
181
- interface GetSitSegmentsParams {
181
+ interface GetSitSegmentsParams$1 {
182
182
  idFlexNum: string;
183
183
  }
184
- interface GetSitSegmentsResponse {
185
- segments: SitSegment[];
184
+ interface GetSitSegmentsResponse$1 {
185
+ segments: SitSegment$1[];
186
186
  }
187
187
  interface SaveAndPreviewSitRequestInput {
188
188
  itemType: string;
@@ -216,6 +216,8 @@ interface SubmitSitRequestResponse {
216
216
  itemKey: string;
217
217
  }
218
218
  interface GetSitHistoryParams {
219
+ sitName: string;
220
+ transactionId?: string;
219
221
  startDate?: string;
220
222
  endDate?: string;
221
223
  }
@@ -231,10 +233,10 @@ interface GetSitHistoryResponse {
231
233
  }
232
234
 
233
235
  declare class SitRequestsModule extends BaseClient {
234
- getSegments(params: GetSitSegmentsParams): Promise<GetSitSegmentsResponse>;
236
+ getSegments(params: GetSitSegmentsParams$1): Promise<GetSitSegmentsResponse$1>;
235
237
  saveAndPreview(input: SaveAndPreviewSitRequestInput): Promise<SaveAndPreviewSitRequestResponse>;
236
238
  submit(input: SubmitSitRequestInput): Promise<SubmitSitRequestResponse>;
237
- getHistory(params?: GetSitHistoryParams): Promise<GetSitHistoryResponse>;
239
+ getHistory(params: GetSitHistoryParams): Promise<GetSitHistoryResponse>;
238
240
  }
239
241
 
240
242
  interface Notification {
@@ -448,7 +450,6 @@ interface GetPayslipRunBalancesResponse {
448
450
  }
449
451
 
450
452
  declare class PayslipModule extends BaseClient {
451
- private getEmployeeNumberFromContext;
452
453
  getHeader(params: GetPayslipHeaderParams): Promise<PayslipHeader>;
453
454
  getDetails(params: GetPayslipDetailsParams): Promise<GetPayslipDetailsResponse>;
454
455
  getLeaveDetails(params: GetPayslipLeaveDetailsParams): Promise<GetPayslipLeaveDetailsResponse>;
@@ -559,6 +560,169 @@ declare class HealthModule extends BaseClient {
559
560
  ping(): Promise<string>;
560
561
  }
561
562
 
563
+ declare enum MessageRole {
564
+ USER = "user",
565
+ ASSISTANT = "assistant",
566
+ SYSTEM = "system"
567
+ }
568
+ declare enum ActionType {
569
+ NAVIGATE = "navigate",
570
+ API_CALL = "api_call",
571
+ DOWNLOAD = "download",
572
+ CLOSE_NOTIFICATION = "close_notification",
573
+ SUBMIT_LEAVE = "submit_leave",
574
+ APPROVE_NOTIFICATION = "approve_notification",
575
+ DECLINE_NOTIFICATION = "decline_notification"
576
+ }
577
+ declare enum UserIntent {
578
+ NOTIFICATIONS_SUMMARY = "notifications_summary",
579
+ NOTIFICATION_CLOSE = "notification_close",
580
+ NOTIFICATION_ACTION = "notification_action",
581
+ PAYSLIP_QUERY = "payslip_query",
582
+ PAYSLIP_RETRIEVAL = "payslip_retrieval",
583
+ SALARY_DEDUCTION = "salary_deduction",
584
+ LEAVE_BALANCE = "leave_balance",
585
+ LEAVE_REQUEST = "leave_request",
586
+ PROFILE_INFO = "profile_info",
587
+ HIRING_DATE = "hiring_date",
588
+ POSITION_INFO = "position_info",
589
+ GENERAL_QUERY = "general_query",
590
+ OUT_OF_SCOPE = "out_of_scope"
591
+ }
592
+ interface ChatMessage {
593
+ role: MessageRole;
594
+ content: string;
595
+ }
596
+ interface CallToAction {
597
+ id: string;
598
+ label: string;
599
+ type: ActionType;
600
+ params?: Record<string, any>;
601
+ path?: string;
602
+ icon?: string;
603
+ variant?: 'default' | 'outline' | 'ghost' | 'destructive';
604
+ }
605
+ interface AiResponse {
606
+ message: string;
607
+ ctas?: CallToAction[];
608
+ metadata?: {
609
+ intent?: UserIntent;
610
+ model?: string;
611
+ tokensUsed?: number;
612
+ [key: string]: any;
613
+ };
614
+ requiresAction?: boolean;
615
+ chartData?: any;
616
+ threadId?: string;
617
+ }
618
+ interface ChatRequest {
619
+ message: string;
620
+ language?: 'en' | 'ar';
621
+ history?: ChatMessage[];
622
+ threadId?: string;
623
+ }
624
+ interface VoiceTranscription {
625
+ text: string;
626
+ language: string;
627
+ confidence?: number;
628
+ duration?: number;
629
+ }
630
+ interface VoiceResponse {
631
+ transcription: VoiceTranscription;
632
+ response: AiResponse;
633
+ }
634
+ interface ChatHistory {
635
+ id: string;
636
+ messages: Array<ChatMessage & {
637
+ timestamp: Date;
638
+ }>;
639
+ createdAt: Date;
640
+ updatedAt: Date;
641
+ }
642
+ interface ChatThread {
643
+ id: string;
644
+ userId: string;
645
+ username: string;
646
+ title: string | null;
647
+ status: string;
648
+ intent: string | null;
649
+ createdAt: Date;
650
+ updatedAt: Date;
651
+ lastMessageAt: Date;
652
+ messageCount: number;
653
+ }
654
+ interface ThreadMessage {
655
+ id: string;
656
+ threadId: string;
657
+ role: 'user' | 'assistant';
658
+ content: string;
659
+ metadata?: {
660
+ intent?: string;
661
+ ctas?: CallToAction[];
662
+ tokensUsed?: number;
663
+ [key: string]: any;
664
+ };
665
+ createdAt: Date;
666
+ }
667
+ interface GetThreadMessagesResponse {
668
+ thread: ChatThread;
669
+ messages: ThreadMessage[];
670
+ }
671
+ interface GetThreadsResponse {
672
+ threads: ChatThread[];
673
+ }
674
+ interface CreateThreadResponse {
675
+ thread: ChatThread;
676
+ }
677
+ interface DeleteThreadResponse {
678
+ success: boolean;
679
+ message: string;
680
+ }
681
+
682
+ declare class AiModule extends BaseClient {
683
+ sendMessage(request: ChatRequest): Promise<AiResponse>;
684
+ sendVoice(audioBlob: Blob, options?: {
685
+ language?: 'en' | 'ar';
686
+ threadId?: string;
687
+ }): Promise<VoiceResponse>;
688
+ saveChatMessage(message: ChatMessage): void;
689
+ getLocalChatHistory(): Array<ChatMessage & {
690
+ timestamp: Date;
691
+ }>;
692
+ clearChatHistory(): void;
693
+ getChatThreads(): Promise<ChatThread[]>;
694
+ getThreadMessages(threadId: string): Promise<GetThreadMessagesResponse>;
695
+ createThread(): Promise<ChatThread>;
696
+ deleteThread(threadId: string): Promise<void>;
697
+ }
698
+
699
+ interface GetSitSegmentsParams {
700
+ idFlexNum: string;
701
+ }
702
+ interface SitSegment {
703
+ segmentNumber?: string;
704
+ segmentName?: string;
705
+ segmentPrompt?: string;
706
+ applicationColumnName?: string;
707
+ requiredFlag?: string;
708
+ defaultType?: string;
709
+ originalDefaultValue?: string;
710
+ executedDefaultValue?: string;
711
+ valueSetId?: string;
712
+ flexValueSetName?: string;
713
+ validationType?: string;
714
+ enabledFlag?: string;
715
+ displayedFlag?: string;
716
+ updatableFlag?: string;
717
+ insertableFlag?: string;
718
+ executionStatus?: string;
719
+ }
720
+ type GetSitSegmentsResponse = SitSegment[];
721
+
722
+ declare class SegmentsModule extends BaseClient {
723
+ getSitSegments(params: GetSitSegmentsParams): Promise<GetSitSegmentsResponse>;
724
+ }
725
+
562
726
  declare class OracleEBSClient {
563
727
  readonly auth: AuthModule;
564
728
  readonly leaves: LeavesModule;
@@ -569,6 +733,8 @@ declare class OracleEBSClient {
569
733
  readonly accrualBalances: AccrualBalancesModule;
570
734
  readonly forms: FormsModule;
571
735
  readonly health: HealthModule;
736
+ readonly ai: AiModule;
737
+ readonly segments: SegmentsModule;
572
738
  constructor(config: OracleEBSConfig);
573
739
  setToken(token: string, user?: {
574
740
  userName?: string;
@@ -581,4 +747,4 @@ declare class OracleEBSClient {
581
747
  clearToken(): void;
582
748
  }
583
749
 
584
- export { type APIResponse as A, type GetPayslipDetailsParams as B, type CacheOptions as C, type PayslipDetail as D, type GetPayslipDetailsResponse as E, type PersonalInformation as F, type GetAbsenceTypesParams as G, type EmployeeHierarchyNode as H, type GetEmployeeHierarchyResponse as I, type GetTableColumnsParams as J, type GetTableColumnsResponse as K, type LoginCredentials as L, type DffSegment as M, type Notification as N, OracleEBSClient as O, type ProcessApprovalInput as P, type GetDffSegmentsParams as Q, type RetryOptions as R, type SitSegment as S, type TableColumn as T, type UserContext as U, type GetDffSegmentsResponse as V, type HealthCheckResponse as W, type AccrualBalance as X, type GetAccrualBalancesParams as Y, type GetAccrualBalancesResponse as Z, type OracleEBSConfig as a, type LoginResponse as b, type Responsibility as c, type AbsenceType as d, type GetAbsenceTypesResponse as e, type LeaveHistoryRecord as f, type GetLeaveHistoryResponse as g, type CreateLeaveRequestInput as h, type CreateLeaveRequestResponse as i, type GetSitSegmentsParams as j, type GetSitSegmentsResponse as k, type SaveAndPreviewSitRequestInput as l, type SaveAndPreviewSitRequestResponse as m, type SubmitSitRequestInput as n, type SubmitSitRequestResponse as o, type GetSitHistoryParams as p, type SitHistoryRecord as q, type GetSitHistoryResponse as r, type GetNotificationsResponse as s, type NotificationDetails as t, type GetNotificationDetailsParams as u, type ProcessApprovalResponse as v, type CloseFyiParams as w, type CloseFyiResponse as x, type GetPayslipHeaderParams as y, type PayslipHeader as z };
750
+ export { type GetAccrualBalancesParams as $, type APIResponse as A, type CloseFyiResponse as B, type CacheOptions as C, type GetPayslipHeaderParams as D, type PayslipHeader as E, type GetPayslipDetailsParams as F, type GetAbsenceTypesParams as G, type PayslipDetail as H, type GetPayslipDetailsResponse as I, type PersonalInformation as J, type EmployeeHierarchyNode as K, type LoginCredentials as L, type GetEmployeeHierarchyResponse as M, type Notification as N, OracleEBSClient as O, type ProcessApprovalInput as P, type GetTableColumnsParams as Q, type RetryOptions as R, type SitSegment$1 as S, type TableColumn as T, type UserContext as U, type GetTableColumnsResponse as V, type DffSegment as W, type GetDffSegmentsParams as X, type GetDffSegmentsResponse as Y, type HealthCheckResponse as Z, type AccrualBalance as _, type OracleEBSConfig as a, type GetAccrualBalancesResponse as a0, MessageRole as a1, ActionType as a2, UserIntent as a3, type ChatMessage as a4, type CallToAction as a5, type AiResponse as a6, type ChatRequest as a7, type VoiceTranscription as a8, type VoiceResponse as a9, type ChatHistory as aa, type ChatThread as ab, type ThreadMessage as ac, type GetThreadMessagesResponse as ad, type GetThreadsResponse as ae, type CreateThreadResponse as af, type DeleteThreadResponse as ag, type LoginResponse as b, type Responsibility as c, type AbsenceType as d, type GetAbsenceTypesResponse as e, type LeaveHistoryRecord as f, type GetLeaveHistoryResponse as g, type CreateLeaveRequestInput as h, type CreateLeaveRequestResponse as i, type GetSitSegmentsParams$1 as j, type GetSitSegmentsResponse$1 as k, type SaveAndPreviewSitRequestInput as l, type SaveAndPreviewSitRequestResponse as m, type SubmitSitRequestInput as n, type SubmitSitRequestResponse as o, type GetSitHistoryParams as p, type SitHistoryRecord as q, type GetSitHistoryResponse as r, type SitSegment as s, type GetSitSegmentsParams as t, type GetSitSegmentsResponse as u, type GetNotificationsResponse as v, type NotificationDetails as w, type GetNotificationDetailsParams as x, type ProcessApprovalResponse as y, type CloseFyiParams as z };