Skip to content

Commit ad7cbd4

Browse files
committed
fix(connectors): correct Grain id field/include flags and incident.io timestamp value shape (verified vs raw API specs)
1 parent af4e6c6 commit ad7cbd4

2 files changed

Lines changed: 23 additions & 29 deletions

File tree

apps/sim/connectors/grain/grain.ts

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,15 @@ interface GrainMeetingType {
4747
* A Grain recording as returned by the v2 recordings endpoints. Only the fields the
4848
* connector reads are modeled; the API returns additional optional fields.
4949
*
50-
* The v2 Public API returns the recording identifier as `recording_id` (confirmed in
51-
* the live list/get response examples). The legacy `id` field is also modeled and used
52-
* as a defensive fallback by {@link recordingId} so the connector tolerates either shape.
50+
* The v2 Public API returns the recording identifier as `id` (confirmed against the
51+
* Grain Public API reference and the in-repo Grain tools).
5352
*
54-
* `source` and `tags` are always present on the recording object. `teams`,
55-
* `meeting_type`, and `participants` are populated only when requested via the
56-
* corresponding `include` flag — the connector requests all three (see
57-
* {@link RECORDING_INCLUDE}) so they are available for tag mapping.
53+
* `source`, `tags`, `teams`, and `meeting_type` are returned by default on the
54+
* recording object. `participants` is populated only when requested via the
55+
* `include.participants` flag — the connector requests it (see {@link RECORDING_INCLUDE})
56+
* so participant names are available for tag mapping.
5857
*/
5958
interface GrainRecording {
60-
recording_id?: string
6159
id?: string
6260
title?: string
6361
start_datetime?: string
@@ -71,14 +69,6 @@ interface GrainRecording {
7169
participants?: GrainParticipant[]
7270
}
7371

74-
/**
75-
* The get-recording endpoint may return the recording bare or wrapped in a `Recording`
76-
* envelope depending on API version. This models both shapes.
77-
*/
78-
interface GrainRecordingResponse extends GrainRecording {
79-
Recording?: GrainRecording
80-
}
81-
8272
interface GrainRecordingsListResponse {
8373
recordings?: GrainRecording[]
8474
cursor?: string | null
@@ -97,11 +87,12 @@ interface GrainTranscriptSegment {
9787
}
9888

9989
/**
100-
* The `include` flags requested on every recordings call. Grain gates `participants`,
101-
* `teams`, and `meeting_type` behind include flags; all three feed connector tag
102-
* mapping, so they are always requested. Requesting an already-default field is a no-op.
90+
* The `include` flags requested on every recordings call. Grain returns `teams` and
91+
* `meeting_type` by default, but gates `participants` behind an include flag. Participant
92+
* names feed connector tag mapping, so the flag is always requested. Only documented
93+
* include flags are sent to avoid the API rejecting unknown keys.
10394
*/
104-
const RECORDING_INCLUDE = { participants: true, teams: true, meeting_type: true } as const
95+
const RECORDING_INCLUDE = { participants: true } as const
10596

10697
/**
10798
* Builds the auth + version headers shared by every Grain API request.
@@ -115,12 +106,11 @@ function grainHeaders(accessToken: string): Record<string, string> {
115106
}
116107

117108
/**
118-
* Resolves the recording's unique identifier. Prefers the documented v2 field
119-
* `recording_id`, falling back to the legacy `id` field. Returns an empty string when
120-
* neither is present.
109+
* Resolves the recording's unique identifier. The v2 Public API returns the recording
110+
* id as the `id` field. Returns an empty string when it is absent.
121111
*/
122112
function recordingId(recording: GrainRecording): string {
123-
return (recording.recording_id ?? recording.id ?? '').trim()
113+
return (recording.id ?? '').trim()
124114
}
125115

126116
/**
@@ -249,8 +239,7 @@ async function fetchRecording(accessToken: string, id: string): Promise<GrainRec
249239
throw new Error(`Failed to fetch Grain recording: ${response.status}`)
250240
}
251241

252-
const data = (await response.json()) as GrainRecordingResponse
253-
return data.Recording ?? data
242+
return (await response.json()) as GrainRecording
254243
}
255244

256245
/**

apps/sim/connectors/incidentio/incidentio.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ interface IncidentioRoleAssignment {
4040

4141
interface IncidentioTimestampValue {
4242
incident_timestamp?: { id?: string; name?: string; rank?: number }
43-
value?: string
43+
/**
44+
* The v2 API nests the timestamp string under `value.value` (an object), not a
45+
* flat string. A flat string is tolerated defensively for older shapes.
46+
*/
47+
value?: { value?: string } | string
4448
}
4549

4650
interface IncidentioIncident {
@@ -256,8 +260,9 @@ function formatIncidentContent(incident: IncidentioIncident, updates: Incidentio
256260
const timestampLines = (incident.incident_timestamp_values ?? [])
257261
.map((entry) => {
258262
const name = entry.incident_timestamp?.name
259-
if (!name || !entry.value) return undefined
260-
return `${name}: ${entry.value}`
263+
const value = typeof entry.value === 'string' ? entry.value : entry.value?.value
264+
if (!name || !value) return undefined
265+
return `${name}: ${value}`
261266
})
262267
.filter((line): line is string => Boolean(line))
263268
if (timestampLines.length > 0) {

0 commit comments

Comments
 (0)