@fewchurs/react 0.0.0-stage → 1.0.1
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/LICENSE +41 -0
- package/README.md +25 -2
- package/dist/core.d.mts +213 -0
- package/dist/core.d.ts +213 -0
- package/dist/core.js +425 -0
- package/dist/core.js.map +1 -0
- package/dist/core.mjs +375 -0
- package/dist/core.mjs.map +1 -0
- package/dist/index.d.mts +523 -0
- package/dist/index.d.ts +523 -0
- package/dist/index.js +1823 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1742 -0
- package/dist/index.mjs.map +1 -0
- package/dist/styles.css +484 -0
- package/package.json +113 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Fewchurs SDK License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fewchurs. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and its source code (the "SDK") are proprietary to Fewchurs.
|
|
6
|
+
The source code is published for transparency only. It is not open source.
|
|
7
|
+
|
|
8
|
+
1. Permitted use. You may install the SDK, unmodified, as an npm
|
|
9
|
+
dependency of your own applications, and deploy it as part of those
|
|
10
|
+
applications, including in the bundles they serve to browsers, solely to
|
|
11
|
+
connect them to the Fewchurs service under a valid Fewchurs account. You
|
|
12
|
+
may customise its look and text through the props, CSS variables, slots,
|
|
13
|
+
hooks and stylesheet overrides the SDK documents.
|
|
14
|
+
|
|
15
|
+
2. Restrictions. Except as allowed in section 1, you may not:
|
|
16
|
+
a. copy, modify, translate or create derivative works of the SDK;
|
|
17
|
+
b. distribute, sublicense, sell, rent or lease the SDK on its own or as
|
|
18
|
+
part of a library, SDK, framework or developer tool;
|
|
19
|
+
c. use the SDK, or any part of it, to build or run a product or service
|
|
20
|
+
that competes with Fewchurs, or to connect to any service other than
|
|
21
|
+
Fewchurs;
|
|
22
|
+
d. remove or alter any copyright or license notice in the SDK.
|
|
23
|
+
|
|
24
|
+
3. Ownership. Fewchurs keeps all rights, title and interest in the SDK. No
|
|
25
|
+
rights are granted except those stated in this license.
|
|
26
|
+
|
|
27
|
+
4. Termination. This license ends automatically if you breach it, or when
|
|
28
|
+
your Fewchurs account ends. On termination you must stop deploying new
|
|
29
|
+
versions of your applications that include the SDK.
|
|
30
|
+
|
|
31
|
+
5. No warranty. THE SDK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
32
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
33
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
34
|
+
|
|
35
|
+
6. Limitation of liability. IN NO EVENT SHALL FEWCHURS BE LIABLE FOR ANY
|
|
36
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
37
|
+
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SDK OR THE USE
|
|
38
|
+
OF OR OTHER DEALINGS IN THE SDK.
|
|
39
|
+
|
|
40
|
+
Your use of the Fewchurs service itself is governed separately by your
|
|
41
|
+
agreement with Fewchurs (https://www.fewchurs.com).
|
package/README.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @fewchurs/react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Fewchurs feature-request board for any React app — the client, the store, the hooks and the
|
|
4
|
+
components. See the [repository README](../../README.md) for the full guide.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pnpm add @fewchurs/react
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { FewchursBoard, FewchursProvider } from "@fewchurs/react";
|
|
12
|
+
import "@fewchurs/react/styles.css";
|
|
13
|
+
|
|
14
|
+
<FewchursProvider apiKey={import.meta.env.VITE_FEWCHURS_KEY}>
|
|
15
|
+
<FewchursBoard />
|
|
16
|
+
</FewchursProvider>;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`FewchursBoardDialog` renders the same board in a modal (`open`, `onClose`, plus every board
|
|
20
|
+
prop), and `initialFeatureId` opens the board on one request with its comments expanded.
|
|
21
|
+
|
|
22
|
+
In a Next.js app, use [`@fewchurs/next`](../next) instead: it renders the board on the server
|
|
23
|
+
and keeps the API key out of the browser.
|
|
24
|
+
|
|
25
|
+
`@fewchurs/react/core` is the server-safe half — the fetch client, the types, validation and
|
|
26
|
+
error mapping, with no React and no `"use client"` boundary.
|
package/dist/core.d.mts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
type FewchursError = {
|
|
2
|
+
code: "invalid_key";
|
|
3
|
+
status: 401;
|
|
4
|
+
message: string;
|
|
5
|
+
} | {
|
|
6
|
+
code: "validation_failed";
|
|
7
|
+
status: 400;
|
|
8
|
+
message: string;
|
|
9
|
+
} | {
|
|
10
|
+
code: "rate_limited";
|
|
11
|
+
status: 429;
|
|
12
|
+
message: string;
|
|
13
|
+
} | {
|
|
14
|
+
code: "not_found";
|
|
15
|
+
status: 404;
|
|
16
|
+
message: string;
|
|
17
|
+
} | {
|
|
18
|
+
code: "limit_reached";
|
|
19
|
+
status: 402;
|
|
20
|
+
message: string;
|
|
21
|
+
} | {
|
|
22
|
+
code: "server";
|
|
23
|
+
status: number;
|
|
24
|
+
message: string;
|
|
25
|
+
} | {
|
|
26
|
+
code: "network";
|
|
27
|
+
message: string;
|
|
28
|
+
};
|
|
29
|
+
type Result<T> = {
|
|
30
|
+
ok: true;
|
|
31
|
+
data: T;
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
error: FewchursError;
|
|
35
|
+
};
|
|
36
|
+
/** Safe to show a visitor: never leaks a server message that may name internals. */
|
|
37
|
+
declare function userMessage(error: FewchursError): string;
|
|
38
|
+
declare function networkError(message?: string): FewchursError;
|
|
39
|
+
declare function validationError(message: string): FewchursError;
|
|
40
|
+
declare function errorFromResponse(status: number, body: unknown): FewchursError;
|
|
41
|
+
|
|
42
|
+
/** A status the server does not know about yet still renders, as `"unknown"`. */
|
|
43
|
+
type FeatureStatus = "open" | "planned" | "in_progress" | "done" | "declined" | "unknown";
|
|
44
|
+
type FeatureSort = "top" | "new";
|
|
45
|
+
interface Feature {
|
|
46
|
+
id: string;
|
|
47
|
+
title: string;
|
|
48
|
+
description: string;
|
|
49
|
+
status: FeatureStatus;
|
|
50
|
+
upvoteCount: number;
|
|
51
|
+
commentCount: number;
|
|
52
|
+
followerCount: number;
|
|
53
|
+
hasVoted: boolean;
|
|
54
|
+
isFollowing: boolean;
|
|
55
|
+
isMine: boolean;
|
|
56
|
+
createdAt: string;
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
}
|
|
59
|
+
interface Comment {
|
|
60
|
+
id: string;
|
|
61
|
+
text: string;
|
|
62
|
+
authorName: string;
|
|
63
|
+
isDeveloper: boolean;
|
|
64
|
+
isMine: boolean;
|
|
65
|
+
createdAt: string;
|
|
66
|
+
}
|
|
67
|
+
interface FeaturePage {
|
|
68
|
+
features: Feature[];
|
|
69
|
+
nextCursor: string | null;
|
|
70
|
+
}
|
|
71
|
+
interface CommentPage {
|
|
72
|
+
comments: Comment[];
|
|
73
|
+
nextCursor: string | null;
|
|
74
|
+
}
|
|
75
|
+
interface FewchursConfig {
|
|
76
|
+
showBranding: boolean;
|
|
77
|
+
hideVoteCounts: boolean;
|
|
78
|
+
appName: string | null;
|
|
79
|
+
}
|
|
80
|
+
interface SubmitFeatureInput {
|
|
81
|
+
title: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
email?: string;
|
|
84
|
+
isSubscriber?: boolean;
|
|
85
|
+
}
|
|
86
|
+
interface CreateCommentInput {
|
|
87
|
+
featureId: string;
|
|
88
|
+
text: string;
|
|
89
|
+
authorName?: string;
|
|
90
|
+
}
|
|
91
|
+
interface ListFeaturesParams {
|
|
92
|
+
sort?: FeatureSort;
|
|
93
|
+
limit?: number;
|
|
94
|
+
cursor?: string | null;
|
|
95
|
+
status?: FeatureStatus[];
|
|
96
|
+
}
|
|
97
|
+
interface ListCommentsParams {
|
|
98
|
+
limit?: number;
|
|
99
|
+
cursor?: string | null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
103
|
+
interface FewchursClientOptions {
|
|
104
|
+
/** Server-side, or in a SPA where the key is publishable. Omit when calling your own proxy. */
|
|
105
|
+
apiKey?: string;
|
|
106
|
+
/** `https://www.fewchurs.com/api/v1` by default, or a proxy path such as `/api/fewchurs`. */
|
|
107
|
+
baseUrl?: string;
|
|
108
|
+
deviceId?: string | null | (() => string | null);
|
|
109
|
+
/** Sent as `Accept-Language`, so server-side copy and emails match the visitor. */
|
|
110
|
+
language?: string;
|
|
111
|
+
fetch?: FetchLike;
|
|
112
|
+
retries?: number;
|
|
113
|
+
retryDelayMs?: number;
|
|
114
|
+
}
|
|
115
|
+
interface FewchursClient {
|
|
116
|
+
readonly baseUrl: string;
|
|
117
|
+
getDeviceId(): string | null;
|
|
118
|
+
getConfig(signal?: AbortSignal): Promise<Result<FewchursConfig>>;
|
|
119
|
+
listFeatures(params?: ListFeaturesParams, signal?: AbortSignal): Promise<Result<FeaturePage>>;
|
|
120
|
+
getFeature(featureId: string, signal?: AbortSignal): Promise<Result<Feature>>;
|
|
121
|
+
submitFeature(input: SubmitFeatureInput): Promise<Result<Feature>>;
|
|
122
|
+
vote(featureId: string): Promise<Result<{
|
|
123
|
+
upvoteCount: number;
|
|
124
|
+
hasVoted: boolean;
|
|
125
|
+
}>>;
|
|
126
|
+
unvote(featureId: string): Promise<Result<{
|
|
127
|
+
upvoteCount: number;
|
|
128
|
+
hasVoted: boolean;
|
|
129
|
+
}>>;
|
|
130
|
+
follow(featureId: string, email: string): Promise<Result<{
|
|
131
|
+
following: boolean;
|
|
132
|
+
}>>;
|
|
133
|
+
unfollow(featureId: string): Promise<Result<{
|
|
134
|
+
following: boolean;
|
|
135
|
+
}>>;
|
|
136
|
+
listComments(featureId: string, params?: ListCommentsParams, signal?: AbortSignal): Promise<Result<CommentPage>>;
|
|
137
|
+
createComment(input: CreateCommentInput): Promise<Result<Comment>>;
|
|
138
|
+
}
|
|
139
|
+
declare function createFewchursClient(options?: FewchursClientOptions): FewchursClient;
|
|
140
|
+
|
|
141
|
+
declare const SDK_VERSION = "1.0.1";
|
|
142
|
+
|
|
143
|
+
declare const SDK_HEADER = "react/1.0.1";
|
|
144
|
+
declare const DEFAULT_BASE_URL = "https://www.fewchurs.com/api/v1";
|
|
145
|
+
declare const DEFAULT_PAGE_SIZE = 20;
|
|
146
|
+
/** Mirrors the server's zod schemas, so the UI can reject input before a round trip. */
|
|
147
|
+
declare const LIMITS: {
|
|
148
|
+
readonly titleMin: 3;
|
|
149
|
+
readonly titleMax: 100;
|
|
150
|
+
readonly descriptionMax: 1000;
|
|
151
|
+
readonly commentMin: 1;
|
|
152
|
+
readonly commentMax: 1000;
|
|
153
|
+
readonly authorNameMax: 60;
|
|
154
|
+
};
|
|
155
|
+
/** What the Roadmap tab asks for, and what it keeps if the server ignores the filter. */
|
|
156
|
+
declare const ROADMAP_STATUSES: FeatureStatus[];
|
|
157
|
+
|
|
158
|
+
declare function createDeviceId(): string;
|
|
159
|
+
|
|
160
|
+
interface ListQuery {
|
|
161
|
+
sort: FeatureSort;
|
|
162
|
+
status?: FeatureStatus[];
|
|
163
|
+
}
|
|
164
|
+
declare function listKey({ sort, status }: ListQuery): string;
|
|
165
|
+
/**
|
|
166
|
+
* One feature, fetched by id, kept in `lists` beside the real lists. That way a deep-linked
|
|
167
|
+
* request goes through the same vote, comment and follow updates as a row in a list.
|
|
168
|
+
*/
|
|
169
|
+
declare function featureKey(featureId: string): string;
|
|
170
|
+
|
|
171
|
+
type LoadStatus = "idle" | "loading" | "loadingMore" | "ready" | "error";
|
|
172
|
+
interface ListState {
|
|
173
|
+
features: Feature[];
|
|
174
|
+
cursor: string | null;
|
|
175
|
+
status: LoadStatus;
|
|
176
|
+
error: FewchursError | null;
|
|
177
|
+
}
|
|
178
|
+
interface CommentsState {
|
|
179
|
+
comments: Comment[];
|
|
180
|
+
cursor: string | null;
|
|
181
|
+
status: LoadStatus;
|
|
182
|
+
error: FewchursError | null;
|
|
183
|
+
}
|
|
184
|
+
interface StoreState {
|
|
185
|
+
config: FewchursConfig | null;
|
|
186
|
+
lists: Record<string, ListState>;
|
|
187
|
+
comments: Record<string, CommentsState>;
|
|
188
|
+
}
|
|
189
|
+
type FewchursEventName = "boardOpened" | "featureSubmitted" | "voted" | "commented" | "followed" | "error";
|
|
190
|
+
interface FewchursEvent {
|
|
191
|
+
name: FewchursEventName;
|
|
192
|
+
featureId?: string;
|
|
193
|
+
hasVoted?: boolean;
|
|
194
|
+
following?: boolean;
|
|
195
|
+
error?: FewchursError;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
declare function normalizeStatus(value: unknown): FeatureStatus;
|
|
199
|
+
declare function normalizeFeature(value: unknown, deviceId: string | null): Feature;
|
|
200
|
+
declare function normalizeComment(value: unknown, deviceId: string | null): Comment;
|
|
201
|
+
declare function normalizeFeaturePage(value: unknown, deviceId: string | null): FeaturePage;
|
|
202
|
+
declare function normalizeCommentPage(value: unknown, deviceId: string | null): CommentPage;
|
|
203
|
+
declare function normalizeConfig(value: unknown): FewchursConfig;
|
|
204
|
+
declare function normalizeVote(value: unknown): {
|
|
205
|
+
upvoteCount: number;
|
|
206
|
+
hasVoted: boolean;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
declare function validateFeatureInput(input: SubmitFeatureInput): FewchursError | null;
|
|
210
|
+
declare function validateCommentInput(input: CreateCommentInput): FewchursError | null;
|
|
211
|
+
declare function validateEmail(email: string): FewchursError | null;
|
|
212
|
+
|
|
213
|
+
export { type Comment, type CommentPage, type CommentsState, type CreateCommentInput, DEFAULT_BASE_URL, DEFAULT_PAGE_SIZE, type Feature, type FeaturePage, type FeatureSort, type FeatureStatus, type FetchLike, type FewchursClient, type FewchursClientOptions, type FewchursConfig, type FewchursError, type FewchursEvent, type FewchursEventName, LIMITS, type ListCommentsParams, type ListFeaturesParams, type ListQuery, type ListState, type LoadStatus, ROADMAP_STATUSES, type Result, SDK_HEADER, SDK_VERSION, type StoreState, type SubmitFeatureInput, createDeviceId, createFewchursClient, errorFromResponse, featureKey, listKey, networkError, normalizeComment, normalizeCommentPage, normalizeConfig, normalizeFeature, normalizeFeaturePage, normalizeStatus, normalizeVote, userMessage, validateCommentInput, validateEmail, validateFeatureInput, validationError };
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
type FewchursError = {
|
|
2
|
+
code: "invalid_key";
|
|
3
|
+
status: 401;
|
|
4
|
+
message: string;
|
|
5
|
+
} | {
|
|
6
|
+
code: "validation_failed";
|
|
7
|
+
status: 400;
|
|
8
|
+
message: string;
|
|
9
|
+
} | {
|
|
10
|
+
code: "rate_limited";
|
|
11
|
+
status: 429;
|
|
12
|
+
message: string;
|
|
13
|
+
} | {
|
|
14
|
+
code: "not_found";
|
|
15
|
+
status: 404;
|
|
16
|
+
message: string;
|
|
17
|
+
} | {
|
|
18
|
+
code: "limit_reached";
|
|
19
|
+
status: 402;
|
|
20
|
+
message: string;
|
|
21
|
+
} | {
|
|
22
|
+
code: "server";
|
|
23
|
+
status: number;
|
|
24
|
+
message: string;
|
|
25
|
+
} | {
|
|
26
|
+
code: "network";
|
|
27
|
+
message: string;
|
|
28
|
+
};
|
|
29
|
+
type Result<T> = {
|
|
30
|
+
ok: true;
|
|
31
|
+
data: T;
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
error: FewchursError;
|
|
35
|
+
};
|
|
36
|
+
/** Safe to show a visitor: never leaks a server message that may name internals. */
|
|
37
|
+
declare function userMessage(error: FewchursError): string;
|
|
38
|
+
declare function networkError(message?: string): FewchursError;
|
|
39
|
+
declare function validationError(message: string): FewchursError;
|
|
40
|
+
declare function errorFromResponse(status: number, body: unknown): FewchursError;
|
|
41
|
+
|
|
42
|
+
/** A status the server does not know about yet still renders, as `"unknown"`. */
|
|
43
|
+
type FeatureStatus = "open" | "planned" | "in_progress" | "done" | "declined" | "unknown";
|
|
44
|
+
type FeatureSort = "top" | "new";
|
|
45
|
+
interface Feature {
|
|
46
|
+
id: string;
|
|
47
|
+
title: string;
|
|
48
|
+
description: string;
|
|
49
|
+
status: FeatureStatus;
|
|
50
|
+
upvoteCount: number;
|
|
51
|
+
commentCount: number;
|
|
52
|
+
followerCount: number;
|
|
53
|
+
hasVoted: boolean;
|
|
54
|
+
isFollowing: boolean;
|
|
55
|
+
isMine: boolean;
|
|
56
|
+
createdAt: string;
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
}
|
|
59
|
+
interface Comment {
|
|
60
|
+
id: string;
|
|
61
|
+
text: string;
|
|
62
|
+
authorName: string;
|
|
63
|
+
isDeveloper: boolean;
|
|
64
|
+
isMine: boolean;
|
|
65
|
+
createdAt: string;
|
|
66
|
+
}
|
|
67
|
+
interface FeaturePage {
|
|
68
|
+
features: Feature[];
|
|
69
|
+
nextCursor: string | null;
|
|
70
|
+
}
|
|
71
|
+
interface CommentPage {
|
|
72
|
+
comments: Comment[];
|
|
73
|
+
nextCursor: string | null;
|
|
74
|
+
}
|
|
75
|
+
interface FewchursConfig {
|
|
76
|
+
showBranding: boolean;
|
|
77
|
+
hideVoteCounts: boolean;
|
|
78
|
+
appName: string | null;
|
|
79
|
+
}
|
|
80
|
+
interface SubmitFeatureInput {
|
|
81
|
+
title: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
email?: string;
|
|
84
|
+
isSubscriber?: boolean;
|
|
85
|
+
}
|
|
86
|
+
interface CreateCommentInput {
|
|
87
|
+
featureId: string;
|
|
88
|
+
text: string;
|
|
89
|
+
authorName?: string;
|
|
90
|
+
}
|
|
91
|
+
interface ListFeaturesParams {
|
|
92
|
+
sort?: FeatureSort;
|
|
93
|
+
limit?: number;
|
|
94
|
+
cursor?: string | null;
|
|
95
|
+
status?: FeatureStatus[];
|
|
96
|
+
}
|
|
97
|
+
interface ListCommentsParams {
|
|
98
|
+
limit?: number;
|
|
99
|
+
cursor?: string | null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
103
|
+
interface FewchursClientOptions {
|
|
104
|
+
/** Server-side, or in a SPA where the key is publishable. Omit when calling your own proxy. */
|
|
105
|
+
apiKey?: string;
|
|
106
|
+
/** `https://www.fewchurs.com/api/v1` by default, or a proxy path such as `/api/fewchurs`. */
|
|
107
|
+
baseUrl?: string;
|
|
108
|
+
deviceId?: string | null | (() => string | null);
|
|
109
|
+
/** Sent as `Accept-Language`, so server-side copy and emails match the visitor. */
|
|
110
|
+
language?: string;
|
|
111
|
+
fetch?: FetchLike;
|
|
112
|
+
retries?: number;
|
|
113
|
+
retryDelayMs?: number;
|
|
114
|
+
}
|
|
115
|
+
interface FewchursClient {
|
|
116
|
+
readonly baseUrl: string;
|
|
117
|
+
getDeviceId(): string | null;
|
|
118
|
+
getConfig(signal?: AbortSignal): Promise<Result<FewchursConfig>>;
|
|
119
|
+
listFeatures(params?: ListFeaturesParams, signal?: AbortSignal): Promise<Result<FeaturePage>>;
|
|
120
|
+
getFeature(featureId: string, signal?: AbortSignal): Promise<Result<Feature>>;
|
|
121
|
+
submitFeature(input: SubmitFeatureInput): Promise<Result<Feature>>;
|
|
122
|
+
vote(featureId: string): Promise<Result<{
|
|
123
|
+
upvoteCount: number;
|
|
124
|
+
hasVoted: boolean;
|
|
125
|
+
}>>;
|
|
126
|
+
unvote(featureId: string): Promise<Result<{
|
|
127
|
+
upvoteCount: number;
|
|
128
|
+
hasVoted: boolean;
|
|
129
|
+
}>>;
|
|
130
|
+
follow(featureId: string, email: string): Promise<Result<{
|
|
131
|
+
following: boolean;
|
|
132
|
+
}>>;
|
|
133
|
+
unfollow(featureId: string): Promise<Result<{
|
|
134
|
+
following: boolean;
|
|
135
|
+
}>>;
|
|
136
|
+
listComments(featureId: string, params?: ListCommentsParams, signal?: AbortSignal): Promise<Result<CommentPage>>;
|
|
137
|
+
createComment(input: CreateCommentInput): Promise<Result<Comment>>;
|
|
138
|
+
}
|
|
139
|
+
declare function createFewchursClient(options?: FewchursClientOptions): FewchursClient;
|
|
140
|
+
|
|
141
|
+
declare const SDK_VERSION = "1.0.1";
|
|
142
|
+
|
|
143
|
+
declare const SDK_HEADER = "react/1.0.1";
|
|
144
|
+
declare const DEFAULT_BASE_URL = "https://www.fewchurs.com/api/v1";
|
|
145
|
+
declare const DEFAULT_PAGE_SIZE = 20;
|
|
146
|
+
/** Mirrors the server's zod schemas, so the UI can reject input before a round trip. */
|
|
147
|
+
declare const LIMITS: {
|
|
148
|
+
readonly titleMin: 3;
|
|
149
|
+
readonly titleMax: 100;
|
|
150
|
+
readonly descriptionMax: 1000;
|
|
151
|
+
readonly commentMin: 1;
|
|
152
|
+
readonly commentMax: 1000;
|
|
153
|
+
readonly authorNameMax: 60;
|
|
154
|
+
};
|
|
155
|
+
/** What the Roadmap tab asks for, and what it keeps if the server ignores the filter. */
|
|
156
|
+
declare const ROADMAP_STATUSES: FeatureStatus[];
|
|
157
|
+
|
|
158
|
+
declare function createDeviceId(): string;
|
|
159
|
+
|
|
160
|
+
interface ListQuery {
|
|
161
|
+
sort: FeatureSort;
|
|
162
|
+
status?: FeatureStatus[];
|
|
163
|
+
}
|
|
164
|
+
declare function listKey({ sort, status }: ListQuery): string;
|
|
165
|
+
/**
|
|
166
|
+
* One feature, fetched by id, kept in `lists` beside the real lists. That way a deep-linked
|
|
167
|
+
* request goes through the same vote, comment and follow updates as a row in a list.
|
|
168
|
+
*/
|
|
169
|
+
declare function featureKey(featureId: string): string;
|
|
170
|
+
|
|
171
|
+
type LoadStatus = "idle" | "loading" | "loadingMore" | "ready" | "error";
|
|
172
|
+
interface ListState {
|
|
173
|
+
features: Feature[];
|
|
174
|
+
cursor: string | null;
|
|
175
|
+
status: LoadStatus;
|
|
176
|
+
error: FewchursError | null;
|
|
177
|
+
}
|
|
178
|
+
interface CommentsState {
|
|
179
|
+
comments: Comment[];
|
|
180
|
+
cursor: string | null;
|
|
181
|
+
status: LoadStatus;
|
|
182
|
+
error: FewchursError | null;
|
|
183
|
+
}
|
|
184
|
+
interface StoreState {
|
|
185
|
+
config: FewchursConfig | null;
|
|
186
|
+
lists: Record<string, ListState>;
|
|
187
|
+
comments: Record<string, CommentsState>;
|
|
188
|
+
}
|
|
189
|
+
type FewchursEventName = "boardOpened" | "featureSubmitted" | "voted" | "commented" | "followed" | "error";
|
|
190
|
+
interface FewchursEvent {
|
|
191
|
+
name: FewchursEventName;
|
|
192
|
+
featureId?: string;
|
|
193
|
+
hasVoted?: boolean;
|
|
194
|
+
following?: boolean;
|
|
195
|
+
error?: FewchursError;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
declare function normalizeStatus(value: unknown): FeatureStatus;
|
|
199
|
+
declare function normalizeFeature(value: unknown, deviceId: string | null): Feature;
|
|
200
|
+
declare function normalizeComment(value: unknown, deviceId: string | null): Comment;
|
|
201
|
+
declare function normalizeFeaturePage(value: unknown, deviceId: string | null): FeaturePage;
|
|
202
|
+
declare function normalizeCommentPage(value: unknown, deviceId: string | null): CommentPage;
|
|
203
|
+
declare function normalizeConfig(value: unknown): FewchursConfig;
|
|
204
|
+
declare function normalizeVote(value: unknown): {
|
|
205
|
+
upvoteCount: number;
|
|
206
|
+
hasVoted: boolean;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
declare function validateFeatureInput(input: SubmitFeatureInput): FewchursError | null;
|
|
210
|
+
declare function validateCommentInput(input: CreateCommentInput): FewchursError | null;
|
|
211
|
+
declare function validateEmail(email: string): FewchursError | null;
|
|
212
|
+
|
|
213
|
+
export { type Comment, type CommentPage, type CommentsState, type CreateCommentInput, DEFAULT_BASE_URL, DEFAULT_PAGE_SIZE, type Feature, type FeaturePage, type FeatureSort, type FeatureStatus, type FetchLike, type FewchursClient, type FewchursClientOptions, type FewchursConfig, type FewchursError, type FewchursEvent, type FewchursEventName, LIMITS, type ListCommentsParams, type ListFeaturesParams, type ListQuery, type ListState, type LoadStatus, ROADMAP_STATUSES, type Result, SDK_HEADER, SDK_VERSION, type StoreState, type SubmitFeatureInput, createDeviceId, createFewchursClient, errorFromResponse, featureKey, listKey, networkError, normalizeComment, normalizeCommentPage, normalizeConfig, normalizeFeature, normalizeFeaturePage, normalizeStatus, normalizeVote, userMessage, validateCommentInput, validateEmail, validateFeatureInput, validationError };
|