@seriphxyz/core 0.1.2 → 0.1.7
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/README.md +277 -0
- package/dist/index.d.ts +244 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +526 -19
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# @seriphxyz/core
|
|
2
|
+
|
|
3
|
+
> **Note:** This repo is a read-only mirror. Source lives in a private monorepo.
|
|
4
|
+
> For issues/PRs, please open them here and we'll sync changes back.
|
|
5
|
+
|
|
6
|
+
Framework-agnostic API client, types, and headless controllers for [Seriph](https://seriph.xyz) widgets.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @seriphxyz/core
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This is the base package used by `@seriphxyz/astro`, `@seriphxyz/react`, and `@seriphxyz/solid`. Use it directly when building custom integrations or with any JavaScript framework.
|
|
15
|
+
|
|
16
|
+
## API Functions
|
|
17
|
+
|
|
18
|
+
### Comments
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { fetchComments, postComment } from "@seriphxyz/core";
|
|
22
|
+
|
|
23
|
+
// Fetch comments for a page
|
|
24
|
+
const comments = await fetchComments({
|
|
25
|
+
siteKey: "your-key",
|
|
26
|
+
pageId: "my-page",
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Post a new comment
|
|
30
|
+
await postComment({
|
|
31
|
+
siteKey: "your-key",
|
|
32
|
+
pageId: "my-page",
|
|
33
|
+
authorName: "John",
|
|
34
|
+
content: "Great post!",
|
|
35
|
+
authorEmail: "john@example.com", // optional
|
|
36
|
+
parentId: "comment-id", // optional, for replies
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Reactions
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { fetchReactions, addReaction, removeReaction } from "@seriphxyz/core";
|
|
44
|
+
|
|
45
|
+
// Fetch reactions for a page
|
|
46
|
+
const { counts, userReactions } = await fetchReactions({
|
|
47
|
+
siteKey: "your-key",
|
|
48
|
+
pageId: "my-page",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Add a reaction
|
|
52
|
+
await addReaction({
|
|
53
|
+
siteKey: "your-key",
|
|
54
|
+
pageId: "my-page",
|
|
55
|
+
reactionType: "like", // or 'clap', 'heart', etc.
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Remove a reaction
|
|
59
|
+
await removeReaction({
|
|
60
|
+
siteKey: "your-key",
|
|
61
|
+
pageId: "my-page",
|
|
62
|
+
reactionType: "like",
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Forms
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { submitForm } from "@seriphxyz/core";
|
|
70
|
+
|
|
71
|
+
await submitForm({
|
|
72
|
+
siteKey: "your-key",
|
|
73
|
+
formSlug: "contact",
|
|
74
|
+
data: {
|
|
75
|
+
name: "John",
|
|
76
|
+
email: "john@example.com",
|
|
77
|
+
message: "Hello!",
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Subscriptions
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { subscribe } from "@seriphxyz/core";
|
|
86
|
+
|
|
87
|
+
await subscribe({
|
|
88
|
+
siteKey: "your-key",
|
|
89
|
+
email: "user@example.com",
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Waitlist
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { joinWaitlist } from "@seriphxyz/core";
|
|
97
|
+
|
|
98
|
+
await joinWaitlist({
|
|
99
|
+
siteKey: "your-key",
|
|
100
|
+
email: "user@example.com",
|
|
101
|
+
name: "John", // optional
|
|
102
|
+
source: "homepage", // optional
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Feedback
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { submitFeedback } from "@seriphxyz/core";
|
|
110
|
+
|
|
111
|
+
await submitFeedback({
|
|
112
|
+
siteKey: "your-key",
|
|
113
|
+
type: "bug", // 'bug' | 'feature' | 'general'
|
|
114
|
+
content: "Found an issue...",
|
|
115
|
+
email: "user@example.com", // optional
|
|
116
|
+
pageUrl: "/about", // optional
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Polls
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { fetchPoll, votePoll } from "@seriphxyz/core";
|
|
124
|
+
|
|
125
|
+
// Fetch poll data
|
|
126
|
+
const poll = await fetchPoll({
|
|
127
|
+
siteKey: "your-key",
|
|
128
|
+
pollId: 123,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Vote on a poll
|
|
132
|
+
await votePoll({
|
|
133
|
+
siteKey: "your-key",
|
|
134
|
+
pollId: 123,
|
|
135
|
+
selectedOptions: ["option-1", "option-2"],
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Views
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { getViewCounts, recordView } from "@seriphxyz/core";
|
|
143
|
+
|
|
144
|
+
// Get view counts
|
|
145
|
+
const { views, uniqueVisitors } = await getViewCounts({
|
|
146
|
+
siteKey: "your-key",
|
|
147
|
+
pageId: "my-page",
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Record a view
|
|
151
|
+
await recordView({
|
|
152
|
+
siteKey: "your-key",
|
|
153
|
+
pageId: "my-page",
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Announcements
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { fetchAnnouncements, dismissAnnouncement } from "@seriphxyz/core";
|
|
161
|
+
|
|
162
|
+
// Fetch active announcements
|
|
163
|
+
const announcements = await fetchAnnouncements({
|
|
164
|
+
siteKey: "your-key",
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Dismiss an announcement
|
|
168
|
+
await dismissAnnouncement({
|
|
169
|
+
siteKey: "your-key",
|
|
170
|
+
announcementId: 123,
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Posts
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import { fetchPosts, fetchPost } from "@seriphxyz/core";
|
|
178
|
+
|
|
179
|
+
// Fetch all published posts
|
|
180
|
+
const posts = await fetchPosts({
|
|
181
|
+
siteKey: "your-key",
|
|
182
|
+
tag: "tutorials", // optional filter
|
|
183
|
+
limit: 10, // optional
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Fetch a single post
|
|
187
|
+
const post = await fetchPost({
|
|
188
|
+
siteKey: "your-key",
|
|
189
|
+
slug: "my-post",
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Headless Controllers
|
|
194
|
+
|
|
195
|
+
Controllers manage state without any DOM dependencies. Use them to build custom UI or integrate with any framework.
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import {
|
|
199
|
+
SubscribeController,
|
|
200
|
+
FormController,
|
|
201
|
+
ReactionsController,
|
|
202
|
+
CommentsController,
|
|
203
|
+
WaitlistController,
|
|
204
|
+
FeedbackController,
|
|
205
|
+
PollController,
|
|
206
|
+
AnnouncementsController,
|
|
207
|
+
ViewCountsController,
|
|
208
|
+
} from "@seriphxyz/core";
|
|
209
|
+
|
|
210
|
+
// Example: Subscribe controller
|
|
211
|
+
const controller = new SubscribeController({ siteKey: "your-key" });
|
|
212
|
+
|
|
213
|
+
// Subscribe to state changes
|
|
214
|
+
controller.subscribe((state) => {
|
|
215
|
+
console.log(state.status); // 'idle' | 'loading' | 'success' | 'error'
|
|
216
|
+
console.log(state.message);
|
|
217
|
+
console.log(state.error);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Submit
|
|
221
|
+
await controller.submit("user@example.com");
|
|
222
|
+
|
|
223
|
+
// Reset
|
|
224
|
+
controller.reset();
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Available Controllers
|
|
228
|
+
|
|
229
|
+
| Controller | Purpose |
|
|
230
|
+
|------------|---------|
|
|
231
|
+
| `SubscribeController` | Email subscriptions |
|
|
232
|
+
| `FormController` | Form submissions |
|
|
233
|
+
| `ReactionsController` | Page reactions |
|
|
234
|
+
| `CommentsController` | Threaded comments |
|
|
235
|
+
| `WaitlistController` | Waitlist signups |
|
|
236
|
+
| `FeedbackController` | Feedback forms |
|
|
237
|
+
| `PollController` | Polls and voting |
|
|
238
|
+
| `AnnouncementsController` | Site announcements |
|
|
239
|
+
| `ViewCountsController` | Page view tracking |
|
|
240
|
+
|
|
241
|
+
## Visitor Management
|
|
242
|
+
|
|
243
|
+
Reactions and views track visitors using localStorage. For authenticated users, you can set a custom visitor ID:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
import { setVisitorId, getVisitorId } from "@seriphxyz/core";
|
|
247
|
+
|
|
248
|
+
// Set custom visitor ID (e.g., for logged-in users)
|
|
249
|
+
setVisitorId("user-123");
|
|
250
|
+
|
|
251
|
+
// Get current visitor ID
|
|
252
|
+
const visitorId = getVisitorId();
|
|
253
|
+
|
|
254
|
+
// Revert to localStorage-based ID
|
|
255
|
+
setVisitorId(null);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Types
|
|
259
|
+
|
|
260
|
+
All types are exported for TypeScript users:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
import type {
|
|
264
|
+
SeriphConfig,
|
|
265
|
+
Comment,
|
|
266
|
+
ReactionCounts,
|
|
267
|
+
SeriphPost,
|
|
268
|
+
Poll,
|
|
269
|
+
Announcement,
|
|
270
|
+
FeedbackType,
|
|
271
|
+
ControllerStatus,
|
|
272
|
+
} from "@seriphxyz/core";
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## License
|
|
276
|
+
|
|
277
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare const DEFAULT_ENDPOINT = "https://seriph.xyz";
|
|
8
8
|
export declare const API_PATH = "/api/v1";
|
|
9
|
+
export declare const VISITOR_STORAGE_KEY = "seriph_visitor_id";
|
|
9
10
|
export interface SeriphConfig {
|
|
10
11
|
/** Your site key (required) */
|
|
11
12
|
siteKey: string;
|
|
@@ -52,6 +53,17 @@ export interface SeriphPost {
|
|
|
52
53
|
export declare function buildUrl(endpoint: string | undefined, path: string): string;
|
|
53
54
|
/** Get site key from config */
|
|
54
55
|
export declare function getSiteKey(config: SeriphConfig): string;
|
|
56
|
+
/**
|
|
57
|
+
* Set a custom visitor ID (e.g., authenticated user ID).
|
|
58
|
+
* Useful for non-static sites where you have user sessions.
|
|
59
|
+
* Set to null to revert to localStorage-based ID.
|
|
60
|
+
*/
|
|
61
|
+
export declare function setVisitorId(id: string | null): void;
|
|
62
|
+
/**
|
|
63
|
+
* Get the current visitor ID.
|
|
64
|
+
* Priority: custom ID > localStorage
|
|
65
|
+
*/
|
|
66
|
+
export declare function getVisitorId(): string;
|
|
55
67
|
export interface SubmitFormOptions extends SeriphConfig {
|
|
56
68
|
formSlug: string;
|
|
57
69
|
data: Record<string, unknown>;
|
|
@@ -74,7 +86,11 @@ export declare function postComment(options: PostCommentOptions): Promise<Commen
|
|
|
74
86
|
export interface FetchReactionsOptions extends SeriphConfig {
|
|
75
87
|
pageId: string;
|
|
76
88
|
}
|
|
77
|
-
export
|
|
89
|
+
export interface FetchReactionsResponse extends ReactionCounts {
|
|
90
|
+
/** Reaction types the current visitor has added (based on visitor token) */
|
|
91
|
+
userReactions: string[];
|
|
92
|
+
}
|
|
93
|
+
export declare function fetchReactions(options: FetchReactionsOptions): Promise<FetchReactionsResponse>;
|
|
78
94
|
export interface AddReactionOptions extends SeriphConfig {
|
|
79
95
|
pageId: string;
|
|
80
96
|
reactionType?: string;
|
|
@@ -107,6 +123,98 @@ export interface FetchPostOptions extends SeriphConfig {
|
|
|
107
123
|
slug: string;
|
|
108
124
|
}
|
|
109
125
|
export declare function fetchPost(options: FetchPostOptions): Promise<SeriphPost | null>;
|
|
126
|
+
export interface JoinWaitlistOptions extends SeriphConfig {
|
|
127
|
+
email: string;
|
|
128
|
+
name?: string;
|
|
129
|
+
/** Where the signup came from (e.g., "homepage", "blog") */
|
|
130
|
+
source?: string;
|
|
131
|
+
}
|
|
132
|
+
export interface JoinWaitlistResponse {
|
|
133
|
+
success: boolean;
|
|
134
|
+
message: string;
|
|
135
|
+
/** Position in waitlist (if site chooses to show it) */
|
|
136
|
+
position?: number;
|
|
137
|
+
}
|
|
138
|
+
export declare function joinWaitlist(options: JoinWaitlistOptions): Promise<JoinWaitlistResponse>;
|
|
139
|
+
export interface ViewCountsOptions extends SeriphConfig {
|
|
140
|
+
pageId: string;
|
|
141
|
+
}
|
|
142
|
+
export interface ViewCounts {
|
|
143
|
+
pageId: string;
|
|
144
|
+
views: number;
|
|
145
|
+
uniqueVisitors: number;
|
|
146
|
+
}
|
|
147
|
+
export interface RecordViewResponse extends ViewCounts {
|
|
148
|
+
isNewVisitor: boolean;
|
|
149
|
+
}
|
|
150
|
+
export declare function getViewCounts(options: ViewCountsOptions): Promise<ViewCounts>;
|
|
151
|
+
export declare function recordView(options: ViewCountsOptions): Promise<RecordViewResponse>;
|
|
152
|
+
export type FeedbackType = "bug" | "feature" | "general";
|
|
153
|
+
export interface SubmitFeedbackOptions extends SeriphConfig {
|
|
154
|
+
type: FeedbackType;
|
|
155
|
+
content: string;
|
|
156
|
+
email?: string;
|
|
157
|
+
/** Page URL where feedback was submitted */
|
|
158
|
+
pageUrl?: string;
|
|
159
|
+
}
|
|
160
|
+
export interface SubmitFeedbackResponse {
|
|
161
|
+
success: boolean;
|
|
162
|
+
message: string;
|
|
163
|
+
}
|
|
164
|
+
export declare function submitFeedback(options: SubmitFeedbackOptions): Promise<SubmitFeedbackResponse>;
|
|
165
|
+
export type ShowResultsMode = "always" | "after_vote" | "after_end" | "never";
|
|
166
|
+
export interface PollOption {
|
|
167
|
+
id: string;
|
|
168
|
+
text: string;
|
|
169
|
+
}
|
|
170
|
+
export interface PollSettings {
|
|
171
|
+
multiSelect: boolean;
|
|
172
|
+
showResults: ShowResultsMode;
|
|
173
|
+
}
|
|
174
|
+
export interface Poll {
|
|
175
|
+
id: number;
|
|
176
|
+
question: string;
|
|
177
|
+
options: PollOption[];
|
|
178
|
+
settings: PollSettings;
|
|
179
|
+
endsAt?: string;
|
|
180
|
+
isActive: boolean;
|
|
181
|
+
}
|
|
182
|
+
export interface PollWithResults extends Poll {
|
|
183
|
+
results: Record<string, number>;
|
|
184
|
+
totalVotes: number;
|
|
185
|
+
/** Options the current visitor has voted for */
|
|
186
|
+
userVotes?: string[];
|
|
187
|
+
}
|
|
188
|
+
export interface FetchPollOptions extends SeriphConfig {
|
|
189
|
+
pollId: number;
|
|
190
|
+
}
|
|
191
|
+
export declare function fetchPoll(options: FetchPollOptions): Promise<PollWithResults>;
|
|
192
|
+
export interface VotePollOptions extends SeriphConfig {
|
|
193
|
+
pollId: number;
|
|
194
|
+
selectedOptions: string[];
|
|
195
|
+
}
|
|
196
|
+
export interface VotePollResponse {
|
|
197
|
+
success: boolean;
|
|
198
|
+
results: Record<string, number>;
|
|
199
|
+
totalVotes: number;
|
|
200
|
+
}
|
|
201
|
+
export declare function votePoll(options: VotePollOptions): Promise<VotePollResponse>;
|
|
202
|
+
export type AnnouncementType = "info" | "warning" | "success" | "error";
|
|
203
|
+
export interface Announcement {
|
|
204
|
+
id: number;
|
|
205
|
+
content: string;
|
|
206
|
+
announcementType: AnnouncementType;
|
|
207
|
+
linkUrl?: string;
|
|
208
|
+
linkText?: string;
|
|
209
|
+
isDismissible: boolean;
|
|
210
|
+
}
|
|
211
|
+
export interface FetchAnnouncementsOptions extends SeriphConfig {
|
|
212
|
+
}
|
|
213
|
+
export declare function fetchAnnouncements(options: FetchAnnouncementsOptions): Promise<Announcement[]>;
|
|
214
|
+
export interface DismissAnnouncementOptions extends SeriphConfig {
|
|
215
|
+
announcementId: number;
|
|
216
|
+
}
|
|
217
|
+
export declare function dismissAnnouncement(options: DismissAnnouncementOptions): Promise<void>;
|
|
110
218
|
export type ControllerStatus = "idle" | "loading" | "success" | "error";
|
|
111
219
|
/** State for subscribe controllers */
|
|
112
220
|
export interface SubscribeState {
|
|
@@ -133,6 +241,13 @@ export interface CommentsState {
|
|
|
133
241
|
status: ControllerStatus;
|
|
134
242
|
error: Error | null;
|
|
135
243
|
}
|
|
244
|
+
/** State for waitlist controllers */
|
|
245
|
+
export interface WaitlistState {
|
|
246
|
+
status: ControllerStatus;
|
|
247
|
+
message: string | null;
|
|
248
|
+
position: number | null;
|
|
249
|
+
error: Error | null;
|
|
250
|
+
}
|
|
136
251
|
export interface ControllerListener<T> {
|
|
137
252
|
(state: T): void;
|
|
138
253
|
}
|
|
@@ -162,6 +277,32 @@ export declare class SubscribeController {
|
|
|
162
277
|
/** Reset to idle state */
|
|
163
278
|
reset(): void;
|
|
164
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* Headless controller for waitlist forms.
|
|
282
|
+
* Manages state without any DOM/framework dependencies.
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* const controller = new WaitlistController({ siteKey: 'xxx' });
|
|
286
|
+
* controller.subscribe((state) => {
|
|
287
|
+
* console.log(state.status, state.message, state.position);
|
|
288
|
+
* });
|
|
289
|
+
* await controller.join('user@example.com', { name: 'John', source: 'homepage' });
|
|
290
|
+
*/
|
|
291
|
+
export declare class WaitlistController {
|
|
292
|
+
private config;
|
|
293
|
+
private listeners;
|
|
294
|
+
private _state;
|
|
295
|
+
constructor(config: SeriphConfig);
|
|
296
|
+
getState(): WaitlistState;
|
|
297
|
+
subscribe(listener: ControllerListener<WaitlistState>): () => void;
|
|
298
|
+
private notify;
|
|
299
|
+
/** Join the waitlist */
|
|
300
|
+
join(email: string, options?: {
|
|
301
|
+
name?: string;
|
|
302
|
+
source?: string;
|
|
303
|
+
}): Promise<JoinWaitlistResponse>;
|
|
304
|
+
reset(): void;
|
|
305
|
+
}
|
|
165
306
|
/**
|
|
166
307
|
* Headless controller for forms.
|
|
167
308
|
* Manages state without any DOM/framework dependencies.
|
|
@@ -217,4 +358,106 @@ export declare class CommentsController {
|
|
|
217
358
|
parentId?: string;
|
|
218
359
|
}): Promise<Comment>;
|
|
219
360
|
}
|
|
361
|
+
/** State for feedback controllers */
|
|
362
|
+
export interface FeedbackState {
|
|
363
|
+
status: ControllerStatus;
|
|
364
|
+
message: string | null;
|
|
365
|
+
error: Error | null;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Headless controller for feedback forms.
|
|
369
|
+
* Manages state without any DOM/framework dependencies.
|
|
370
|
+
*/
|
|
371
|
+
export declare class FeedbackController {
|
|
372
|
+
private config;
|
|
373
|
+
private listeners;
|
|
374
|
+
private _state;
|
|
375
|
+
constructor(config: SeriphConfig);
|
|
376
|
+
getState(): FeedbackState;
|
|
377
|
+
subscribe(listener: ControllerListener<FeedbackState>): () => void;
|
|
378
|
+
private notify;
|
|
379
|
+
submit(type: FeedbackType, content: string, options?: {
|
|
380
|
+
email?: string;
|
|
381
|
+
pageUrl?: string;
|
|
382
|
+
}): Promise<SubmitFeedbackResponse>;
|
|
383
|
+
reset(): void;
|
|
384
|
+
}
|
|
385
|
+
/** State for poll controllers */
|
|
386
|
+
export interface PollState {
|
|
387
|
+
poll: PollWithResults | null;
|
|
388
|
+
status: ControllerStatus;
|
|
389
|
+
error: Error | null;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Headless controller for polls.
|
|
393
|
+
* Manages poll state, voting, and results.
|
|
394
|
+
*/
|
|
395
|
+
export declare class PollController {
|
|
396
|
+
private config;
|
|
397
|
+
private pollId;
|
|
398
|
+
private listeners;
|
|
399
|
+
private _state;
|
|
400
|
+
constructor(config: SeriphConfig, pollId: number);
|
|
401
|
+
getState(): PollState;
|
|
402
|
+
subscribe(listener: ControllerListener<PollState>): () => void;
|
|
403
|
+
private notify;
|
|
404
|
+
/** Fetch poll data from the server */
|
|
405
|
+
fetch(): Promise<PollWithResults>;
|
|
406
|
+
/** Vote on the poll */
|
|
407
|
+
vote(selectedOptions: string[]): Promise<VotePollResponse>;
|
|
408
|
+
/** Check if user has voted */
|
|
409
|
+
hasVoted(): boolean;
|
|
410
|
+
}
|
|
411
|
+
/** State for announcements controllers */
|
|
412
|
+
export interface AnnouncementsState {
|
|
413
|
+
announcements: Announcement[];
|
|
414
|
+
dismissed: Set<number>;
|
|
415
|
+
status: ControllerStatus;
|
|
416
|
+
error: Error | null;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Headless controller for announcements.
|
|
420
|
+
* Manages announcement list and dismissals.
|
|
421
|
+
*/
|
|
422
|
+
export declare class AnnouncementsController {
|
|
423
|
+
private config;
|
|
424
|
+
private listeners;
|
|
425
|
+
private _state;
|
|
426
|
+
constructor(config: SeriphConfig);
|
|
427
|
+
getState(): AnnouncementsState;
|
|
428
|
+
/** Get visible (non-dismissed) announcements */
|
|
429
|
+
getVisibleAnnouncements(): Announcement[];
|
|
430
|
+
subscribe(listener: ControllerListener<AnnouncementsState>): () => void;
|
|
431
|
+
private notify;
|
|
432
|
+
/** Fetch announcements from the server */
|
|
433
|
+
fetch(): Promise<Announcement[]>;
|
|
434
|
+
/** Dismiss an announcement */
|
|
435
|
+
dismiss(announcementId: number): Promise<void>;
|
|
436
|
+
}
|
|
437
|
+
/** State for view counts controllers */
|
|
438
|
+
export interface ViewCountsState {
|
|
439
|
+
pageId: string;
|
|
440
|
+
views: number;
|
|
441
|
+
uniqueVisitors: number;
|
|
442
|
+
status: ControllerStatus;
|
|
443
|
+
error: Error | null;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Headless controller for view counts.
|
|
447
|
+
* Tracks page views and unique visitors.
|
|
448
|
+
*/
|
|
449
|
+
export declare class ViewCountsController {
|
|
450
|
+
private config;
|
|
451
|
+
private pageId;
|
|
452
|
+
private listeners;
|
|
453
|
+
private _state;
|
|
454
|
+
constructor(config: SeriphConfig, pageId: string);
|
|
455
|
+
getState(): ViewCountsState;
|
|
456
|
+
subscribe(listener: ControllerListener<ViewCountsState>): () => void;
|
|
457
|
+
private notify;
|
|
458
|
+
/** Fetch view counts from the server */
|
|
459
|
+
fetch(): Promise<ViewCounts>;
|
|
460
|
+
/** Record a view (automatically tracks unique visitors via visitor token) */
|
|
461
|
+
record(): Promise<RecordViewResponse>;
|
|
462
|
+
}
|
|
220
463
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// =============================================================================
|
|
10
10
|
export const DEFAULT_ENDPOINT = "https://seriph.xyz";
|
|
11
11
|
export const API_PATH = "/api/v1";
|
|
12
|
+
export const VISITOR_STORAGE_KEY = "seriph_visitor_id";
|
|
12
13
|
// =============================================================================
|
|
13
14
|
// Helpers
|
|
14
15
|
// =============================================================================
|
|
@@ -24,6 +25,56 @@ export function getSiteKey(config) {
|
|
|
24
25
|
}
|
|
25
26
|
return config.siteKey;
|
|
26
27
|
}
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Visitor Token Management
|
|
30
|
+
// =============================================================================
|
|
31
|
+
/** Custom visitor ID set by the site (e.g., authenticated user ID) */
|
|
32
|
+
let customVisitorId = null;
|
|
33
|
+
/** Generate a random UUID v4 */
|
|
34
|
+
function generateUUID() {
|
|
35
|
+
// Use crypto.randomUUID if available, otherwise fallback
|
|
36
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
37
|
+
return crypto.randomUUID();
|
|
38
|
+
}
|
|
39
|
+
// Fallback for older environments
|
|
40
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
41
|
+
const r = (Math.random() * 16) | 0;
|
|
42
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
43
|
+
return v.toString(16);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Set a custom visitor ID (e.g., authenticated user ID).
|
|
48
|
+
* Useful for non-static sites where you have user sessions.
|
|
49
|
+
* Set to null to revert to localStorage-based ID.
|
|
50
|
+
*/
|
|
51
|
+
export function setVisitorId(id) {
|
|
52
|
+
customVisitorId = id;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the current visitor ID.
|
|
56
|
+
* Priority: custom ID > localStorage
|
|
57
|
+
*/
|
|
58
|
+
export function getVisitorId() {
|
|
59
|
+
// Use custom ID if set (for authenticated users)
|
|
60
|
+
if (customVisitorId) {
|
|
61
|
+
return customVisitorId;
|
|
62
|
+
}
|
|
63
|
+
// Use localStorage for anonymous visitors
|
|
64
|
+
let visitorId = localStorage.getItem(VISITOR_STORAGE_KEY);
|
|
65
|
+
if (!visitorId) {
|
|
66
|
+
visitorId = generateUUID();
|
|
67
|
+
localStorage.setItem(VISITOR_STORAGE_KEY, visitorId);
|
|
68
|
+
}
|
|
69
|
+
return visitorId;
|
|
70
|
+
}
|
|
71
|
+
/** Get common headers for API requests */
|
|
72
|
+
function getHeaders(siteKey) {
|
|
73
|
+
return {
|
|
74
|
+
"X-Seriph-Key": siteKey,
|
|
75
|
+
"X-Seriph-Visitor": getVisitorId(),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
27
78
|
export async function submitForm(options) {
|
|
28
79
|
const { endpoint, formSlug, data, formLoadTime } = options;
|
|
29
80
|
const siteKey = getSiteKey(options);
|
|
@@ -35,8 +86,8 @@ export async function submitForm(options) {
|
|
|
35
86
|
const response = await fetch(url, {
|
|
36
87
|
method: "POST",
|
|
37
88
|
headers: {
|
|
89
|
+
...getHeaders(siteKey),
|
|
38
90
|
"Content-Type": "application/json",
|
|
39
|
-
"X-Seriph-Key": siteKey,
|
|
40
91
|
},
|
|
41
92
|
body: JSON.stringify(payload),
|
|
42
93
|
});
|
|
@@ -50,9 +101,7 @@ export async function fetchComments(options) {
|
|
|
50
101
|
const siteKey = getSiteKey(options);
|
|
51
102
|
const url = buildUrl(endpoint, `/comments/${encodeURIComponent(pageId)}`);
|
|
52
103
|
const response = await fetch(url, {
|
|
53
|
-
headers:
|
|
54
|
-
"X-Seriph-Key": siteKey,
|
|
55
|
-
},
|
|
104
|
+
headers: getHeaders(siteKey),
|
|
56
105
|
});
|
|
57
106
|
if (!response.ok) {
|
|
58
107
|
throw new Error(`Failed to fetch comments: ${response.statusText}`);
|
|
@@ -67,8 +116,8 @@ export async function postComment(options) {
|
|
|
67
116
|
const response = await fetch(url, {
|
|
68
117
|
method: "POST",
|
|
69
118
|
headers: {
|
|
119
|
+
...getHeaders(siteKey),
|
|
70
120
|
"Content-Type": "application/json",
|
|
71
|
-
"X-Seriph-Key": siteKey,
|
|
72
121
|
},
|
|
73
122
|
body: JSON.stringify({
|
|
74
123
|
authorName,
|
|
@@ -88,15 +137,16 @@ export async function fetchReactions(options) {
|
|
|
88
137
|
const siteKey = getSiteKey(options);
|
|
89
138
|
const url = buildUrl(endpoint, `/reactions/${encodeURIComponent(pageId)}`);
|
|
90
139
|
const response = await fetch(url, {
|
|
91
|
-
headers:
|
|
92
|
-
"X-Seriph-Key": siteKey,
|
|
93
|
-
},
|
|
140
|
+
headers: getHeaders(siteKey),
|
|
94
141
|
});
|
|
95
142
|
if (!response.ok) {
|
|
96
143
|
throw new Error(`Failed to fetch reactions: ${response.statusText}`);
|
|
97
144
|
}
|
|
98
145
|
const data = await response.json();
|
|
99
|
-
return
|
|
146
|
+
return {
|
|
147
|
+
...data.data,
|
|
148
|
+
userReactions: data.data.userReactions || [],
|
|
149
|
+
};
|
|
100
150
|
}
|
|
101
151
|
export async function addReaction(options) {
|
|
102
152
|
const { endpoint, pageId, reactionType = "like" } = options;
|
|
@@ -105,8 +155,8 @@ export async function addReaction(options) {
|
|
|
105
155
|
const response = await fetch(url, {
|
|
106
156
|
method: "POST",
|
|
107
157
|
headers: {
|
|
158
|
+
...getHeaders(siteKey),
|
|
108
159
|
"Content-Type": "application/json",
|
|
109
|
-
"X-Seriph-Key": siteKey,
|
|
110
160
|
},
|
|
111
161
|
body: JSON.stringify({ reactionType }),
|
|
112
162
|
});
|
|
@@ -123,8 +173,8 @@ export async function removeReaction(options) {
|
|
|
123
173
|
const response = await fetch(url, {
|
|
124
174
|
method: "DELETE",
|
|
125
175
|
headers: {
|
|
176
|
+
...getHeaders(siteKey),
|
|
126
177
|
"Content-Type": "application/json",
|
|
127
|
-
"X-Seriph-Key": siteKey,
|
|
128
178
|
},
|
|
129
179
|
body: JSON.stringify({ reactionType }),
|
|
130
180
|
});
|
|
@@ -141,8 +191,8 @@ export async function subscribe(options) {
|
|
|
141
191
|
const response = await fetch(url, {
|
|
142
192
|
method: "POST",
|
|
143
193
|
headers: {
|
|
194
|
+
...getHeaders(siteKey),
|
|
144
195
|
"Content-Type": "application/json",
|
|
145
|
-
"X-Seriph-Key": siteKey,
|
|
146
196
|
},
|
|
147
197
|
body: JSON.stringify({ email }),
|
|
148
198
|
});
|
|
@@ -161,9 +211,7 @@ export async function fetchPosts(options) {
|
|
|
161
211
|
url.searchParams.set("tag", tag);
|
|
162
212
|
}
|
|
163
213
|
const response = await fetch(url.toString(), {
|
|
164
|
-
headers:
|
|
165
|
-
"X-Seriph-Key": siteKey,
|
|
166
|
-
},
|
|
214
|
+
headers: getHeaders(siteKey),
|
|
167
215
|
});
|
|
168
216
|
if (!response.ok) {
|
|
169
217
|
throw new Error(`Failed to fetch posts: ${response.status} ${response.statusText}`);
|
|
@@ -176,9 +224,7 @@ export async function fetchPost(options) {
|
|
|
176
224
|
const siteKey = getSiteKey(options);
|
|
177
225
|
const baseUrl = (endpoint || DEFAULT_ENDPOINT).replace(/\/+$/, "") + API_PATH;
|
|
178
226
|
const response = await fetch(`${baseUrl}/posts/${encodeURIComponent(slug)}`, {
|
|
179
|
-
headers:
|
|
180
|
-
"X-Seriph-Key": siteKey,
|
|
181
|
-
},
|
|
227
|
+
headers: getHeaders(siteKey),
|
|
182
228
|
});
|
|
183
229
|
if (response.status === 404) {
|
|
184
230
|
return null;
|
|
@@ -189,6 +235,128 @@ export async function fetchPost(options) {
|
|
|
189
235
|
const data = await response.json();
|
|
190
236
|
return data.public_post || data;
|
|
191
237
|
}
|
|
238
|
+
export async function joinWaitlist(options) {
|
|
239
|
+
const { endpoint, email, name, source } = options;
|
|
240
|
+
const siteKey = getSiteKey(options);
|
|
241
|
+
const url = buildUrl(endpoint, "/waitlist");
|
|
242
|
+
const response = await fetch(url, {
|
|
243
|
+
method: "POST",
|
|
244
|
+
headers: {
|
|
245
|
+
...getHeaders(siteKey),
|
|
246
|
+
"Content-Type": "application/json",
|
|
247
|
+
},
|
|
248
|
+
body: JSON.stringify({ email, name, source }),
|
|
249
|
+
});
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
throw new Error(`Failed to join waitlist: ${response.statusText}`);
|
|
252
|
+
}
|
|
253
|
+
return response.json();
|
|
254
|
+
}
|
|
255
|
+
export async function getViewCounts(options) {
|
|
256
|
+
const { endpoint, pageId } = options;
|
|
257
|
+
const siteKey = getSiteKey(options);
|
|
258
|
+
const url = buildUrl(endpoint, `/views/${encodeURIComponent(pageId)}`);
|
|
259
|
+
const response = await fetch(url, {
|
|
260
|
+
headers: getHeaders(siteKey),
|
|
261
|
+
});
|
|
262
|
+
if (!response.ok) {
|
|
263
|
+
throw new Error(`Failed to get view counts: ${response.statusText}`);
|
|
264
|
+
}
|
|
265
|
+
const data = await response.json();
|
|
266
|
+
return data.data;
|
|
267
|
+
}
|
|
268
|
+
export async function recordView(options) {
|
|
269
|
+
const { endpoint, pageId } = options;
|
|
270
|
+
const siteKey = getSiteKey(options);
|
|
271
|
+
const url = buildUrl(endpoint, `/views/${encodeURIComponent(pageId)}`);
|
|
272
|
+
const response = await fetch(url, {
|
|
273
|
+
method: "POST",
|
|
274
|
+
headers: getHeaders(siteKey),
|
|
275
|
+
});
|
|
276
|
+
if (!response.ok) {
|
|
277
|
+
throw new Error(`Failed to record view: ${response.statusText}`);
|
|
278
|
+
}
|
|
279
|
+
const data = await response.json();
|
|
280
|
+
return data.data;
|
|
281
|
+
}
|
|
282
|
+
export async function submitFeedback(options) {
|
|
283
|
+
const { endpoint, type, content, email, pageUrl } = options;
|
|
284
|
+
const siteKey = getSiteKey(options);
|
|
285
|
+
const url = buildUrl(endpoint, "/feedback");
|
|
286
|
+
const response = await fetch(url, {
|
|
287
|
+
method: "POST",
|
|
288
|
+
headers: {
|
|
289
|
+
...getHeaders(siteKey),
|
|
290
|
+
"Content-Type": "application/json",
|
|
291
|
+
},
|
|
292
|
+
body: JSON.stringify({
|
|
293
|
+
feedback_type: type,
|
|
294
|
+
content,
|
|
295
|
+
email,
|
|
296
|
+
page_url: pageUrl,
|
|
297
|
+
}),
|
|
298
|
+
});
|
|
299
|
+
if (!response.ok) {
|
|
300
|
+
throw new Error(`Failed to submit feedback: ${response.statusText}`);
|
|
301
|
+
}
|
|
302
|
+
return response.json();
|
|
303
|
+
}
|
|
304
|
+
export async function fetchPoll(options) {
|
|
305
|
+
const { endpoint, pollId } = options;
|
|
306
|
+
const siteKey = getSiteKey(options);
|
|
307
|
+
const url = buildUrl(endpoint, `/polls/${pollId}`);
|
|
308
|
+
const response = await fetch(url, {
|
|
309
|
+
headers: getHeaders(siteKey),
|
|
310
|
+
});
|
|
311
|
+
if (!response.ok) {
|
|
312
|
+
throw new Error(`Failed to fetch poll: ${response.statusText}`);
|
|
313
|
+
}
|
|
314
|
+
const data = await response.json();
|
|
315
|
+
return data.data;
|
|
316
|
+
}
|
|
317
|
+
export async function votePoll(options) {
|
|
318
|
+
const { endpoint, pollId, selectedOptions } = options;
|
|
319
|
+
const siteKey = getSiteKey(options);
|
|
320
|
+
const url = buildUrl(endpoint, `/polls/${pollId}/vote`);
|
|
321
|
+
const response = await fetch(url, {
|
|
322
|
+
method: "POST",
|
|
323
|
+
headers: {
|
|
324
|
+
...getHeaders(siteKey),
|
|
325
|
+
"Content-Type": "application/json",
|
|
326
|
+
},
|
|
327
|
+
body: JSON.stringify({ selected_options: selectedOptions }),
|
|
328
|
+
});
|
|
329
|
+
if (!response.ok) {
|
|
330
|
+
throw new Error(`Failed to vote: ${response.statusText}`);
|
|
331
|
+
}
|
|
332
|
+
const data = await response.json();
|
|
333
|
+
return data.data;
|
|
334
|
+
}
|
|
335
|
+
export async function fetchAnnouncements(options) {
|
|
336
|
+
const { endpoint } = options;
|
|
337
|
+
const siteKey = getSiteKey(options);
|
|
338
|
+
const url = buildUrl(endpoint, "/announcements");
|
|
339
|
+
const response = await fetch(url, {
|
|
340
|
+
headers: getHeaders(siteKey),
|
|
341
|
+
});
|
|
342
|
+
if (!response.ok) {
|
|
343
|
+
throw new Error(`Failed to fetch announcements: ${response.statusText}`);
|
|
344
|
+
}
|
|
345
|
+
const data = await response.json();
|
|
346
|
+
return data.data || [];
|
|
347
|
+
}
|
|
348
|
+
export async function dismissAnnouncement(options) {
|
|
349
|
+
const { endpoint, announcementId } = options;
|
|
350
|
+
const siteKey = getSiteKey(options);
|
|
351
|
+
const url = buildUrl(endpoint, `/announcements/${announcementId}/dismiss`);
|
|
352
|
+
const response = await fetch(url, {
|
|
353
|
+
method: "POST",
|
|
354
|
+
headers: getHeaders(siteKey),
|
|
355
|
+
});
|
|
356
|
+
if (!response.ok) {
|
|
357
|
+
throw new Error(`Failed to dismiss announcement: ${response.statusText}`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
192
360
|
/**
|
|
193
361
|
* Headless controller for subscribe forms.
|
|
194
362
|
* Manages state without any DOM/framework dependencies.
|
|
@@ -247,6 +415,70 @@ export class SubscribeController {
|
|
|
247
415
|
this.notify();
|
|
248
416
|
}
|
|
249
417
|
}
|
|
418
|
+
/**
|
|
419
|
+
* Headless controller for waitlist forms.
|
|
420
|
+
* Manages state without any DOM/framework dependencies.
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* const controller = new WaitlistController({ siteKey: 'xxx' });
|
|
424
|
+
* controller.subscribe((state) => {
|
|
425
|
+
* console.log(state.status, state.message, state.position);
|
|
426
|
+
* });
|
|
427
|
+
* await controller.join('user@example.com', { name: 'John', source: 'homepage' });
|
|
428
|
+
*/
|
|
429
|
+
export class WaitlistController {
|
|
430
|
+
config;
|
|
431
|
+
listeners = new Set();
|
|
432
|
+
_state = { status: "idle", message: null, position: null, error: null };
|
|
433
|
+
constructor(config) {
|
|
434
|
+
this.config = config;
|
|
435
|
+
}
|
|
436
|
+
getState() {
|
|
437
|
+
return { ...this._state };
|
|
438
|
+
}
|
|
439
|
+
subscribe(listener) {
|
|
440
|
+
this.listeners.add(listener);
|
|
441
|
+
listener(this.getState());
|
|
442
|
+
return () => this.listeners.delete(listener);
|
|
443
|
+
}
|
|
444
|
+
notify() {
|
|
445
|
+
const state = this.getState();
|
|
446
|
+
for (const listener of this.listeners) {
|
|
447
|
+
listener(state);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/** Join the waitlist */
|
|
451
|
+
async join(email, options) {
|
|
452
|
+
this._state = { status: "loading", message: null, position: null, error: null };
|
|
453
|
+
this.notify();
|
|
454
|
+
try {
|
|
455
|
+
const result = await joinWaitlist({
|
|
456
|
+
...this.config,
|
|
457
|
+
email,
|
|
458
|
+
name: options?.name,
|
|
459
|
+
source: options?.source,
|
|
460
|
+
});
|
|
461
|
+
this._state = {
|
|
462
|
+
status: "success",
|
|
463
|
+
message: result.message,
|
|
464
|
+
position: result.position ?? null,
|
|
465
|
+
error: null,
|
|
466
|
+
};
|
|
467
|
+
this.notify();
|
|
468
|
+
return result;
|
|
469
|
+
}
|
|
470
|
+
catch (e) {
|
|
471
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
472
|
+
this._state = { status: "error", message: error.message, position: null, error };
|
|
473
|
+
this.notify();
|
|
474
|
+
throw error;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
reset() {
|
|
478
|
+
this._state = { status: "idle", message: null, position: null, error: null };
|
|
479
|
+
this.notify();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
250
482
|
/**
|
|
251
483
|
* Headless controller for forms.
|
|
252
484
|
* Manages state without any DOM/framework dependencies.
|
|
@@ -336,7 +568,13 @@ export class ReactionsController {
|
|
|
336
568
|
this.notify();
|
|
337
569
|
try {
|
|
338
570
|
const result = await fetchReactions({ ...this.config, pageId: this.pageId });
|
|
339
|
-
this._state = {
|
|
571
|
+
this._state = {
|
|
572
|
+
...this._state,
|
|
573
|
+
counts: result.counts,
|
|
574
|
+
userReactions: result.userReactions,
|
|
575
|
+
status: "success",
|
|
576
|
+
error: null,
|
|
577
|
+
};
|
|
340
578
|
this.notify();
|
|
341
579
|
return this.getState();
|
|
342
580
|
}
|
|
@@ -444,3 +682,272 @@ export class CommentsController {
|
|
|
444
682
|
}
|
|
445
683
|
}
|
|
446
684
|
}
|
|
685
|
+
/**
|
|
686
|
+
* Headless controller for feedback forms.
|
|
687
|
+
* Manages state without any DOM/framework dependencies.
|
|
688
|
+
*/
|
|
689
|
+
export class FeedbackController {
|
|
690
|
+
config;
|
|
691
|
+
listeners = new Set();
|
|
692
|
+
_state = { status: "idle", message: null, error: null };
|
|
693
|
+
constructor(config) {
|
|
694
|
+
this.config = config;
|
|
695
|
+
}
|
|
696
|
+
getState() {
|
|
697
|
+
return { ...this._state };
|
|
698
|
+
}
|
|
699
|
+
subscribe(listener) {
|
|
700
|
+
this.listeners.add(listener);
|
|
701
|
+
listener(this.getState());
|
|
702
|
+
return () => this.listeners.delete(listener);
|
|
703
|
+
}
|
|
704
|
+
notify() {
|
|
705
|
+
const state = this.getState();
|
|
706
|
+
for (const listener of this.listeners) {
|
|
707
|
+
listener(state);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
async submit(type, content, options) {
|
|
711
|
+
this._state = { status: "loading", message: null, error: null };
|
|
712
|
+
this.notify();
|
|
713
|
+
try {
|
|
714
|
+
const result = await submitFeedback({
|
|
715
|
+
...this.config,
|
|
716
|
+
type,
|
|
717
|
+
content,
|
|
718
|
+
email: options?.email,
|
|
719
|
+
pageUrl: options?.pageUrl,
|
|
720
|
+
});
|
|
721
|
+
this._state = { status: "success", message: result.message, error: null };
|
|
722
|
+
this.notify();
|
|
723
|
+
return result;
|
|
724
|
+
}
|
|
725
|
+
catch (e) {
|
|
726
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
727
|
+
this._state = { status: "error", message: error.message, error };
|
|
728
|
+
this.notify();
|
|
729
|
+
throw error;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
reset() {
|
|
733
|
+
this._state = { status: "idle", message: null, error: null };
|
|
734
|
+
this.notify();
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Headless controller for polls.
|
|
739
|
+
* Manages poll state, voting, and results.
|
|
740
|
+
*/
|
|
741
|
+
export class PollController {
|
|
742
|
+
config;
|
|
743
|
+
pollId;
|
|
744
|
+
listeners = new Set();
|
|
745
|
+
_state = { poll: null, status: "idle", error: null };
|
|
746
|
+
constructor(config, pollId) {
|
|
747
|
+
this.config = config;
|
|
748
|
+
this.pollId = pollId;
|
|
749
|
+
}
|
|
750
|
+
getState() {
|
|
751
|
+
return { ...this._state };
|
|
752
|
+
}
|
|
753
|
+
subscribe(listener) {
|
|
754
|
+
this.listeners.add(listener);
|
|
755
|
+
listener(this.getState());
|
|
756
|
+
return () => this.listeners.delete(listener);
|
|
757
|
+
}
|
|
758
|
+
notify() {
|
|
759
|
+
const state = this.getState();
|
|
760
|
+
for (const listener of this.listeners) {
|
|
761
|
+
listener(state);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
/** Fetch poll data from the server */
|
|
765
|
+
async fetch() {
|
|
766
|
+
this._state = { ...this._state, status: "loading", error: null };
|
|
767
|
+
this.notify();
|
|
768
|
+
try {
|
|
769
|
+
const poll = await fetchPoll({ ...this.config, pollId: this.pollId });
|
|
770
|
+
this._state = { poll, status: "success", error: null };
|
|
771
|
+
this.notify();
|
|
772
|
+
return poll;
|
|
773
|
+
}
|
|
774
|
+
catch (e) {
|
|
775
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
776
|
+
this._state = { ...this._state, status: "error", error };
|
|
777
|
+
this.notify();
|
|
778
|
+
throw error;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
/** Vote on the poll */
|
|
782
|
+
async vote(selectedOptions) {
|
|
783
|
+
try {
|
|
784
|
+
const result = await votePoll({
|
|
785
|
+
...this.config,
|
|
786
|
+
pollId: this.pollId,
|
|
787
|
+
selectedOptions,
|
|
788
|
+
});
|
|
789
|
+
// Update state with new results
|
|
790
|
+
if (this._state.poll) {
|
|
791
|
+
this._state.poll = {
|
|
792
|
+
...this._state.poll,
|
|
793
|
+
results: result.results,
|
|
794
|
+
totalVotes: result.totalVotes,
|
|
795
|
+
userVotes: selectedOptions,
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
this.notify();
|
|
799
|
+
return result;
|
|
800
|
+
}
|
|
801
|
+
catch (e) {
|
|
802
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
803
|
+
this._state = { ...this._state, error };
|
|
804
|
+
this.notify();
|
|
805
|
+
throw error;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
/** Check if user has voted */
|
|
809
|
+
hasVoted() {
|
|
810
|
+
return !!this._state.poll?.userVotes && this._state.poll.userVotes.length > 0;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Headless controller for announcements.
|
|
815
|
+
* Manages announcement list and dismissals.
|
|
816
|
+
*/
|
|
817
|
+
export class AnnouncementsController {
|
|
818
|
+
config;
|
|
819
|
+
listeners = new Set();
|
|
820
|
+
_state = {
|
|
821
|
+
announcements: [],
|
|
822
|
+
dismissed: new Set(),
|
|
823
|
+
status: "idle",
|
|
824
|
+
error: null,
|
|
825
|
+
};
|
|
826
|
+
constructor(config) {
|
|
827
|
+
this.config = config;
|
|
828
|
+
}
|
|
829
|
+
getState() {
|
|
830
|
+
return {
|
|
831
|
+
...this._state,
|
|
832
|
+
announcements: [...this._state.announcements],
|
|
833
|
+
dismissed: new Set(this._state.dismissed),
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
/** Get visible (non-dismissed) announcements */
|
|
837
|
+
getVisibleAnnouncements() {
|
|
838
|
+
return this._state.announcements.filter((a) => !this._state.dismissed.has(a.id));
|
|
839
|
+
}
|
|
840
|
+
subscribe(listener) {
|
|
841
|
+
this.listeners.add(listener);
|
|
842
|
+
listener(this.getState());
|
|
843
|
+
return () => this.listeners.delete(listener);
|
|
844
|
+
}
|
|
845
|
+
notify() {
|
|
846
|
+
const state = this.getState();
|
|
847
|
+
for (const listener of this.listeners) {
|
|
848
|
+
listener(state);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
/** Fetch announcements from the server */
|
|
852
|
+
async fetch() {
|
|
853
|
+
this._state = { ...this._state, status: "loading", error: null };
|
|
854
|
+
this.notify();
|
|
855
|
+
try {
|
|
856
|
+
const announcements = await fetchAnnouncements(this.config);
|
|
857
|
+
this._state = { ...this._state, announcements, status: "success", error: null };
|
|
858
|
+
this.notify();
|
|
859
|
+
return announcements;
|
|
860
|
+
}
|
|
861
|
+
catch (e) {
|
|
862
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
863
|
+
this._state = { ...this._state, status: "error", error };
|
|
864
|
+
this.notify();
|
|
865
|
+
throw error;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
/** Dismiss an announcement */
|
|
869
|
+
async dismiss(announcementId) {
|
|
870
|
+
try {
|
|
871
|
+
await dismissAnnouncement({ ...this.config, announcementId });
|
|
872
|
+
this._state.dismissed.add(announcementId);
|
|
873
|
+
this.notify();
|
|
874
|
+
}
|
|
875
|
+
catch (e) {
|
|
876
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
877
|
+
this._state = { ...this._state, error };
|
|
878
|
+
this.notify();
|
|
879
|
+
throw error;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Headless controller for view counts.
|
|
885
|
+
* Tracks page views and unique visitors.
|
|
886
|
+
*/
|
|
887
|
+
export class ViewCountsController {
|
|
888
|
+
config;
|
|
889
|
+
pageId;
|
|
890
|
+
listeners = new Set();
|
|
891
|
+
_state;
|
|
892
|
+
constructor(config, pageId) {
|
|
893
|
+
this.config = config;
|
|
894
|
+
this.pageId = pageId;
|
|
895
|
+
this._state = { pageId, views: 0, uniqueVisitors: 0, status: "idle", error: null };
|
|
896
|
+
}
|
|
897
|
+
getState() {
|
|
898
|
+
return { ...this._state };
|
|
899
|
+
}
|
|
900
|
+
subscribe(listener) {
|
|
901
|
+
this.listeners.add(listener);
|
|
902
|
+
listener(this.getState());
|
|
903
|
+
return () => this.listeners.delete(listener);
|
|
904
|
+
}
|
|
905
|
+
notify() {
|
|
906
|
+
const state = this.getState();
|
|
907
|
+
for (const listener of this.listeners) {
|
|
908
|
+
listener(state);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
/** Fetch view counts from the server */
|
|
912
|
+
async fetch() {
|
|
913
|
+
this._state = { ...this._state, status: "loading", error: null };
|
|
914
|
+
this.notify();
|
|
915
|
+
try {
|
|
916
|
+
const counts = await getViewCounts({ ...this.config, pageId: this.pageId });
|
|
917
|
+
this._state = {
|
|
918
|
+
...this._state,
|
|
919
|
+
views: counts.views,
|
|
920
|
+
uniqueVisitors: counts.uniqueVisitors,
|
|
921
|
+
status: "success",
|
|
922
|
+
error: null,
|
|
923
|
+
};
|
|
924
|
+
this.notify();
|
|
925
|
+
return counts;
|
|
926
|
+
}
|
|
927
|
+
catch (e) {
|
|
928
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
929
|
+
this._state = { ...this._state, status: "error", error };
|
|
930
|
+
this.notify();
|
|
931
|
+
throw error;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
/** Record a view (automatically tracks unique visitors via visitor token) */
|
|
935
|
+
async record() {
|
|
936
|
+
try {
|
|
937
|
+
const result = await recordView({ ...this.config, pageId: this.pageId });
|
|
938
|
+
this._state = {
|
|
939
|
+
...this._state,
|
|
940
|
+
views: result.views,
|
|
941
|
+
uniqueVisitors: result.uniqueVisitors,
|
|
942
|
+
};
|
|
943
|
+
this.notify();
|
|
944
|
+
return result;
|
|
945
|
+
}
|
|
946
|
+
catch (e) {
|
|
947
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
948
|
+
this._state = { ...this._state, error };
|
|
949
|
+
this.notify();
|
|
950
|
+
throw error;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|