@jamwidgets/astro 0.2.3 → 0.3.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/README.md +6 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +2 -3
- package/package.json +7 -4
- package/src/Analytics.astro +30 -0
- package/src/Comments.astro +3 -11
- package/src/Form.astro +3 -11
- package/src/Reactions.astro +2 -10
- package/src/SubscribeForm.astro +3 -11
- package/src/loader.ts +4 -2
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ Add your JamWidgets site key to your `.env`:
|
|
|
17
17
|
|
|
18
18
|
```
|
|
19
19
|
JAMWIDGETS_SITE_KEY=your_site_key_here
|
|
20
|
+
SITE_URL=https://example.com
|
|
20
21
|
```
|
|
21
22
|
|
|
22
23
|
## Content Loader (Posts)
|
|
@@ -31,12 +32,16 @@ import { jamwidgetsPostsLoader } from "@jamwidgets/astro/loader";
|
|
|
31
32
|
const posts = defineCollection({
|
|
32
33
|
loader: jamwidgetsPostsLoader({
|
|
33
34
|
siteKey: import.meta.env.JAMWIDGETS_SITE_KEY,
|
|
35
|
+
origin: import.meta.env.SITE_URL,
|
|
34
36
|
}),
|
|
35
37
|
});
|
|
36
38
|
|
|
37
39
|
export const collections = { posts };
|
|
38
40
|
```
|
|
39
41
|
|
|
42
|
+
Set `origin` to an allowed origin for production builds. JamWidgets rejects the
|
|
43
|
+
request when the site restricts origins and the loader omits it.
|
|
44
|
+
|
|
40
45
|
Then use in your pages:
|
|
41
46
|
|
|
42
47
|
```astro
|
|
@@ -59,6 +64,7 @@ const posts = await getCollection("posts");
|
|
|
59
64
|
jamwidgetsPostsLoader({
|
|
60
65
|
siteKey: string; // Required - your JamWidgets site key
|
|
61
66
|
endpoint?: string; // Default: 'https://jamwidgets.com'
|
|
67
|
+
origin?: string; // Site URL used for allowed-origin validation
|
|
62
68
|
tag?: string; // Filter posts by tag
|
|
63
69
|
limit?: number; // Max posts to fetch (default: 500)
|
|
64
70
|
onError?: 'throw' | 'warn' | 'ignore'; // Error handling
|
package/dist/loader.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface JamwidgetsPostsLoaderOptions {
|
|
|
26
26
|
siteKey: string;
|
|
27
27
|
/** Base URL of your Jamwidgets instance (default: 'https://jamwidgets.com') */
|
|
28
28
|
endpoint?: string;
|
|
29
|
+
/** Site origin sent for allowed-origin validation */
|
|
30
|
+
origin?: string;
|
|
29
31
|
/** Filter posts by tag */
|
|
30
32
|
tag?: string;
|
|
31
33
|
/** Maximum number of posts to fetch (default: 500) */
|
package/dist/loader.js
CHANGED
|
@@ -24,7 +24,7 @@ export { coreFetchPosts as fetchPosts, coreFetchPost as fetchPost };
|
|
|
24
24
|
* Posts are fetched at build time and cached by Astro.
|
|
25
25
|
*/
|
|
26
26
|
export function jamwidgetsPostsLoader(options) {
|
|
27
|
-
const { endpoint = DEFAULT_ENDPOINT, tag, limit = 500, onError = "throw", } = options;
|
|
27
|
+
const { endpoint = DEFAULT_ENDPOINT, origin, tag, limit = 500, onError = "throw", } = options;
|
|
28
28
|
const siteKey = getSiteKey({ siteKey: options.siteKey });
|
|
29
29
|
const baseUrl = endpoint.replace(/\/+$/, "") + API_PATH;
|
|
30
30
|
return {
|
|
@@ -41,10 +41,9 @@ export function jamwidgetsPostsLoader(options) {
|
|
|
41
41
|
const response = await fetch(url.toString(), {
|
|
42
42
|
headers: {
|
|
43
43
|
"X-Jamwidgets-Key": siteKey,
|
|
44
|
-
// Legacy headers for backward compatibility
|
|
45
44
|
"X-Seriph-Key": siteKey,
|
|
46
|
-
// User-Agent to avoid bot detection (Cloudflare, etc.)
|
|
47
45
|
"User-Agent": "JamwidgetsAstroLoader/1.0",
|
|
46
|
+
...(origin ? { Origin: origin } : {}),
|
|
48
47
|
},
|
|
49
48
|
});
|
|
50
49
|
if (!response.ok) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jamwidgets/astro",
|
|
3
|
-
"version": "0.2
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Astro components and content loader for Jamwidgets (forms, comments, reactions, posts)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"./PoweredBy": "./src/PoweredBy.astro",
|
|
27
27
|
"./Reactions": "./src/Reactions.astro",
|
|
28
28
|
"./Views": "./src/Views.astro",
|
|
29
|
+
"./Analytics": "./src/Analytics.astro",
|
|
29
30
|
"./Poll": "./src/Poll.astro",
|
|
30
31
|
"./Subscribe": "./src/Subscribe.astro",
|
|
31
32
|
"./SubscribeForm": "./src/SubscribeForm.astro",
|
|
@@ -40,7 +41,8 @@
|
|
|
40
41
|
],
|
|
41
42
|
"scripts": {
|
|
42
43
|
"build": "tsc",
|
|
43
|
-
"dev": "tsc --watch"
|
|
44
|
+
"dev": "tsc --watch",
|
|
45
|
+
"test": "vitest run test/loader.test.ts"
|
|
44
46
|
},
|
|
45
47
|
"keywords": [
|
|
46
48
|
"astro",
|
|
@@ -55,13 +57,14 @@
|
|
|
55
57
|
],
|
|
56
58
|
"license": "MIT",
|
|
57
59
|
"dependencies": {
|
|
58
|
-
"@jamwidgets/core": "^0.
|
|
60
|
+
"@jamwidgets/core": "^0.3.1"
|
|
59
61
|
},
|
|
60
62
|
"peerDependencies": {
|
|
61
63
|
"astro": "^5.0.0 || ^6.0.0 || ^7.0.0"
|
|
62
64
|
},
|
|
63
65
|
"devDependencies": {
|
|
64
66
|
"astro": "^7.1.3",
|
|
65
|
-
"typescript": "^5.9.3"
|
|
67
|
+
"typescript": "^5.9.3",
|
|
68
|
+
"vitest": "^4.1.10"
|
|
66
69
|
}
|
|
67
70
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Falls back to the `jamwidgets-site-key` meta tag. */
|
|
4
|
+
siteKey?: string;
|
|
5
|
+
/** Defaults to `https://jamwidgets.com`. */
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { siteKey = "", endpoint = "" } = Astro.props;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<div
|
|
13
|
+
data-jamwidgets-analytics
|
|
14
|
+
data-site-key={siteKey}
|
|
15
|
+
data-endpoint={endpoint}
|
|
16
|
+
hidden
|
|
17
|
+
>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<script>
|
|
21
|
+
import { initAnalytics } from "@jamwidgets/core";
|
|
22
|
+
|
|
23
|
+
const el = document.querySelector("[data-jamwidgets-analytics]") as
|
|
24
|
+
| HTMLElement
|
|
25
|
+
| null;
|
|
26
|
+
initAnalytics({
|
|
27
|
+
siteKey: el?.dataset.siteKey || undefined,
|
|
28
|
+
endpoint: el?.dataset.endpoint || undefined,
|
|
29
|
+
});
|
|
30
|
+
</script>
|
package/src/Comments.astro
CHANGED
|
@@ -92,6 +92,8 @@ import PoweredBy from "./PoweredBy.astro";
|
|
|
92
92
|
</div>
|
|
93
93
|
|
|
94
94
|
<script>
|
|
95
|
+
import { getAttributionHeaders, getVisitorId } from "@jamwidgets/core";
|
|
96
|
+
|
|
95
97
|
interface Comment {
|
|
96
98
|
id: string;
|
|
97
99
|
authorName: string;
|
|
@@ -100,17 +102,6 @@ import PoweredBy from "./PoweredBy.astro";
|
|
|
100
102
|
replies: Comment[];
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
// Get or create a visitor ID for anonymous users
|
|
104
|
-
const VISITOR_KEY = "jamwidgets_visitor_id";
|
|
105
|
-
function getVisitorId(): string {
|
|
106
|
-
let id = localStorage.getItem(VISITOR_KEY);
|
|
107
|
-
if (!id) {
|
|
108
|
-
id = crypto.randomUUID();
|
|
109
|
-
localStorage.setItem(VISITOR_KEY, id);
|
|
110
|
-
}
|
|
111
|
-
return id;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
105
|
// Store form load timestamps for spam detection
|
|
115
106
|
const formTimestamps = new WeakMap<Element, number>();
|
|
116
107
|
|
|
@@ -130,6 +121,7 @@ import PoweredBy from "./PoweredBy.astro";
|
|
|
130
121
|
|
|
131
122
|
const visitorId = getVisitorId();
|
|
132
123
|
const headers = {
|
|
124
|
+
...getAttributionHeaders(pageId),
|
|
133
125
|
"X-JamWidgets-Key": siteKey,
|
|
134
126
|
"X-JamWidgets-Visitor": visitorId,
|
|
135
127
|
};
|
package/src/Form.astro
CHANGED
|
@@ -65,22 +65,13 @@ import PoweredBy from "./PoweredBy.astro";
|
|
|
65
65
|
</form>
|
|
66
66
|
|
|
67
67
|
<script>
|
|
68
|
+
import { getAttributionHeaders, getVisitorId } from "@jamwidgets/core";
|
|
69
|
+
|
|
68
70
|
interface FormSubmitResponse {
|
|
69
71
|
success: boolean;
|
|
70
72
|
message: string;
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
// Get or create a visitor ID for anonymous users
|
|
74
|
-
const VISITOR_KEY = "jamwidgets_visitor_id";
|
|
75
|
-
function getVisitorId(): string {
|
|
76
|
-
let id = localStorage.getItem(VISITOR_KEY);
|
|
77
|
-
if (!id) {
|
|
78
|
-
id = crypto.randomUUID();
|
|
79
|
-
localStorage.setItem(VISITOR_KEY, id);
|
|
80
|
-
}
|
|
81
|
-
return id;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
75
|
// Store form load timestamps for spam detection
|
|
85
76
|
const formTimestamps = new WeakMap<Element, number>();
|
|
86
77
|
|
|
@@ -134,6 +125,7 @@ import PoweredBy from "./PoweredBy.astro";
|
|
|
134
125
|
const response = await fetch(`${endpoint}/forms/${formSlug}/submit`, {
|
|
135
126
|
method: "POST",
|
|
136
127
|
headers: {
|
|
128
|
+
...getAttributionHeaders(),
|
|
137
129
|
"Content-Type": "application/json",
|
|
138
130
|
"X-JamWidgets-Key": siteKey,
|
|
139
131
|
"X-JamWidgets-Visitor": getVisitorId(),
|
package/src/Reactions.astro
CHANGED
|
@@ -87,16 +87,7 @@ const baseUrl = endpoint.replace(/\/+$/, "") + API_PATH;
|
|
|
87
87
|
</div>
|
|
88
88
|
|
|
89
89
|
<script>
|
|
90
|
-
|
|
91
|
-
const VISITOR_KEY = "jamwidgets_visitor_id";
|
|
92
|
-
function getVisitorId(): string {
|
|
93
|
-
let id = localStorage.getItem(VISITOR_KEY);
|
|
94
|
-
if (!id) {
|
|
95
|
-
id = crypto.randomUUID();
|
|
96
|
-
localStorage.setItem(VISITOR_KEY, id);
|
|
97
|
-
}
|
|
98
|
-
return id;
|
|
99
|
-
}
|
|
90
|
+
import { getAttributionHeaders, getVisitorId } from "@jamwidgets/core";
|
|
100
91
|
|
|
101
92
|
document.querySelectorAll("[data-jamwidgets-reactions]").forEach((container) => {
|
|
102
93
|
const endpoint = (container as HTMLElement).dataset.endpoint;
|
|
@@ -107,6 +98,7 @@ const baseUrl = endpoint.replace(/\/+$/, "") + API_PATH;
|
|
|
107
98
|
|
|
108
99
|
const visitorId = getVisitorId();
|
|
109
100
|
const headers = {
|
|
101
|
+
...getAttributionHeaders(pageId),
|
|
110
102
|
"X-JamWidgets-Key": siteKey,
|
|
111
103
|
"X-JamWidgets-Visitor": visitorId,
|
|
112
104
|
};
|
package/src/SubscribeForm.astro
CHANGED
|
@@ -71,22 +71,13 @@ const baseUrl = endpoint.replace(/\/+$/, "") + API_PATH;
|
|
|
71
71
|
</form>
|
|
72
72
|
|
|
73
73
|
<script>
|
|
74
|
+
import { getAttributionHeaders, getVisitorId } from "@jamwidgets/core";
|
|
75
|
+
|
|
74
76
|
interface SubscribeResponse {
|
|
75
77
|
success: boolean;
|
|
76
78
|
message: string;
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
// Get or create a visitor ID for anonymous users
|
|
80
|
-
const VISITOR_KEY = "jamwidgets_visitor_id";
|
|
81
|
-
function getVisitorId(): string {
|
|
82
|
-
let id = localStorage.getItem(VISITOR_KEY);
|
|
83
|
-
if (!id) {
|
|
84
|
-
id = crypto.randomUUID();
|
|
85
|
-
localStorage.setItem(VISITOR_KEY, id);
|
|
86
|
-
}
|
|
87
|
-
return id;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
81
|
document.querySelectorAll("[data-jamwidgets-subscribe-form]").forEach((form) => {
|
|
91
82
|
form.addEventListener("submit", async (e) => {
|
|
92
83
|
e.preventDefault();
|
|
@@ -114,6 +105,7 @@ const baseUrl = endpoint.replace(/\/+$/, "") + API_PATH;
|
|
|
114
105
|
const response = await fetch(`${endpoint}/subscribe`, {
|
|
115
106
|
method: "POST",
|
|
116
107
|
headers: {
|
|
108
|
+
...getAttributionHeaders(),
|
|
117
109
|
"Content-Type": "application/json",
|
|
118
110
|
"X-JamWidgets-Key": siteKey,
|
|
119
111
|
"X-JamWidgets-Visitor": getVisitorId(),
|
package/src/loader.ts
CHANGED
|
@@ -39,6 +39,8 @@ export interface JamwidgetsPostsLoaderOptions {
|
|
|
39
39
|
siteKey: string;
|
|
40
40
|
/** Base URL of your Jamwidgets instance (default: 'https://jamwidgets.com') */
|
|
41
41
|
endpoint?: string;
|
|
42
|
+
/** Site origin sent for allowed-origin validation */
|
|
43
|
+
origin?: string;
|
|
42
44
|
/** Filter posts by tag */
|
|
43
45
|
tag?: string;
|
|
44
46
|
/** Maximum number of posts to fetch (default: 500) */
|
|
@@ -63,6 +65,7 @@ interface ApiResponse {
|
|
|
63
65
|
export function jamwidgetsPostsLoader(options: JamwidgetsPostsLoaderOptions): Loader {
|
|
64
66
|
const {
|
|
65
67
|
endpoint = DEFAULT_ENDPOINT,
|
|
68
|
+
origin,
|
|
66
69
|
tag,
|
|
67
70
|
limit = 500,
|
|
68
71
|
onError = "throw",
|
|
@@ -89,10 +92,9 @@ export function jamwidgetsPostsLoader(options: JamwidgetsPostsLoaderOptions): Lo
|
|
|
89
92
|
const response = await fetch(url.toString(), {
|
|
90
93
|
headers: {
|
|
91
94
|
"X-Jamwidgets-Key": siteKey,
|
|
92
|
-
// Legacy headers for backward compatibility
|
|
93
95
|
"X-Seriph-Key": siteKey,
|
|
94
|
-
// User-Agent to avoid bot detection (Cloudflare, etc.)
|
|
95
96
|
"User-Agent": "JamwidgetsAstroLoader/1.0",
|
|
97
|
+
...(origin ? { Origin: origin } : {}),
|
|
96
98
|
},
|
|
97
99
|
});
|
|
98
100
|
|