@elixpo/lixblogs-cli 1.3.3 → 1.4.4

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.
Files changed (40) hide show
  1. package/README.md +9 -7
  2. package/dist/lixblogs.mjs +102 -0
  3. package/package.json +9 -10
  4. package/API.md +0 -104
  5. package/CHANGELOG.md +0 -10
  6. package/RELEASE.md +0 -30
  7. package/THREAT_MODEL.md +0 -91
  8. package/bin/lixblogs.mjs +0 -802
  9. package/src/api/AnalyticsClient.js +0 -40
  10. package/src/api/BlogClient.js +0 -140
  11. package/src/api/CollaborationClient.js +0 -73
  12. package/src/api/OrgClient.js +0 -158
  13. package/src/auth/AuthProvider.js +0 -90
  14. package/src/auth/AuthenticatedClient.js +0 -131
  15. package/src/auth/ElixpoAuthProvider.js +0 -281
  16. package/src/auth/MockAuthProvider.js +0 -170
  17. package/src/auth/productionGate.js +0 -44
  18. package/src/cli/contract.js +0 -46
  19. package/src/cli/ui.js +0 -54
  20. package/src/commands/analytics/index.js +0 -57
  21. package/src/commands/auth/login.js +0 -117
  22. package/src/commands/auth/logout.js +0 -21
  23. package/src/commands/auth/profileAlias.js +0 -29
  24. package/src/commands/auth/profiles.js +0 -27
  25. package/src/commands/auth/revoke.js +0 -45
  26. package/src/commands/auth/status.js +0 -33
  27. package/src/commands/blog/index.js +0 -85
  28. package/src/commands/blog/input.js +0 -59
  29. package/src/commands/collab/index.js +0 -53
  30. package/src/commands/org/index.js +0 -22
  31. package/src/commands/skill/index.js +0 -83
  32. package/src/config/CredentialStore.js +0 -142
  33. package/src/config/KeychainCredentialStore.js +0 -180
  34. package/src/config/ProfileRegistry.js +0 -105
  35. package/src/config/config.js +0 -60
  36. package/src/config/credentialStoreFactory.js +0 -63
  37. package/src/config/providerFactory.js +0 -42
  38. package/src/config/redact.js +0 -74
  39. package/src/content/markdown.js +0 -68
  40. package/src/content/validate.js +0 -45
