@credal/actions 0.2.221 → 0.2.223
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/actions/actionMapper.js +38 -1
- package/dist/actions/autogen/templates.d.ts +5 -0
- package/dist/actions/autogen/templates.js +570 -0
- package/dist/actions/autogen/types.d.ts +541 -5
- package/dist/actions/autogen/types.js +236 -0
- package/dist/actions/providers/google-oauth/editAGoogleCalendarEvent.js +3 -1
- package/dist/actions/providers/google-oauth/scheduleCalendarMeeting.js +16 -5
- package/dist/actions/providers/google-oauth/updateCalendarEvent.js +2 -0
- package/dist/actions/providers/servicenow/getChangeRequests.d.ts +3 -0
- package/dist/actions/providers/servicenow/getChangeRequests.js +56 -0
- package/dist/actions/providers/servicenow/getIncidents.d.ts +3 -0
- package/dist/actions/providers/servicenow/getIncidents.js +58 -0
- package/dist/actions/providers/servicenow/getRecordsByQuery.d.ts +3 -0
- package/dist/actions/providers/servicenow/getRecordsByQuery.js +42 -0
- package/dist/actions/providers/servicenow/getSCTasks.d.ts +3 -0
- package/dist/actions/providers/servicenow/getSCTasks.js +53 -0
- package/dist/actions/providers/servicenow/getVIPTickets.d.ts +3 -0
- package/dist/actions/providers/servicenow/getVIPTickets.js +61 -0
- package/dist/actions/providers/servicenow/utils/tableQuery.d.ts +22 -0
- package/dist/actions/providers/servicenow/utils/tableQuery.js +62 -0
- package/package.json +1 -1
|
@@ -37,6 +37,7 @@ export var ProviderName;
|
|
|
37
37
|
ProviderName["LINEAR"] = "linear";
|
|
38
38
|
ProviderName["HUBSPOT"] = "hubspot";
|
|
39
39
|
ProviderName["SMARTSHEET"] = "smartsheet";
|
|
40
|
+
ProviderName["SERVICENOW"] = "servicenow";
|
|
40
41
|
ProviderName["BOXUSER"] = "boxUser";
|
|
41
42
|
})(ProviderName || (ProviderName = {}));
|
|
42
43
|
export var ActionName;
|
|
@@ -183,6 +184,11 @@ export var ActionName;
|
|
|
183
184
|
ActionName["GETSHEETROWS"] = "getSheetRows";
|
|
184
185
|
ActionName["ADDROWTOSHEET"] = "addRowToSheet";
|
|
185
186
|
ActionName["UPDATEROW"] = "updateRow";
|
|
187
|
+
ActionName["GETRECORDSBYQUERY"] = "getRecordsByQuery";
|
|
188
|
+
ActionName["GETINCIDENTS"] = "getIncidents";
|
|
189
|
+
ActionName["GETCHANGEREQUESTS"] = "getChangeRequests";
|
|
190
|
+
ActionName["GETSCTASKS"] = "getSCTasks";
|
|
191
|
+
ActionName["GETVIPTICKETS"] = "getVIPTickets";
|
|
186
192
|
})(ActionName || (ActionName = {}));
|
|
187
193
|
export const AuthParamsSchema = z.object({
|
|
188
194
|
authToken: z.string().optional(),
|
|
@@ -2413,6 +2419,10 @@ export const googleOauthScheduleCalendarMeetingParamsSchema = z.object({
|
|
|
2413
2419
|
.string()
|
|
2414
2420
|
.describe("The time zone for the meeting, IANA Time Zone identifier (e.g., 'America/New_York')")
|
|
2415
2421
|
.optional(),
|
|
2422
|
+
transparency: z
|
|
2423
|
+
.enum(["opaque", "transparent"])
|
|
2424
|
+
.describe('Opaque is the default value, and it blocks time on the calendar. This is equivalent to setting "Show me as" to "Busy" in the UI. Transparent means the event does not block time on the calendar. This is equivalent to setting "Show me as" to "Available" in the UI.')
|
|
2425
|
+
.optional(),
|
|
2416
2426
|
recurrence: z
|
|
2417
2427
|
.object({
|
|
2418
2428
|
frequency: z.enum(["DAILY", "WEEKLY", "MONTHLY", "YEARLY"]).describe("How often the meeting repeats").optional(),
|
|
@@ -2558,6 +2568,10 @@ export const googleOauthUpdateCalendarEventParamsSchema = z.object({
|
|
|
2558
2568
|
.string()
|
|
2559
2569
|
.describe("The time zone for the event, IANA Time Zone identifier (e.g., 'America/New_York')")
|
|
2560
2570
|
.optional(),
|
|
2571
|
+
transparency: z
|
|
2572
|
+
.enum(["opaque", "transparent"])
|
|
2573
|
+
.describe('Opaque is the default value, and it blocks time on the calendar. This is equivalent to setting "Show me as" to "Busy" in the UI. Transparent means the event does not block time on the calendar.')
|
|
2574
|
+
.optional(),
|
|
2561
2575
|
})
|
|
2562
2576
|
.describe("The fields to update on the event")
|
|
2563
2577
|
.optional(),
|
|
@@ -2592,6 +2606,10 @@ export const googleOauthEditAGoogleCalendarEventParamsSchema = z.object({
|
|
|
2592
2606
|
.string()
|
|
2593
2607
|
.describe("The time zone for the event, IANA Time Zone identifier (e.g., 'America/New_York')")
|
|
2594
2608
|
.optional(),
|
|
2609
|
+
transparency: z
|
|
2610
|
+
.enum(["opaque", "transparent"])
|
|
2611
|
+
.describe('Opaque is the default value, and it blocks time on the calendar. This is equivalent to setting "Show me as" to "Busy" in the UI. Transparent means the event does not block time on the calendar.')
|
|
2612
|
+
.optional(),
|
|
2595
2613
|
});
|
|
2596
2614
|
export const googleOauthEditAGoogleCalendarEventOutputSchema = z.object({
|
|
2597
2615
|
success: z.boolean().describe("Whether the event was edited successfully"),
|
|
@@ -5540,3 +5558,221 @@ export const smartsheetUpdateRowOutputSchema = z.object({
|
|
|
5540
5558
|
error: z.string().describe("Error message if the operation failed").optional(),
|
|
5541
5559
|
rowId: z.string().describe("The ID of the updated row").optional(),
|
|
5542
5560
|
});
|
|
5561
|
+
export const servicenowGetRecordsByQueryParamsSchema = z.object({
|
|
5562
|
+
tableName: z
|
|
5563
|
+
.string()
|
|
5564
|
+
.describe("The ServiceNow table to query (e.g. incident, change_request, sc_request, sys_user, kb_knowledge)"),
|
|
5565
|
+
query: z
|
|
5566
|
+
.string()
|
|
5567
|
+
.describe('ServiceNow encoded query string (sysparm_query) — NOT SQL, JQL, or natural language. Conditions are joined with ^ for AND and ^OR for OR, with no spaces around the ^. Format examples: field=value, field!=value, field>value, fieldLIKEvalue, fieldISEMPTY. Sort with ^ORDERBY<field> (ascending) or ^ORDERBYDESC<field> (descending). Example: "active=true^priority=1^ORDERBYDESCsys_created_on" means active records with priority 1, sorted by most recently created first. If omitted, records are returned unfiltered up to the limit.\n')
|
|
5568
|
+
.optional(),
|
|
5569
|
+
fields: z
|
|
5570
|
+
.array(z.string())
|
|
5571
|
+
.describe("Field names to return for each record (sysparm_fields). All fields are returned if omitted.")
|
|
5572
|
+
.optional(),
|
|
5573
|
+
limit: z.coerce.number().describe("Maximum number of records to return (defaults to 25)").optional(),
|
|
5574
|
+
offset: z.coerce.number().describe("Number of records to skip, for pagination (defaults to 0)").optional(),
|
|
5575
|
+
includeDisplayValues: z
|
|
5576
|
+
.boolean()
|
|
5577
|
+
.describe('If false (default), each field is returned as a plain scalar value (e.g. active: true, priority: "1"). If true, every field is instead returned as an object {value: "<raw value>", display_value: "<human-readable value>"} — useful for reference fields like assigned_to, where value is a sys_id and display_value is the user\'s name.\n')
|
|
5578
|
+
.optional(),
|
|
5579
|
+
});
|
|
5580
|
+
export const servicenowGetRecordsByQueryOutputSchema = z.object({
|
|
5581
|
+
success: z.boolean().describe("Whether the query was successful"),
|
|
5582
|
+
records: z.array(z.object({}).catchall(z.any())).describe("The records matching the query").optional(),
|
|
5583
|
+
error: z.string().describe("Error message if the query failed").optional(),
|
|
5584
|
+
});
|
|
5585
|
+
export const servicenowGetIncidentsParamsSchema = z.object({
|
|
5586
|
+
query: z
|
|
5587
|
+
.string()
|
|
5588
|
+
.describe('Optional additional ServiceNow encoded query (sysparm_query) ANDed onto the base incident lookup — NOT SQL, JQL, or natural language. Conditions are joined with ^ for AND and ^OR for OR, with no spaces around the ^. Example: "priority=1^state!=7" for open, priority-1 incidents. Leave empty to return all incidents up to the limit.\n')
|
|
5589
|
+
.optional(),
|
|
5590
|
+
additionalFields: z
|
|
5591
|
+
.array(z.string())
|
|
5592
|
+
.describe('Extra ServiceNow field technical names to fetch for instance-specific/custom fields not covered by the standard output (e.g. a custom "Program Office" field). Values are returned per record under extraFields, keyed by the field name given here.\n')
|
|
5593
|
+
.optional(),
|
|
5594
|
+
limit: z.coerce.number().describe("Maximum number of incidents to return (defaults to 25)").optional(),
|
|
5595
|
+
offset: z.coerce.number().describe("Number of records to skip, for pagination (defaults to 0)").optional(),
|
|
5596
|
+
});
|
|
5597
|
+
export const servicenowGetIncidentsOutputSchema = z.object({
|
|
5598
|
+
success: z.boolean().describe("Whether the query was successful"),
|
|
5599
|
+
records: z
|
|
5600
|
+
.array(z.object({
|
|
5601
|
+
number: z.string().describe("The incident ticket number (e.g. INC0010023)").optional(),
|
|
5602
|
+
caller: z.string().describe("The name of the person who reported the incident").optional(),
|
|
5603
|
+
assignee: z.string().describe("The name of the person assigned to the incident").optional(),
|
|
5604
|
+
assignmentGroup: z.string().describe("The name of the group assigned to the incident").optional(),
|
|
5605
|
+
shortDescription: z.string().describe("The short description of the incident").optional(),
|
|
5606
|
+
description: z.string().describe("The full description of the incident").optional(),
|
|
5607
|
+
state: z.string().describe("The current state of the incident").optional(),
|
|
5608
|
+
incidentState: z
|
|
5609
|
+
.string()
|
|
5610
|
+
.describe("The current incident-specific state (legacy field on some instances; may be absent)")
|
|
5611
|
+
.optional(),
|
|
5612
|
+
priority: z.string().describe("The priority of the incident").optional(),
|
|
5613
|
+
impact: z.string().describe("The impact of the incident").optional(),
|
|
5614
|
+
urgency: z.string().describe("The urgency of the incident").optional(),
|
|
5615
|
+
openedAt: z.string().describe("The date and time the incident was opened").optional(),
|
|
5616
|
+
updatedAt: z.string().describe("The date and time the incident was last updated").optional(),
|
|
5617
|
+
closedAt: z
|
|
5618
|
+
.string()
|
|
5619
|
+
.describe("The date and time the incident was closed or completed, if applicable")
|
|
5620
|
+
.optional(),
|
|
5621
|
+
workNotes: z.string().describe("Internal work notes on the incident").optional(),
|
|
5622
|
+
comments: z.string().describe("Additional (customer-visible) comments on the incident").optional(),
|
|
5623
|
+
timeToClosureMinutes: z.coerce
|
|
5624
|
+
.number()
|
|
5625
|
+
.describe("Minutes elapsed from opening to final closure, calculated from openedAt and closedAt")
|
|
5626
|
+
.optional(),
|
|
5627
|
+
extraFields: z
|
|
5628
|
+
.object({})
|
|
5629
|
+
.catchall(z.any())
|
|
5630
|
+
.describe("Values for any fields requested via the additionalFields parameter, keyed by field name")
|
|
5631
|
+
.optional(),
|
|
5632
|
+
}))
|
|
5633
|
+
.describe("The incident records matching the query")
|
|
5634
|
+
.optional(),
|
|
5635
|
+
error: z.string().describe("Error message if the query failed").optional(),
|
|
5636
|
+
});
|
|
5637
|
+
export const servicenowGetChangeRequestsParamsSchema = z.object({
|
|
5638
|
+
query: z
|
|
5639
|
+
.string()
|
|
5640
|
+
.describe('Optional additional ServiceNow encoded query (sysparm_query) ANDed onto the base change request lookup — NOT SQL, JQL, or natural language. Conditions are joined with ^ for AND and ^OR for OR, with no spaces around the ^. Example: "priority=1^state!=3" for open, priority-1 change requests. Leave empty to return all change requests up to the limit.\n')
|
|
5641
|
+
.optional(),
|
|
5642
|
+
additionalFields: z
|
|
5643
|
+
.array(z.string())
|
|
5644
|
+
.describe('Extra ServiceNow field technical names to fetch for instance-specific/custom fields not covered by the standard output (e.g. a custom "Program Office" field). Values are returned per record under extraFields, keyed by the field name given here.\n')
|
|
5645
|
+
.optional(),
|
|
5646
|
+
limit: z.coerce.number().describe("Maximum number of change requests to return (defaults to 25)").optional(),
|
|
5647
|
+
offset: z.coerce.number().describe("Number of records to skip, for pagination (defaults to 0)").optional(),
|
|
5648
|
+
});
|
|
5649
|
+
export const servicenowGetChangeRequestsOutputSchema = z.object({
|
|
5650
|
+
success: z.boolean().describe("Whether the query was successful"),
|
|
5651
|
+
records: z
|
|
5652
|
+
.array(z.object({
|
|
5653
|
+
number: z.string().describe("The change request number (e.g. CHG0010023)").optional(),
|
|
5654
|
+
requestor: z.string().describe("The name of the person who requested the change").optional(),
|
|
5655
|
+
assignee: z.string().describe("The name of the person assigned to the change request").optional(),
|
|
5656
|
+
assignmentGroup: z.string().describe("The name of the group assigned to the change request").optional(),
|
|
5657
|
+
shortDescription: z.string().describe("The short description of the change request").optional(),
|
|
5658
|
+
description: z.string().describe("The full description of the change request").optional(),
|
|
5659
|
+
state: z.string().describe("The current state of the change request").optional(),
|
|
5660
|
+
priority: z.string().describe("The priority of the change request").optional(),
|
|
5661
|
+
impact: z.string().describe("The impact of the change request").optional(),
|
|
5662
|
+
urgency: z.string().describe("The urgency of the change request").optional(),
|
|
5663
|
+
openedAt: z.string().describe("The date and time the change request was opened").optional(),
|
|
5664
|
+
updatedAt: z.string().describe("The date and time the change request was last updated").optional(),
|
|
5665
|
+
closedAt: z
|
|
5666
|
+
.string()
|
|
5667
|
+
.describe("The date and time the change request was closed or completed, if applicable")
|
|
5668
|
+
.optional(),
|
|
5669
|
+
workNotes: z.string().describe("Internal work notes on the change request").optional(),
|
|
5670
|
+
comments: z.string().describe("Additional (customer-visible) comments on the change request").optional(),
|
|
5671
|
+
timeToClosureMinutes: z.coerce
|
|
5672
|
+
.number()
|
|
5673
|
+
.describe("Minutes elapsed from opening to final closure, calculated from openedAt and closedAt")
|
|
5674
|
+
.optional(),
|
|
5675
|
+
extraFields: z
|
|
5676
|
+
.object({})
|
|
5677
|
+
.catchall(z.any())
|
|
5678
|
+
.describe("Values for any fields requested via the additionalFields parameter, keyed by field name")
|
|
5679
|
+
.optional(),
|
|
5680
|
+
}))
|
|
5681
|
+
.describe("The change request records matching the query")
|
|
5682
|
+
.optional(),
|
|
5683
|
+
error: z.string().describe("Error message if the query failed").optional(),
|
|
5684
|
+
});
|
|
5685
|
+
export const servicenowGetSCTasksParamsSchema = z.object({
|
|
5686
|
+
query: z
|
|
5687
|
+
.string()
|
|
5688
|
+
.describe('Optional additional ServiceNow encoded query (sysparm_query) ANDed onto the base SCTASK lookup — NOT SQL, JQL, or natural language. Conditions are joined with ^ for AND and ^OR for OR, with no spaces around the ^. Example: "priority=1^state!=3" for open, priority-1 SCTASKs. Leave empty to return all SCTASKs up to the limit.\n')
|
|
5689
|
+
.optional(),
|
|
5690
|
+
additionalFields: z
|
|
5691
|
+
.array(z.string())
|
|
5692
|
+
.describe('Extra ServiceNow field technical names to fetch for instance-specific/custom fields not covered by the standard output (e.g. a custom "Program Office" field). Values are returned per record under extraFields, keyed by the field name given here.\n')
|
|
5693
|
+
.optional(),
|
|
5694
|
+
limit: z.coerce.number().describe("Maximum number of SCTASKs to return (defaults to 25)").optional(),
|
|
5695
|
+
offset: z.coerce.number().describe("Number of records to skip, for pagination (defaults to 0)").optional(),
|
|
5696
|
+
});
|
|
5697
|
+
export const servicenowGetSCTasksOutputSchema = z.object({
|
|
5698
|
+
success: z.boolean().describe("Whether the query was successful"),
|
|
5699
|
+
records: z
|
|
5700
|
+
.array(z.object({
|
|
5701
|
+
number: z.string().describe("The SCTASK ticket number (e.g. SCTASK0010023)").optional(),
|
|
5702
|
+
ritmNumber: z
|
|
5703
|
+
.string()
|
|
5704
|
+
.describe("The number of the parent Requested Item (RITM) this SCTASK belongs to")
|
|
5705
|
+
.optional(),
|
|
5706
|
+
assignee: z.string().describe("The name of the person assigned to the SCTASK").optional(),
|
|
5707
|
+
assignmentGroup: z.string().describe("The name of the group assigned to the SCTASK").optional(),
|
|
5708
|
+
shortDescription: z.string().describe("The short description of the SCTASK").optional(),
|
|
5709
|
+
description: z.string().describe("The full description of the SCTASK").optional(),
|
|
5710
|
+
state: z.string().describe("The current state of the SCTASK").optional(),
|
|
5711
|
+
priority: z.string().describe("The priority of the SCTASK").optional(),
|
|
5712
|
+
openedAt: z.string().describe("The date and time the SCTASK was opened").optional(),
|
|
5713
|
+
updatedAt: z.string().describe("The date and time the SCTASK was last updated").optional(),
|
|
5714
|
+
closedAt: z.string().describe("The date and time the SCTASK was closed or completed, if applicable").optional(),
|
|
5715
|
+
workNotes: z.string().describe("Internal work notes on the SCTASK").optional(),
|
|
5716
|
+
comments: z.string().describe("Additional (customer-visible) comments on the SCTASK").optional(),
|
|
5717
|
+
timeToClosureMinutes: z.coerce
|
|
5718
|
+
.number()
|
|
5719
|
+
.describe("Minutes elapsed from opening to final closure, calculated from openedAt and closedAt")
|
|
5720
|
+
.optional(),
|
|
5721
|
+
extraFields: z
|
|
5722
|
+
.object({})
|
|
5723
|
+
.catchall(z.any())
|
|
5724
|
+
.describe("Values for any fields requested via the additionalFields parameter, keyed by field name")
|
|
5725
|
+
.optional(),
|
|
5726
|
+
}))
|
|
5727
|
+
.describe("The SCTASK records matching the query")
|
|
5728
|
+
.optional(),
|
|
5729
|
+
error: z.string().describe("Error message if the query failed").optional(),
|
|
5730
|
+
});
|
|
5731
|
+
export const servicenowGetVIPTicketsParamsSchema = z.object({
|
|
5732
|
+
ticketType: z.enum(["incident", "sc_task"]).describe("Which kind of ticket to look up VIP records for"),
|
|
5733
|
+
query: z
|
|
5734
|
+
.string()
|
|
5735
|
+
.describe('Optional additional ServiceNow encoded query (sysparm_query) ANDed onto the base VIP lookup — NOT SQL, JQL, or natural language. Conditions are joined with ^ for AND and ^OR for OR, with no spaces around the ^. Example: "priority=1" to further narrow to priority-1 VIP tickets. Leave empty to return all VIP tickets of the given type up to the limit.\n')
|
|
5736
|
+
.optional(),
|
|
5737
|
+
additionalFields: z
|
|
5738
|
+
.array(z.string())
|
|
5739
|
+
.describe('Extra ServiceNow field technical names to fetch for instance-specific/custom fields not covered by the standard output (e.g. a custom "Program Office" field). Values are returned per record under extraFields, keyed by the field name given here.\n')
|
|
5740
|
+
.optional(),
|
|
5741
|
+
limit: z.coerce.number().describe("Maximum number of VIP tickets to return (defaults to 25)").optional(),
|
|
5742
|
+
offset: z.coerce.number().describe("Number of records to skip, for pagination (defaults to 0)").optional(),
|
|
5743
|
+
});
|
|
5744
|
+
export const servicenowGetVIPTicketsOutputSchema = z.object({
|
|
5745
|
+
success: z.boolean().describe("Whether the query was successful"),
|
|
5746
|
+
records: z
|
|
5747
|
+
.array(z.object({
|
|
5748
|
+
ticketType: z.string().describe("Whether this record is an incident or a SCTASK").optional(),
|
|
5749
|
+
number: z.string().describe("The ticket number").optional(),
|
|
5750
|
+
ritmNumber: z
|
|
5751
|
+
.string()
|
|
5752
|
+
.describe("The number of the parent Requested Item (RITM), if this is a SCTASK")
|
|
5753
|
+
.optional(),
|
|
5754
|
+
vipUser: z.string().describe("The name of the VIP caller or requester associated with this ticket").optional(),
|
|
5755
|
+
assignee: z.string().describe("The name of the person assigned to the ticket").optional(),
|
|
5756
|
+
assignmentGroup: z.string().describe("The name of the group assigned to the ticket").optional(),
|
|
5757
|
+
shortDescription: z.string().describe("The short description of the ticket").optional(),
|
|
5758
|
+
description: z.string().describe("The full description of the ticket").optional(),
|
|
5759
|
+
state: z.string().describe("The current state of the ticket").optional(),
|
|
5760
|
+
openedAt: z.string().describe("The date and time the ticket was opened").optional(),
|
|
5761
|
+
updatedAt: z.string().describe("The date and time the ticket was last updated").optional(),
|
|
5762
|
+
closedAt: z.string().describe("The date and time the ticket was closed or completed, if applicable").optional(),
|
|
5763
|
+
workNotes: z.string().describe("Internal work notes on the ticket").optional(),
|
|
5764
|
+
comments: z.string().describe("Additional (customer-visible) comments on the ticket").optional(),
|
|
5765
|
+
timeToClosureMinutes: z.coerce
|
|
5766
|
+
.number()
|
|
5767
|
+
.describe("Minutes elapsed from opening to final closure, calculated from openedAt and closedAt")
|
|
5768
|
+
.optional(),
|
|
5769
|
+
extraFields: z
|
|
5770
|
+
.object({})
|
|
5771
|
+
.catchall(z.any())
|
|
5772
|
+
.describe("Values for any fields requested via the additionalFields parameter, keyed by field name")
|
|
5773
|
+
.optional(),
|
|
5774
|
+
}))
|
|
5775
|
+
.describe("The VIP ticket records matching the query")
|
|
5776
|
+
.optional(),
|
|
5777
|
+
error: z.string().describe("Error message if the query failed").optional(),
|
|
5778
|
+
});
|
|
@@ -5,7 +5,7 @@ const editAGoogleCalendarEvent = async ({ params, authParams, }) => {
|
|
|
5
5
|
if (!authParams.authToken) {
|
|
6
6
|
return { success: false, error: MISSING_AUTH_TOKEN, eventId: "", eventUrl: "", eventDayOfWeek: "" };
|
|
7
7
|
}
|
|
8
|
-
const { calendarId, eventId, title, description, start, end, location, attendees, status, organizer, timeZone } = params;
|
|
8
|
+
const { calendarId, eventId, title, description, start, end, location, attendees, status, organizer, timeZone, transparency, } = params;
|
|
9
9
|
const url = `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}`;
|
|
10
10
|
const body = {};
|
|
11
11
|
if (title !== undefined)
|
|
@@ -32,6 +32,8 @@ const editAGoogleCalendarEvent = async ({ params, authParams, }) => {
|
|
|
32
32
|
body.status = status;
|
|
33
33
|
if (organizer !== undefined)
|
|
34
34
|
body.organizer = organizer;
|
|
35
|
+
if (transparency !== undefined)
|
|
36
|
+
body.transparency = transparency;
|
|
35
37
|
try {
|
|
36
38
|
const res = await axiosClient.patch(url, body, {
|
|
37
39
|
headers: {
|
|
@@ -18,10 +18,17 @@ function generateRecurrenceRule(recurrence) {
|
|
|
18
18
|
const year = date.getUTCFullYear();
|
|
19
19
|
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
20
20
|
const day = String(date.getUTCDate()).padStart(2, "0");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
// Use date-only format for UNTIL when BYDAY is specified (day-based recurrence)
|
|
22
|
+
// This is required by Google Calendar API for WEEKLY+BYDAY recurrences
|
|
23
|
+
if (recurrence.byDay && recurrence.byDay.length > 0) {
|
|
24
|
+
rrule += `;UNTIL=${year}${month}${day}`;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const hour = String(date.getUTCHours()).padStart(2, "0");
|
|
28
|
+
const minute = String(date.getUTCMinutes()).padStart(2, "0");
|
|
29
|
+
const second = String(date.getUTCSeconds()).padStart(2, "0");
|
|
30
|
+
rrule += `;UNTIL=${year}${month}${day}T${hour}${minute}${second}Z`; // trufflehog:ignore
|
|
31
|
+
}
|
|
25
32
|
}
|
|
26
33
|
if (recurrence.byDay && recurrence.byDay.length > 0) {
|
|
27
34
|
rrule += `;BYDAY=${recurrence.byDay.join(",")}`;
|
|
@@ -39,7 +46,7 @@ const scheduleCalendarMeeting = async ({ params, authParams, }) => {
|
|
|
39
46
|
if (!authParams.authToken) {
|
|
40
47
|
throw new Error(MISSING_AUTH_TOKEN);
|
|
41
48
|
}
|
|
42
|
-
const { calendarId, name, start, end, description, attendees, useGoogleMeet, timeZone, recurrence } = params;
|
|
49
|
+
const { calendarId, name, start, end, description, attendees, useGoogleMeet, timeZone, recurrence, transparency } = params;
|
|
43
50
|
// https://developers.google.com/calendar/api/v3/reference/events/insert
|
|
44
51
|
let createEventApiUrl = `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(calendarId)}/events`;
|
|
45
52
|
const data = {
|
|
@@ -81,6 +88,10 @@ const scheduleCalendarMeeting = async ({ params, authParams, }) => {
|
|
|
81
88
|
};
|
|
82
89
|
}
|
|
83
90
|
}
|
|
91
|
+
// Add transparency if specified
|
|
92
|
+
if (transparency !== undefined) {
|
|
93
|
+
data.transparency = transparency;
|
|
94
|
+
}
|
|
84
95
|
try {
|
|
85
96
|
const response = await axiosClient.post(createEventApiUrl, data, {
|
|
86
97
|
headers: {
|
|
@@ -32,6 +32,8 @@ const updateCalendarEvent = async ({ params, authParams, }) => {
|
|
|
32
32
|
body.status = updates.status;
|
|
33
33
|
if (updates.organizer != undefined)
|
|
34
34
|
body.organizer = updates.organizer;
|
|
35
|
+
if (updates.transparency != undefined)
|
|
36
|
+
body.transparency = updates.transparency;
|
|
35
37
|
}
|
|
36
38
|
try {
|
|
37
39
|
const res = await axiosClient.patch(url, body, {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { computeTimeToClosureMinutes, extractAdditionalFields, queryServiceNowTable } from "./utils/tableQuery.js";
|
|
2
|
+
const CHANGE_REQUEST_FIELDS = [
|
|
3
|
+
"number",
|
|
4
|
+
"short_description",
|
|
5
|
+
"description",
|
|
6
|
+
"state",
|
|
7
|
+
"priority",
|
|
8
|
+
"impact",
|
|
9
|
+
"urgency",
|
|
10
|
+
"requested_by",
|
|
11
|
+
"assigned_to",
|
|
12
|
+
"assignment_group",
|
|
13
|
+
"opened_at",
|
|
14
|
+
"sys_updated_on",
|
|
15
|
+
"closed_at",
|
|
16
|
+
"work_notes",
|
|
17
|
+
"comments",
|
|
18
|
+
];
|
|
19
|
+
const getChangeRequests = async ({ params, authParams, }) => {
|
|
20
|
+
const { query, additionalFields, limit, offset } = params;
|
|
21
|
+
const result = await queryServiceNowTable({
|
|
22
|
+
authParams,
|
|
23
|
+
tableName: "change_request",
|
|
24
|
+
fields: CHANGE_REQUEST_FIELDS,
|
|
25
|
+
filter: query,
|
|
26
|
+
additionalFields,
|
|
27
|
+
limit,
|
|
28
|
+
offset,
|
|
29
|
+
});
|
|
30
|
+
if ("error" in result) {
|
|
31
|
+
return { success: false, error: result.error };
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
success: true,
|
|
35
|
+
records: result.records.map(record => ({
|
|
36
|
+
number: record.number,
|
|
37
|
+
requestor: record.requested_by,
|
|
38
|
+
assignee: record.assigned_to,
|
|
39
|
+
assignmentGroup: record.assignment_group,
|
|
40
|
+
shortDescription: record.short_description,
|
|
41
|
+
description: record.description,
|
|
42
|
+
state: record.state,
|
|
43
|
+
priority: record.priority,
|
|
44
|
+
impact: record.impact,
|
|
45
|
+
urgency: record.urgency,
|
|
46
|
+
openedAt: record.opened_at,
|
|
47
|
+
updatedAt: record.sys_updated_on,
|
|
48
|
+
closedAt: record.closed_at,
|
|
49
|
+
workNotes: record.work_notes,
|
|
50
|
+
comments: record.comments,
|
|
51
|
+
timeToClosureMinutes: computeTimeToClosureMinutes(record.opened_at, record.closed_at),
|
|
52
|
+
extraFields: extractAdditionalFields(record, additionalFields),
|
|
53
|
+
})),
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
export default getChangeRequests;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { computeTimeToClosureMinutes, extractAdditionalFields, queryServiceNowTable } from "./utils/tableQuery.js";
|
|
2
|
+
const INCIDENT_FIELDS = [
|
|
3
|
+
"number",
|
|
4
|
+
"short_description",
|
|
5
|
+
"description",
|
|
6
|
+
"state",
|
|
7
|
+
"incident_state",
|
|
8
|
+
"priority",
|
|
9
|
+
"impact",
|
|
10
|
+
"urgency",
|
|
11
|
+
"caller_id",
|
|
12
|
+
"assigned_to",
|
|
13
|
+
"assignment_group",
|
|
14
|
+
"opened_at",
|
|
15
|
+
"sys_updated_on",
|
|
16
|
+
"closed_at",
|
|
17
|
+
"work_notes",
|
|
18
|
+
"comments",
|
|
19
|
+
];
|
|
20
|
+
const getIncidents = async ({ params, authParams, }) => {
|
|
21
|
+
const { query, additionalFields, limit, offset } = params;
|
|
22
|
+
const result = await queryServiceNowTable({
|
|
23
|
+
authParams,
|
|
24
|
+
tableName: "incident",
|
|
25
|
+
fields: INCIDENT_FIELDS,
|
|
26
|
+
filter: query,
|
|
27
|
+
additionalFields,
|
|
28
|
+
limit,
|
|
29
|
+
offset,
|
|
30
|
+
});
|
|
31
|
+
if ("error" in result) {
|
|
32
|
+
return { success: false, error: result.error };
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
success: true,
|
|
36
|
+
records: result.records.map(record => ({
|
|
37
|
+
number: record.number,
|
|
38
|
+
caller: record.caller_id,
|
|
39
|
+
assignee: record.assigned_to,
|
|
40
|
+
assignmentGroup: record.assignment_group,
|
|
41
|
+
shortDescription: record.short_description,
|
|
42
|
+
description: record.description,
|
|
43
|
+
state: record.state,
|
|
44
|
+
incidentState: record.incident_state,
|
|
45
|
+
priority: record.priority,
|
|
46
|
+
impact: record.impact,
|
|
47
|
+
urgency: record.urgency,
|
|
48
|
+
openedAt: record.opened_at,
|
|
49
|
+
updatedAt: record.sys_updated_on,
|
|
50
|
+
closedAt: record.closed_at,
|
|
51
|
+
workNotes: record.work_notes,
|
|
52
|
+
comments: record.comments,
|
|
53
|
+
timeToClosureMinutes: computeTimeToClosureMinutes(record.opened_at, record.closed_at),
|
|
54
|
+
extraFields: extractAdditionalFields(record, additionalFields),
|
|
55
|
+
})),
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export default getIncidents;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ApiError, axiosClient } from "../../util/axiosClient.js";
|
|
2
|
+
const DEFAULT_LIMIT = 25;
|
|
3
|
+
const MAX_LIMIT = 10000;
|
|
4
|
+
const getRecordsByQuery = async ({ params, authParams, }) => {
|
|
5
|
+
const { authToken, baseUrl } = authParams;
|
|
6
|
+
const { tableName, query, fields, limit = DEFAULT_LIMIT, offset = 0, includeDisplayValues = false } = params;
|
|
7
|
+
if (!authToken || !baseUrl) {
|
|
8
|
+
return { success: false, error: "authToken and baseUrl are required for the ServiceNow API" };
|
|
9
|
+
}
|
|
10
|
+
const cappedLimit = Math.min(limit, MAX_LIMIT);
|
|
11
|
+
const queryParams = new URLSearchParams();
|
|
12
|
+
queryParams.append("sysparm_limit", cappedLimit.toString());
|
|
13
|
+
queryParams.append("sysparm_offset", offset.toString());
|
|
14
|
+
// "all" nests each field as {value, display_value}; "false" keeps fields as plain scalars
|
|
15
|
+
queryParams.append("sysparm_display_value", includeDisplayValues ? "all" : "false");
|
|
16
|
+
queryParams.append("sysparm_exclude_reference_link", "true");
|
|
17
|
+
if (query) {
|
|
18
|
+
queryParams.append("sysparm_query", query);
|
|
19
|
+
}
|
|
20
|
+
if (fields && fields.length > 0) {
|
|
21
|
+
queryParams.append("sysparm_fields", fields.join(","));
|
|
22
|
+
}
|
|
23
|
+
const url = `${baseUrl.replace(/\/+$/, "")}/api/now/table/${encodeURIComponent(tableName)}?${queryParams.toString()}`;
|
|
24
|
+
try {
|
|
25
|
+
const response = await axiosClient.get(url, {
|
|
26
|
+
headers: {
|
|
27
|
+
Accept: "application/json",
|
|
28
|
+
Authorization: `Bearer ${authToken}`,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
const result = response.data.result;
|
|
32
|
+
return { success: true, records: Array.isArray(result) ? result : [] };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error("Error querying ServiceNow records:", error);
|
|
36
|
+
return {
|
|
37
|
+
success: false,
|
|
38
|
+
error: error instanceof ApiError ? error.message : "An unknown error occurred",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
export default getRecordsByQuery;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { computeTimeToClosureMinutes, extractAdditionalFields, queryServiceNowTable } from "./utils/tableQuery.js";
|
|
2
|
+
const SC_TASK_FIELDS = [
|
|
3
|
+
"number",
|
|
4
|
+
"request_item",
|
|
5
|
+
"short_description",
|
|
6
|
+
"description",
|
|
7
|
+
"state",
|
|
8
|
+
"priority",
|
|
9
|
+
"assigned_to",
|
|
10
|
+
"assignment_group",
|
|
11
|
+
"opened_at",
|
|
12
|
+
"sys_updated_on",
|
|
13
|
+
"closed_at",
|
|
14
|
+
"work_notes",
|
|
15
|
+
"comments",
|
|
16
|
+
];
|
|
17
|
+
const getSCTasks = async ({ params, authParams, }) => {
|
|
18
|
+
const { query, additionalFields, limit, offset } = params;
|
|
19
|
+
const result = await queryServiceNowTable({
|
|
20
|
+
authParams,
|
|
21
|
+
tableName: "sc_task",
|
|
22
|
+
fields: SC_TASK_FIELDS,
|
|
23
|
+
filter: query,
|
|
24
|
+
additionalFields,
|
|
25
|
+
limit,
|
|
26
|
+
offset,
|
|
27
|
+
});
|
|
28
|
+
if ("error" in result) {
|
|
29
|
+
return { success: false, error: result.error };
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
records: result.records.map(record => ({
|
|
34
|
+
number: record.number,
|
|
35
|
+
// request_item's display value is the parent Requested Item's number (e.g. RITM0010023)
|
|
36
|
+
ritmNumber: record.request_item,
|
|
37
|
+
assignee: record.assigned_to,
|
|
38
|
+
assignmentGroup: record.assignment_group,
|
|
39
|
+
shortDescription: record.short_description,
|
|
40
|
+
description: record.description,
|
|
41
|
+
state: record.state,
|
|
42
|
+
priority: record.priority,
|
|
43
|
+
openedAt: record.opened_at,
|
|
44
|
+
updatedAt: record.sys_updated_on,
|
|
45
|
+
closedAt: record.closed_at,
|
|
46
|
+
workNotes: record.work_notes,
|
|
47
|
+
comments: record.comments,
|
|
48
|
+
timeToClosureMinutes: computeTimeToClosureMinutes(record.opened_at, record.closed_at),
|
|
49
|
+
extraFields: extractAdditionalFields(record, additionalFields),
|
|
50
|
+
})),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export default getSCTasks;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { computeTimeToClosureMinutes, extractAdditionalFields, queryServiceNowTable, } from "./utils/tableQuery.js";
|
|
2
|
+
const SHARED_FIELDS = [
|
|
3
|
+
"number",
|
|
4
|
+
"assigned_to",
|
|
5
|
+
"assignment_group",
|
|
6
|
+
"short_description",
|
|
7
|
+
"description",
|
|
8
|
+
"state",
|
|
9
|
+
"opened_at",
|
|
10
|
+
"sys_updated_on",
|
|
11
|
+
"closed_at",
|
|
12
|
+
"work_notes",
|
|
13
|
+
"comments",
|
|
14
|
+
];
|
|
15
|
+
// vip is a standard (non-custom) boolean field on sys_user used to flag VIP users.
|
|
16
|
+
const INCIDENT_VIP_FIELDS = [...SHARED_FIELDS, "caller_id"];
|
|
17
|
+
const INCIDENT_VIP_BASE_FILTER = "caller_id.vip=true";
|
|
18
|
+
const SC_TASK_VIP_FIELDS = [...SHARED_FIELDS, "request_item", "request_item.requested_for"];
|
|
19
|
+
const SC_TASK_VIP_BASE_FILTER = "request_item.requested_for.vip=true";
|
|
20
|
+
function mapRecord(record, ticketType, additionalFields) {
|
|
21
|
+
return {
|
|
22
|
+
ticketType,
|
|
23
|
+
number: record.number,
|
|
24
|
+
ritmNumber: ticketType === "sc_task" ? record.request_item : undefined,
|
|
25
|
+
vipUser: ticketType === "incident" ? record.caller_id : record["request_item.requested_for"],
|
|
26
|
+
assignee: record.assigned_to,
|
|
27
|
+
assignmentGroup: record.assignment_group,
|
|
28
|
+
shortDescription: record.short_description,
|
|
29
|
+
description: record.description,
|
|
30
|
+
state: record.state,
|
|
31
|
+
openedAt: record.opened_at,
|
|
32
|
+
updatedAt: record.sys_updated_on,
|
|
33
|
+
closedAt: record.closed_at,
|
|
34
|
+
workNotes: record.work_notes,
|
|
35
|
+
comments: record.comments,
|
|
36
|
+
timeToClosureMinutes: computeTimeToClosureMinutes(record.opened_at, record.closed_at),
|
|
37
|
+
extraFields: extractAdditionalFields(record, additionalFields),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const getVIPTickets = async ({ params, authParams, }) => {
|
|
41
|
+
const { ticketType, query, additionalFields, limit, offset } = params;
|
|
42
|
+
const isIncident = ticketType === "incident";
|
|
43
|
+
const result = await queryServiceNowTable({
|
|
44
|
+
authParams,
|
|
45
|
+
tableName: isIncident ? "incident" : "sc_task",
|
|
46
|
+
fields: isIncident ? INCIDENT_VIP_FIELDS : SC_TASK_VIP_FIELDS,
|
|
47
|
+
baseFilter: isIncident ? INCIDENT_VIP_BASE_FILTER : SC_TASK_VIP_BASE_FILTER,
|
|
48
|
+
filter: query,
|
|
49
|
+
additionalFields,
|
|
50
|
+
limit,
|
|
51
|
+
offset,
|
|
52
|
+
});
|
|
53
|
+
if ("error" in result) {
|
|
54
|
+
return { success: false, error: result.error };
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
records: result.records.map(record => mapRecord(record, ticketType, additionalFields)),
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
export default getVIPTickets;
|