@seolful/nextjs-connector 1.0.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.
Files changed (98) hide show
  1. package/bin/seolful-next.mjs +4 -0
  2. package/dist/api.d.ts +4 -0
  3. package/dist/api.d.ts.map +1 -0
  4. package/dist/api.js +43 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/cli/handshake.d.ts +17 -0
  7. package/dist/cli/handshake.d.ts.map +1 -0
  8. package/dist/cli/handshake.js +30 -0
  9. package/dist/cli/handshake.js.map +1 -0
  10. package/dist/cli/init.d.ts +2 -0
  11. package/dist/cli/init.d.ts.map +1 -0
  12. package/dist/cli/init.js +173 -0
  13. package/dist/cli/init.js.map +1 -0
  14. package/dist/cli/scaffold.d.ts +6 -0
  15. package/dist/cli/scaffold.d.ts.map +1 -0
  16. package/dist/cli/scaffold.js +101 -0
  17. package/dist/cli/scaffold.js.map +1 -0
  18. package/dist/config.d.ts +5 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +44 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/crawler/analyze.d.ts +18 -0
  23. package/dist/crawler/analyze.d.ts.map +1 -0
  24. package/dist/crawler/analyze.js +114 -0
  25. package/dist/crawler/analyze.js.map +1 -0
  26. package/dist/crawler/crawl-service.d.ts +10 -0
  27. package/dist/crawler/crawl-service.d.ts.map +1 -0
  28. package/dist/crawler/crawl-service.js +79 -0
  29. package/dist/crawler/crawl-service.js.map +1 -0
  30. package/dist/crawler/discover.d.ts +5 -0
  31. package/dist/crawler/discover.d.ts.map +1 -0
  32. package/dist/crawler/discover.js +49 -0
  33. package/dist/crawler/discover.js.map +1 -0
  34. package/dist/handlers/audit-data.d.ts +3 -0
  35. package/dist/handlers/audit-data.d.ts.map +1 -0
  36. package/dist/handlers/audit-data.js +46 -0
  37. package/dist/handlers/audit-data.js.map +1 -0
  38. package/dist/handlers/crawl.d.ts +2 -0
  39. package/dist/handlers/crawl.d.ts.map +1 -0
  40. package/dist/handlers/crawl.js +11 -0
  41. package/dist/handlers/crawl.js.map +1 -0
  42. package/dist/handlers/demote-h1.d.ts +3 -0
  43. package/dist/handlers/demote-h1.d.ts.map +1 -0
  44. package/dist/handlers/demote-h1.js +28 -0
  45. package/dist/handlers/demote-h1.js.map +1 -0
  46. package/dist/handlers/update-ai-visibility.d.ts +3 -0
  47. package/dist/handlers/update-ai-visibility.d.ts.map +1 -0
  48. package/dist/handlers/update-ai-visibility.js +38 -0
  49. package/dist/handlers/update-ai-visibility.js.map +1 -0
  50. package/dist/handlers/update-seo.d.ts +3 -0
  51. package/dist/handlers/update-seo.d.ts.map +1 -0
  52. package/dist/handlers/update-seo.js +65 -0
  53. package/dist/handlers/update-seo.js.map +1 -0
  54. package/dist/helpers/generate-metadata.d.ts +3 -0
  55. package/dist/helpers/generate-metadata.d.ts.map +1 -0
  56. package/dist/helpers/generate-metadata.js +15 -0
  57. package/dist/helpers/generate-metadata.js.map +1 -0
  58. package/dist/helpers/get-page-seo.d.ts +3 -0
  59. package/dist/helpers/get-page-seo.d.ts.map +1 -0
  60. package/dist/helpers/get-page-seo.js +10 -0
  61. package/dist/helpers/get-page-seo.js.map +1 -0
  62. package/dist/helpers/seolful-h1.d.ts +10 -0
  63. package/dist/helpers/seolful-h1.d.ts.map +1 -0
  64. package/dist/helpers/seolful-h1.js +11 -0
  65. package/dist/helpers/seolful-h1.js.map +1 -0
  66. package/dist/helpers/seolful-image.d.ts +8 -0
  67. package/dist/helpers/seolful-image.d.ts.map +1 -0
  68. package/dist/helpers/seolful-image.js +8 -0
  69. package/dist/helpers/seolful-image.js.map +1 -0
  70. package/dist/helpers/seolful-schema.d.ts +6 -0
  71. package/dist/helpers/seolful-schema.d.ts.map +1 -0
  72. package/dist/helpers/seolful-schema.js +10 -0
  73. package/dist/helpers/seolful-schema.js.map +1 -0
  74. package/dist/index.d.ts +11 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +13 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/middleware/validate-token.d.ts +8 -0
  79. package/dist/middleware/validate-token.d.ts.map +1 -0
  80. package/dist/middleware/validate-token.js +29 -0
  81. package/dist/middleware/validate-token.js.map +1 -0
  82. package/dist/storage/file-adapter.d.ts +24 -0
  83. package/dist/storage/file-adapter.d.ts.map +1 -0
  84. package/dist/storage/file-adapter.js +118 -0
  85. package/dist/storage/file-adapter.js.map +1 -0
  86. package/dist/storage/index.d.ts +4 -0
  87. package/dist/storage/index.d.ts.map +1 -0
  88. package/dist/storage/index.js +13 -0
  89. package/dist/storage/index.js.map +1 -0
  90. package/dist/storage/types.d.ts +2 -0
  91. package/dist/storage/types.d.ts.map +1 -0
  92. package/dist/storage/types.js +2 -0
  93. package/dist/storage/types.js.map +1 -0
  94. package/dist/types.d.ts +60 -0
  95. package/dist/types.d.ts.map +1 -0
  96. package/dist/types.js +35 -0
  97. package/dist/types.js.map +1 -0
  98. package/package.json +61 -0
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { init } from '../dist/cli/init.js'
3
+
4
+ init()
package/dist/api.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { NextRequest } from 'next/server';
2
+ export declare function GET(request: NextRequest): Promise<Response>;
3
+ export declare function POST(request: NextRequest): Promise<Response>;
4
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAyBzC,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CASjE;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAelE"}
package/dist/api.js ADDED
@@ -0,0 +1,43 @@
1
+ import { validateToken } from './middleware/validate-token.js';
2
+ import { auditDataHandler } from './handlers/audit-data.js';
3
+ import { crawlHandler } from './handlers/crawl.js';
4
+ import { updateSeoHandler } from './handlers/update-seo.js';
5
+ import { aiVisibilityHandler } from './handlers/update-ai-visibility.js';
6
+ import { demoteH1Handler } from './handlers/demote-h1.js';
7
+ function resolvePath(request) {
8
+ const url = new URL(request.url);
9
+ const match = url.pathname.match(/\/api\/seolful\/v1\/(.+)/);
10
+ return match?.[1] ?? '';
11
+ }
12
+ async function withAuth(request, handler) {
13
+ const result = await validateToken(request.headers);
14
+ if (!result.valid) {
15
+ return Response.json({ error: result.error }, { status: result.status });
16
+ }
17
+ return handler(request);
18
+ }
19
+ export async function GET(request) {
20
+ const path = resolvePath(request);
21
+ switch (path) {
22
+ case 'audit-data':
23
+ return withAuth(request, auditDataHandler);
24
+ default:
25
+ return Response.json({ error: 'Not found' }, { status: 404 });
26
+ }
27
+ }
28
+ export async function POST(request) {
29
+ const path = resolvePath(request);
30
+ switch (path) {
31
+ case 'crawl':
32
+ return withAuth(request, crawlHandler);
33
+ case 'update-seo':
34
+ return withAuth(request, updateSeoHandler);
35
+ case 'update-ai-visibility':
36
+ return withAuth(request, aiVisibilityHandler);
37
+ case 'demote-h1':
38
+ return withAuth(request, demoteH1Handler);
39
+ default:
40
+ return Response.json({ error: 'Not found' }, { status: 404 });
41
+ }
42
+ }
43
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEzD,SAAS,WAAW,CAAC,OAAoB;IACvC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAChC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAA;IAC5D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AACzB,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,OAAoB,EACpB,OAAgD;IAEhD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IACnD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IAC1E,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAoB;IAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;IAEjC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,YAAY;YACf,OAAO,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAA;QAC5C;YACE,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACjE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAoB;IAC7C,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;IAEjC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO;YACV,OAAO,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;QACxC,KAAK,YAAY;YACf,OAAO,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAA;QAC5C,KAAK,sBAAsB;YACzB,OAAO,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAA;QAC/C,KAAK,WAAW;YACd,OAAO,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;QAC3C;YACE,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACjE,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface HandshakePayload {
2
+ clientId: string;
3
+ token: string;
4
+ siteUrl: string;
5
+ siteName: string;
6
+ connectionKey: string;
7
+ connectorVersion: string;
8
+ }
9
+ export interface HandshakeResult {
10
+ status: string;
11
+ siteId: number;
12
+ siteUuid: string;
13
+ publishEndpoint: string;
14
+ newConnectionKey?: string;
15
+ }
16
+ export declare function performHandshake(appUrl: string, payload: HandshakePayload): Promise<HandshakeResult>;
17
+ //# sourceMappingURL=handshake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../../src/cli/handshake.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CAgC1B"}
@@ -0,0 +1,30 @@
1
+ export async function performHandshake(appUrl, payload) {
2
+ const endpoint = `${appUrl}/api/plugin/handshake`;
3
+ const response = await fetch(endpoint, {
4
+ method: 'POST',
5
+ headers: { 'Content-Type': 'application/json' },
6
+ body: JSON.stringify({
7
+ client_id: payload.clientId,
8
+ token: payload.token,
9
+ site_url: payload.siteUrl,
10
+ site_name: payload.siteName,
11
+ platform: 'nextjs',
12
+ connection_key: payload.connectionKey,
13
+ connector_version: payload.connectorVersion,
14
+ }),
15
+ signal: AbortSignal.timeout(15_000),
16
+ });
17
+ if (!response.ok) {
18
+ const body = await response.text().catch(() => '');
19
+ throw new Error(`Handshake failed: HTTP ${response.status} — ${body.slice(0, 200)}`);
20
+ }
21
+ const data = (await response.json());
22
+ return {
23
+ status: data.status,
24
+ siteId: data.site_id,
25
+ siteUuid: data.site_uuid,
26
+ publishEndpoint: data.publish_endpoint,
27
+ newConnectionKey: data.new_connection_key ?? undefined,
28
+ };
29
+ }
30
+ //# sourceMappingURL=handshake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handshake.js","sourceRoot":"","sources":["../../src/cli/handshake.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,EACd,OAAyB;IAEzB,MAAM,QAAQ,GAAG,GAAG,MAAM,uBAAuB,CAAA;IAEjD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;QACrC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,SAAS,EAAE,OAAO,CAAC,QAAQ;YAC3B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,OAAO,CAAC,OAAO;YACzB,SAAS,EAAE,OAAO,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ;YAClB,cAAc,EAAE,OAAO,CAAC,aAAa;YACrC,iBAAiB,EAAE,OAAO,CAAC,gBAAgB;SAC5C,CAAC;QACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACpC,CAAC,CAAA;IAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;QAClD,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;IACtF,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAA;IAE/D,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,MAAgB;QAC7B,MAAM,EAAE,IAAI,CAAC,OAAiB;QAC9B,QAAQ,EAAE,IAAI,CAAC,SAAmB;QAClC,eAAe,EAAE,IAAI,CAAC,gBAA0B;QAChD,gBAAgB,EAAG,IAAI,CAAC,kBAAyC,IAAI,SAAS;KAC/E,CAAA;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function init(): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AA2DA,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA4I1C"}
@@ -0,0 +1,173 @@
1
+ import { createInterface } from 'node:readline/promises';
2
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { randomBytes } from 'node:crypto';
5
+ import bcrypt from 'bcryptjs';
6
+ import { performHandshake } from './handshake.js';
7
+ import { writeEnvLocal, updateGitignore, scaffoldApiRoute, injectIntoLayout } from './scaffold.js';
8
+ function randomString(length) {
9
+ return randomBytes(Math.ceil(length / 2))
10
+ .toString('hex')
11
+ .slice(0, length);
12
+ }
13
+ function decodeConnectionKey(key) {
14
+ try {
15
+ const padded = key.replace(/-/g, '+').replace(/_/g, '/');
16
+ const json = Buffer.from(padded, 'base64').toString('utf8');
17
+ const decoded = JSON.parse(json);
18
+ if (!decoded.url)
19
+ return null;
20
+ return { url: decoded.url.replace(/\/$/, ''), tok: decoded.tok ?? '' };
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ function isNextJsProject(cwd) {
27
+ const pkgPath = join(cwd, 'package.json');
28
+ if (!existsSync(pkgPath))
29
+ return false;
30
+ try {
31
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
32
+ return Boolean(pkg.dependencies?.next || pkg.devDependencies?.next);
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ function getPackageVersion() {
39
+ try {
40
+ const pkgPath = new URL('../../package.json', import.meta.url);
41
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
42
+ return pkg.version ?? '1.0.0';
43
+ }
44
+ catch {
45
+ return '1.0.0';
46
+ }
47
+ }
48
+ function parseArgs() {
49
+ const args = process.argv.slice(2);
50
+ const result = {};
51
+ for (let i = 0; i < args.length; i++) {
52
+ if (args[i].startsWith('--')) {
53
+ const [key, ...rest] = args[i].replace(/^--/, '').split('=');
54
+ result[key] = rest.length ? rest.join('=') : (args[++i] ?? '');
55
+ }
56
+ }
57
+ return result;
58
+ }
59
+ export async function init() {
60
+ const cwd = process.cwd();
61
+ console.log('\n Seolful Next.js Connector Setup\n');
62
+ if (!isNextJsProject(cwd)) {
63
+ console.error(' ✖ No Next.js project found in the current directory.');
64
+ console.error(' Run this command from the root of your Next.js app.\n');
65
+ process.exit(1);
66
+ }
67
+ const flags = parseArgs();
68
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
69
+ try {
70
+ // Step 1: Get connection key
71
+ const connectionKey = flags['key'] ?? (await rl.question(' Connection key (from Seolful dashboard): '));
72
+ if (!connectionKey.trim()) {
73
+ console.error('\n ✖ A connection key is required.\n');
74
+ process.exit(1);
75
+ }
76
+ const decoded = decodeConnectionKey(connectionKey.trim());
77
+ if (!decoded) {
78
+ console.error('\n ✖ Invalid connection key. Copy a fresh one from your Seolful dashboard.\n');
79
+ process.exit(1);
80
+ }
81
+ // Step 2: Get site URL
82
+ const defaultUrl = process.env.NEXT_PUBLIC_SITE_URL ?? process.env.SEOLFUL_SITE_URL ?? 'http://localhost:3000';
83
+ const siteUrl = (flags['site-url'] ??
84
+ ((await rl.question(` Site URL [${defaultUrl}]: `)) || defaultUrl)).replace(/\/$/, '');
85
+ // Step 3: Get site name
86
+ let defaultName = 'My Next.js Site';
87
+ try {
88
+ const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf8'));
89
+ if (pkg.name)
90
+ defaultName = pkg.name;
91
+ }
92
+ catch {
93
+ // ignore
94
+ }
95
+ const siteName = flags['site-name'] ?? ((await rl.question(` Site name [${defaultName}]: `)) || defaultName);
96
+ rl.close();
97
+ console.log();
98
+ console.log(` Seolful app: ${decoded.url}`);
99
+ console.log(` Site URL: ${siteUrl}`);
100
+ console.log(` Site name: ${siteName}`);
101
+ console.log();
102
+ // Step 4: Generate credentials
103
+ const clientId = randomString(12);
104
+ const token = randomString(40);
105
+ // Step 5: Handshake
106
+ process.stdout.write(' Connecting to Seolful... ');
107
+ const result = await performHandshake(decoded.url, {
108
+ clientId,
109
+ token,
110
+ siteUrl,
111
+ siteName,
112
+ connectionKey: connectionKey.trim(),
113
+ connectorVersion: getPackageVersion(),
114
+ });
115
+ console.log('✔ Connected');
116
+ // Step 6: Store credentials
117
+ const storageDir = join(cwd, '.seolful');
118
+ if (!existsSync(storageDir))
119
+ mkdirSync(storageDir, { recursive: true });
120
+ const tokenHash = await bcrypt.hash(token, 10);
121
+ writeFileSync(join(storageDir, 'connection.json'), JSON.stringify({
122
+ clientId,
123
+ tokenHash,
124
+ siteUrl,
125
+ connectedAt: new Date().toISOString(),
126
+ }, null, 2));
127
+ const configData = {
128
+ appUrl: decoded.url,
129
+ siteUrl,
130
+ siteName,
131
+ };
132
+ if (result.newConnectionKey) {
133
+ configData.connectionKey = result.newConnectionKey;
134
+ }
135
+ writeFileSync(join(storageDir, 'config.json'), JSON.stringify(configData, null, 2));
136
+ // Step 7: Write .env.local
137
+ writeEnvLocal(cwd, 'SEOLFUL_CLIENT_ID', clientId);
138
+ writeEnvLocal(cwd, 'SEOLFUL_TOKEN', token);
139
+ writeEnvLocal(cwd, 'SEOLFUL_APP_URL', decoded.url);
140
+ writeEnvLocal(cwd, 'SEOLFUL_SITE_URL', siteUrl);
141
+ // Step 8: Scaffold API route
142
+ const routePath = scaffoldApiRoute(cwd);
143
+ // Step 9: Inject SEO into root layout
144
+ const layoutModified = injectIntoLayout(cwd);
145
+ // Step 10: Update .gitignore
146
+ updateGitignore(cwd);
147
+ // Step 11: Success
148
+ console.log();
149
+ console.log(' ✔ .env.local updated');
150
+ console.log(' ✔ .seolful/ created');
151
+ console.log(` ✔ ${routePath}`);
152
+ if (layoutModified) {
153
+ console.log(` ✔ ${layoutModified} — auto-injection enabled`);
154
+ }
155
+ console.log(' ✔ .gitignore updated');
156
+ console.log();
157
+ if (!layoutModified) {
158
+ console.log(' Note: Could not auto-modify your root layout.');
159
+ console.log(' Add this to your layout.tsx generateMetadata:');
160
+ console.log(' import { withSeolfulMetadata } from \'@seolful/next\'');
161
+ console.log();
162
+ }
163
+ console.log(' Seolful is ready — start your dev server and trigger a sync from the dashboard.');
164
+ console.log();
165
+ }
166
+ catch (error) {
167
+ rl.close();
168
+ const message = error instanceof Error ? error.message : String(error);
169
+ console.error(`\n ✖ ${message}\n`);
170
+ process.exit(1);
171
+ }
172
+ }
173
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function writeEnvLocal(cwd: string, key: string, value: string): void;
2
+ export declare function updateGitignore(cwd: string): void;
3
+ export declare function scaffoldApiRoute(cwd: string): string;
4
+ export declare function putFile(filePath: string, content: string): void;
5
+ export declare function injectIntoLayout(cwd: string): string | null;
6
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/cli/scaffold.ts"],"names":[],"mappings":"AAGA,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAU3E;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAQjD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkBpD;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0E3D"}
@@ -0,0 +1,101 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ export function writeEnvLocal(cwd, key, value) {
4
+ const envPath = join(cwd, '.env.local');
5
+ let contents = existsSync(envPath) ? readFileSync(envPath, 'utf8') : '';
6
+ const pattern = new RegExp(`^${key}=.*`, 'm');
7
+ if (pattern.test(contents)) {
8
+ contents = contents.replace(pattern, `${key}=${value}`);
9
+ }
10
+ else {
11
+ contents += (contents.endsWith('\n') || contents === '' ? '' : '\n') + `${key}=${value}\n`;
12
+ }
13
+ writeFileSync(envPath, contents);
14
+ }
15
+ export function updateGitignore(cwd) {
16
+ const gitignorePath = join(cwd, '.gitignore');
17
+ let contents = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf8') : '';
18
+ if (!contents.includes('.seolful/')) {
19
+ contents += (contents.endsWith('\n') || contents === '' ? '' : '\n') + '\n# Seolful connector data\n.seolful/\n';
20
+ writeFileSync(gitignorePath, contents);
21
+ }
22
+ }
23
+ export function scaffoldApiRoute(cwd) {
24
+ const routeContent = `export { GET, POST } from '@seolful/next/api'
25
+ `;
26
+ // Detect src/ directory usage
27
+ const useSrc = existsSync(join(cwd, 'src', 'app'));
28
+ const appDir = useSrc ? join(cwd, 'src', 'app') : join(cwd, 'app');
29
+ const routeDir = join(appDir, 'api', 'seolful', 'v1', '[...path]');
30
+ const routePath = join(routeDir, 'route.ts');
31
+ if (!existsSync(routeDir)) {
32
+ mkdirSync(routeDir, { recursive: true });
33
+ }
34
+ writeFileSync(routePath, routeContent);
35
+ const relative = useSrc ? 'src/app/api/seolful/v1/[...path]/route.ts' : 'app/api/seolful/v1/[...path]/route.ts';
36
+ return relative;
37
+ }
38
+ export function putFile(filePath, content) {
39
+ const dir = dirname(filePath);
40
+ if (!existsSync(dir))
41
+ mkdirSync(dir, { recursive: true });
42
+ writeFileSync(filePath, content);
43
+ }
44
+ export function injectIntoLayout(cwd) {
45
+ const useSrc = existsSync(join(cwd, 'src', 'app'));
46
+ const appDir = useSrc ? join(cwd, 'src', 'app') : join(cwd, 'app');
47
+ // Find the root layout file
48
+ let layoutPath = null;
49
+ for (const ext of ['tsx', 'ts', 'jsx', 'js']) {
50
+ const candidate = join(appDir, `layout.${ext}`);
51
+ if (existsSync(candidate)) {
52
+ layoutPath = candidate;
53
+ break;
54
+ }
55
+ }
56
+ if (!layoutPath)
57
+ return null;
58
+ let content = readFileSync(layoutPath, 'utf8');
59
+ // Already injected
60
+ if (content.includes('@seolful/next') || content.includes('withSeolfulMetadata')) {
61
+ return null;
62
+ }
63
+ // Pattern: `export const metadata: Metadata = { ... };`
64
+ // Convert to generateMetadata that wraps the static object with Seolful overrides
65
+ const staticMetadataMatch = content.match(/export\s+const\s+metadata\s*(?::\s*Metadata\s*)?=\s*(\{[\s\S]*?\n\};?)/m);
66
+ if (staticMetadataMatch) {
67
+ const metadataObject = staticMetadataMatch[1].replace(/;$/, '');
68
+ const fullMatch = staticMetadataMatch[0];
69
+ // Add the import
70
+ const seolfulImport = `import { withSeolfulMetadata } from '@seolful/next'\n`;
71
+ // Check if there's already an import from 'next' for Metadata type
72
+ if (content.includes("import type { Metadata }")) {
73
+ content = content.replace(/import type \{ Metadata \}[^\n]*\n/, (match) => match + seolfulImport);
74
+ }
75
+ else if (content.includes("from 'next'") || content.includes('from "next"')) {
76
+ // Add after the existing next import
77
+ content = content.replace(/(from ['"]next['"][^\n]*\n)/, (match) => match + seolfulImport);
78
+ }
79
+ else {
80
+ // Add at the top
81
+ content = seolfulImport + content;
82
+ }
83
+ // Replace static metadata with generateMetadata function
84
+ const replacement = `const baseMetadata = ${metadataObject}
85
+
86
+ export async function generateMetadata({ params }: { params: Promise<Record<string, string>> }) {
87
+ return withSeolfulMetadata('/', baseMetadata)
88
+ }`;
89
+ content = content.replace(fullMatch, replacement);
90
+ writeFileSync(layoutPath, content);
91
+ const relative = useSrc ? 'src/app/layout.tsx' : 'app/layout.tsx';
92
+ return relative;
93
+ }
94
+ // Pattern: already has generateMetadata — wrap the return value
95
+ if (content.includes('generateMetadata')) {
96
+ // Too complex to auto-modify — skip
97
+ return null;
98
+ }
99
+ return null;
100
+ }
101
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/cli/scaffold.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { SeolfulConfig } from './types.js';
2
+ export declare function getStorageDir(): string;
3
+ export declare function getConfig(): SeolfulConfig;
4
+ export declare function clearConfigCache(): void;
5
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAI/C,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,wBAAgB,SAAS,IAAI,aAAa,CA+BzC;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
package/dist/config.js ADDED
@@ -0,0 +1,44 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ let cached = null;
4
+ export function getStorageDir() {
5
+ if (process.env.SEOLFUL_STORAGE_DIR)
6
+ return process.env.SEOLFUL_STORAGE_DIR;
7
+ if (process.env.VERCEL === '1')
8
+ return '/tmp/.seolful';
9
+ return join(process.cwd(), '.seolful');
10
+ }
11
+ export function getConfig() {
12
+ if (cached)
13
+ return cached;
14
+ const storageDir = getStorageDir();
15
+ const configPath = join(storageDir, 'config.json');
16
+ let fileConfig = {};
17
+ if (existsSync(configPath)) {
18
+ try {
19
+ fileConfig = JSON.parse(readFileSync(configPath, 'utf8'));
20
+ }
21
+ catch {
22
+ // Ignore malformed config
23
+ }
24
+ }
25
+ cached = {
26
+ appUrl: process.env.SEOLFUL_APP_URL ?? fileConfig.appUrl ?? '',
27
+ siteUrl: process.env.SEOLFUL_SITE_URL ?? fileConfig.siteUrl ?? '',
28
+ siteName: process.env.SEOLFUL_SITE_NAME ?? fileConfig.siteName ?? '',
29
+ connectionKey: process.env.SEOLFUL_CONNECTION_KEY ?? fileConfig.connectionKey,
30
+ storageDir,
31
+ crawl: {
32
+ urls: fileConfig.crawl?.urls ?? [],
33
+ sitemapUrl: process.env.SEOLFUL_SITEMAP_URL ?? fileConfig.crawl?.sitemapUrl,
34
+ useSitemap: fileConfig.crawl?.useSitemap ?? true,
35
+ delayMs: Number(process.env.SEOLFUL_CRAWL_DELAY_MS ?? fileConfig.crawl?.delayMs ?? 300),
36
+ timeout: Number(process.env.SEOLFUL_CRAWL_TIMEOUT ?? fileConfig.crawl?.timeout ?? 10),
37
+ },
38
+ };
39
+ return cached;
40
+ }
41
+ export function clearConfigCache() {
42
+ cached = null;
43
+ }
44
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,IAAI,MAAM,GAAyB,IAAI,CAAA;AAEvC,MAAM,UAAU,aAAa;IAC3B,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAA;IAC3E,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,eAAe,CAAA;IACtD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAA;IAEzB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAA;IAElD,IAAI,UAAU,GAA2B,EAAE,CAAA;IAC3C,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,GAAG;QACP,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,UAAU,CAAC,MAAM,IAAI,EAAE;QAC9D,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,UAAU,CAAC,OAAO,IAAI,EAAE;QACjE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,UAAU,CAAC,QAAQ,IAAI,EAAE;QACpE,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,UAAU,CAAC,aAAa;QAC7E,UAAU;QACV,KAAK,EAAE;YACL,IAAI,EAAE,UAAU,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE;YAClC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,UAAU,CAAC,KAAK,EAAE,UAAU;YAC3E,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,IAAI,IAAI;YAChD,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,UAAU,CAAC,KAAK,EAAE,OAAO,IAAI,GAAG,CAAC;YACvF,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,UAAU,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC;SACtF;KACF,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,IAAI,CAAA;AACf,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ImageAlt } from '../types.js';
2
+ export interface PageAnalysis {
3
+ url: string;
4
+ slug: string;
5
+ title: string | null;
6
+ metaDescription: string | null;
7
+ h1: string | null;
8
+ h1Count: number;
9
+ h1Secondary: string | null;
10
+ wordCount: number;
11
+ imageAlts: ImageAlt[];
12
+ internalLinkCount: number;
13
+ structuredData: object[];
14
+ noindex: boolean;
15
+ canonicalUrl: string | null;
16
+ }
17
+ export declare function analyzePage(url: string, html: string): PageAnalysis;
18
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/crawler/analyze.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAqBnE"}
@@ -0,0 +1,114 @@
1
+ import { parse } from 'node-html-parser';
2
+ export function analyzePage(url, html) {
3
+ const root = parse(html);
4
+ const h1s = extractAllH1s(root);
5
+ const pathname = safePathname(url);
6
+ return {
7
+ url,
8
+ slug: pathname,
9
+ title: extractTitle(root),
10
+ metaDescription: extractMetaDescription(root),
11
+ h1: h1s[0] ?? null,
12
+ h1Count: h1s.length,
13
+ h1Secondary: h1s[1] ?? null,
14
+ wordCount: countWords(root),
15
+ imageAlts: extractImageAlts(root),
16
+ internalLinkCount: countInternalLinks(root, url),
17
+ structuredData: extractStructuredData(root),
18
+ noindex: detectNoindex(root),
19
+ canonicalUrl: extractCanonical(root),
20
+ };
21
+ }
22
+ function safePathname(url) {
23
+ try {
24
+ return new URL(url).pathname;
25
+ }
26
+ catch {
27
+ return '/';
28
+ }
29
+ }
30
+ function extractTitle(root) {
31
+ const title = root.querySelector('title');
32
+ const text = title?.textContent?.trim();
33
+ return text || null;
34
+ }
35
+ function extractMetaDescription(root) {
36
+ const meta = root.querySelector('meta[name="description"]');
37
+ const content = meta?.getAttribute('content')?.trim();
38
+ return content || null;
39
+ }
40
+ function extractAllH1s(root) {
41
+ return root
42
+ .querySelectorAll('h1')
43
+ .map((el) => el.textContent.trim())
44
+ .filter(Boolean);
45
+ }
46
+ function countWords(root) {
47
+ const body = root.querySelector('body');
48
+ if (!body)
49
+ return 0;
50
+ // Remove script and style elements
51
+ for (const el of body.querySelectorAll('script, style')) {
52
+ el.remove();
53
+ }
54
+ const text = body.textContent.replace(/\s+/g, ' ').trim();
55
+ if (!text)
56
+ return 0;
57
+ return text.split(/\s+/).length;
58
+ }
59
+ function extractImageAlts(root) {
60
+ return root.querySelectorAll('img').reduce((acc, img) => {
61
+ const src = img.getAttribute('src') || img.getAttribute('data-src');
62
+ if (!src)
63
+ return acc;
64
+ const alt = img.getAttribute('alt') ?? '';
65
+ acc.push({ src, alt, missing: alt === '' });
66
+ return acc;
67
+ }, []);
68
+ }
69
+ function countInternalLinks(root, pageUrl) {
70
+ let host = '';
71
+ try {
72
+ host = new URL(pageUrl).host;
73
+ }
74
+ catch {
75
+ return 0;
76
+ }
77
+ let count = 0;
78
+ for (const a of root.querySelectorAll('a[href]')) {
79
+ const href = a.getAttribute('href') ?? '';
80
+ if (href.startsWith('/') || href.includes(host)) {
81
+ count++;
82
+ }
83
+ }
84
+ return count;
85
+ }
86
+ function extractStructuredData(root) {
87
+ const schemas = [];
88
+ for (const script of root.querySelectorAll('script[type="application/ld+json"]')) {
89
+ try {
90
+ const decoded = JSON.parse(script.textContent);
91
+ if (decoded && typeof decoded === 'object') {
92
+ schemas.push(decoded);
93
+ }
94
+ }
95
+ catch {
96
+ // skip malformed JSON-LD
97
+ }
98
+ }
99
+ return schemas;
100
+ }
101
+ function detectNoindex(root) {
102
+ for (const name of ['robots', 'googlebot']) {
103
+ const meta = root.querySelector(`meta[name="${name}"]`);
104
+ const content = meta?.getAttribute('content')?.toLowerCase() ?? '';
105
+ if (content.includes('noindex'))
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+ function extractCanonical(root) {
111
+ const link = root.querySelector('link[rel="canonical"]');
112
+ return link?.getAttribute('href') ?? null;
113
+ }
114
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/crawler/analyze.ts"],"names":[],"mappings":"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"}