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