featurebase-node 0.15.1 → 0.15.2

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/client.d.mts +2 -2
  3. package/client.d.mts.map +1 -1
  4. package/client.d.ts +2 -2
  5. package/client.d.ts.map +1 -1
  6. package/client.js.map +1 -1
  7. package/client.mjs.map +1 -1
  8. package/package.json +1 -1
  9. package/resources/changelogs/changelogs.d.mts +1166 -6
  10. package/resources/changelogs/changelogs.d.mts.map +1 -1
  11. package/resources/changelogs/changelogs.d.ts +1166 -6
  12. package/resources/changelogs/changelogs.d.ts.map +1 -1
  13. package/resources/changelogs/changelogs.js +53 -3
  14. package/resources/changelogs/changelogs.js.map +1 -1
  15. package/resources/changelogs/changelogs.mjs +53 -3
  16. package/resources/changelogs/changelogs.mjs.map +1 -1
  17. package/resources/changelogs/index.d.mts +1 -1
  18. package/resources/changelogs/index.d.mts.map +1 -1
  19. package/resources/changelogs/index.d.ts +1 -1
  20. package/resources/changelogs/index.d.ts.map +1 -1
  21. package/resources/changelogs/index.js.map +1 -1
  22. package/resources/changelogs/index.mjs.map +1 -1
  23. package/resources/feedback/comments.d.mts +4 -2
  24. package/resources/feedback/comments.d.mts.map +1 -1
  25. package/resources/feedback/comments.d.ts +4 -2
  26. package/resources/feedback/comments.d.ts.map +1 -1
  27. package/resources/feedback/custom-fields.d.mts +12 -0
  28. package/resources/feedback/custom-fields.d.mts.map +1 -1
  29. package/resources/feedback/custom-fields.d.ts +12 -0
  30. package/resources/feedback/custom-fields.d.ts.map +1 -1
  31. package/resources/feedback/posts/index.d.mts +1 -0
  32. package/resources/feedback/posts/index.d.mts.map +1 -1
  33. package/resources/feedback/posts/index.d.ts +1 -0
  34. package/resources/feedback/posts/index.d.ts.map +1 -1
  35. package/resources/feedback/posts/index.js +3 -1
  36. package/resources/feedback/posts/index.js.map +1 -1
  37. package/resources/feedback/posts/index.mjs +1 -0
  38. package/resources/feedback/posts/index.mjs.map +1 -1
  39. package/resources/feedback/posts/insights.d.mts +254 -0
  40. package/resources/feedback/posts/insights.d.mts.map +1 -0
  41. package/resources/feedback/posts/insights.d.ts +254 -0
  42. package/resources/feedback/posts/insights.d.ts.map +1 -0
  43. package/resources/feedback/posts/insights.js +269 -0
  44. package/resources/feedback/posts/insights.js.map +1 -0
  45. package/resources/feedback/posts/insights.mjs +265 -0
  46. package/resources/feedback/posts/insights.mjs.map +1 -0
  47. package/resources/feedback/posts/posts.d.mts +647 -20
  48. package/resources/feedback/posts/posts.d.mts.map +1 -1
  49. package/resources/feedback/posts/posts.d.ts +647 -20
  50. package/resources/feedback/posts/posts.d.ts.map +1 -1
  51. package/resources/feedback/posts/posts.js +199 -7
  52. package/resources/feedback/posts/posts.js.map +1 -1
  53. package/resources/feedback/posts/posts.mjs +199 -7
  54. package/resources/feedback/posts/posts.mjs.map +1 -1
  55. package/resources/index.d.mts +1 -1
  56. package/resources/index.d.mts.map +1 -1
  57. package/resources/index.d.ts +1 -1
  58. package/resources/index.d.ts.map +1 -1
  59. package/resources/index.js.map +1 -1
  60. package/resources/index.mjs.map +1 -1
  61. package/resources/support/tickets/tickets.d.mts +9 -5
  62. package/resources/support/tickets/tickets.d.mts.map +1 -1
  63. package/resources/support/tickets/tickets.d.ts +9 -5
  64. package/resources/support/tickets/tickets.d.ts.map +1 -1
  65. package/resources/support/tickets/tickets.js.map +1 -1
  66. package/resources/support/tickets/tickets.mjs.map +1 -1
  67. package/src/client.ts +2 -0
  68. package/src/resources/changelogs/changelogs.ts +2003 -51
  69. package/src/resources/changelogs/index.ts +1 -0
  70. package/src/resources/feedback/comments.ts +4 -2
  71. package/src/resources/feedback/custom-fields.ts +15 -0
  72. package/src/resources/feedback/posts/index.ts +7 -0
  73. package/src/resources/feedback/posts/insights.ts +340 -0
  74. package/src/resources/feedback/posts/posts.ts +764 -20
  75. package/src/resources/index.ts +1 -0
  76. package/src/resources/support/tickets/tickets.ts +9 -5
  77. package/src/version.ts +1 -1
  78. package/version.d.mts +1 -1
  79. package/version.d.ts +1 -1
  80. package/version.js +1 -1
  81. package/version.mjs +1 -1
