@content-streamline/nextjs 0.0.5 → 0.0.7
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/dist/api/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,IAAI,EACJ,kBAAkB,EAClB,aAAa,EACd,MAAM,mBAAmB,CAAC;AAE3B,cAAM,oBAAoB;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;YAKlC,KAAK;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,IAAI,EACJ,kBAAkB,EAClB,aAAa,EACd,MAAM,mBAAmB,CAAC;AAE3B,cAAM,oBAAoB;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;YAKlC,KAAK;IAsDnB;;OAEG;IACG,SAAS,CAAC,IAAI,GAAE,MAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAS5E;;OAEG;IACG,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IA4BrD;;OAEG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,aAAa,GAAE,UAAU,GAAG,MAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAIxG;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,oBAAoB,CAE1F"}
|
package/dist/api/client.js
CHANGED
|
@@ -13,14 +13,31 @@ class ContentStreamlineAPI {
|
|
|
13
13
|
'Content-Type': 'application/json',
|
|
14
14
|
...options.headers,
|
|
15
15
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
let response;
|
|
17
|
+
try {
|
|
18
|
+
response = await fetch(url, {
|
|
19
|
+
...options,
|
|
20
|
+
headers,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
// Network error (connection failed, timeout, etc.)
|
|
25
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
26
|
+
throw new Error(`Network error: ${errorMessage}`);
|
|
27
|
+
}
|
|
20
28
|
if (!response.ok) {
|
|
21
|
-
|
|
29
|
+
let errorMessage = `API request failed: ${response.status} ${response.statusText}`;
|
|
30
|
+
try {
|
|
22
31
|
const errorText = await response.text();
|
|
23
|
-
if (errorText
|
|
32
|
+
if (errorText) {
|
|
33
|
+
errorMessage += ` - ${errorText}`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Ignore error reading response body
|
|
38
|
+
}
|
|
39
|
+
if (response.status === 401) {
|
|
40
|
+
if (errorMessage.includes('Missing access token')) {
|
|
24
41
|
throw new Error('Missing access token');
|
|
25
42
|
}
|
|
26
43
|
throw new Error('Invalid access token');
|
|
@@ -31,9 +48,15 @@ class ContentStreamlineAPI {
|
|
|
31
48
|
if (response.status === 404) {
|
|
32
49
|
throw new Error('Post not found');
|
|
33
50
|
}
|
|
34
|
-
throw new Error(
|
|
51
|
+
throw new Error(errorMessage);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const data = await response.json();
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
throw new Error(`Failed to parse API response as JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
35
59
|
}
|
|
36
|
-
return response.json();
|
|
37
60
|
}
|
|
38
61
|
/**
|
|
39
62
|
* List all posts with pagination
|
|
@@ -55,9 +78,18 @@ class ContentStreamlineAPI {
|
|
|
55
78
|
let hasMore = true;
|
|
56
79
|
while (hasMore) {
|
|
57
80
|
const response = await this.listPosts(currentPage, platform);
|
|
81
|
+
// Validate response structure
|
|
82
|
+
if (!response || !Array.isArray(response.data)) {
|
|
83
|
+
throw new Error(`Invalid API response: expected PostsResponse with data array, got ${typeof response}`);
|
|
84
|
+
}
|
|
58
85
|
allPosts.push(...response.data);
|
|
59
86
|
hasMore = response.pagination.next_page !== null;
|
|
60
87
|
currentPage = response.pagination.next_page || currentPage + 1;
|
|
88
|
+
// Safety check to prevent infinite loops
|
|
89
|
+
if (currentPage > 1000) {
|
|
90
|
+
console.warn('Content Streamline: Stopping pagination at page 1000 to prevent infinite loop');
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
61
93
|
}
|
|
62
94
|
return allPosts;
|
|
63
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-cache.d.ts","sourceRoot":"","sources":["../../src/cache/file-cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"file-cache.d.ts","sourceRoot":"","sources":["../../src/cache/file-cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAkBlG;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAIzC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,GAAG,aAAa,CAO5E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CA8BvG;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAO/C;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB9E;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAa,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAS3G;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CA0BzD;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,gBAAgB,GAAE,OAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrG;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAOrE;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,aAAa,GAAE,MAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAqBrF;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAYhD"}
|
package/dist/cache/file-cache.js
CHANGED
|
@@ -4,8 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { writeFile, readFile, mkdir, readdir, unlink } from 'fs/promises';
|
|
6
6
|
import { join } from 'path';
|
|
7
|
+
import { tmpdir } from 'os';
|
|
7
8
|
import { createHash } from 'crypto';
|
|
8
|
-
|
|
9
|
+
function resolveCacheDir() {
|
|
10
|
+
const configured = process.env.CONTENT_STREAMLINE_CACHE_DIR?.trim();
|
|
11
|
+
if (configured)
|
|
12
|
+
return configured;
|
|
13
|
+
// Vercel serverless filesystem is read-only except for /tmp
|
|
14
|
+
if (process.env.VERCEL) {
|
|
15
|
+
return join(tmpdir(), 'content-streamline-cache');
|
|
16
|
+
}
|
|
17
|
+
return join(process.cwd(), '.next', 'content-streamline-cache');
|
|
18
|
+
}
|
|
19
|
+
const CACHE_DIR = resolveCacheDir();
|
|
9
20
|
const POSTS_INDEX_FILE = join(CACHE_DIR, 'posts-index.json');
|
|
10
21
|
const POSTS_DIR = join(CACHE_DIR, 'posts');
|
|
11
22
|
/**
|
|
@@ -86,7 +97,12 @@ export async function cachePost(post) {
|
|
|
86
97
|
for (const translation of post.post_translations) {
|
|
87
98
|
const filename = `${post.id}-${translation.language}.json`;
|
|
88
99
|
const filepath = join(POSTS_DIR, filename);
|
|
89
|
-
|
|
100
|
+
try {
|
|
101
|
+
await writeFile(filepath, JSON.stringify(post, null, 2), 'utf-8');
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.warn(`Content Streamline: Failed to write cache file ${filepath}:`, error instanceof Error ? error.message : String(error));
|
|
105
|
+
}
|
|
90
106
|
}
|
|
91
107
|
}
|
|
92
108
|
/**
|
|
@@ -144,7 +160,12 @@ export async function updatePostsIndex(posts, apiCallSucceeded = true) {
|
|
|
144
160
|
last_sync: new Date().toISOString(),
|
|
145
161
|
metadata: createCacheMetadata(apiCallSucceeded),
|
|
146
162
|
};
|
|
147
|
-
|
|
163
|
+
try {
|
|
164
|
+
await writeFile(POSTS_INDEX_FILE, JSON.stringify(index, null, 2), 'utf-8');
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.warn(`Content Streamline: Failed to write posts index cache file ${POSTS_INDEX_FILE}:`, error instanceof Error ? error.message : String(error));
|
|
168
|
+
}
|
|
148
169
|
}
|
|
149
170
|
/**
|
|
150
171
|
* Get the posts index
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AA+BlE;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AA+BlE;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAyGlB;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,GACA,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAoDpC;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA2BpC;AAGD,YAAY,EACV,IAAI,EACJ,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,aAAa,EACb,UAAU,GACX,MAAM,mBAAmB,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -67,36 +67,62 @@ export async function getAllPosts(options) {
|
|
|
67
67
|
let posts;
|
|
68
68
|
try {
|
|
69
69
|
const api = createAPIClient(apiConfig.baseUrl, apiConfig.accessToken);
|
|
70
|
+
console.log(`Content Streamline: Fetching posts from API (forceRefresh: ${forceRefresh}, platform: ${platform || 'all'})`);
|
|
70
71
|
posts = await api.getAllPosts(platform);
|
|
72
|
+
console.log(`Content Streamline: Successfully fetched ${posts.length} posts from API`);
|
|
71
73
|
}
|
|
72
74
|
catch (error) {
|
|
73
75
|
// API call failed - DON'T cache the error, just return empty
|
|
74
76
|
// This allows subsequent calls to retry the API
|
|
75
|
-
|
|
77
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
78
|
+
console.error('Content Streamline: Failed to fetch posts from API:', errorMessage);
|
|
79
|
+
if (error instanceof Error && error.stack) {
|
|
80
|
+
console.error('Content Streamline: Error stack:', error.stack);
|
|
81
|
+
}
|
|
76
82
|
// Try to return stale cache if available (better than nothing)
|
|
77
83
|
const staleCached = await getAllCachedPosts();
|
|
78
84
|
if (staleCached.length > 0) {
|
|
79
|
-
console.warn(
|
|
85
|
+
console.warn(`Content Streamline: Returning ${staleCached.length} stale cached posts due to API error`);
|
|
80
86
|
if (platform) {
|
|
81
|
-
|
|
87
|
+
const filtered = staleCached.filter(post => post.platform.toLowerCase() === platform.toLowerCase());
|
|
88
|
+
return filtered;
|
|
82
89
|
}
|
|
83
90
|
return staleCached;
|
|
84
91
|
}
|
|
92
|
+
console.warn('Content Streamline: No cached data available, returning empty array');
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
// Validate that we got posts
|
|
96
|
+
if (!Array.isArray(posts)) {
|
|
97
|
+
console.error('Content Streamline: API returned invalid response (not an array):', typeof posts);
|
|
85
98
|
return [];
|
|
86
99
|
}
|
|
87
100
|
// API call succeeded - cache the results with success metadata
|
|
101
|
+
// Note: We cache individual post details, but failures here don't prevent returning the posts
|
|
102
|
+
let cachedCount = 0;
|
|
88
103
|
for (const post of posts) {
|
|
89
104
|
try {
|
|
90
105
|
const api = createAPIClient(apiConfig.baseUrl, apiConfig.accessToken);
|
|
91
106
|
const fullPost = await api.getPost(post.id, 'markdown');
|
|
92
107
|
await cachePost(fullPost);
|
|
108
|
+
cachedCount++;
|
|
93
109
|
}
|
|
94
110
|
catch (error) {
|
|
95
|
-
|
|
111
|
+
// Log but don't fail - we still want to return the posts
|
|
112
|
+
console.warn(`Content Streamline: Failed to cache full details for post ${post.id}:`, error instanceof Error ? error.message : String(error));
|
|
96
113
|
}
|
|
97
114
|
}
|
|
115
|
+
if (cachedCount > 0) {
|
|
116
|
+
console.log(`Content Streamline: Cached ${cachedCount} of ${posts.length} posts`);
|
|
117
|
+
}
|
|
98
118
|
// Update index with success metadata
|
|
99
|
-
|
|
119
|
+
try {
|
|
120
|
+
await updatePostsIndex(posts, true);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.warn('Content Streamline: Failed to update posts index cache (non-fatal):', error instanceof Error ? error.message : String(error));
|
|
124
|
+
}
|
|
125
|
+
console.log(`Content Streamline: Returning ${posts.length} posts`);
|
|
100
126
|
return posts;
|
|
101
127
|
}
|
|
102
128
|
/**
|