@content-streamline/nextjs 0.0.3 → 0.0.5
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 +205 -90
- package/dist/cache/file-cache.d.ts +28 -4
- package/dist/cache/file-cache.d.ts.map +1 -1
- package/dist/cache/file-cache.js +79 -3
- package/dist/components/LatestPosts.d.ts +53 -0
- package/dist/components/LatestPosts.d.ts.map +1 -0
- package/dist/components/LatestPosts.js +29 -0
- package/dist/components/PostsList.d.ts +8 -3
- package/dist/components/PostsList.d.ts.map +1 -1
- package/dist/components/PostsList.js +9 -7
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/styles.css +263 -43
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +72 -15
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -6,22 +6,40 @@ import { createAPIClient } from '../api/client.js';
|
|
|
6
6
|
import { getAllCachedPosts, getCachedPost, cachePost, updatePostsIndex, shouldRefreshCache, } from '../cache/file-cache.js';
|
|
7
7
|
/**
|
|
8
8
|
* Get API configuration from environment variables
|
|
9
|
+
* Returns null if not configured (instead of throwing)
|
|
9
10
|
*/
|
|
10
11
|
function getAPIConfig() {
|
|
11
12
|
const baseUrl = process.env.CONTENT_STREAMLINE_API_BASE_URL || process.env.API_BASE_URL;
|
|
12
13
|
const accessToken = process.env.CONTENT_STREAMLINE_API_ACCESS_TOKEN || process.env.API_ACCESS_TOKEN;
|
|
13
14
|
if (!baseUrl || !accessToken) {
|
|
14
|
-
|
|
15
|
+
return null;
|
|
15
16
|
}
|
|
16
17
|
return { baseUrl, accessToken };
|
|
17
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Get API configuration, throwing if not configured
|
|
21
|
+
* Use this when API is required
|
|
22
|
+
*/
|
|
23
|
+
function requireAPIConfig() {
|
|
24
|
+
const config = getAPIConfig();
|
|
25
|
+
if (!config) {
|
|
26
|
+
throw new Error('Missing API configuration. Set CONTENT_STREAMLINE_API_BASE_URL and CONTENT_STREAMLINE_API_ACCESS_TOKEN environment variables.');
|
|
27
|
+
}
|
|
28
|
+
return config;
|
|
29
|
+
}
|
|
18
30
|
/**
|
|
19
31
|
* Get all posts (with automatic cache refresh)
|
|
20
32
|
* Use this in Server Components or API Routes
|
|
33
|
+
*
|
|
34
|
+
* Note: Only successful API responses are cached. Failed API calls
|
|
35
|
+
* (network errors, auth failures, etc.) will NOT be cached, allowing
|
|
36
|
+
* subsequent calls to retry the API.
|
|
21
37
|
*/
|
|
22
38
|
export async function getAllPosts(options) {
|
|
23
|
-
const { maxCacheAge =
|
|
24
|
-
// Check
|
|
39
|
+
const { maxCacheAge = 15, forceRefresh = false, platform } = options || {};
|
|
40
|
+
// Check if API is configured
|
|
41
|
+
const apiConfig = getAPIConfig();
|
|
42
|
+
// Check cache freshness (this also validates cache metadata)
|
|
25
43
|
if (!forceRefresh) {
|
|
26
44
|
const needsRefresh = await shouldRefreshCache(maxCacheAge);
|
|
27
45
|
if (!needsRefresh) {
|
|
@@ -40,13 +58,36 @@ export async function getAllPosts(options) {
|
|
|
40
58
|
}
|
|
41
59
|
}
|
|
42
60
|
}
|
|
61
|
+
// If API is not configured, return empty array but DON'T cache it
|
|
62
|
+
if (!apiConfig) {
|
|
63
|
+
console.warn('Content Streamline: API not configured. Set CONTENT_STREAMLINE_API_BASE_URL and CONTENT_STREAMLINE_API_ACCESS_TOKEN environment variables.');
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
43
66
|
// Fetch from API
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
let posts;
|
|
68
|
+
try {
|
|
69
|
+
const api = createAPIClient(apiConfig.baseUrl, apiConfig.accessToken);
|
|
70
|
+
posts = await api.getAllPosts(platform);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
// API call failed - DON'T cache the error, just return empty
|
|
74
|
+
// This allows subsequent calls to retry the API
|
|
75
|
+
console.error('Content Streamline: Failed to fetch posts from API:', error);
|
|
76
|
+
// Try to return stale cache if available (better than nothing)
|
|
77
|
+
const staleCached = await getAllCachedPosts();
|
|
78
|
+
if (staleCached.length > 0) {
|
|
79
|
+
console.warn('Content Streamline: Returning stale cached data due to API error');
|
|
80
|
+
if (platform) {
|
|
81
|
+
return staleCached.filter(post => post.platform.toLowerCase() === platform.toLowerCase());
|
|
82
|
+
}
|
|
83
|
+
return staleCached;
|
|
84
|
+
}
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
// API call succeeded - cache the results with success metadata
|
|
48
88
|
for (const post of posts) {
|
|
49
89
|
try {
|
|
90
|
+
const api = createAPIClient(apiConfig.baseUrl, apiConfig.accessToken);
|
|
50
91
|
const fullPost = await api.getPost(post.id, 'markdown');
|
|
51
92
|
await cachePost(fullPost);
|
|
52
93
|
}
|
|
@@ -54,17 +95,22 @@ export async function getAllPosts(options) {
|
|
|
54
95
|
console.error(`Failed to cache post ${post.id}:`, error);
|
|
55
96
|
}
|
|
56
97
|
}
|
|
57
|
-
// Update index
|
|
58
|
-
await updatePostsIndex(posts);
|
|
98
|
+
// Update index with success metadata
|
|
99
|
+
await updatePostsIndex(posts, true);
|
|
59
100
|
return posts;
|
|
60
101
|
}
|
|
61
102
|
/**
|
|
62
103
|
* Get a single post by ID
|
|
63
104
|
* Use this in Server Components or API Routes
|
|
105
|
+
*
|
|
106
|
+
* Note: Only successful API responses are cached. Failed API calls
|
|
107
|
+
* will NOT be cached, allowing subsequent calls to retry the API.
|
|
64
108
|
*/
|
|
65
109
|
export async function getPost(id, options) {
|
|
66
|
-
const { language = 'en', contentFormat = 'markdown', maxCacheAge =
|
|
67
|
-
//
|
|
110
|
+
const { language = 'en', contentFormat = 'markdown', maxCacheAge = 15, forceRefresh = false, } = options || {};
|
|
111
|
+
// Check if API is configured
|
|
112
|
+
const apiConfig = getAPIConfig();
|
|
113
|
+
// Try cache first (cache validation includes metadata checks)
|
|
68
114
|
if (!forceRefresh) {
|
|
69
115
|
const needsRefresh = await shouldRefreshCache(maxCacheAge);
|
|
70
116
|
if (!needsRefresh) {
|
|
@@ -74,17 +120,28 @@ export async function getPost(id, options) {
|
|
|
74
120
|
}
|
|
75
121
|
}
|
|
76
122
|
}
|
|
123
|
+
// If API is not configured, return null but DON'T cache it
|
|
124
|
+
if (!apiConfig) {
|
|
125
|
+
console.warn('Content Streamline: API not configured. Set CONTENT_STREAMLINE_API_BASE_URL and CONTENT_STREAMLINE_API_ACCESS_TOKEN environment variables.');
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
77
128
|
// Fetch from API
|
|
78
129
|
try {
|
|
79
|
-
const
|
|
80
|
-
const api = createAPIClient(baseUrl, accessToken);
|
|
130
|
+
const api = createAPIClient(apiConfig.baseUrl, apiConfig.accessToken);
|
|
81
131
|
const post = await api.getPost(id, contentFormat);
|
|
82
|
-
//
|
|
132
|
+
// API call succeeded - cache it
|
|
83
133
|
await cachePost(post);
|
|
84
134
|
return post;
|
|
85
135
|
}
|
|
86
136
|
catch (error) {
|
|
87
|
-
|
|
137
|
+
// API call failed - DON'T cache the error
|
|
138
|
+
// Try to return stale cache if available
|
|
139
|
+
console.error(`Content Streamline: Failed to fetch post ${id}:`, error);
|
|
140
|
+
const staleCached = await getCachedPost(id, language);
|
|
141
|
+
if (staleCached) {
|
|
142
|
+
console.warn(`Content Streamline: Returning stale cached data for post ${id} due to API error`);
|
|
143
|
+
return staleCached;
|
|
144
|
+
}
|
|
88
145
|
return null;
|
|
89
146
|
}
|
|
90
147
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -39,6 +39,15 @@ export interface PostsResponse {
|
|
|
39
39
|
export interface PostDetailResponse extends Post {
|
|
40
40
|
post_translations: PostTranslation[];
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Metadata stored with cache entries to track API state
|
|
44
|
+
*/
|
|
45
|
+
export interface CacheMetadata {
|
|
46
|
+
timestamp: number;
|
|
47
|
+
apiConfigured: boolean;
|
|
48
|
+
apiCallSucceeded: boolean;
|
|
49
|
+
envConfigHash?: string;
|
|
50
|
+
}
|
|
42
51
|
export interface CachedPostIndex {
|
|
43
52
|
posts: Array<{
|
|
44
53
|
id: number;
|
|
@@ -47,5 +56,6 @@ export interface CachedPostIndex {
|
|
|
47
56
|
updated_at: string;
|
|
48
57
|
}>;
|
|
49
58
|
last_sync: string;
|
|
59
|
+
metadata?: CacheMetadata;
|
|
50
60
|
}
|
|
51
61
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,IAAI,EAAE,CAAC;CACd;AAED,MAAM,WAAW,kBAAmB,SAAQ,IAAI;IAC9C,iBAAiB,EAAE,eAAe,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,IAAI,EAAE,CAAC;CACd;AAED,MAAM,WAAW,kBAAmB,SAAQ,IAAI;IAC9C,iBAAiB,EAAE,eAAe,EAAE,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B"}
|