@jamwidgets/astro 0.1.0

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/src/index.ts ADDED
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @jamwidgets/astro
3
+ *
4
+ * Astro components and content loader for Jamwidgets.
5
+ * Re-exports all types, API functions, and controllers from @jamwidgets/core.
6
+ */
7
+
8
+ // Re-export everything from core
9
+ export {
10
+ // Constants
11
+ DEFAULT_ENDPOINT,
12
+ API_PATH,
13
+ VISITOR_STORAGE_KEY,
14
+
15
+ // Types
16
+ type JamWidgetsConfig,
17
+ type SeriphConfig, // deprecated alias
18
+ type Comment,
19
+ type ReactionCounts,
20
+ type FormSubmitResponse,
21
+ type SubscribeResponse,
22
+ type JamwidgetsPost,
23
+ type SeriphPost, // deprecated alias
24
+ type Announcement,
25
+ type AnnouncementType,
26
+ type Poll,
27
+ type PollOption,
28
+ type PollSettings,
29
+ type PollWithResults,
30
+ type ShowResultsMode,
31
+ type FeedbackType,
32
+
33
+ // Helpers
34
+ buildUrl,
35
+ getSiteKey,
36
+ getVisitorId,
37
+ setVisitorId,
38
+
39
+ // API Functions - Forms
40
+ type SubmitFormOptions,
41
+ submitForm,
42
+
43
+ // API Functions - Comments
44
+ type FetchCommentsOptions,
45
+ fetchComments,
46
+ type PostCommentOptions,
47
+ postComment,
48
+
49
+ // API Functions - Reactions
50
+ type FetchReactionsOptions,
51
+ type FetchReactionsResponse,
52
+ fetchReactions,
53
+ type AddReactionOptions,
54
+ addReaction,
55
+ type RemoveReactionOptions,
56
+ removeReaction,
57
+
58
+ // API Functions - Subscriptions
59
+ type SubscribeOptions,
60
+ subscribe,
61
+
62
+ // API Functions - Waitlist
63
+ type JoinWaitlistOptions,
64
+ type JoinWaitlistResponse,
65
+ joinWaitlist,
66
+
67
+ // API Functions - Views
68
+ type ViewCountsOptions,
69
+ type ViewCounts,
70
+ type RecordViewResponse,
71
+ getViewCounts,
72
+ recordView,
73
+
74
+ // API Functions - Feedback
75
+ type SubmitFeedbackOptions,
76
+ type SubmitFeedbackResponse,
77
+ submitFeedback,
78
+
79
+ // API Functions - Polls
80
+ type FetchPollOptions,
81
+ fetchPoll,
82
+ type VotePollOptions,
83
+ type VotePollResponse,
84
+ votePoll,
85
+
86
+ // API Functions - Announcements
87
+ type FetchAnnouncementsOptions,
88
+ fetchAnnouncements,
89
+ type DismissAnnouncementOptions,
90
+ dismissAnnouncement,
91
+
92
+ // API Functions - Posts
93
+ type FetchPostsOptions,
94
+ fetchPosts,
95
+ type FetchPostOptions,
96
+ fetchPost,
97
+
98
+ // Controllers
99
+ type ControllerStatus,
100
+ type ControllerListener,
101
+ type SubscribeState,
102
+ type FormState,
103
+ type ReactionsState,
104
+ type CommentsState,
105
+ type WaitlistState,
106
+ type ViewCountsState,
107
+ type FeedbackState,
108
+ type PollState,
109
+ type AnnouncementsState,
110
+ SubscribeController,
111
+ WaitlistController,
112
+ FormController,
113
+ ReactionsController,
114
+ CommentsController,
115
+ ViewCountsController,
116
+ FeedbackController,
117
+ PollController,
118
+ AnnouncementsController,
119
+ } from "@jamwidgets/core";
120
+
121
+ // Re-export loader (Astro-specific)
122
+ export {
123
+ jamwidgetsPostsLoader,
124
+ seriphPostsLoader, // deprecated alias
125
+ type JamwidgetsPostsLoaderOptions,
126
+ type SeriphPostsLoaderOptions, // deprecated alias
127
+ } from "./loader.js";
package/src/loader.ts ADDED
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Astro Content Loader for Jamwidgets Posts
3
+ *
4
+ * Use this loader to fetch posts from your Jamwidgets instance at build time.
5
+ *
6
+ * @example
7
+ * // In src/content.config.ts
8
+ * import { defineCollection } from 'astro:content';
9
+ * import { jamwidgetsPostsLoader } from '@jamwidgets/astro/loader';
10
+ *
11
+ * const posts = defineCollection({
12
+ * loader: jamwidgetsPostsLoader({
13
+ * siteKey: import.meta.env.JAMWIDGETS_SITE_KEY,
14
+ * }),
15
+ * });
16
+ *
17
+ * export const collections = { posts };
18
+ */
19
+
20
+ import {
21
+ DEFAULT_ENDPOINT,
22
+ API_PATH,
23
+ getSiteKey,
24
+ fetchPosts as coreFetchPosts,
25
+ fetchPost as coreFetchPost,
26
+ type JamwidgetsPost,
27
+ type SeriphPost, // deprecated alias
28
+ type FetchPostsOptions,
29
+ type FetchPostOptions,
30
+ } from "@jamwidgets/core";
31
+
32
+ // Re-export types and functions from core
33
+ export type { JamwidgetsPost, SeriphPost, FetchPostsOptions, FetchPostOptions };
34
+ export { coreFetchPosts as fetchPosts, coreFetchPost as fetchPost };
35
+
36
+ export interface JamwidgetsPostsLoaderOptions {
37
+ /** Your site key (required) */
38
+ siteKey: string;
39
+ /** Base URL of your Jamwidgets instance (default: 'https://jamwidgets.com') */
40
+ endpoint?: string;
41
+ /** Filter posts by tag */
42
+ tag?: string;
43
+ /** Maximum number of posts to fetch (default: 500) */
44
+ limit?: number;
45
+ /** How to handle errors: 'throw' (default), 'warn', or 'ignore' */
46
+ onError?: "throw" | "warn" | "ignore";
47
+ }
48
+
49
+ /** @deprecated Use JamwidgetsPostsLoaderOptions instead */
50
+ export type SeriphPostsLoaderOptions = JamwidgetsPostsLoaderOptions;
51
+
52
+ interface LoaderContext {
53
+ store: {
54
+ set: (entry: { id: string; data: JamwidgetsPost }) => void;
55
+ clear: () => void;
56
+ };
57
+ logger: {
58
+ info: (message: string) => void;
59
+ warn: (message: string) => void;
60
+ error: (message: string) => void;
61
+ };
62
+ generateDigest: (data: unknown) => string;
63
+ }
64
+
65
+ interface ApiResponse {
66
+ posts: JamwidgetsPost[];
67
+ total: number;
68
+ }
69
+
70
+ /**
71
+ * Creates an Astro content loader that fetches posts from Jamwidgets.
72
+ *
73
+ * Posts are fetched at build time and cached by Astro.
74
+ */
75
+ export function jamwidgetsPostsLoader(options: JamwidgetsPostsLoaderOptions) {
76
+ const {
77
+ endpoint = DEFAULT_ENDPOINT,
78
+ tag,
79
+ limit = 500,
80
+ onError = "throw",
81
+ } = options;
82
+
83
+ const siteKey = getSiteKey({ siteKey: options.siteKey });
84
+ const baseUrl = endpoint.replace(/\/+$/, "") + API_PATH;
85
+
86
+ return {
87
+ name: "jamwidgets-posts-loader",
88
+
89
+ async load(context: LoaderContext) {
90
+ const { store, logger } = context;
91
+
92
+ try {
93
+ const url = new URL(`${baseUrl}/posts`);
94
+ url.searchParams.set("limit", String(limit));
95
+ if (tag) {
96
+ url.searchParams.set("tag", tag);
97
+ }
98
+
99
+ logger.info(`Fetching posts from ${url.toString()}`);
100
+
101
+ const response = await fetch(url.toString(), {
102
+ headers: {
103
+ "X-Jamwidgets-Key": siteKey,
104
+ "X-JamWidgets-Key": siteKey, // backward compat
105
+ },
106
+ });
107
+
108
+ if (!response.ok) {
109
+ throw new Error(
110
+ `Failed to fetch posts: ${response.status} ${response.statusText}`,
111
+ );
112
+ }
113
+
114
+ const data: ApiResponse = await response.json();
115
+
116
+ store.clear();
117
+
118
+ for (const post of data.posts) {
119
+ store.set({
120
+ id: post.slug,
121
+ data: post,
122
+ });
123
+ }
124
+
125
+ logger.info(`Loaded ${data.posts.length} posts from Jamwidgets`);
126
+ } catch (error) {
127
+ const message = error instanceof Error ? error.message : String(error);
128
+
129
+ if (onError === "throw") {
130
+ logger.error(`Error loading posts: ${message}`);
131
+ throw error;
132
+ } else if (onError === "warn") {
133
+ logger.warn(`Error loading posts (continuing anyway): ${message}`);
134
+ }
135
+ }
136
+ },
137
+ };
138
+ }
139
+
140
+ /** @deprecated Use jamwidgetsPostsLoader instead */
141
+ export const seriphPostsLoader = jamwidgetsPostsLoader;