@leadcms/sdk 1.3.0-pre → 2.1.0
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 +82 -3
- package/dist/cli/index.js +55 -62
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -18
- package/dist/index.js.map +1 -1
- package/dist/lib/cms.d.ts +1 -1
- package/dist/lib/cms.d.ts.map +1 -1
- package/dist/lib/cms.js +49 -72
- package/dist/lib/cms.js.map +1 -1
- package/dist/lib/config.d.ts +0 -8
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +13 -40
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/console-colors.d.ts +49 -0
- package/dist/lib/console-colors.d.ts.map +1 -0
- package/dist/lib/console-colors.js +121 -0
- package/dist/lib/console-colors.js.map +1 -0
- package/dist/lib/content-transformation.d.ts +90 -0
- package/dist/lib/content-transformation.d.ts.map +1 -0
- package/dist/lib/content-transformation.js +335 -0
- package/dist/lib/content-transformation.js.map +1 -0
- package/dist/lib/data-service.d.ts +97 -0
- package/dist/lib/data-service.d.ts.map +1 -0
- package/dist/lib/data-service.js +389 -0
- package/dist/lib/data-service.js.map +1 -0
- package/dist/scripts/fetch-leadcms-content.d.ts +19 -0
- package/dist/scripts/fetch-leadcms-content.d.ts.map +1 -0
- package/dist/scripts/fetch-leadcms-content.js +301 -0
- package/dist/scripts/fetch-leadcms-content.js.map +1 -0
- package/dist/scripts/generate-env-js.d.ts +2 -0
- package/dist/scripts/generate-env-js.d.ts.map +1 -0
- package/dist/scripts/generate-env-js.js +22 -0
- package/dist/scripts/generate-env-js.js.map +1 -0
- package/dist/scripts/leadcms-helpers.d.ts +25 -0
- package/dist/scripts/leadcms-helpers.d.ts.map +1 -0
- package/dist/scripts/leadcms-helpers.js +78 -0
- package/dist/scripts/leadcms-helpers.js.map +1 -0
- package/dist/scripts/push-leadcms-content.d.ts +50 -0
- package/dist/scripts/push-leadcms-content.d.ts.map +1 -0
- package/dist/scripts/push-leadcms-content.js +1022 -0
- package/dist/scripts/push-leadcms-content.js.map +1 -0
- package/dist/scripts/sse-watcher.d.ts +20 -0
- package/dist/scripts/sse-watcher.d.ts.map +1 -0
- package/dist/scripts/sse-watcher.js +268 -0
- package/dist/scripts/sse-watcher.js.map +1 -0
- package/dist/scripts/status-leadcms-content.d.ts +4 -0
- package/dist/scripts/status-leadcms-content.d.ts.map +1 -0
- package/dist/scripts/status-leadcms-content.js +36 -0
- package/dist/scripts/status-leadcms-content.js.map +1 -0
- package/package.json +14 -12
- package/dist/scripts/fetch-leadcms-content.mjs +0 -367
- package/dist/scripts/generate-env-js.mjs +0 -24
- package/dist/scripts/leadcms-helpers.mjs +0 -208
- package/dist/scripts/sse-watcher.mjs +0 -300
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
import "dotenv/config"
|
|
2
|
-
import { EventSource } from "eventsource"
|
|
3
|
-
import {
|
|
4
|
-
saveContentFile,
|
|
5
|
-
leadCMSUrl,
|
|
6
|
-
leadCMSApiKey,
|
|
7
|
-
defaultLanguage,
|
|
8
|
-
CONTENT_DIR,
|
|
9
|
-
} from "./leadcms-helpers.mjs"
|
|
10
|
-
import { fetchContentTypes } from "./leadcms-helpers.mjs"
|
|
11
|
-
import { fetchLeadCMSContent } from "./fetch-leadcms-content.mjs"
|
|
12
|
-
|
|
13
|
-
// Log environment configuration for debugging
|
|
14
|
-
console.log(`[SSE ENV] LeadCMS URL: ${leadCMSUrl}`)
|
|
15
|
-
console.log(
|
|
16
|
-
`[SSE ENV] LeadCMS API Key: ${leadCMSApiKey ? `${leadCMSApiKey.substring(0, 8)}...` : "NOT_SET"}`
|
|
17
|
-
)
|
|
18
|
-
console.log(`[SSE ENV] Default Language: ${defaultLanguage}`)
|
|
19
|
-
console.log(`[SSE ENV] Content Dir: ${CONTENT_DIR}`)
|
|
20
|
-
|
|
21
|
-
// Helper function to trigger content fetch
|
|
22
|
-
async function triggerContentFetch() {
|
|
23
|
-
try {
|
|
24
|
-
console.log("[SSE] Starting content fetch...")
|
|
25
|
-
await fetchLeadCMSContent()
|
|
26
|
-
console.log("[SSE] Content fetch completed successfully")
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.error("[SSE] Content fetch failed:", error.message)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function buildSSEUrl() {
|
|
33
|
-
console.log(`[SSE URL] Building SSE URL with base: ${leadCMSUrl}`)
|
|
34
|
-
const url = new URL("/api/sse/stream", leadCMSUrl)
|
|
35
|
-
url.searchParams.set("entities", "Content")
|
|
36
|
-
url.searchParams.set("includeContent", "true")
|
|
37
|
-
url.searchParams.set("includeLiveDrafts", "true")
|
|
38
|
-
const finalUrl = url.toString()
|
|
39
|
-
console.log(`[SSE URL] Final SSE URL: ${finalUrl}`)
|
|
40
|
-
return finalUrl
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function startSSEWatcher() {
|
|
44
|
-
console.log(`[SSE] Starting SSE watcher...`)
|
|
45
|
-
const typeMap = await fetchContentTypes()
|
|
46
|
-
const sseUrl = buildSSEUrl()
|
|
47
|
-
const eventSourceOptions = {}
|
|
48
|
-
|
|
49
|
-
if (leadCMSApiKey) {
|
|
50
|
-
console.log(`[SSE] Using API key for authentication`)
|
|
51
|
-
eventSourceOptions.fetch = (input, init) => {
|
|
52
|
-
console.log(`[SSE FETCH] Making authenticated request to: ${input}`)
|
|
53
|
-
console.log(
|
|
54
|
-
`[SSE FETCH] Headers:`,
|
|
55
|
-
JSON.stringify(
|
|
56
|
-
{
|
|
57
|
-
...init?.headers,
|
|
58
|
-
Authorization: `Bearer ${leadCMSApiKey.substring(0, 8)}...`,
|
|
59
|
-
},
|
|
60
|
-
null,
|
|
61
|
-
2
|
|
62
|
-
)
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
return fetch(input, {
|
|
66
|
-
...init,
|
|
67
|
-
headers: {
|
|
68
|
-
...init?.headers,
|
|
69
|
-
Authorization: `Bearer ${leadCMSApiKey}`,
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
.then((response) => {
|
|
73
|
-
console.log(`[SSE FETCH] Response status: ${response.status} ${response.statusText}`)
|
|
74
|
-
console.log(
|
|
75
|
-
`[SSE FETCH] Response headers:`,
|
|
76
|
-
JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2)
|
|
77
|
-
)
|
|
78
|
-
if (!response.ok) {
|
|
79
|
-
console.error(`[SSE FETCH] Failed response: ${response.status} ${response.statusText}`)
|
|
80
|
-
}
|
|
81
|
-
return response
|
|
82
|
-
})
|
|
83
|
-
.catch((error) => {
|
|
84
|
-
console.error(`[SSE FETCH] Fetch error:`, error.message)
|
|
85
|
-
throw error
|
|
86
|
-
})
|
|
87
|
-
}
|
|
88
|
-
} else {
|
|
89
|
-
console.warn(`[SSE] No API key provided - attempting unauthenticated connection`)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log(`[SSE] Connecting to: ${sseUrl}`)
|
|
93
|
-
console.log(`[SSE] Event source options:`, JSON.stringify(eventSourceOptions, null, 2))
|
|
94
|
-
const es = new EventSource(sseUrl, eventSourceOptions)
|
|
95
|
-
|
|
96
|
-
es.onopen = () => {
|
|
97
|
-
console.log("[SSE] Connection opened successfully")
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
es.onmessage = (event) => {
|
|
101
|
-
console.log(`[SSE] Received message:`, event.data)
|
|
102
|
-
try {
|
|
103
|
-
const data = JSON.parse(event.data)
|
|
104
|
-
console.log(`[SSE] Parsed message data:`, JSON.stringify(data, null, 2))
|
|
105
|
-
|
|
106
|
-
if (data.entityType === "Content") {
|
|
107
|
-
console.log(`[SSE] Content message - Operation: ${data.operation}`)
|
|
108
|
-
console.log(`[SSE] Content change detected - triggering full fetch`)
|
|
109
|
-
triggerContentFetch()
|
|
110
|
-
} else {
|
|
111
|
-
console.log(`[SSE] Non-content message - Entity type: ${data.entityType}`)
|
|
112
|
-
}
|
|
113
|
-
} catch (e) {
|
|
114
|
-
console.warn("[SSE] Failed to parse SSE message:", e.message)
|
|
115
|
-
console.warn("[SSE] Raw event data:", event.data)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
es.addEventListener("connected", (event) => {
|
|
120
|
-
console.log(`[SSE] Received 'connected' event:`, event.data)
|
|
121
|
-
try {
|
|
122
|
-
const data = JSON.parse(event.data)
|
|
123
|
-
console.log(
|
|
124
|
-
`[SSE] Connected successfully - Client ID: ${data.clientId}, Starting change log ID: ${data.startingChangeLogId}`
|
|
125
|
-
)
|
|
126
|
-
} catch (e) {
|
|
127
|
-
console.warn("[SSE] Failed to parse connected event:", e.message)
|
|
128
|
-
console.warn("[SSE] Raw connected event data:", event.data)
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
es.addEventListener("heartbeat", (event) => {
|
|
133
|
-
console.log(`[SSE] Received heartbeat:`, event.data)
|
|
134
|
-
try {
|
|
135
|
-
const data = JSON.parse(event.data)
|
|
136
|
-
console.log(`[SSE] Heartbeat at ${data.timestamp}`)
|
|
137
|
-
} catch (e) {
|
|
138
|
-
console.warn("[SSE] Failed to parse heartbeat event:", e.message)
|
|
139
|
-
console.warn("[SSE] Raw heartbeat event data:", event.data)
|
|
140
|
-
}
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
es.addEventListener("draft-updated", (event) => {
|
|
144
|
-
console.log(`[SSE] Received 'draft-updated' event:`, event.data)
|
|
145
|
-
try {
|
|
146
|
-
const data = JSON.parse(event.data)
|
|
147
|
-
console.log(`[SSE] Draft updated data:`, JSON.stringify(data, null, 2))
|
|
148
|
-
|
|
149
|
-
if (data.createdById && data.data) {
|
|
150
|
-
console.log(`[SSE] Processing draft update for user: ${data.createdById}`)
|
|
151
|
-
let contentData
|
|
152
|
-
try {
|
|
153
|
-
contentData = typeof data.data === "string" ? JSON.parse(data.data) : data.data
|
|
154
|
-
console.log(`[SSE] Draft content data:`, JSON.stringify(contentData, null, 2))
|
|
155
|
-
} catch (e) {
|
|
156
|
-
console.warn("[SSE] Failed to parse draft content data:", e.message)
|
|
157
|
-
console.warn("[SSE] Raw data:", data.data)
|
|
158
|
-
return
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Determine content type for draft handling
|
|
162
|
-
let contentType = undefined
|
|
163
|
-
if (contentData && contentData.type && typeMap && typeMap[contentData.type]) {
|
|
164
|
-
contentType = typeMap[contentData.type]
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
console.log(`[SSE] Draft updated - triggering full fetch`)
|
|
168
|
-
triggerContentFetch()
|
|
169
|
-
|
|
170
|
-
if (contentType === "MDX" || contentType === "JSON") {
|
|
171
|
-
if (contentData && typeof contentData === "object") {
|
|
172
|
-
const previewSlug = `${contentData.slug}-${data.createdById}`
|
|
173
|
-
console.log(`[SSE] Saving draft content file for preview: ${previewSlug}`)
|
|
174
|
-
;(async () => {
|
|
175
|
-
try {
|
|
176
|
-
await saveContentFile({
|
|
177
|
-
content: contentData,
|
|
178
|
-
typeMap,
|
|
179
|
-
contentDir: CONTENT_DIR,
|
|
180
|
-
previewSlug: previewSlug,
|
|
181
|
-
})
|
|
182
|
-
console.log(`[SSE] Saved draft preview for ${previewSlug}`)
|
|
183
|
-
} catch (error) {
|
|
184
|
-
console.error(`[SSE] Error processing draft update:`, error.message)
|
|
185
|
-
}
|
|
186
|
-
})()
|
|
187
|
-
}
|
|
188
|
-
} else {
|
|
189
|
-
console.log(`[SSE] Draft is not MDX or JSON (type: ${contentType}), skipping file save.`)
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
} catch (e) {
|
|
193
|
-
console.warn("[SSE] Failed to parse draft-updated event:", e.message)
|
|
194
|
-
console.warn("[SSE] Raw draft-updated event data:", event.data)
|
|
195
|
-
}
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
// Handle legacy DraftModified messages for backward compatibility
|
|
199
|
-
es.addEventListener("message", (event) => {
|
|
200
|
-
try {
|
|
201
|
-
const data = JSON.parse(event.data)
|
|
202
|
-
|
|
203
|
-
// Only handle DraftModified operations here for backward compatibility
|
|
204
|
-
if (data.entityType === "Content" && data.operation === "DraftModified" && data.createdById && data.data) {
|
|
205
|
-
console.log(`[SSE] Received legacy 'DraftModified' message for user: ${data.createdById}`)
|
|
206
|
-
let contentData
|
|
207
|
-
try {
|
|
208
|
-
contentData = typeof data.data === "string" ? JSON.parse(data.data) : data.data
|
|
209
|
-
console.log(`[SSE] Legacy draft content data:`, JSON.stringify(contentData, null, 2))
|
|
210
|
-
} catch (e) {
|
|
211
|
-
console.warn("[SSE] Failed to parse legacy draft content data:", e.message)
|
|
212
|
-
console.warn("[SSE] Raw data:", data.data)
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Determine content type for legacy draft handling
|
|
217
|
-
let contentType = undefined
|
|
218
|
-
if (contentData && contentData.type && typeMap && typeMap[contentData.type]) {
|
|
219
|
-
contentType = typeMap[contentData.type]
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
console.log(`[SSE] Legacy draft modified - triggering full fetch`)
|
|
223
|
-
triggerContentFetch()
|
|
224
|
-
|
|
225
|
-
if (contentType === "MDX" || contentType === "JSON") {
|
|
226
|
-
if (contentData && typeof contentData === "object") {
|
|
227
|
-
const previewSlug = `${contentData.slug}-${data.createdById}`
|
|
228
|
-
console.log(`[SSE] Saving legacy draft content file for preview: ${previewSlug}`)
|
|
229
|
-
;(async () => {
|
|
230
|
-
try {
|
|
231
|
-
await saveContentFile({
|
|
232
|
-
content: contentData,
|
|
233
|
-
typeMap,
|
|
234
|
-
contentDir: CONTENT_DIR,
|
|
235
|
-
previewSlug: previewSlug,
|
|
236
|
-
})
|
|
237
|
-
console.log(`[SSE] Saved legacy draft preview for ${previewSlug}`)
|
|
238
|
-
} catch (error) {
|
|
239
|
-
console.error(`[SSE] Error processing legacy draft modification:`, error.message)
|
|
240
|
-
}
|
|
241
|
-
})()
|
|
242
|
-
}
|
|
243
|
-
} else {
|
|
244
|
-
console.log(`[SSE] Legacy draft is not MDX or JSON (type: ${contentType}), skipping file save.`)
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
} catch {
|
|
248
|
-
// Silently ignore parse errors for non-JSON messages
|
|
249
|
-
}
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
es.addEventListener("content-updated", (event) => {
|
|
253
|
-
console.log(`[SSE] Received 'content-updated' event:`, event.data)
|
|
254
|
-
try {
|
|
255
|
-
const data = JSON.parse(event.data)
|
|
256
|
-
console.log(`[SSE] Content updated data:`, JSON.stringify(data, null, 2))
|
|
257
|
-
|
|
258
|
-
console.log(`[SSE] Content updated - triggering full fetch`)
|
|
259
|
-
triggerContentFetch()
|
|
260
|
-
} catch (e) {
|
|
261
|
-
console.warn("[SSE] Failed to parse content-updated event:", e.message)
|
|
262
|
-
console.warn("[SSE] Raw content-updated event data:", event.data)
|
|
263
|
-
}
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
es.onerror = (err) => {
|
|
267
|
-
console.error("[SSE] Connection error occurred:", {
|
|
268
|
-
type: err.type,
|
|
269
|
-
message: err.message,
|
|
270
|
-
code: err.code,
|
|
271
|
-
timestamp: new Date().toISOString(),
|
|
272
|
-
readyState: es.readyState,
|
|
273
|
-
url: es.url,
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
// Log specific error types
|
|
277
|
-
if (err.code === 401) {
|
|
278
|
-
console.error("[SSE] Authentication failed (401) - check your LEADCMS_API_KEY")
|
|
279
|
-
console.error(
|
|
280
|
-
"[SSE] Current API Key (first 8 chars):",
|
|
281
|
-
leadCMSApiKey ? leadCMSApiKey.substring(0, 8) : "NOT_SET"
|
|
282
|
-
)
|
|
283
|
-
} else if (err.code === 403) {
|
|
284
|
-
console.error("[SSE] Forbidden (403) - insufficient permissions")
|
|
285
|
-
} else if (err.code === 404) {
|
|
286
|
-
console.error("[SSE] Not Found (404) - check your LEADCMS_URL and endpoint path")
|
|
287
|
-
} else if (err.code >= 500) {
|
|
288
|
-
console.error("[SSE] Server error (5xx) - LeadCMS server issue")
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
console.log("[SSE] Closing connection and will reconnect in 5s")
|
|
292
|
-
es.close()
|
|
293
|
-
setTimeout(() => {
|
|
294
|
-
console.log("[SSE] Attempting to reconnect...")
|
|
295
|
-
startSSEWatcher()
|
|
296
|
-
}, 5000)
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
startSSEWatcher()
|