blogger-feed 0.0.0 → 0.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.md +21 -0
- package/README.md +254 -0
- package/dist/blogger-feed.min.js +2 -0
- package/dist/blogger-feed.min.js.map +1 -0
- package/dist/index.cjs +918 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +532 -0
- package/dist/index.d.ts +532 -0
- package/dist/index.js +914 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -2
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present Deo Kumar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# blogger-feed
|
|
2
|
+
|
|
3
|
+
A lightweight, type-safe Blogger feed API client for fetching Blogger blog metadata, posts, pages, comments, and pagination data.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Fetch blog metadata, recent posts, pages, and comments
|
|
8
|
+
- Strong TypeScript support with exported response models
|
|
9
|
+
- Built for Node.js and browser environments
|
|
10
|
+
- Supports ESM and CommonJS imports
|
|
11
|
+
- Automatic pagination handling with `next()` and `previous()` helpers
|
|
12
|
+
- Optional JSONP mode for browser usage
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Install the package using your preferred package manager:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install blogger-feed
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
yarn add blogger-feed
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add blogger-feed
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
Import the client and create a new `BloggerFeed` instance with a blog URL or Blogger blog ID.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { BloggerFeed } from "blogger-feed";
|
|
36
|
+
|
|
37
|
+
const feed = new BloggerFeed("https://example-blog.blogspot.com");
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## API Reference
|
|
41
|
+
|
|
42
|
+
### `new BloggerFeed(urlOrId, options?)`
|
|
43
|
+
|
|
44
|
+
Creates a new Blogger feed client.
|
|
45
|
+
|
|
46
|
+
- `urlOrId: string | URL` — Blogger blog URL or numeric blog ID
|
|
47
|
+
- `options.jsonp?: boolean` — enable JSONP callbacks in browser environments
|
|
48
|
+
|
|
49
|
+
Example:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const feed = new BloggerFeed("https://example-blog.blogspot.com", {
|
|
53
|
+
jsonp: false,
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Static exports
|
|
58
|
+
|
|
59
|
+
- `BloggerFeed.SDKError` — SDK error type
|
|
60
|
+
- `BloggerFeed.SDKRequestError` — request error type
|
|
61
|
+
- `BloggerFeed.parseFeed` — parse raw Blogger feed objects
|
|
62
|
+
|
|
63
|
+
### `feed.blog.get()`
|
|
64
|
+
|
|
65
|
+
Fetch blog metadata.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
const blog = await feed.blog.get();
|
|
69
|
+
if (!blog) {
|
|
70
|
+
console.log("Blog not found");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
console.log(blog.title, blog.url);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If the blog cannot be found, this method returns `null`.
|
|
77
|
+
|
|
78
|
+
### `feed.posts.list(options?)`
|
|
79
|
+
|
|
80
|
+
List posts with optional filters.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const postsPage = await feed.posts.list({
|
|
84
|
+
maxResults: 5,
|
|
85
|
+
orderBy: "published",
|
|
86
|
+
label: "javascript",
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Supported options:
|
|
91
|
+
|
|
92
|
+
- `maxResults?: number`
|
|
93
|
+
- `startIndex?: number`
|
|
94
|
+
- `orderBy?: 'published' | 'updated'`
|
|
95
|
+
- `publishedMin?: Date | string`
|
|
96
|
+
- `publishedMax?: Date | string`
|
|
97
|
+
- `updatedMin?: Date | string`
|
|
98
|
+
- `updatedMax?: Date | string`
|
|
99
|
+
- `label?: string`
|
|
100
|
+
- `summary?: boolean`
|
|
101
|
+
|
|
102
|
+
### `feed.posts.get(postId, options?)`
|
|
103
|
+
|
|
104
|
+
Retrieve a single post by ID.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
const post = await feed.posts.get("12345");
|
|
108
|
+
if (!post) {
|
|
109
|
+
console.log("Post not found");
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If the post is not found, this method returns `null`.
|
|
114
|
+
|
|
115
|
+
Supported options:
|
|
116
|
+
|
|
117
|
+
- `summary?: boolean`
|
|
118
|
+
|
|
119
|
+
### `feed.posts.query(query, options?)`
|
|
120
|
+
|
|
121
|
+
Search posts with query.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
const searchPage = await feed.posts.query("hello", { maxResults: 10 });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `feed.pages.list(options?)`
|
|
128
|
+
|
|
129
|
+
List pages for the blog.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const pagesPage = await feed.pages.list({ maxResults: 10 });
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Supported options:
|
|
136
|
+
|
|
137
|
+
- `maxResults?: number`
|
|
138
|
+
- `startIndex?: number`
|
|
139
|
+
- `orderBy?: 'published' | 'updated'`
|
|
140
|
+
- `publishedMin?: Date | string`
|
|
141
|
+
- `publishedMax?: Date | string`
|
|
142
|
+
- `updatedMin?: Date | string`
|
|
143
|
+
- `updatedMax?: Date | string`
|
|
144
|
+
- `summary?: boolean`
|
|
145
|
+
|
|
146
|
+
### `feed.pages.get(pageId, options?)`
|
|
147
|
+
|
|
148
|
+
Retrieve a single page by ID.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const page = await feed.pages.get("67890");
|
|
152
|
+
if (!page) {
|
|
153
|
+
console.log("Page not found");
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
If the page is not found, this method returns `null`.
|
|
158
|
+
|
|
159
|
+
Supported options:
|
|
160
|
+
|
|
161
|
+
- `summary?: boolean`
|
|
162
|
+
|
|
163
|
+
### `feed.comments.list(options?)`
|
|
164
|
+
|
|
165
|
+
List comments for the blog or a specific post.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
const commentsPage = await feed.comments.list({
|
|
169
|
+
maxResults: 20,
|
|
170
|
+
postId: "12345",
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Supported options:
|
|
175
|
+
|
|
176
|
+
- `maxResults?: number`
|
|
177
|
+
- `startIndex?: number`
|
|
178
|
+
- `orderBy?: 'published' | 'updated'`
|
|
179
|
+
- `publishedMin?: Date | string`
|
|
180
|
+
- `publishedMax?: Date | string`
|
|
181
|
+
- `updatedMin?: Date | string`
|
|
182
|
+
- `updatedMax?: Date | string`
|
|
183
|
+
- `summary?: boolean`
|
|
184
|
+
- `postId?: string`
|
|
185
|
+
|
|
186
|
+
### `feed.comments.get(postId, commentId, options?)`
|
|
187
|
+
|
|
188
|
+
Retrieve a single comment by post and comment ID.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
const comment = await feed.comments.get("12345", "67890");
|
|
192
|
+
if (!comment) {
|
|
193
|
+
console.log("Comment not found");
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
If the comment is not found, this method returns `null`.
|
|
198
|
+
|
|
199
|
+
Supported options:
|
|
200
|
+
|
|
201
|
+
- `summary?: boolean`
|
|
202
|
+
|
|
203
|
+
## Pagination
|
|
204
|
+
|
|
205
|
+
List methods return a pagination object, not a bare array. The returned object includes:
|
|
206
|
+
|
|
207
|
+
- `items` — the current page of entries
|
|
208
|
+
- `itemsPerPage` — number of items returned in this page
|
|
209
|
+
- `startIndex` — index of the first item in the current page
|
|
210
|
+
- `totalResults` — total available entries
|
|
211
|
+
- `selfUrl` — current page URL
|
|
212
|
+
- `previousUrl` — previous page URL, if available
|
|
213
|
+
- `nextUrl` — next page URL, if available
|
|
214
|
+
- `next()` — fetch the next page or `null`
|
|
215
|
+
- `previous()` — fetch the previous page or `null`
|
|
216
|
+
|
|
217
|
+
Example:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
const postsPage = await feed.posts.list({ maxResults: 5 });
|
|
221
|
+
console.log(postsPage.items.length);
|
|
222
|
+
|
|
223
|
+
const nextPage = await postsPage.next();
|
|
224
|
+
if (nextPage) {
|
|
225
|
+
console.log(nextPage.items.length, "more posts");
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Types
|
|
230
|
+
|
|
231
|
+
The package exports helpful type definitions for TypeScript users, including:
|
|
232
|
+
|
|
233
|
+
- `Blog`
|
|
234
|
+
- `Post`
|
|
235
|
+
- `Comment`
|
|
236
|
+
- `Author`
|
|
237
|
+
- `Link`
|
|
238
|
+
- `Extended`
|
|
239
|
+
- `PostCommentInfo`
|
|
240
|
+
- `Feed`
|
|
241
|
+
|
|
242
|
+
These types describe the structure of Blogger feed responses and are available from the package exports.
|
|
243
|
+
|
|
244
|
+
## Browser Usage
|
|
245
|
+
|
|
246
|
+
To use the library in browser environments where CORS prevents direct JSON requests, enable JSONP mode:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const feed = new BloggerFeed("https://example-blog.blogspot.com", {
|
|
250
|
+
jsonp: true,
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
> Note: JSONP mode is only supported in browser environments.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(){var e=class{constructor(e){this.c=e}_paginate(e,t){var n;return{items:(n=e===`comments`?t.comments:t.posts)==null?[]:n,itemsPerPage:t.itemsPerPage,startIndex:t.startIndex,totalResults:t.totalResults,selfUrl:t.selfUrl,previousUrl:t.previousUrl,nextUrl:t.nextUrl,previous:async({signal:n}={})=>{if(!t.previousUrl)return null;let r=await this.c.req(t.previousUrl,{signal:n});return this._paginate(e,r)},next:async({signal:n}={})=>{if(!t.nextUrl)return null;let r=await this.c.req(t.nextUrl,{signal:n});return this._paginate(e,r)}}}},t=class extends e{async get({signal:e}={}){let{blog:t}=await this.c.req(`./posts/summary`,{params:{maxResults:0},signal:e});return t}},n=class extends Error{constructor(e,t){super(e,t),this.name=`SDKError`}},r=class extends n{constructor(e,t,n){super(e,n),this.name=`SDKRequestError`,this.url=String(t)}};function i(e){return typeof e==`string`}function a(e){return e===void 0}function o(e){return Array.isArray(e)}function s(e){return typeof e==`object`&&!!e&&!o(e)}function c(e,...t){let n=e;for(let e=0;e<t.length;e+=1){if(!n||!Object.hasOwn(n,t[e]))return;n=n[t[e]]}return n}function l(e,t){if(!i(e))throw TypeError(`${t} must be of type string, current type is ${typeof e}`)}function u(e,t){if(l(e,t),e.trim().length===0)throw TypeError(`${t} cannot be a blank string`)}let d=0,f=0;function p(){let e=Date.now();return e===d?f++:(d=e,f=0),`${e}_${f}`}function m(e){let t=[],n=null;if(o(e)&&e.length>0)for(let r=0;r<e.length;r+=1){let a=e[r],o=c(a,`rel`),s=c(a,`href`),l=c(a,`type`),u=c(a,`title`);i(o)&&i(s)&&(t.push({rel:o,href:s,type:i(l)?l:null,title:i(u)?u:null}),o===`alternate`&&l===`text/html`&&(n=s))}return{alternate:n,links:t}}function h(e){let t={self:null,previous:null,next:null},{links:n}=m(c(e,`link`));for(let e=0;e<n.length;e+=1){let{rel:r,href:i,type:a}=n[e];a!==`text/html`&&(r===`self`?t.self=i:r===`previous`?t.previous=i:r===`next`&&(t.next=i))}return t}function g(e){let t=[];if(o(e)&&e.length>0)for(let n=0;n<e.length;n+=1){let r=e[n],a=c(r,`term`);i(a)&&t.push(a)}return t}function _(e){let[t,n,r]=[`georss$box`,`georss$featurename`,`georss$point`].map(t=>{let n=c(e,t,`$t`);return i(n)?n:null});return{box:t,featureName:n,point:r}}function v(e){let t={feed:null,number:null,title:null},n=m(e).links.filter(e=>e.rel===`replies`);if(n)for(let{title:e,type:r,href:a}of n)if(r===`text/html`&&i(e)){let n=e.match(/\d+/);t.title=e,t.number=n!=null&&n[0]?Number.parseInt(n[0],10):0}else r===`application/atom+xml`&&i(a)&&(t.feed=a);return t}function y(e){let t=[];if(o(e)&&e.length>0)for(let n=0;n<e.length;n+=1){let n=e[0],r=c(n,`name`,`$t`),a=c(n,`uri`,`$t`),o=c(n,`gd$image`,`src`),s=i(r)?r:`Unknown`,l=i(o)&&o.trim().toLowerCase()!==`https://img1.blogblog.com/img/b16-rounded.gif`?o:null,u=i(a)?a:null;t.push({name:s,url:u,image:l})}return t}function b(e){let t={class:null,time:null,removed:!1},n=c(e,`gd$extendedProperty`);if(s(e)&&o(n)&&n.length>0)for(let e=0;e<n.length;e+=1){let{name:r,value:a}=n[e]||{};if(i(r)&&i(a)){let e={"blogger.itemClass":[`class`,a],"blogger.displayTime":[`time`,a],"blogger.contentRemoved":[`removed`,a===`true`]}[r];if(o(e)){let[n,r]=e;n in t&&(t[n]=r)}}}return t}function x(e){let t=c(e,`media$thumbnail`,`url`),n=i(t)?t:null,r=[n,n];if(n!==null)return r;let a=c(e,`content`,`$t`),o=c(e,`summary`,`$t`),s=null;i(a)?s=a:i(o)&&(s=o);let l=s?/<img +(.*?)src=([""])([^""]+?)([""])(.*?) *\/?>/i.exec(s):null;return l!=null&&l[3]&&(r[1]=l[3]),r}function S(e){let t=c(e,`openSearch$itemsPerPage`,`$t`);return i(t)?Number(t):null}function C(e){let t=c(e,`openSearch$startIndex`,`$t`);return i(t)?Number(t):null}function w(e){let t=c(e,`openSearch$totalResults`,`$t`);return i(t)?Number(t):null}function T(e){let t=c(e,`id`,`$t`),n=c(e,`title`,`$t`),r=c(e,`subtitle`,`$t`),a=c(e,`updated`,`$t`),{alternate:o,links:l}=m(c(e,`link`));if(s(e)&&i(t)&&i(n)&&i(a)&&i(o)){let s=c(e,`category`);return{id:t.replace(/^.*blog-(\d+).*$/,`$1`),title:n,subtitle:i(r)?r:null,labels:g(s),url:o,links:l,updated:a,author:y(c(e,`author`))[0]}}return null}function E(e){let t=c(e,`id`,`$t`),n=c(e,`title`,`$t`),r=c(e,`published`,`$t`),a=c(e,`updated`,`$t`),o=c(e,`summary`,`$t`),l=c(e,`content`,`$t`),u=c(e,`link`),{alternate:d,links:f}=m(u);if(s(e)&&i(d)&&i(t)&&i(n)&&i(r)&&i(a)){let[s,p]=x(e);return{id:t.replace(/^.*(?:page|post)-(\d+)$/,`$1`),title:n,published:r,updated:a,labels:g(c(e,`category`)),url:d,links:f,author:y(c(e,`author`))[0],thumbnail:s,thumbnailAlt:p,summary:i(o)?o:null,content:i(l)?l:null,comments:v(u),geo:_(e)}}return null}function D(e){let t=c(e,`id`,`$t`),n=c(e,`title`,`$t`),r=c(e,`published`,`$t`),a=c(e,`updated`,`$t`),o=c(e,`thr$in-reply-to`),l=c(o,`href`),u=c(o,`ref`),d=c(e,`summary`,`$t`),f=c(e,`content`,`$t`),{alternate:p,links:h}=m(c(e,`link`));if(s(e)&&i(p)&&i(t)&&i(n)&&i(r)&&i(a)&&i(l)&&i(u)){var g,_;let o=(g=h.find(e=>e.rel===`related`))==null?void 0:g.href.match(/\/feeds\/(.*)\/comments\/[^/]+\/(\d+)/);return{title:n,published:r,updated:a,url:p,links:h,author:y(c(e,`author`))[0],summary:i(d)?d:null,content:i(f)?f:null,extended:b(e),id:t.replace(/^.*(?:page|post)-(\d+)$/,`$1`),post:{id:u.replace(/^.*(?:page|post)-(\d+)$/,`$1`),url:l.split(`?`)[0]},inReplyTo:(_=o==null?void 0:o[2])==null?null:_}}return null}function O(e){let t=null,n=null;if(o(e)&&(t=[],n=[],e.length>0))for(let r=0;r<e.length;r+=1){let i=e[r];if(s(i))if(`thr$in-reply-to`in i){let e=D(i);e&&n.push(e)}else{let e=E(i);e&&t.push(e)}}return{posts:t,comments:n}}function k(e,t){let{posts:n,comments:r}=O(e),i=h(t);return{blog:T(t),links:m(c(t,`link`)).links,posts:n,comments:r,itemsPerPage:S(t),startIndex:C(t),totalResults:w(t),selfUrl:i.self,previousUrl:i.previous,nextUrl:i.next}}function A(e){return o(e)?e:s(e)?[e]:null}function j(e){let t=c(e,`feed`);return s(t)?k(A(c(t,`entry`)),t):k(A(c(e,`entry`)))}async function M(e,{signal:t}={}){var n;let i=await fetch(e,{signal:t}).catch(t=>{throw new r(`Fetch to JSON`,String(e),{cause:t})});if(!i.ok){var a;throw await((a=i.body)==null?void 0:a.cancel()),new r(`Failed to fetch ${i.url} (status: ${i.status})`,i.url)}let o=(n=i.headers.get(`Content-Type`))==null?void 0:n.includes(`application/json`);if(!o){var s;throw await((s=i.body)==null?void 0:s.cancel()),new r(`Request was success but Content-Type '${o}' is not supported`,i.url)}return await i.json()}let N={};async function P(e,{signal:t}={}){return new Promise((r,i)=>{var a;let o=!1,s=e=>{o||(o=!0,r(e))},c=e=>{o||(o=!0,i(e))};if(t!=null&&t.aborted){var l;c((l=t.reason)==null?new DOMException(`Aborted`,`AbortError`):l);return}let u=`callback_${p()}`,d=`window.__deox_blogger_feed_jsonp_callbacks__.${u}`,f=e({callback:d,id:u}),m=document.createElement(`script`);m.async=!0,m.src=String(f);let h=()=>{delete N[u],t==null||t.removeEventListener(`abort`,g),m.onerror=null,m.onload=null,m.remove()},g=()=>{var e;N[u]=()=>{},c((e=t==null?void 0:t.reason)==null?new DOMException(`Aborted`,`AbortError`):e)};t==null||t.addEventListener(`abort`,g,{once:!0}),N[u]=e=>{s(e)},m.onload=()=>{h(),o||c(new n(`JSONP callback \`${d}\` was not invoked for '${m.src}'`))},m.onerror=e=>{h(),c(new n(typeof e==`string`?e:`Failed to load script from '${m.src}'`))},(a=window).__deox_blogger_feed_jsonp_callbacks__!=null||(a.__deox_blogger_feed_jsonp_callbacks__=N),document.head.appendChild(m)})}let F={maxResults:`max-results`,startIndex:`start-index`,orderBy:`orderby`,publishedMin:`published-min`,publishedMax:`published-max`,updatedMin:`updated-min`,updatedMax:`updated-max`,sort:`sort`,query:`q`};async function I(e,{params:t,include:n,exclude:r,base:i,jsonp:a,signal:o}={}){let s={};if(t)for(let e in t){if(!(e in F))continue;let i=t[e];if((!n||n.includes(e))&&(!r||!r.includes(e))){let t=F[e];s[t]=i instanceof Date?i.toISOString():String(i)}}s.alt=`json`,s.redirect=`false`;let c=new URL(e,i);for(let e in s)c.searchParams.append(e,s[e]);return j(a?await P(({callback:e})=>{let t=new URL(c);return t.searchParams.append(`callback`,e),t},{signal:o}):await M(c,{signal:o}))}var L=class{constructor(e,t={}){if(i(e)&&/^\d{12,24}$/.test(e))this._blogId=e,this._base=z(e);else{let t=null;if(e instanceof URL)t=e;else if(typeof e==`string`)try{t=new URL(/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(e)?e:`https://${e}`)}catch(e){}if(!t)throw Error(`Argument 'urlOrId' is not a valid blogger blog url or blog id`);if(!/^https?:$/i.test(t.protocol))throw Error(`Argument 'urlOrId' has unsupported protocol '${t.protocol}'`);this._blogUrl=R(t.origin),this._base=B(t.origin)}if(this._jsonp=t.jsonp===!0,this._jsonp&&(typeof window!=`object`||typeof document!=`object`))throw Error(`options.jsonp is set to true but current environment does't support it, please set it to false to use json`)}async getBlog(){if(!this._blog){let{blog:e}=await this.req(`./posts/summary`,{params:{maxResults:0}});if(!e)throw new n(`The blog was not found.`);this._blog=e}return this._blog}async getBlogId(){return this._blogId!=null||(this._blogId=(await this.getBlog()).id),this._blogId}async getBlogUrl(){return this._blogUrl!=null||(this._blogUrl=R((await this.getBlog()).url)),this._blogUrl}async getDomainBase(){return B(await this.getBlogUrl())}async getServiceBase(){return z(await this.getBlogId())}async req(e,t){return I(e,{base:this._base,jsonp:this._jsonp,...t})}};function R(e){return e.endsWith(`/`)?e:`${e}/`}function z(e){return`https://www.blogger.com/feeds/${e}/`}function B(e){return`${R(e)}feeds/`}var V=class extends e{async list(e={},{signal:t}={}){let{postId:n}=e;a(n)||u(n,`options.postId`);let r=await this.c.req(`./${n?`${encodeURI(n)}/`:``}comments/${e.summary===!0?`summary`:`default`}`,{params:e,exclude:[`query`],signal:t});return n&&r.comments&&(r.comments=r.comments.filter(e=>e.post.id===n)),this._paginate(`comments`,r)}async get(e,t,n={},{signal:r}={}){var i;u(e,`Argument 'postId'`),u(t,`Argument 'commentId'`);let{comments:a}=await this.c.req(`./${encodeURI(e)}/comments/${n.summary===!0?`summary`:`default`}/${encodeURI(t)}`,{base:await this.c.getServiceBase(),exclude:[`query`],signal:r});return(i=a==null?void 0:a.find(e=>e.id===t))==null?null:i}},H=class extends e{async list(e={},{signal:t}={}){let n=await this.c.req(`./pages/${e.summary===!0?`summary`:`default`}`,{params:e,exclude:[`query`],signal:t});return this._paginate(`posts`,n)}async get(e,t={},{signal:n}={}){var r;u(e,`Argument 'pageId'`);let{posts:i}=await this.c.req(`./pages/${t.summary===!0?`summary`:`default`}/${encodeURI(e)}`,{exclude:[`query`],signal:n});return(r=i==null?void 0:i.find(t=>t.id===e))==null?null:r}},U=class extends e{async list(e={},{signal:t}={}){let{label:n}=e;a(n)||u(n,`options.label`);let r=await this.c.req(`./posts/${e.summary===!0?`summary`:`default`}${n?`/-/${encodeURI(n)}`:``}`,{params:e,exclude:[`query`],signal:t});return this._paginate(`posts`,r)}async get(e,t={},{signal:n}={}){var r;u(e,`Argument 'postId'`);let{posts:i}=await this.c.req(`./posts/${t.summary===!0?`summary`:`default`}/${encodeURIComponent(e)}`,{exclude:[`query`],signal:n});return(r=i==null?void 0:i.find(t=>t.id===e))==null?null:r}async query(e,t={},{signal:n}={}){u(e,`Argument 'query'`);let r=await this.c.req(`./posts/${t.summary===!0?`summary`:`default`}`,{params:{...t,query:e},signal:n});return this._paginate(`posts`,r)}},W=class{constructor(e,n={}){let r=new L(e,n);this.posts=new U(r),this.pages=new H(r),this.comments=new V(r),this.blog=new t(r)}};W.SDKError=n,W.SDKRequestError=r,W.parseFeed=j;let G=()=>typeof globalThis<`u`?globalThis:typeof window<`u`?window:self;G().BloggerFeed=W})();
|
|
2
|
+
//# sourceMappingURL=blogger-feed.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blogger-feed.min.js","names":[],"sources":["../src/methods.ts","../src/blog.ts","../src/errors.ts","../src/constants.ts","../src/utils.ts","../src/feed-parser.ts","../src/request.ts","../src/client.ts","../src/comments.ts","../src/pages.ts","../src/posts.ts","../src/blogger-feed.ts","../src/iife.ts"],"sourcesContent":["import type { Client } from './client';\nimport type { Comment, Feed, Post } from './types';\n\ninterface PaginationItemsMap {\n posts: Post[];\n comments: Comment[];\n}\n\nexport interface WithPagination<T extends keyof PaginationItemsMap> {\n readonly items: PaginationItemsMap[T];\n readonly itemsPerPage: number | null;\n readonly startIndex: number | null;\n readonly totalResults: number | null;\n readonly selfUrl: string | null;\n readonly previousUrl: string | null;\n readonly nextUrl: string | null;\n readonly next: (requestOptions?: { signal?: AbortSignal }) => Promise<WithPagination<T> | null>;\n readonly previous: (requestOptions?: { signal?: AbortSignal }) => Promise<WithPagination<T> | null>;\n}\n\nexport class Methods {\n protected readonly c: Client;\n\n constructor(client: Client) {\n this.c = client;\n }\n\n /** Adds pagination properties and methods to feed entries array */\n protected _paginate<T extends keyof PaginationItemsMap>(type: T, feed: Feed): WithPagination<T> {\n return {\n items: ((type === 'comments' ? feed.comments : feed.posts) ?? []) as PaginationItemsMap[T],\n itemsPerPage: feed.itemsPerPage,\n startIndex: feed.startIndex,\n totalResults: feed.totalResults,\n selfUrl: feed.selfUrl,\n previousUrl: feed.previousUrl,\n nextUrl: feed.nextUrl,\n previous: async ({ signal } = {}) => {\n if (!feed.previousUrl) {\n return null;\n }\n const result = await this.c.req(feed.previousUrl, { signal });\n return this._paginate(type, result);\n },\n next: async ({ signal } = {}) => {\n if (!feed.nextUrl) {\n return null;\n }\n const result = await this.c.req(feed.nextUrl, {\n signal,\n });\n return this._paginate(type, result);\n },\n };\n }\n}\n","import { Methods } from './methods';\nimport type { Blog } from './types';\n\n/**\n * A class having methods related to Blog\n */\nexport class BlogMethods extends Methods {\n /**\n * Retrieve blog information\n *\n * @returns The blog info\n */\n async get({ signal }: { signal?: AbortSignal } = {}): Promise<Blog | null> {\n const { blog } = await this.c.req('./posts/summary', {\n params: {\n // do not load entries since we only need blog info\n maxResults: 0,\n },\n signal,\n });\n\n return blog;\n }\n}\n","/**\n * Represents a SDK error\n */\nexport class SDKError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'SDKError';\n }\n}\n\n/**\n * Represents a error thrown while making an API request\n */\nexport class SDKRequestError extends SDKError {\n readonly url: string;\n\n constructor(message: string, url: string | URL, options?: ErrorOptions) {\n super(message, options);\n this.name = 'SDKRequestError';\n this.url = String(url);\n }\n}\n","/** Name for global variable for jsonp callbacks */\nexport const JSONP_NAMESPACE: string = '__deox_blogger_feed_jsonp_callbacks__';\n","export function isString(input: unknown): input is string {\n return typeof input === 'string';\n}\n\nexport function isUndefined(input: unknown): input is undefined {\n return typeof input === 'undefined';\n}\n\nexport function isArray(input: unknown): input is any[] {\n return Array.isArray(input);\n}\n\nexport function isObject(input: unknown): input is NonNullable<object> {\n return typeof input === 'object' && input !== null && !isArray(input);\n}\n\nexport function getNested(obj: unknown, ...levels: string[]): unknown {\n let current = obj;\n\n for (let i = 0; i < levels.length; i += 1) {\n if (!current || !Object.hasOwn(current, levels[i])) {\n return undefined;\n }\n current = current[levels[i] as never];\n }\n\n return current;\n}\n\n/** asserts: input must be string */\nexport function assertString(input: unknown, name: string): asserts input is string {\n if (!isString(input)) {\n throw new TypeError(`${name} must be of type string, current type is ${typeof input}`);\n }\n}\n\n/** asserts: string must not be empty */\nexport function assertNonEmptyString(input: unknown, name: string): asserts input is string {\n assertString(input, name);\n\n if (input.length === 0) {\n throw new TypeError(`${name} cannot be an empty string`);\n }\n}\n\n/** asserts: string must not be blank */\nexport function assertNonBlankString(input: unknown, name: string): asserts input is string {\n assertString(input, name);\n\n if ((input as string).trim().length === 0) {\n throw new TypeError(`${name} cannot be a blank string`);\n }\n}\n\nlet lastTime = 0;\nlet counter = 0;\n\nexport function generateId() {\n const now = Date.now();\n\n if (now === lastTime) {\n counter++;\n } else {\n lastTime = now;\n counter = 0;\n }\n\n return `${now}_${counter}`;\n}\n","import type { Author, Blog, Comment, Extended, Feed, Geo, Link, Post, PostCommentInfo } from './types';\nimport { getNested, isArray, isObject, isString } from './utils';\n\n/**\n * Gets the links details from link array\n *\n * @param linkArray The link array\n *\n * @returns An object containing link and links\n */\nfunction getLinks(linkArray: unknown): { alternate: string | null; links: Link[] } {\n const links: Link[] = [];\n let href: string | null = null;\n\n if (isArray(linkArray) && linkArray.length > 0) {\n for (let i = 0; i < linkArray.length; i += 1) {\n const link: unknown = linkArray[i];\n\n const linkRelLike = getNested(link, 'rel');\n const linkHrefLike = getNested(link, 'href');\n const linkTypeLike = getNested(link, 'type');\n const linkTitleLike = getNested(link, 'title');\n\n if (isString(linkRelLike) && isString(linkHrefLike)) {\n links.push({\n rel: linkRelLike,\n href: linkHrefLike,\n type: isString(linkTypeLike) ? linkTypeLike : null,\n title: isString(linkTitleLike) ? linkTitleLike : null,\n });\n\n if (linkRelLike === 'alternate' && linkTypeLike === 'text/html') {\n href = linkHrefLike;\n }\n }\n }\n }\n\n return { alternate: href, links };\n}\n\n/**\n * Gets pagination urls from feed\n *\n * @param feed The feed object\n *\n * @returns An object containing `self`, `previous` and `next` url\n */\nfunction getPagination(feed: unknown): Record<'self' | 'previous' | 'next', string | null> {\n const result: Record<'self' | 'previous' | 'next', string | null> = { self: null, previous: null, next: null };\n\n const { links } = getLinks(getNested(feed, 'link'));\n\n for (let i = 0; i < links.length; i += 1) {\n const { rel, href, type } = links[i];\n if (type === 'text/html') {\n continue;\n }\n if (rel === 'self') {\n result.self = href;\n } else if (rel === 'previous') {\n result.previous = href;\n } else if (rel === 'next') {\n result.next = href;\n }\n }\n\n return result;\n}\n\n/**\n * Gets category from category array\n *\n * @param categoryArray The category array\n *\n * @returns An Array of string representing categories\n */\nfunction getLabels(categoryArray: unknown): string[] {\n const labels: string[] = [];\n\n if (isArray(categoryArray) && categoryArray.length > 0) {\n for (let i = 0; i < categoryArray.length; i += 1) {\n const category: unknown = categoryArray[i];\n\n const categoryTermLike = getNested(category, 'term');\n if (isString(categoryTermLike)) {\n labels.push(categoryTermLike);\n }\n }\n }\n\n return labels;\n}\n\n/**\n * Gets Geo details from post entry\n *\n * @param postEntry The post entry object\n *\n * @returns An object containing `box`, `featureName` and `point`\n */\nfunction getGeo(postEntry: unknown): Geo {\n const [box, featureName, point] = ['georss$box', 'georss$featurename', 'georss$point'].map((key) => {\n const valueLike = getNested(postEntry, key, '$t');\n if (isString(valueLike)) {\n return valueLike;\n }\n return null;\n });\n\n return { box, featureName, point };\n}\n\n/**\n * Gets comments details from link array of a post entry object\n *\n * @param linkArray The link array\n *\n * @returns An object containing `feed`, `number` and `title`\n */\nfunction getPostComments(linkArray: unknown): PostCommentInfo {\n const result: PostCommentInfo = { feed: null, number: null, title: null };\n\n const replies = getLinks(linkArray).links.filter((link) => link.rel === 'replies');\n if (replies) {\n for (const { title, type, href } of replies) {\n if (type === 'text/html' && isString(title)) {\n const numberMatches = title.match(/\\d+/);\n result.title = title;\n result.number = numberMatches?.[0] ? Number.parseInt(numberMatches[0], 10) : 0;\n } else if (type === 'application/atom+xml' && isString(href)) {\n result.feed = href;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Gets authors from author array\n *\n * @param authorArray The author array\n *\n * @returns An object containing `name`, `url`, `image` and `public`\n */\nfunction getAuthors(authorArray: unknown): Author[] {\n const authors: Author[] = [];\n\n if (isArray(authorArray) && authorArray.length > 0) {\n for (let i = 0; i < authorArray.length; i += 1) {\n const author: unknown = authorArray[0];\n const authorNameLike = getNested(author, 'name', '$t');\n const authorUriLike = getNested(author, 'uri', '$t');\n const authorImageLike = getNested(author, 'gd$image', 'src');\n\n const name = isString(authorNameLike) ? authorNameLike : 'Unknown';\n const image =\n isString(authorImageLike) && authorImageLike.trim().toLowerCase() !== 'https://img1.blogblog.com/img/b16-rounded.gif'\n ? authorImageLike\n : null;\n const url = isString(authorUriLike) ? authorUriLike : null;\n\n authors.push({ name, url, image });\n }\n }\n\n return authors;\n}\n\n/**\n * Gets extended details from a comment entry object\n *\n * @param commentEntry The comment entry object\n *\n * @returns An object containing `class`, `time`, `removed`\n */\nfunction getExtended(commentEntry: unknown): Extended {\n const result: Extended = { class: null, time: null, removed: false };\n\n const extendedArray = getNested(commentEntry, 'gd$extendedProperty');\n\n if (isObject(commentEntry) && isArray(extendedArray) && extendedArray.length > 0) {\n for (let i = 0; i < extendedArray.length; i += 1) {\n const extended = (extendedArray[i] || {}) as Record<string, unknown>;\n const { name, value } = extended;\n if (isString(name) && isString(value)) {\n const data: Record<string, ['class' | 'time' | 'removed', string | boolean]> = {\n 'blogger.itemClass': ['class', value],\n 'blogger.displayTime': ['time', value],\n 'blogger.contentRemoved': ['removed', value === 'true'],\n };\n const dataArray = data[name];\n if (isArray(dataArray)) {\n const [key, val] = dataArray;\n if (key in result) {\n result[key] = val as never;\n }\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Gets thumbnail urls from a post entry object\n *\n * @param postEntry The post entry object\n *\n * @returns An Array having 2 elements.\n * Element at index 0 will be thumbnail url or null from post entry.\n * Element at index 1 will be thumbnail url or null from post content otherwise post entry\n */\nfunction getThumbnail(postEntry: unknown): [string | null, string | null] {\n const postMediaThumbnailLike = getNested(postEntry, 'media$thumbnail', 'url');\n\n const thumbnail: string | null = isString(postMediaThumbnailLike) ? postMediaThumbnailLike : null;\n\n const result: [string | null, string | null] = [thumbnail, thumbnail];\n\n if (thumbnail !== null) {\n return result;\n }\n\n const postContentLike = getNested(postEntry, 'content', '$t');\n const postSummaryLike = getNested(postEntry, 'summary', '$t');\n\n let content: string | null = null;\n if (isString(postContentLike)) {\n content = postContentLike;\n } else if (isString(postSummaryLike)) {\n content = postSummaryLike;\n }\n\n const matches = content ? /<img +(.*?)src=([\"\"])([^\"\"]+?)([\"\"])(.*?) *\\/?>/i.exec(content) : null;\n\n if (matches?.[3]) {\n result[1] = matches[3];\n }\n\n return result;\n}\n\n/**\n * Gets items per page number from feed object\n *\n * @param feedObject The feed object\n *\n * @returns The items per page number or `null`\n */\nfunction getItemsPerPage(feedObject: unknown): number | null {\n const resultString = getNested(feedObject, 'openSearch$itemsPerPage', '$t');\n\n if (isString(resultString)) {\n return Number(resultString);\n }\n\n return null;\n}\n\n/**\n * Gets start index number from feed object\n *\n * @param feedObject The feed object\n *\n * @returns The start index or `null`\n */\nfunction getStartIndex(feedObject: unknown): number | null {\n const resultString = getNested(feedObject, 'openSearch$startIndex', '$t');\n\n if (isString(resultString)) {\n return Number(resultString);\n }\n\n return null;\n}\n\n/**\n * Gets total result number from feed object\n *\n * @param feedObject The feed object\n *\n * @returns The total result or `null`\n */\nfunction getTotalResult(feedObject: unknown): number | null {\n const resultString = getNested(feedObject, 'openSearch$totalResults', '$t');\n\n if (isString(resultString)) {\n return Number(resultString);\n }\n\n return null;\n}\n\n/**\n * Gets blog details from feed object\n *\n * @param feedObject The feed object\n *\n * @returns The {@link Blog} if available otherwise `null`\n */\nfunction getBlog(feedObject: unknown): Blog | null {\n const feedIdLike = getNested(feedObject, 'id', '$t');\n const feedTitleLike = getNested(feedObject, 'title', '$t');\n const feedSubtitleLike = getNested(feedObject, 'subtitle', '$t');\n const feedUpdatedLike = getNested(feedObject, 'updated', '$t');\n const feedLinkLike = getNested(feedObject, 'link');\n const { alternate, links } = getLinks(feedLinkLike);\n\n if (isObject(feedObject) && isString(feedIdLike) && isString(feedTitleLike) && isString(feedUpdatedLike) && isString(alternate)) {\n const feedCategoryLike = getNested(feedObject, 'category');\n\n return {\n id: feedIdLike.replace(/^.*blog-(\\d+).*$/, '$1'),\n title: feedTitleLike,\n subtitle: isString(feedSubtitleLike) ? feedSubtitleLike : null,\n labels: getLabels(feedCategoryLike),\n url: alternate,\n links,\n updated: feedUpdatedLike,\n author: getAuthors(getNested(feedObject, 'author'))[0],\n };\n }\n\n return null;\n}\n\n/**\n * Gets post details from post entry object\n *\n * @param postEntry The post entry object\n *\n * @returns The {@link Post} if available otherwise `null`\n */\nfunction getPost(postEntry: unknown): Post | null {\n const postIdLike = getNested(postEntry, 'id', '$t');\n const postTitleLike = getNested(postEntry, 'title', '$t');\n const postPublishedLike = getNested(postEntry, 'published', '$t');\n const postUpdatedLike = getNested(postEntry, 'updated', '$t');\n const postSummaryLike = getNested(postEntry, 'summary', '$t');\n const postContentLike = getNested(postEntry, 'content', '$t');\n const postLinkLike = getNested(postEntry, 'link');\n const { alternate, links } = getLinks(postLinkLike);\n\n if (\n isObject(postEntry) &&\n isString(alternate) &&\n isString(postIdLike) &&\n isString(postTitleLike) &&\n isString(postPublishedLike) &&\n isString(postUpdatedLike)\n ) {\n const [thumbnail, thumbnailAlt] = getThumbnail(postEntry);\n\n return {\n id: postIdLike.replace(/^.*(?:page|post)-(\\d+)$/, '$1'),\n title: postTitleLike,\n published: postPublishedLike,\n updated: postUpdatedLike,\n labels: getLabels(getNested(postEntry, 'category')),\n url: alternate,\n links,\n author: getAuthors(getNested(postEntry, 'author'))[0],\n thumbnail,\n thumbnailAlt,\n summary: isString(postSummaryLike) ? postSummaryLike : null,\n content: isString(postContentLike) ? postContentLike : null,\n comments: getPostComments(postLinkLike),\n geo: getGeo(postEntry),\n };\n }\n\n return null;\n}\n\n/**\n * Gets comment details from comment entry object\n *\n * @param commentEntry The comment entry object\n *\n * @returns The {@link Comment} if available otherwise `null`\n */\nfunction getComment(commentEntry: unknown): Comment | null {\n const commentIdLike = getNested(commentEntry, 'id', '$t');\n const commentTitleLike = getNested(commentEntry, 'title', '$t');\n const commentPublishedLike = getNested(commentEntry, 'published', '$t');\n const commentUpdatedLike = getNested(commentEntry, 'updated', '$t');\n const commentInReplyToLike = getNested(commentEntry, 'thr$in-reply-to');\n const commentInReplyToHrefLike = getNested(commentInReplyToLike, 'href');\n const commentInReplyToRefLike = getNested(commentInReplyToLike, 'ref');\n const commentSummaryLike = getNested(commentEntry, 'summary', '$t');\n const commentContentLike = getNested(commentEntry, 'content', '$t');\n const commentLinkLike = getNested(commentEntry, 'link');\n const { alternate, links } = getLinks(commentLinkLike);\n\n if (\n isObject(commentEntry) &&\n isString(alternate) &&\n isString(commentIdLike) &&\n isString(commentTitleLike) &&\n isString(commentPublishedLike) &&\n isString(commentUpdatedLike) &&\n isString(commentInReplyToHrefLike) &&\n isString(commentInReplyToRefLike)\n ) {\n const inReplyToMatches = links.find((link) => link.rel === 'related')?.href.match(/\\/feeds\\/(.*)\\/comments\\/[^/]+\\/(\\d+)/);\n\n return {\n title: commentTitleLike,\n published: commentPublishedLike,\n updated: commentUpdatedLike,\n url: alternate,\n links,\n author: getAuthors(getNested(commentEntry, 'author'))[0],\n summary: isString(commentSummaryLike) ? commentSummaryLike : null,\n content: isString(commentContentLike) ? commentContentLike : null,\n extended: getExtended(commentEntry),\n id: commentIdLike.replace(/^.*(?:page|post)-(\\d+)$/, '$1'),\n post: {\n id: commentInReplyToRefLike.replace(/^.*(?:page|post)-(\\d+)$/, '$1'),\n url: commentInReplyToHrefLike.split('?')[0],\n },\n inReplyTo: inReplyToMatches?.[2] ?? null,\n };\n }\n\n return null;\n}\n\n/**\n * Gets the posts and comments from entry array\n *\n * @param entryArray The array of entry object\n *\n * @returns An object containing `posts` and `comments`\n */\nfunction getEntries(entryArray: unknown): { posts: Post[] | null; comments: Comment[] | null } {\n let posts: Post[] | null = null;\n let comments: Comment[] | null = null;\n\n if (isArray(entryArray)) {\n posts = [];\n comments = [];\n\n if (entryArray.length > 0) {\n for (let i = 0; i < entryArray.length; i += 1) {\n const post: unknown = entryArray[i];\n if (isObject(post)) {\n if ('thr$in-reply-to' in post) {\n const commentLike = getComment(post);\n if (commentLike) {\n comments.push(commentLike);\n }\n } else {\n const postLike = getPost(post);\n if (postLike) {\n posts.push(postLike);\n }\n }\n }\n }\n }\n }\n\n return { posts, comments };\n}\n\n/**\n * Gets all possible information from entry object and feed object\n *\n * @param entryArray The entry array\n * @param feed The feed object\n *\n * @returns An object\n */\nfunction getFeedFromEntry(entryArray: unknown, feedObject?: unknown): Feed {\n const { posts, comments } = getEntries(entryArray);\n\n const pagination = getPagination(feedObject);\n\n return {\n blog: getBlog(feedObject),\n links: getLinks(getNested(feedObject, 'link')).links,\n posts,\n comments,\n itemsPerPage: getItemsPerPage(feedObject),\n startIndex: getStartIndex(feedObject),\n totalResults: getTotalResult(feedObject),\n selfUrl: pagination.self,\n previousUrl: pagination.previous,\n nextUrl: pagination.next,\n };\n}\n\n/**\n * Get entry array from input\n *\n * @param input The input\n *\n * if input is an object add it to an array\n * else if input is an array use it\n * otherwise null\n *\n * @returns Array of entry object\n */\nfunction getEntryArray(input: unknown): unknown[] | null {\n if (isArray(input)) {\n return input as unknown[];\n }\n if (isObject(input)) {\n return [input];\n }\n return null;\n}\n\n/**\n * Get the information from Blogger feed json object\n *\n * @param input A feed object\n *\n * Possible inputs:\n *\n * ```ts\n * type Input =\n * | { feed: { entry?: object | unknown[] } }\n * | { entry?: object | unknown[] }\n * ```\n *\n * @returns An object containing information from feed\n */\nexport function parseFeed(input: unknown): Feed {\n const inputFeedLike = getNested(input, 'feed');\n\n // Check if input.feed is an object\n if (isObject(inputFeedLike)) {\n const inputFeedEntryLike = getNested(inputFeedLike, 'entry');\n return getFeedFromEntry(getEntryArray(inputFeedEntryLike), inputFeedLike);\n }\n\n const inputEntryLike = getNested(input, 'entry');\n return getFeedFromEntry(getEntryArray(inputEntryLike));\n}\n","import { JSONP_NAMESPACE } from './constants';\nimport { SDKError, SDKRequestError } from './errors';\nimport { parseFeed } from './feed-parser';\nimport type { Feed } from './types';\nimport { generateId } from './utils';\n\n/**\n * Fetches JSON using Fetch API\n *\n * @param url The url to fetch\n *\n * @returns The json data\n */\nasync function fetchJSON<T = unknown>(url: string | URL, { signal }: { signal?: AbortSignal } = {}): Promise<T> {\n const response = await fetch(url, {\n signal,\n }).catch((error) => {\n throw new SDKRequestError('Fetch to JSON', String(url), {\n cause: error,\n });\n });\n\n if (!response.ok) {\n await response.body?.cancel();\n throw new SDKRequestError(`Failed to fetch ${response.url} (status: ${response.status})`, response.url);\n }\n\n const contentType = response.headers.get('Content-Type')?.includes('application/json');\n if (!contentType) {\n await response.body?.cancel();\n throw new SDKRequestError(`Request was success but Content-Type '${contentType}' is not supported`, response.url);\n }\n\n return (await response.json()) as T;\n}\n\n/** A callback function for constructing jsonp url with given callback param */\ntype JSONPGetUrl = (data: { callback: string; id: string }) => string | URL;\n\n/** Pending jsonp requests */\nconst jsonpQueue: Record<string, (data: unknown) => void> = {};\n\n/**\n * Fetches JSONP data through callback using script element\n *\n * @param getUrl A callback function for constructing jsonp url with given callback param\n * @param scriptOptions Assign object to script element\n *\n * @returns The data which was sent to the callback\n */\nasync function fetchJSONP<T = unknown>(getUrl: JSONPGetUrl, { signal }: { signal?: AbortSignal } = {}): Promise<T> {\n return new Promise<T>((res, rej) => {\n let settled = false;\n const resolve = (value: T) => {\n if (!settled) {\n settled = true;\n res(value);\n }\n };\n const reject = (error: unknown) => {\n if (!settled) {\n settled = true;\n rej(error);\n }\n };\n\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const id = `callback_${generateId()}`;\n const callback = `window.${JSONP_NAMESPACE}.${id}`;\n const url = getUrl({ callback, id });\n\n const script = document.createElement('script');\n script.async = true;\n script.src = String(url);\n\n const cleanup = () => {\n delete jsonpQueue[id];\n signal?.removeEventListener('abort', onAbort);\n script.onerror = null;\n script.onload = null;\n script.remove();\n };\n\n const onAbort = () => {\n // use noop function for late JSONP calls\n jsonpQueue[id] = () => {};\n reject(signal?.reason ?? new DOMException('Aborted', 'AbortError'));\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n\n jsonpQueue[id] = (data) => {\n resolve(data as T);\n };\n script.onload = () => {\n cleanup();\n\n if (!settled) {\n reject(new SDKError(`JSONP callback \\`${callback}\\` was not invoked for '${script.src}'`));\n }\n };\n script.onerror = (event) => {\n cleanup();\n reject(new SDKError(typeof event === 'string' ? event : `Failed to load script from '${script.src}'`));\n };\n\n (window as unknown as Record<string, unknown>)[JSONP_NAMESPACE] ??= jsonpQueue;\n document.head.appendChild(script);\n });\n}\n\n/**\n * An interface of parameters which can be used for blogger feed api\n */\nexport interface Params {\n maxResults?: number;\n startIndex?: number;\n orderBy?: 'lastmodified' | 'starttime' | 'published' | 'updated';\n publishedMin?: Date | string;\n publishedMax?: Date | string;\n updatedMin?: Date | string;\n updatedMax?: Date | string;\n sort?: string;\n query?: string;\n}\n\n/** List of supported query params options and map to valid params */\nconst validParamsMap: Record<keyof Params, string> = {\n maxResults: 'max-results',\n startIndex: 'start-index',\n orderBy: 'orderby',\n publishedMin: 'published-min',\n publishedMax: 'published-max',\n updatedMin: 'updated-min',\n updatedMax: 'updated-max',\n sort: 'sort',\n query: 'q',\n};\n\n/**\n * An interface representing options for {@link fetchFeed}\n */\nexport interface FetchFeedOptions {\n params?: Params;\n include?: (keyof Params)[];\n exclude?: (keyof Params)[];\n base?: string | URL;\n jsonp?: boolean;\n signal?: AbortSignal;\n}\n\n/**\n * Fetches and parses the blogger feed\n *\n * @param path The feed url\n * @param param1 Options\n *\n * @returns The parsed feed data\n */\nexport async function fetchFeed(path: string | URL, { params, include, exclude, base, jsonp, signal }: FetchFeedOptions = {}): Promise<Feed> {\n const queries: Record<string, string> = {};\n\n if (params) {\n for (const key in params) {\n if (!(key in validParamsMap)) {\n continue;\n }\n const value = params[key as keyof typeof params];\n\n const allowed = (!include || (include as string[]).includes(key)) && (!exclude || !(exclude as string[]).includes(key));\n\n if (allowed) {\n const mapped = validParamsMap[key as keyof Params];\n queries[mapped] = value instanceof Date ? value.toISOString() : String(value);\n }\n }\n }\n\n // Set alt to json in order to load the json data instead of xml\n queries.alt = 'json';\n\n // Set redirect to false\n queries.redirect = 'false';\n\n const endpoint = new URL(path, base);\n\n for (const name in queries) {\n endpoint.searchParams.append(name, queries[name]);\n }\n\n if (jsonp) {\n const data = await fetchJSONP(\n ({ callback }) => {\n const url = new URL(endpoint);\n url.searchParams.append('callback', callback);\n return url;\n },\n { signal },\n );\n return parseFeed(data);\n }\n\n const data = await fetchJSON(endpoint, { signal });\n return parseFeed(data);\n}\n","import { SDKError } from './errors';\nimport { type FetchFeedOptions, fetchFeed } from './request';\nimport type { Blog, Feed } from './types';\nimport { isString } from './utils';\n\n/**\n * An interface representing options for {@link Client} constructor\n */\nexport interface ClientOptions {\n /** When set to `true`, enables jsonp callbacks */\n jsonp?: boolean;\n}\n\n/**\n * A class for fetching Blogger feed\n */\nexport class Client {\n private _jsonp: boolean;\n private _base: string;\n\n private _blogUrl: string | undefined;\n private _blogId: string | undefined;\n\n private _blog?: Blog;\n\n /**\n * Creates an instance of {@link Client}\n *\n * @param urlOrId The url or id of the blog\n * @param options Options\n */\n constructor(urlOrId: string | URL, options: ClientOptions = {}) {\n if (isString(urlOrId) && /^\\d{12,24}$/.test(urlOrId)) {\n this._blogId = urlOrId;\n this._base = getServiceBase(urlOrId);\n } else {\n let url: URL | null = null;\n if (urlOrId instanceof URL) {\n url = urlOrId;\n } else if (typeof urlOrId === 'string') {\n try {\n url = new URL(!/^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//.test(urlOrId) ? `https://${urlOrId}` : urlOrId);\n } catch (_) {}\n }\n if (!url) {\n throw new Error(\"Argument 'urlOrId' is not a valid blogger blog url or blog id\");\n }\n if (!/^https?:$/i.test(url.protocol)) {\n throw new Error(`Argument 'urlOrId' has unsupported protocol '${url.protocol}'`);\n }\n\n this._blogUrl = trailingSlash(url.origin);\n this._base = getDomainBase(url.origin);\n }\n this._jsonp = options.jsonp === true;\n\n // Throw an error if jsonp is enabled but current environment is not browser\n if (this._jsonp && (typeof window !== 'object' || typeof document !== 'object')) {\n throw new Error(\"options.jsonp is set to true but current environment does't support it, please set it to false to use json\");\n }\n }\n\n async getBlog(): Promise<{ id: string; url: string }> {\n if (!this._blog) {\n const { blog } = await this.req('./posts/summary', {\n params: {\n // do not load entries since we only need blog info\n maxResults: 0,\n },\n });\n\n if (!blog) {\n throw new SDKError('The blog was not found.');\n }\n\n this._blog = blog;\n }\n\n return this._blog;\n }\n\n async getBlogId(): Promise<string> {\n this._blogId ??= (await this.getBlog()).id;\n return this._blogId;\n }\n\n async getBlogUrl(): Promise<string> {\n this._blogUrl ??= trailingSlash((await this.getBlog()).url);\n return this._blogUrl;\n }\n\n async getDomainBase(): Promise<string> {\n return getDomainBase(await this.getBlogUrl());\n }\n\n async getServiceBase(): Promise<string> {\n return getServiceBase(await this.getBlogId());\n }\n\n async req(path: string, options?: FetchFeedOptions): Promise<Feed> {\n return fetchFeed(path, { base: this._base, jsonp: this._jsonp, ...options });\n }\n}\n\nfunction trailingSlash(url: string): string {\n return url.endsWith('/') ? url : `${url}/`;\n}\n\nfunction getServiceBase(id: string): string {\n return `https://www.blogger.com/feeds/${id}/`;\n}\n\nfunction getDomainBase(origin: string): string {\n return `${trailingSlash(origin)}feeds/`;\n}\n","import { Methods, type WithPagination } from './methods';\nimport type { Comment } from './types';\nimport { assertNonBlankString, isUndefined } from './utils';\n\n/** Options for {@link Comments.list} */\nexport interface CommentsListOptions {\n maxResults?: number;\n startIndex?: number;\n orderBy?: 'published' | 'updated';\n publishedMin?: Date | string;\n publishedMax?: Date | string;\n updatedMin?: Date | string;\n updatedMax?: Date | string;\n summary?: boolean;\n postId?: string;\n}\n\n/** Options for {@link Comments.get} */\nexport interface CommentsGetOptions {\n summary?: boolean;\n}\n\n/**\n * A class having methods related to Comments\n */\nexport class CommentsMethods extends Methods {\n /**\n * Retrieves all the comments of the blog or a post\n *\n * @param options Options for filters\n *\n * @returns On success, an Array of Comment\n */\n async list(options: CommentsListOptions = {}, { signal }: { signal?: AbortSignal } = {}): Promise<WithPagination<'comments'>> {\n const { postId } = options;\n\n // validate post_id if provided\n if (!isUndefined(postId)) {\n assertNonBlankString(postId, 'options.postId');\n }\n\n const result = await this.c.req(`./${postId ? `${encodeURI(postId)}/` : ''}comments/${options.summary === true ? 'summary' : 'default'}`, {\n params: options,\n exclude: ['query'],\n signal,\n });\n\n // Make sure to filter once again if post_id is provided,\n if (postId && result.comments) {\n result.comments = result.comments.filter((c) => c.post.id === postId);\n }\n\n return this._paginate('comments', result);\n }\n\n /**\n * Retrieves a comment\n *\n * @param postId The id of the post\n * @param commentId The id of the comment\n * @param options Options\n *\n * @returns On success, a Comment\n */\n async get(postId: string, commentId: string, options: CommentsGetOptions = {}, { signal }: { signal?: AbortSignal } = {}): Promise<Comment | null> {\n assertNonBlankString(postId, \"Argument 'postId'\");\n assertNonBlankString(commentId, \"Argument 'commentId'\");\n\n const { comments } = await this.c.req(\n `./${encodeURI(postId)}/comments/${options.summary === true ? 'summary' : 'default'}/${encodeURI(commentId)}`,\n {\n // We need to use blogger service base url since comments by id through domain is not available\n base: await this.c.getServiceBase(),\n exclude: ['query'],\n signal,\n },\n );\n\n return comments?.find((c) => c.id === commentId) ?? null;\n }\n}\n","import { Methods, type WithPagination } from './methods';\nimport type { Post } from './types';\nimport { assertNonBlankString } from './utils';\n\n/** Options for {@link Pages.list} */\nexport interface PagesListOptions {\n maxResults?: number;\n startIndex?: number;\n orderBy?: 'published' | 'updated';\n publishedMin?: Date | string;\n publishedMax?: Date | string;\n updatedMin?: Date | string;\n updatedMax?: Date | string;\n summary?: boolean;\n}\n\n/** Options for {@link Pages.get} */\nexport interface PagesGetOptions {\n summary?: boolean;\n}\n\n/**\n * A class having methods related to Pages\n */\nexport class PagesMethods extends Methods {\n /**\n * Retrieves all the pages of the blog\n *\n * @param options Options for filters\n *\n * @returns On success, an Array of Post\n */\n async list(options: PagesListOptions = {}, { signal }: { signal?: AbortSignal } = {}): Promise<WithPagination<'posts'>> {\n const result = await this.c.req(`./pages/${options.summary === true ? 'summary' : 'default'}`, {\n params: options,\n exclude: ['query'],\n signal,\n });\n\n return this._paginate('posts', result);\n }\n\n /**\n * Retrieves a page\n *\n * @param pageId The id of the page\n * @param options Options for filters\n *\n * @returns On success, a Post\n */\n async get(pageId: string, options: PagesGetOptions = {}, { signal }: { signal?: AbortSignal } = {}): Promise<Post | null> {\n assertNonBlankString(pageId, \"Argument 'pageId'\");\n\n const { posts } = await this.c.req(`./pages/${options.summary === true ? 'summary' : 'default'}/${encodeURI(pageId)}`, {\n exclude: ['query'],\n signal,\n });\n\n return posts?.find((p) => p.id === pageId) ?? null;\n }\n}\n","import { Methods, type WithPagination } from './methods';\nimport type { Post } from './types';\nimport { assertNonBlankString, isUndefined } from './utils';\n\n/** Options for {@link Posts.list} */\nexport interface PostsListOptions {\n maxResults?: number;\n startIndex?: number;\n orderBy?: 'published' | 'updated';\n publishedMin?: Date | string;\n publishedMax?: Date | string;\n updatedMin?: Date | string;\n updatedMax?: Date | string;\n label?: string;\n summary?: boolean;\n}\n\n/** Options for {@link Posts.get} */\nexport interface PostsGetOptions {\n summary?: boolean;\n}\n\n/** Options for {@link Posts.query} */\nexport interface PostsQueryOptions extends Omit<PostsListOptions, 'label'> {}\n\nexport class PostsMethods extends Methods {\n /**\n * Retrieves all the posts of the blog\n *\n * @param options Options for filters\n *\n * @returns On success, an Array of Post\n */\n async list(options: PostsListOptions = {}, { signal }: { signal?: AbortSignal } = {}): Promise<WithPagination<'posts'>> {\n const { label } = options;\n\n // validate label if provided\n if (!isUndefined(label)) {\n assertNonBlankString(label, 'options.label');\n }\n\n const result = await this.c.req(`./posts/${options.summary === true ? 'summary' : 'default'}${label ? `/-/${encodeURI(label)}` : ''}`, {\n params: options,\n exclude: ['query'],\n signal,\n });\n\n return this._paginate('posts', result);\n }\n\n /**\n * Retrieves a post\n *\n * @param postId The id of the post\n * @param options Options\n *\n * @returns On success, a Post\n */\n async get(postId: string, options: PostsGetOptions = {}, { signal }: { signal?: AbortSignal } = {}): Promise<Post | null> {\n assertNonBlankString(postId, \"Argument 'postId'\");\n\n const { posts } = await this.c.req(`./posts/${options.summary === true ? 'summary' : 'default'}/${encodeURIComponent(postId)}`, {\n exclude: ['query'],\n signal,\n });\n\n return posts?.find((p) => p.id === postId) ?? null;\n }\n\n /**\n * Retrieves all the posts with query\n *\n * @param query The query\n * @param options Options for filters\n *\n * @returns On success, an Array of Post\n */\n async query(query: string, options: PostsQueryOptions = {}, { signal }: { signal?: AbortSignal } = {}): Promise<WithPagination<'posts'>> {\n assertNonBlankString(query, \"Argument 'query'\");\n\n const result = await this.c.req(`./posts/${options.summary === true ? 'summary' : 'default'}`, {\n params: {\n ...options,\n query,\n },\n signal,\n });\n\n return this._paginate('posts', result);\n }\n}\n","import { BlogMethods } from './blog';\nimport { Client } from './client';\nimport { CommentsMethods } from './comments';\nimport { SDKError, SDKRequestError } from './errors';\nimport { parseFeed } from './feed-parser';\nimport { PagesMethods } from './pages';\nimport { PostsMethods } from './posts';\n\n/**\n * An interface representing options for {@link BloggerFeed}\n */\nexport interface BloggerFeedOptions {\n /**\n * When set to `true`, enables jsonp callbacks, useful when running in browser environments to prevent cors issues.\n *\n * **Warning**: Set it to `true` if and only if you are running it in browser\n * because it loads javascript by appending script element to document.\n *\n * @default false\n */\n jsonp?: boolean;\n}\n\nexport class BloggerFeed {\n static readonly SDKError = SDKError;\n static readonly SDKRequestError = SDKRequestError;\n static readonly parseFeed = parseFeed;\n\n readonly posts: PostsMethods;\n readonly pages: PagesMethods;\n readonly comments: CommentsMethods;\n readonly blog: BlogMethods;\n\n /**\n * Creates an instance of {@link BloggerFeed}\n *\n * @param urlOrId The url or id of the blog\n * @param options Options\n */\n constructor(urlOrId: string | URL, options: BloggerFeedOptions = {}) {\n const client = new Client(urlOrId, options);\n this.posts = new PostsMethods(client);\n this.pages = new PagesMethods(client);\n this.comments = new CommentsMethods(client);\n this.blog = new BlogMethods(client);\n }\n}\n","import { BloggerFeed } from './blogger-feed';\n\nconst GLOBAL_NAME = 'BloggerFeed';\n\nconst getGlobalObject = () => (typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : self);\n\n(getGlobalObject() as unknown as { [GLOBAL_NAME]: typeof BloggerFeed })[GLOBAL_NAME] = BloggerFeed;\n"],"mappings":"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"}
|