@@ -1,68 +0,0 @@
1
- function text(value) {
2
- return [{ type: 'text', text: value }];
3
- }
4
-
5
- export function markdownToBlocks(markdown) {
6
- const lines = String(markdown || '').replace(/\r\n/g, '\n').split('\n');
7
- const blocks = [];
8
- let paragraph = [];
9
- const flush = () => {
10
- if (!paragraph.length) return;
11
- blocks.push({ type: 'paragraph', content: text(paragraph.join(' ').trim()) });
12
- paragraph = [];
13
- };
14
-
15
- for (let index = 0; index < lines.length; index += 1) {
16
- const line = lines[index];
17
- const trimmed = line.trim();
18
- if (!trimmed) { flush(); continue; }
19
- const fence = trimmed.match(/^```([\w+-]*)/);
20
- if (fence) {
21
- flush();
22
- const code = [];
23
- index += 1;
24
- while (index < lines.length && !/^```/.test(lines[index].trim())) code.push(lines[index++]);
25
- blocks.push(fence[1].toLowerCase() === 'mermaid'
26
- ? { type: 'mermaidBlock', props: { diagram: code.join('\n') } }
27
- : { type: 'codeBlock', props: { language: fence[1].toLowerCase() }, content: text(code.join('\n')) });
28
- continue;
29
- }
30
- const heading = trimmed.match(/^(#{1,3})\s+(.+)/);
31
- if (heading) {
32
- flush();
33
- blocks.push({ type: 'heading', props: { level: String(heading[1].length) }, content: text(heading[2]) });
34
- continue;
35
- }
36
- const bullet = trimmed.match(/^[-*]\s+(.+)/);
37
- if (bullet) { flush(); blocks.push({ type: 'bulletListItem', content: text(bullet[1]) }); continue; }
38
- const numbered = trimmed.match(/^\d+\.\s+(.+)/);
39
- if (numbered) { flush(); blocks.push({ type: 'numberedListItem', content: text(numbered[1]) }); continue; }
40
- const quote = trimmed.match(/^>\s?(.*)/);
41
- if (quote) { flush(); blocks.push({ type: 'quote', content: text(quote[1]) }); continue; }
42
- const image = trimmed.match(/^!\[([^\]]*)\]\((https:\/\/[^)]+)\)$/);
43
- if (image) { flush(); blocks.push({ type: 'image', props: { url: image[2], caption: image[1] } }); continue; }
44
- if (/^([-*_])\1{2,}$/.test(trimmed)) { flush(); blocks.push({ type: 'divider' }); continue; }
45
- paragraph.push(trimmed);
46
- }
47
- flush();
48
- return blocks;
49
- }
50
-
51
- function blockText(block) {
52
- return (block?.content || []).map((item) => typeof item === 'string' ? item : item?.text || '').join('');
53
- }
54
-
55
- export function blocksToMarkdown(blocks) {
56
- return (blocks || []).map((block) => {
57
- const value = blockText(block);
58
- if (block.type === 'heading') return `${'#'.repeat(Number(block.props?.level) || 1)} ${value}`;
59
- if (block.type === 'bulletListItem') return `- ${value}`;
60
- if (block.type === 'numberedListItem') return `1. ${value}`;
61
- if (block.type === 'quote') return `> ${value}`;
62
- if (block.type === 'codeBlock') return `\`\`\`${block.props?.language || ''}\n${value}\n\`\`\``;
63
- if (block.type === 'mermaidBlock') return `\`\`\`mermaid\n${block.props?.diagram || ''}\n\`\`\``;
64
- if (block.type === 'image') return `![${block.props?.caption || ''}](${block.props?.url || ''})`;
65
- if (block.type === 'divider') return '---';
66
- return value;
67
- }).join('\n\n');
68
- }
@@ -1,45 +0,0 @@
1
- const MAX_CONTENT_BYTES = 1_500_000;
2
-
3
- export function countWords(blocks) {
4
- const words = [];
5
- const walk = (items) => {
6
- for (const block of items || []) {
7
- for (const item of block?.content || []) {
8
- const value = typeof item === 'string' ? item : item?.text || '';
9
- words.push(...value.trim().split(/\s+/).filter(Boolean));
10
- }
11
- if (block?.children) walk(block.children);
12
- }
13
- };
14
- walk(blocks);
15
- return words.length;
16
- }
17
-
18
- export function validateBlogInput(input, { publishing = false } = {}) {
19
- if (input.title !== undefined && (typeof input.title !== 'string' || input.title.length > 300)) {
20
- throw new Error('Title must be 300 characters or fewer.');
21
- }
22
- if (input.subtitle !== undefined && (typeof input.subtitle !== 'string' || input.subtitle.length > 500)) {
23
- throw new Error('Subtitle must be 500 characters or fewer.');
24
- }
25
- if (input.tags !== undefined && (!Array.isArray(input.tags) || input.tags.length > 5)) {
26
- throw new Error('Use at most five tags.');
27
- }
28
- if (input.coverUrl && !/^https:\/\//i.test(input.coverUrl)) {
29
- throw new Error('Cover URLs must use HTTPS.');
30
- }
31
- if (input.publishedAs && input.publishedAs !== 'personal' && !/^org:[^:]+$/.test(input.publishedAs)) {
32
- throw new Error('Publication must be personal or org:<id>.');
33
- }
34
- if (input.content !== undefined) {
35
- if (!Array.isArray(input.content)) throw new Error('Blog content must be a block array.');
36
- if (Buffer.byteLength(JSON.stringify(input.content), 'utf8') > MAX_CONTENT_BYTES) {
37
- throw new Error('Blog content exceeds the 1.5 MB limit.');
38
- }
39
- }
40
- if (publishing) {
41
- if (!input.title?.trim()) throw new Error('A title is required before publishing.');
42
- if (countWords(input.content) < 20) throw new Error('A post needs at least 20 words before publishing.');
43
- }
44
- return input;
45
- }