@@ -4,6 +4,7 @@ export {
4
4
  Changelogs,
5
5
  type Changelog,
6
6
  type PublishUnpublishSuccess,
7
+ type ChangelogRetrieveResponse,
7
8
  type ChangelogDeleteResponse,
8
9
  type ChangelogCreateParams,
9
10
  type ChangelogRetrieveParams,
@@ -856,8 +856,10 @@ export interface CommentCreateParams {
856
856
 
857
857
  /**
858
858
  * Body param: Author to attribute the post to. If not provided, uses the
859
- * authenticated user. Supports multiple identification methods: id (Featurebase
860
- * ID), userId (external SSO ID), or email.
859
+ * authenticated user unless `source` is given, in which case a guest author is
860
+ * synthesised from `source.label` (or the channel name), because a relayed request
861
+ * belongs to the customer who said it. Supports multiple identification methods:
862
+ * id (Featurebase ID), userId (external SSO ID), or email.
861
863
  */
862
864
  author?: TicketsAPI.AuthorInput;
863
865
 
@@ -193,6 +193,21 @@ export namespace CustomField {
193
193
  * Option display label
194
194
  */
195
195
  label: string;
196
+
197
+ /**
198
+ * Option description
199
+ */
200
+ description?: string;
201
+
202
+ /**
203
+ * Option group label
204
+ */
205
+ group?: string;
206
+
207
+ /**
208
+ * Option icon
209
+ */
210
+ icon?: string;
196
211
  }
197
212
  }
198
213
 
@@ -1,5 +1,12 @@
1
1
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
+ export {
4
+ Insights,
5
+ type InsightListParams,
6
+ type InsightConvertToPostParams,
7
+ type InsightLinkParams,
8
+ type InsightUnlinkParams,
9
+ } from './insights';
3
10
  export {
4
11
  Posts,
5
12
  type Post,
@@ -0,0 +1,340 @@
1
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ import { APIResource } from '../../../core/resource';
4
+ import * as PostsAPI from './posts';
5
+ import { PostsCursorPage } from './posts';
6
+ import { APIPromise } from '../../../core/api-promise';
7
+ import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/pagination';
8
+ import { buildHeaders } from '../../../internal/headers';
9
+ import { RequestOptions } from '../../../internal/request-options';
10
+ import { path } from '../../../internal/utils/path';
11
+
12
+ /**
13
+ * User-submitted feedback and feature requests. Posts belong to boards and can be upvoted, commented on, and tracked through statuses.
14
+ */
15
+ export class Insights extends APIResource {
16
+ /**
17
+ * Returns the insights filed under the request `{id}` — the customer quotes kept
18
+ * as evidence for it. Newest first.
19
+ *
20
+ * Posts linked with `attachTo` are **not** listed here: they are posts, not
21
+ * insights, and they stay in `GET /v2/posts`. This endpoint lists exactly the rows
22
+ * that `POST /v2/posts/{insightId}/link-insight` filed under this request.
23
+ *
24
+ * ### Query parameters
25
+ *
26
+ * - `limit` — insights per page, 1–100. **Defaults to 100**, so most requests
27
+ * return their whole evidence set in one call.
28
+ * - `cursor` — opaque cursor from a previous response's `nextCursor`.
29
+ *
30
+ * ### Response format
31
+ *
32
+ * The standard post list envelope:
33
+ *
34
+ * - `object` — always `"list"`
35
+ * - `data` — the insights, each in the same shape as any other post object, with
36
+ * `kind: 'insight'` and `linkedIssueId` set to `{id}`
37
+ * - `nextCursor` — pass it back as `cursor` for the next page; `null` on the last
38
+ * page
39
+ *
40
+ * `pagination` is never returned by this endpoint — it is cursor-paginated only.
41
+ *
42
+ * ### Notes
43
+ *
44
+ * - Pass the **request's** id, not an insight's. An id that is not a request (an
45
+ * insight, or an unknown id in this workspace) is not an error: the list simply
46
+ * comes back empty.
47
+ * - The insights returned are not readable through `GET /v2/posts/{insightId}` —
48
+ * that endpoint serves work items only.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * // Automatically fetches more pages as needed.
53
+ * for await (const post of client.feedback.posts.insights.list(
54
+ * '507f1f77bcf86cd799439011',
55
+ * )) {
56
+ * // ...
57
+ * }
58
+ * ```
59
+ */
60
+ list(
61
+ id: string,
62
+ params: InsightListParams | null | undefined = {},
63
+ options?: RequestOptions,
64
+ ): PagePromise<PostsCursorPage, PostsAPI.Post> {
65
+ const { 'Featurebase-Version': featurebaseVersion, ...query } = params ?? {};
66
+ return this._client.getAPIList(path`/v2/posts/${id}/insights`, CursorPage<PostsAPI.Post>, {
67
+ query,
68
+ ...options,
69
+ headers: buildHeaders([
70
+ {
71
+ ...(featurebaseVersion?.toString() != null ?
72
+ { 'Featurebase-Version': featurebaseVersion?.toString() }
73
+ : undefined),
74
+ },
75
+ options?.headers,
76
+ ]),
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Promotes the insight `{id}` into a request of its own — the way back from
82
+ * `link-insight`.
83
+ *
84
+ * `kind` becomes `issue`, any link to another request is cleared (that request's
85
+ * `linkedInsightCount` is recounted), and the row is a post again:
86
+ * `GET /v2/posts/{id}` answers it, and `GET /v2/posts` lists it.
87
+ *
88
+ * The promoted request is given the workspace's default status if it had none, is
89
+ * filed on the internal board (its previous board is kept as the request's source
90
+ * category), and is created **hidden from the portal** — publish it with
91
+ * `PATCH /v2/posts/{id}` when you want customers to see it. It then announces
92
+ * itself like a freshly created request: the `post.created` webhook fires and the
93
+ * workspace's tracker integrations receive it, subject to the same rules as any
94
+ * other creation. Featurebase also looks for other existing insights that support
95
+ * the new request, in the background.
96
+ *
97
+ * Calling this on a post that is already a request is a no-op and returns it
98
+ * unchanged.
99
+ *
100
+ * ### Request
101
+ *
102
+ * No body. The insight is named by the path.
103
+ *
104
+ * ### Response
105
+ *
106
+ * The resulting request, in the standard post format.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * const post =
111
+ * await client.feedback.posts.insights.convertToPost(
112
+ * '507f1f77bcf86cd799439011',
113
+ * );
114
+ * ```
115
+ */
116
+ convertToPost(
117
+ id: string,
118
+ params: InsightConvertToPostParams | null | undefined = {},
119
+ options?: RequestOptions,
120
+ ): APIPromise<PostsAPI.Post> {
121
+ const { 'Featurebase-Version': featurebaseVersion } = params ?? {};
122
+ return this._client.post(path`/v2/posts/${id}/convert-to-issue`, {
123
+ ...options,
124
+ headers: buildHeaders([
125
+ {
126
+ ...(featurebaseVersion?.toString() != null ?
127
+ { 'Featurebase-Version': featurebaseVersion?.toString() }
128
+ : undefined),
129
+ },
130
+ options?.headers,
131
+ ]),
132
+ });
133
+ }
134
+
135
+ /**
136
+ * An **insight** is a customer's own words kept as evidence under a request — a
137
+ * quote, not a request of its own, and never returned by `GET /v2/posts`.
138
+ *
139
+ * This endpoint turns the post `{id}` into an insight under the request `issueId`.
140
+ * Use it for the sentence a customer actually said; use `attachTo` on
141
+ * `POST /v2/posts` when the thing you are filing is a request in its own right and
142
+ * should stay one.
143
+ *
144
+ * ### What changes
145
+ *
146
+ * - The post becomes an insight: `kind` is `insight` and `linkedIssueId` is the
147
+ * request.
148
+ * - **It leaves the posts resource.** `GET /v2/posts/{id}` answers `404` from then
149
+ * on, and it no longer appears in `GET /v2/posts`. Read it back through
150
+ * `GET /v2/posts/{issueId}/insights`, which is where it now lives.
151
+ * - Its author counts as a supporter of the request: the insight's upvoters are
152
+ * rolled onto the request (deduped by user, so a customer who had already voted
153
+ * is not counted twice) and the insight's author is subscribed to the request's
154
+ * updates. The request's `upvotes` goes up accordingly.
155
+ * - The request's `linkedInsightCount` is recounted from the live set of insights
156
+ * pointing at it.
157
+ *
158
+ * Linking again to the same request is a no-op and returns the insight unchanged.
159
+ *
160
+ * An insight that is already filed under a DIFFERENT request is MOVED — but only
161
+ * if nobody has confirmed that first link by hand. The old link is dropped first,
162
+ * and the old request is remembered as "not a match" so automatic matching never
163
+ * puts it back there. An insight whose link was already confirmed by a person
164
+ * (every link made through this endpoint counts as confirmed) is refused with
165
+ * `400 Insight is already linked to another issue. Detach it first.` — call
166
+ * `POST /v2/posts/{id}/unlink-insight` first, then link it where you want it.
167
+ *
168
+ * ### Which targets are refused
169
+ *
170
+ * - `404` — no post with `{id}` in this workspace, or one the API key cannot see
171
+ * (`Insight not found.`); no request with `issueId`, or one the API key cannot
172
+ * see (`Issue not found.`).
173
+ * - `400` — `issueId` equals `{id}` (a post cannot be linked to itself); the
174
+ * target is not a request (it is itself an insight, or a record — convert or
175
+ * restore it first); the target is a processed submission (`atomizedAt` — link
176
+ * to the requests that came out of it); the post being linked is a record (link
177
+ * the record's extracted insights instead); the post is already filed under
178
+ * another request by hand (unlink it first).
179
+ * - `400 invalid_id` — `{id}` or `issueId` is not a valid object id.
180
+ *
181
+ * A merged, held-for-moderation, spam-held or closed target is **not** refused
182
+ * here: those guards apply to automatic (AI) attachment only, and a person linking
183
+ * by hand is trusted to mean it.
184
+ *
185
+ * ### Response
186
+ *
187
+ * The updated insight, in the standard post format (`kind: 'insight'`,
188
+ * `linkedIssueId` set). The request it was linked to is not returned — fetch it
189
+ * with `GET /v2/posts/{issueId}` if you need its new `upvotes` and
190
+ * `linkedInsightCount`.
191
+ *
192
+ * ### Body
193
+ *
194
+ * - `issueId` — the request to file this post under. Required.
195
+ * - `linkSource` — deprecated and ignored; a link made through the API is always a
196
+ * manual link.
197
+ *
198
+ * ### Errors
199
+ *
200
+ * Failures raised by the insight service (404 / 400 / 409) are returned as
201
+ * `{ "code": <status>, "message": "..." }` rather than in the Stripe-style
202
+ * envelope the rest of this resource uses. The status code is the contract; do not
203
+ * parse the body shape.
204
+ *
205
+ * @example
206
+ * ```ts
207
+ * const post = await client.feedback.posts.insights.link(
208
+ * '507f1f77bcf86cd799439011',
209
+ * { issueId: '507f1f77bcf86cd799439011' },
210
+ * );
211
+ * ```
212
+ */
213
+ link(id: string, params: InsightLinkParams, options?: RequestOptions): APIPromise<PostsAPI.Post> {
214
+ const { 'Featurebase-Version': featurebaseVersion, ...body } = params;
215
+ return this._client.post(path`/v2/posts/${id}/link-insight`, {
216
+ body,
217
+ ...options,
218
+ headers: buildHeaders([
219
+ {
220
+ ...(featurebaseVersion?.toString() != null ?
221
+ { 'Featurebase-Version': featurebaseVersion?.toString() }
222
+ : undefined),
223
+ },
224
+ options?.headers,
225
+ ]),
226
+ });
227
+ }
228
+
229
+ /**
230
+ * Detaches the insight `{id}` from the request it was filed under.
231
+ *
232
+ * **The row stays an insight** — the customer's words do not disappear, they just
233
+ * return to the unlinked pool. `linkedIssueId` becomes `null`, and
234
+ * `GET /v2/posts/{id}` still answers `404`: an unlinked insight is still not a
235
+ * post. To get a post back, call `POST /v2/posts/{id}/convert-to-issue`.
236
+ *
237
+ * ### What does NOT change
238
+ *
239
+ * The votes this insight rolled onto the request are **not** taken back, and the
240
+ * author stays subscribed to it. They are real demand that was expressed, and the
241
+ * roll-up was deduplicated against votes the customer may have cast independently
242
+ * — unwinding it would remove votes it never created. The request's `upvotes`
243
+ * therefore stays where the link left it. Its `linkedInsightCount` IS recounted
244
+ * and goes down.
245
+ *
246
+ * The request that was just unlinked is remembered as "not a match" for this
247
+ * insight, so automatic matching never files it there again.
248
+ *
249
+ * Calling this on a post that is not an insight, or on an insight that is already
250
+ * unlinked, is a no-op and returns the row unchanged.
251
+ *
252
+ * ### Request
253
+ *
254
+ * No body. The insight is named by the path.
255
+ *
256
+ * ### Response
257
+ *
258
+ * The updated insight, in the standard post format.
259
+ *
260
+ * @example
261
+ * ```ts
262
+ * const post = await client.feedback.posts.insights.unlink(
263
+ * '507f1f77bcf86cd799439011',
264
+ * );
265
+ * ```
266
+ */
267
+ unlink(
268
+ id: string,
269
+ params: InsightUnlinkParams | null | undefined = {},
270
+ options?: RequestOptions,
271
+ ): APIPromise<PostsAPI.Post> {
272
+ const { 'Featurebase-Version': featurebaseVersion } = params ?? {};
273
+ return this._client.post(path`/v2/posts/${id}/unlink-insight`, {
274
+ ...options,
275
+ headers: buildHeaders([
276
+ {
277
+ ...(featurebaseVersion?.toString() != null ?
278
+ { 'Featurebase-Version': featurebaseVersion?.toString() }
279
+ : undefined),
280
+ },
281
+ options?.headers,
282
+ ]),
283
+ });
284
+ }
285
+ }
286
+
287
+ export interface InsightListParams extends CursorPageParams {
288
+ /**
289
+ * Header param: API version for this request. Defaults to your organization's
290
+ * configured API version if not specified.
291
+ */
292
+ 'Featurebase-Version'?: '2026-08-19.orbit' | '2026-01-01.nova' | '2025-12-12.clover';
293
+ }
294
+
295
+ export interface InsightConvertToPostParams {
296
+ /**
297
+ * API version for this request. Defaults to your organization's configured API
298
+ * version if not specified.
299
+ */
300
+ 'Featurebase-Version'?: '2026-08-19.orbit' | '2026-01-01.nova' | '2025-12-12.clover';
301
+ }
302
+
303
+ export interface InsightLinkParams {
304
+ /**
305
+ * Body param: ID of the request this post becomes evidence for. Must be a request
306
+ * in this workspace that can still take evidence.
307
+ */
308
+ issueId: string;
309
+
310
+ /**
311
+ * @deprecated Body param: Deprecated and ignored. A link made through the API is
312
+ * always recorded as a manual link.
313
+ */
314
+ linkSource?: 'manual' | 'ai';
315
+
316
+ /**
317
+ * Header param: API version for this request. Defaults to your organization's
318
+ * configured API version if not specified.
319
+ */
320
+ 'Featurebase-Version'?: '2026-08-19.orbit' | '2026-01-01.nova' | '2025-12-12.clover';
321
+ }
322
+
323
+ export interface InsightUnlinkParams {
324
+ /**
325
+ * API version for this request. Defaults to your organization's configured API
326
+ * version if not specified.
327
+ */
328
+ 'Featurebase-Version'?: '2026-08-19.orbit' | '2026-01-01.nova' | '2025-12-12.clover';
329
+ }
330
+
331
+ export declare namespace Insights {
332
+ export {
333
+ type InsightListParams as InsightListParams,
334
+ type InsightConvertToPostParams as InsightConvertToPostParams,
335
+ type InsightLinkParams as InsightLinkParams,
336
+ type InsightUnlinkParams as InsightUnlinkParams,
337
+ };
338
+ }
339
+
340
+ export { type PostsCursorPage };