folderblog 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/README.md +88 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +99 -0
- package/dist/index.d.ts +99 -0
- package/dist/index.js +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# folderblog
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for **[folder.blog](https://folder.blog)** — git-native blogging.
|
|
4
|
+
|
|
5
|
+
Zero dependencies. Works in Node.js, Deno, Bun, and browsers.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install folderblog
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { folderBlog } from 'folderblog';
|
|
17
|
+
|
|
18
|
+
const blog = folderBlog('yourname.folder.blog');
|
|
19
|
+
|
|
20
|
+
const posts = await blog.posts.list();
|
|
21
|
+
const post = await blog.posts.get('hello-world');
|
|
22
|
+
const site = await blog.site.get();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## API
|
|
26
|
+
|
|
27
|
+
### `blog.posts.list()`
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
const posts = await blog.posts.list();
|
|
31
|
+
|
|
32
|
+
posts[0].slug // "hello-world"
|
|
33
|
+
posts[0].title // "Hello World"
|
|
34
|
+
posts[0].date // "2024-01-15"
|
|
35
|
+
posts[0].tags // ["intro"]
|
|
36
|
+
posts[0].excerpt // "My first post..."
|
|
37
|
+
posts[0].url // "/api/posts/hello-world"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `blog.posts.get(slug)`
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const post = await blog.posts.get('hello-world');
|
|
44
|
+
|
|
45
|
+
post.content // "<p>Full HTML here...</p>"
|
|
46
|
+
post.raw // "# Hello World\n\nFull markdown..."
|
|
47
|
+
post.images // ["/posts/images/photo.jpg"]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### `blog.site.get()`
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const site = await blog.site.get();
|
|
54
|
+
|
|
55
|
+
site.site // "My Blog"
|
|
56
|
+
site.variant // "light" | "dark" | "serif" | "mono"
|
|
57
|
+
site.postsCount // 12
|
|
58
|
+
site.url // "https://yourname.folder.blog"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Error Handling
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { folderBlog, NotFoundError } from 'folderblog';
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
await blog.posts.get('missing');
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error instanceof NotFoundError) {
|
|
70
|
+
// 404
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Types
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import type { Post, PostSummary, Site } from 'folderblog';
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Links
|
|
82
|
+
|
|
83
|
+
- **Website:** [folder.blog](https://folder.blog)
|
|
84
|
+
- **Docs:** [folder.blog/docs](https://folder.blog/docs)
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var d=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var y=(r,t)=>{for(var s in t)d(r,s,{get:t[s],enumerable:!0})},P=(r,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of f(t))!w.call(r,o)&&o!==s&&d(r,o,{get:()=>t[o],enumerable:!(i=g(t,o))||i.enumerable});return r};var x=r=>P(d({},"__esModule",{value:!0}),r);var F={};y(F,{ApiError:()=>c,FolderBlogError:()=>n,NetworkError:()=>p,NotFoundError:()=>a,folderBlog:()=>h});module.exports=x(F);var n=class extends Error{status;url;constructor(t,s){super(t),this.name="FolderBlogError",this.status=s?.status,this.url=s?.url}},a=class extends n{constructor(t,s,i){super(`${t} not found: ${s}`,{status:404,url:i}),this.name="NotFoundError"}},c=class extends n{constructor(t,s,i){super(t,{status:s,url:i}),this.name="ApiError"}},p=class extends n{cause;constructor(t,s){super(t),this.name="NetworkError",this.cause=s}};function E(r){let t=r.trim();return t.endsWith("/")&&(t=t.slice(0,-1)),!t.startsWith("http://")&&!t.startsWith("https://")&&(t=`https://${t}`),t}function h(r,t={}){let s=E(r),i=t.fetch??globalThis.fetch;async function o(l){let e=`${s}${l}`,u;try{u=await i(e,{method:"GET",headers:{Accept:"application/json"}})}catch(m){throw new p(`Failed to fetch ${e}`,m instanceof Error?m:void 0)}if(!u.ok)throw u.status===404?new a("Resource",l,e):new c(`API request failed: ${u.statusText}`,u.status,e);try{return await u.json()}catch{throw new c("Failed to parse JSON response",u.status,e)}}return{posts:{async list(){return(await o("/api/posts")).posts},async get(l){if(!l)throw new n("Post slug is required");try{return await o(`/api/posts/${encodeURIComponent(l)}`)}catch(e){throw e instanceof a?new a("Post",l,e.url):e}}},site:{async get(){return o("/api")}}}}0&&(module.exports={ApiError,FolderBlogError,NetworkError,NotFoundError,folderBlog});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base post fields shared between list and detail responses
|
|
3
|
+
*/
|
|
4
|
+
interface PostBase {
|
|
5
|
+
slug: string;
|
|
6
|
+
title: string;
|
|
7
|
+
date: string;
|
|
8
|
+
tags: string[];
|
|
9
|
+
excerpt: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Post summary in list responses
|
|
13
|
+
*/
|
|
14
|
+
interface PostSummary extends PostBase {
|
|
15
|
+
url: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Full post from detail endpoint
|
|
19
|
+
*/
|
|
20
|
+
interface Post extends PostBase {
|
|
21
|
+
content: string;
|
|
22
|
+
raw: string;
|
|
23
|
+
images: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Site information
|
|
27
|
+
*/
|
|
28
|
+
interface Site {
|
|
29
|
+
site: string;
|
|
30
|
+
variant: "light" | "dark" | "serif" | "mono";
|
|
31
|
+
postsCount: number;
|
|
32
|
+
url: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Client options
|
|
36
|
+
*/
|
|
37
|
+
interface FolderBlogOptions {
|
|
38
|
+
fetch?: typeof fetch;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The FolderBlog client
|
|
42
|
+
*/
|
|
43
|
+
interface FolderBlogClient {
|
|
44
|
+
posts: {
|
|
45
|
+
list(): Promise<PostSummary[]>;
|
|
46
|
+
get(slug: string): Promise<Post>;
|
|
47
|
+
};
|
|
48
|
+
site: {
|
|
49
|
+
get(): Promise<Site>;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create a FolderBlog client
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const blog = folderBlog('yourname.folder.blog');
|
|
59
|
+
* const posts = await blog.posts.list();
|
|
60
|
+
* const post = await blog.posts.get('hello-world');
|
|
61
|
+
* const site = await blog.site.get();
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function folderBlog(domain: string, options?: FolderBlogOptions): FolderBlogClient;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Base error class for folder-blog SDK errors
|
|
68
|
+
*/
|
|
69
|
+
declare class FolderBlogError extends Error {
|
|
70
|
+
/** HTTP status code if applicable */
|
|
71
|
+
readonly status?: number;
|
|
72
|
+
/** The URL that was requested */
|
|
73
|
+
readonly url?: string;
|
|
74
|
+
constructor(message: string, options?: {
|
|
75
|
+
status?: number;
|
|
76
|
+
url?: string;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Error thrown when a resource is not found (404)
|
|
81
|
+
*/
|
|
82
|
+
declare class NotFoundError extends FolderBlogError {
|
|
83
|
+
constructor(resource: string, identifier: string, url?: string);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Error thrown when the API request fails
|
|
87
|
+
*/
|
|
88
|
+
declare class ApiError extends FolderBlogError {
|
|
89
|
+
constructor(message: string, status: number, url?: string);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Error thrown when network/fetch fails
|
|
93
|
+
*/
|
|
94
|
+
declare class NetworkError extends FolderBlogError {
|
|
95
|
+
readonly cause?: Error;
|
|
96
|
+
constructor(message: string, cause?: Error);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { ApiError, type FolderBlogClient, FolderBlogError, type FolderBlogOptions, NetworkError, NotFoundError, type Post, type PostSummary, type Site, folderBlog };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base post fields shared between list and detail responses
|
|
3
|
+
*/
|
|
4
|
+
interface PostBase {
|
|
5
|
+
slug: string;
|
|
6
|
+
title: string;
|
|
7
|
+
date: string;
|
|
8
|
+
tags: string[];
|
|
9
|
+
excerpt: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Post summary in list responses
|
|
13
|
+
*/
|
|
14
|
+
interface PostSummary extends PostBase {
|
|
15
|
+
url: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Full post from detail endpoint
|
|
19
|
+
*/
|
|
20
|
+
interface Post extends PostBase {
|
|
21
|
+
content: string;
|
|
22
|
+
raw: string;
|
|
23
|
+
images: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Site information
|
|
27
|
+
*/
|
|
28
|
+
interface Site {
|
|
29
|
+
site: string;
|
|
30
|
+
variant: "light" | "dark" | "serif" | "mono";
|
|
31
|
+
postsCount: number;
|
|
32
|
+
url: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Client options
|
|
36
|
+
*/
|
|
37
|
+
interface FolderBlogOptions {
|
|
38
|
+
fetch?: typeof fetch;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The FolderBlog client
|
|
42
|
+
*/
|
|
43
|
+
interface FolderBlogClient {
|
|
44
|
+
posts: {
|
|
45
|
+
list(): Promise<PostSummary[]>;
|
|
46
|
+
get(slug: string): Promise<Post>;
|
|
47
|
+
};
|
|
48
|
+
site: {
|
|
49
|
+
get(): Promise<Site>;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create a FolderBlog client
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const blog = folderBlog('yourname.folder.blog');
|
|
59
|
+
* const posts = await blog.posts.list();
|
|
60
|
+
* const post = await blog.posts.get('hello-world');
|
|
61
|
+
* const site = await blog.site.get();
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function folderBlog(domain: string, options?: FolderBlogOptions): FolderBlogClient;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Base error class for folder-blog SDK errors
|
|
68
|
+
*/
|
|
69
|
+
declare class FolderBlogError extends Error {
|
|
70
|
+
/** HTTP status code if applicable */
|
|
71
|
+
readonly status?: number;
|
|
72
|
+
/** The URL that was requested */
|
|
73
|
+
readonly url?: string;
|
|
74
|
+
constructor(message: string, options?: {
|
|
75
|
+
status?: number;
|
|
76
|
+
url?: string;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Error thrown when a resource is not found (404)
|
|
81
|
+
*/
|
|
82
|
+
declare class NotFoundError extends FolderBlogError {
|
|
83
|
+
constructor(resource: string, identifier: string, url?: string);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Error thrown when the API request fails
|
|
87
|
+
*/
|
|
88
|
+
declare class ApiError extends FolderBlogError {
|
|
89
|
+
constructor(message: string, status: number, url?: string);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Error thrown when network/fetch fails
|
|
93
|
+
*/
|
|
94
|
+
declare class NetworkError extends FolderBlogError {
|
|
95
|
+
readonly cause?: Error;
|
|
96
|
+
constructor(message: string, cause?: Error);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { ApiError, type FolderBlogClient, FolderBlogError, type FolderBlogOptions, NetworkError, NotFoundError, type Post, type PostSummary, type Site, folderBlog };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o=class extends Error{status;url;constructor(t,r){super(t),this.name="FolderBlogError",this.status=r?.status,this.url=r?.url}},a=class extends o{constructor(t,r,u){super(`${t} not found: ${r}`,{status:404,url:u}),this.name="NotFoundError"}},l=class extends o{constructor(t,r,u){super(t,{status:r,url:u}),this.name="ApiError"}},c=class extends o{cause;constructor(t,r){super(t),this.name="NetworkError",this.cause=r}};function m(e){let t=e.trim();return t.endsWith("/")&&(t=t.slice(0,-1)),!t.startsWith("http://")&&!t.startsWith("https://")&&(t=`https://${t}`),t}function h(e,t={}){let r=m(e),u=t.fetch??globalThis.fetch;async function p(n){let s=`${r}${n}`,i;try{i=await u(s,{method:"GET",headers:{Accept:"application/json"}})}catch(d){throw new c(`Failed to fetch ${s}`,d instanceof Error?d:void 0)}if(!i.ok)throw i.status===404?new a("Resource",n,s):new l(`API request failed: ${i.statusText}`,i.status,s);try{return await i.json()}catch{throw new l("Failed to parse JSON response",i.status,s)}}return{posts:{async list(){return(await p("/api/posts")).posts},async get(n){if(!n)throw new o("Post slug is required");try{return await p(`/api/posts/${encodeURIComponent(n)}`)}catch(s){throw s instanceof a?new a("Post",n,s.url):s}}},site:{async get(){return p("/api")}}}}export{l as ApiError,o as FolderBlogError,c as NetworkError,a as NotFoundError,h as folderBlog};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "folderblog",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "SDK for consuming folder.blog content APIs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"prepublishOnly": "pnpm build"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"folderblog",
|
|
30
|
+
"blog",
|
|
31
|
+
"cms",
|
|
32
|
+
"headless",
|
|
33
|
+
"api",
|
|
34
|
+
"sdk",
|
|
35
|
+
"markdown",
|
|
36
|
+
"static-site"
|
|
37
|
+
],
|
|
38
|
+
"author": "",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"homepage": "https://folder.blog",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/anthropics/folderblog"
|
|
44
|
+
},
|
|
45
|
+
"sideEffects": false,
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"tsup": "^8.0.0",
|
|
48
|
+
"typescript": "^5.7.2",
|
|
49
|
+
"vitest": "^2.0.0"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|