@hasna/microservices 0.0.6 → 0.0.8
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/microservices/microservice-domains/src/lib/brandsight.ts +138 -73
- package/microservices/microservice-domains/src/lib/godaddy.ts +149 -139
- package/microservices/microservice-domains/src/lib/namecheap.ts +63 -275
- package/microservices/microservice-social/package.json +2 -1
- package/microservices/microservice-social/src/cli/index.ts +906 -12
- package/microservices/microservice-social/src/db/migrations.ts +72 -0
- package/microservices/microservice-social/src/db/social.ts +33 -3
- package/microservices/microservice-social/src/lib/audience.ts +353 -0
- package/microservices/microservice-social/src/lib/content-ai.ts +278 -0
- package/microservices/microservice-social/src/lib/media.ts +311 -0
- package/microservices/microservice-social/src/lib/mentions.ts +434 -0
- package/microservices/microservice-social/src/lib/metrics-sync.ts +264 -0
- package/microservices/microservice-social/src/lib/publisher.ts +377 -0
- package/microservices/microservice-social/src/lib/scheduler.ts +229 -0
- package/microservices/microservice-social/src/lib/sentiment.ts +256 -0
- package/microservices/microservice-social/src/lib/threads.ts +291 -0
- package/microservices/microservice-social/src/mcp/index.ts +776 -6
- package/microservices/microservice-social/src/server/index.ts +441 -0
- package/package.json +1 -1
|
@@ -1,60 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Namecheap API integration for domain management
|
|
3
3
|
*
|
|
4
|
+
* Uses the Connector SDK pattern from connect-namecheap.
|
|
5
|
+
* When @hasna/connect-namecheap is published to npm, replace the
|
|
6
|
+
* relative connector import with the package import.
|
|
7
|
+
*
|
|
4
8
|
* Requires environment variables:
|
|
5
9
|
* NAMECHEAP_API_KEY — API key from Namecheap
|
|
6
10
|
* NAMECHEAP_USERNAME — Namecheap account username
|
|
7
11
|
* NAMECHEAP_CLIENT_IP — Whitelisted client IP address
|
|
8
12
|
*/
|
|
9
13
|
|
|
14
|
+
// Re-export types used by consumers (CLI, MCP, registrar)
|
|
15
|
+
export type {
|
|
16
|
+
ConnectorConfig as NamecheapConfig,
|
|
17
|
+
Domain as NamecheapDomain,
|
|
18
|
+
DomainInfo as NamecheapDomainInfo,
|
|
19
|
+
DnsRecord as NamecheapDnsRecord,
|
|
20
|
+
AvailabilityResult as NamecheapAvailability,
|
|
21
|
+
RenewResult as NamecheapRenewResult,
|
|
22
|
+
} from "../../../../../open-connectors/connectors/connect-namecheap/src/index.js";
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
Connector,
|
|
26
|
+
type ConnectorConfig,
|
|
27
|
+
type Domain as NamecheapDomain,
|
|
28
|
+
type DomainInfo as NamecheapDomainInfo,
|
|
29
|
+
type DnsRecord as NamecheapDnsRecord,
|
|
30
|
+
} from "../../../../../open-connectors/connectors/connect-namecheap/src/index.js";
|
|
31
|
+
|
|
10
32
|
// ============================================================
|
|
11
|
-
//
|
|
33
|
+
// Sync Result Type (microservice-specific, not in connector)
|
|
12
34
|
// ============================================================
|
|
13
35
|
|
|
14
|
-
export interface NamecheapConfig {
|
|
15
|
-
apiKey: string;
|
|
16
|
-
username: string;
|
|
17
|
-
clientIp: string;
|
|
18
|
-
sandbox?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface NamecheapDomain {
|
|
22
|
-
domain: string;
|
|
23
|
-
expiry: string;
|
|
24
|
-
autoRenew: boolean;
|
|
25
|
-
isLocked: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface NamecheapDomainInfo {
|
|
29
|
-
domain: string;
|
|
30
|
-
registrar: string;
|
|
31
|
-
created: string;
|
|
32
|
-
expires: string;
|
|
33
|
-
nameservers: string[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface NamecheapDnsRecord {
|
|
37
|
-
hostId?: string;
|
|
38
|
-
type: string;
|
|
39
|
-
name: string;
|
|
40
|
-
address: string;
|
|
41
|
-
mxPref?: number;
|
|
42
|
-
ttl: number;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface NamecheapAvailability {
|
|
46
|
-
domain: string;
|
|
47
|
-
available: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface NamecheapRenewResult {
|
|
51
|
-
domain: string;
|
|
52
|
-
success: boolean;
|
|
53
|
-
transactionId?: string;
|
|
54
|
-
chargedAmount?: string;
|
|
55
|
-
orderId?: string;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
36
|
export interface NamecheapSyncResult {
|
|
59
37
|
synced: number;
|
|
60
38
|
errors: string[];
|
|
@@ -62,13 +40,14 @@ export interface NamecheapSyncResult {
|
|
|
62
40
|
}
|
|
63
41
|
|
|
64
42
|
// ============================================================
|
|
65
|
-
//
|
|
43
|
+
// Connector Instance Management
|
|
66
44
|
// ============================================================
|
|
67
45
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Create a Namecheap connector from environment variables.
|
|
48
|
+
* Wraps Connector.fromEnv() with the same env var validation.
|
|
49
|
+
*/
|
|
50
|
+
export function getConfig(): ConnectorConfig {
|
|
72
51
|
const apiKey = process.env["NAMECHEAP_API_KEY"];
|
|
73
52
|
const username = process.env["NAMECHEAP_USERNAME"];
|
|
74
53
|
const clientIp = process.env["NAMECHEAP_CLIENT_IP"];
|
|
@@ -85,267 +64,72 @@ export function getConfig(): NamecheapConfig {
|
|
|
85
64
|
};
|
|
86
65
|
}
|
|
87
66
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// ============================================================
|
|
91
|
-
|
|
92
|
-
export function extractTag(xml: string, tag: string): string | null {
|
|
93
|
-
const regex = new RegExp(`<${tag}[^>]*>([^<]*)</${tag}>`, "i");
|
|
94
|
-
const match = xml.match(regex);
|
|
95
|
-
return match ? match[1].trim() : null;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function extractAttribute(xml: string, tag: string, attr: string): string | null {
|
|
99
|
-
const regex = new RegExp(`<${tag}\\s[^>]*${attr}="([^"]*)"`, "i");
|
|
100
|
-
const match = xml.match(regex);
|
|
101
|
-
return match ? match[1] : null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function extractAllTags(xml: string, tag: string): string[] {
|
|
105
|
-
const regex = new RegExp(`<${tag}(?:\\s[^>]*)?\\/?>(?:([^<]*)<\\/${tag}>)?`, "gi");
|
|
106
|
-
const results: string[] = [];
|
|
107
|
-
let match;
|
|
108
|
-
while ((match = regex.exec(xml)) !== null) {
|
|
109
|
-
// Only match exact tag name — skip tags like <DomainListResult> when searching for <Domain>
|
|
110
|
-
const fullMatch = match[0];
|
|
111
|
-
const tagNameCheck = new RegExp(`^<${tag}(?:\\s|\\/>|>)`, "i");
|
|
112
|
-
if (tagNameCheck.test(fullMatch)) {
|
|
113
|
-
results.push(fullMatch);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return results;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function extractAttributeFromElement(element: string, attr: string): string | null {
|
|
120
|
-
const regex = new RegExp(`${attr}="([^"]*)"`, "i");
|
|
121
|
-
const match = element.match(regex);
|
|
122
|
-
return match ? match[1] : null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function checkApiError(xml: string): void {
|
|
126
|
-
const status = extractAttribute(xml, "ApiResponse", "Status");
|
|
127
|
-
if (status === "ERROR") {
|
|
128
|
-
const errorMsg = extractTag(xml, "Message") || extractTag(xml, "Err") || "Unknown Namecheap API error";
|
|
129
|
-
const errorNumber = extractAttribute(xml, "Error", "Number") || extractAttribute(xml, "Err", "Number");
|
|
130
|
-
throw new Error(`Namecheap API error${errorNumber ? ` (${errorNumber})` : ""}: ${errorMsg}`);
|
|
131
|
-
}
|
|
67
|
+
function createConnector(config?: ConnectorConfig): Connector {
|
|
68
|
+
return new Connector(config || getConfig());
|
|
132
69
|
}
|
|
133
70
|
|
|
134
71
|
// ============================================================
|
|
135
|
-
//
|
|
136
|
-
// ============================================================
|
|
137
|
-
|
|
138
|
-
export function buildUrl(command: string, config: NamecheapConfig, extraParams?: Record<string, string>): string {
|
|
139
|
-
const base = config.sandbox ? SANDBOX_BASE : API_BASE;
|
|
140
|
-
const params = new URLSearchParams({
|
|
141
|
-
ApiUser: config.username,
|
|
142
|
-
ApiKey: config.apiKey,
|
|
143
|
-
UserName: config.username,
|
|
144
|
-
ClientIp: config.clientIp,
|
|
145
|
-
Command: command,
|
|
146
|
-
...extraParams,
|
|
147
|
-
});
|
|
148
|
-
return `${base}?${params.toString()}`;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export async function apiRequest(command: string, config: NamecheapConfig, extraParams?: Record<string, string>): Promise<string> {
|
|
152
|
-
const url = buildUrl(command, config, extraParams);
|
|
153
|
-
const response = await fetch(url, {
|
|
154
|
-
signal: AbortSignal.timeout(30000),
|
|
155
|
-
headers: { "User-Agent": "microservice-domains/0.0.1" },
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
if (!response.ok) {
|
|
159
|
-
throw new Error(`Namecheap API HTTP error: ${response.status} ${response.statusText}`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const xml = await response.text();
|
|
163
|
-
checkApiError(xml);
|
|
164
|
-
return xml;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// ============================================================
|
|
168
|
-
// API Functions
|
|
72
|
+
// API Functions (thin wrappers around connector)
|
|
169
73
|
// ============================================================
|
|
170
74
|
|
|
171
75
|
/**
|
|
172
76
|
* List all domains in the Namecheap account
|
|
173
|
-
* Command: namecheap.domains.getList
|
|
174
77
|
*/
|
|
175
|
-
export async function listNamecheapDomains(config?:
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
PageSize: "100",
|
|
179
|
-
Page: "1",
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
const domainElements = extractAllTags(xml, "Domain");
|
|
183
|
-
const domains: NamecheapDomain[] = [];
|
|
184
|
-
|
|
185
|
-
for (const el of domainElements) {
|
|
186
|
-
const name = extractAttributeFromElement(el, "Name");
|
|
187
|
-
const expires = extractAttributeFromElement(el, "Expires");
|
|
188
|
-
const autoRenew = extractAttributeFromElement(el, "AutoRenew");
|
|
189
|
-
const isLocked = extractAttributeFromElement(el, "IsLocked");
|
|
190
|
-
|
|
191
|
-
if (name) {
|
|
192
|
-
domains.push({
|
|
193
|
-
domain: name,
|
|
194
|
-
expiry: expires || "",
|
|
195
|
-
autoRenew: autoRenew === "true",
|
|
196
|
-
isLocked: isLocked === "true",
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return domains;
|
|
78
|
+
export async function listNamecheapDomains(config?: ConnectorConfig): Promise<NamecheapDomain[]> {
|
|
79
|
+
const connector = createConnector(config);
|
|
80
|
+
return connector.domains.list();
|
|
202
81
|
}
|
|
203
82
|
|
|
204
83
|
/**
|
|
205
84
|
* Get detailed info for a specific domain
|
|
206
|
-
* Command: namecheap.domains.getInfo
|
|
207
85
|
*/
|
|
208
|
-
export async function getDomainInfo(domain: string, config?:
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
DomainName: domain,
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// Parse creation and expiry dates
|
|
215
|
-
const createdDate = extractTag(xml, "CreatedDate") || extractAttribute(xml, "DomainGetInfoResult", "CreatedDate") || "";
|
|
216
|
-
const expiresDate = extractTag(xml, "ExpiredDate") || extractAttribute(xml, "DomainGetInfoResult", "ExpiredDate") || "";
|
|
217
|
-
|
|
218
|
-
// Parse nameservers
|
|
219
|
-
const nsSection = xml.match(/<DnsDetails[^>]*>([\s\S]*?)<\/DnsDetails>/i);
|
|
220
|
-
const nameservers: string[] = [];
|
|
221
|
-
if (nsSection) {
|
|
222
|
-
const nsElements = nsSection[1].matchAll(/<Nameserver[^>]*>([^<]*)<\/Nameserver>/gi);
|
|
223
|
-
for (const m of nsElements) {
|
|
224
|
-
if (m[1]) nameservers.push(m[1].trim().toLowerCase());
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return {
|
|
229
|
-
domain,
|
|
230
|
-
registrar: "Namecheap",
|
|
231
|
-
created: createdDate,
|
|
232
|
-
expires: expiresDate,
|
|
233
|
-
nameservers,
|
|
234
|
-
};
|
|
86
|
+
export async function getDomainInfo(domain: string, config?: ConnectorConfig): Promise<NamecheapDomainInfo> {
|
|
87
|
+
const connector = createConnector(config);
|
|
88
|
+
return connector.domains.getInfo(domain);
|
|
235
89
|
}
|
|
236
90
|
|
|
237
91
|
/**
|
|
238
92
|
* Renew a domain
|
|
239
|
-
* Command: namecheap.domains.renew
|
|
240
93
|
*/
|
|
241
|
-
export async function renewDomain(domain: string, years: number = 1, config?:
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
DomainName: domain,
|
|
245
|
-
Years: String(years),
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
const transactionId = extractAttribute(xml, "DomainRenewResult", "TransactionID") || undefined;
|
|
249
|
-
const chargedAmount = extractAttribute(xml, "DomainRenewResult", "ChargedAmount") || undefined;
|
|
250
|
-
const orderId = extractAttribute(xml, "DomainRenewResult", "OrderID") || undefined;
|
|
251
|
-
|
|
252
|
-
return {
|
|
253
|
-
domain,
|
|
254
|
-
success: true,
|
|
255
|
-
transactionId,
|
|
256
|
-
chargedAmount,
|
|
257
|
-
orderId,
|
|
258
|
-
};
|
|
94
|
+
export async function renewDomain(domain: string, years: number = 1, config?: ConnectorConfig) {
|
|
95
|
+
const connector = createConnector(config);
|
|
96
|
+
return connector.domains.renew(domain, years);
|
|
259
97
|
}
|
|
260
98
|
|
|
261
99
|
/**
|
|
262
100
|
* Get DNS host records for a domain
|
|
263
|
-
* Command: namecheap.domains.dns.getHosts
|
|
264
101
|
*/
|
|
265
|
-
export async function getDnsRecords(domain: string, sld: string, tld: string, config?:
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
SLD: sld,
|
|
269
|
-
TLD: tld,
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
const hostElements = extractAllTags(xml, "host");
|
|
273
|
-
const records: NamecheapDnsRecord[] = [];
|
|
274
|
-
|
|
275
|
-
for (const el of hostElements) {
|
|
276
|
-
const type = extractAttributeFromElement(el, "Type");
|
|
277
|
-
const name = extractAttributeFromElement(el, "Name");
|
|
278
|
-
const address = extractAttributeFromElement(el, "Address");
|
|
279
|
-
const hostId = extractAttributeFromElement(el, "HostId");
|
|
280
|
-
const mxPref = extractAttributeFromElement(el, "MXPref");
|
|
281
|
-
const ttl = extractAttributeFromElement(el, "TTL");
|
|
282
|
-
|
|
283
|
-
if (type && name && address) {
|
|
284
|
-
records.push({
|
|
285
|
-
hostId: hostId || undefined,
|
|
286
|
-
type,
|
|
287
|
-
name,
|
|
288
|
-
address,
|
|
289
|
-
mxPref: mxPref ? parseInt(mxPref) : undefined,
|
|
290
|
-
ttl: ttl ? parseInt(ttl) : 1800,
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return records;
|
|
102
|
+
export async function getDnsRecords(domain: string, sld: string, tld: string, config?: ConnectorConfig): Promise<NamecheapDnsRecord[]> {
|
|
103
|
+
const connector = createConnector(config);
|
|
104
|
+
return connector.dns.getHosts(sld, tld);
|
|
296
105
|
}
|
|
297
106
|
|
|
298
107
|
/**
|
|
299
108
|
* Set DNS host records for a domain
|
|
300
|
-
* Command: namecheap.domains.dns.setHosts
|
|
301
109
|
*/
|
|
302
110
|
export async function setDnsRecords(
|
|
303
111
|
domain: string,
|
|
304
112
|
sld: string,
|
|
305
113
|
tld: string,
|
|
306
114
|
records: NamecheapDnsRecord[],
|
|
307
|
-
config?:
|
|
115
|
+
config?: ConnectorConfig
|
|
308
116
|
): Promise<boolean> {
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
SLD: sld,
|
|
312
|
-
TLD: tld,
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
for (let i = 0; i < records.length; i++) {
|
|
316
|
-
const r = records[i];
|
|
317
|
-
const idx = i + 1;
|
|
318
|
-
params[`HostName${idx}`] = r.name;
|
|
319
|
-
params[`RecordType${idx}`] = r.type;
|
|
320
|
-
params[`Address${idx}`] = r.address;
|
|
321
|
-
params[`TTL${idx}`] = String(r.ttl);
|
|
322
|
-
if (r.mxPref !== undefined) {
|
|
323
|
-
params[`MXPref${idx}`] = String(r.mxPref);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
await apiRequest("namecheap.domains.dns.setHosts", cfg, params);
|
|
328
|
-
return true;
|
|
117
|
+
const connector = createConnector(config);
|
|
118
|
+
return connector.dns.setHosts(sld, tld, records);
|
|
329
119
|
}
|
|
330
120
|
|
|
331
121
|
/**
|
|
332
122
|
* Check domain availability
|
|
333
|
-
* Command: namecheap.domains.check
|
|
334
123
|
*/
|
|
335
|
-
export async function checkAvailability(domain: string, config?:
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
DomainList: domain,
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
const available = extractAttribute(xml, "DomainCheckResult", "Available");
|
|
342
|
-
|
|
343
|
-
return {
|
|
344
|
-
domain,
|
|
345
|
-
available: available === "true",
|
|
346
|
-
};
|
|
124
|
+
export async function checkAvailability(domain: string, config?: ConnectorConfig) {
|
|
125
|
+
const connector = createConnector(config);
|
|
126
|
+
return connector.domains.check(domain);
|
|
347
127
|
}
|
|
348
128
|
|
|
129
|
+
// ============================================================
|
|
130
|
+
// Domain Helpers (microservice-specific)
|
|
131
|
+
// ============================================================
|
|
132
|
+
|
|
349
133
|
/**
|
|
350
134
|
* Split a domain name into SLD (second-level domain) and TLD (top-level domain)
|
|
351
135
|
*/
|
|
@@ -367,6 +151,10 @@ export function splitDomain(domain: string): { sld: string; tld: string } {
|
|
|
367
151
|
};
|
|
368
152
|
}
|
|
369
153
|
|
|
154
|
+
// ============================================================
|
|
155
|
+
// Sync to Local DB (microservice business logic)
|
|
156
|
+
// ============================================================
|
|
157
|
+
|
|
370
158
|
/**
|
|
371
159
|
* Sync domains from Namecheap to local database
|
|
372
160
|
* Calls listDomains + getDomainInfo for each, upserts into local domains table
|
|
@@ -393,23 +181,23 @@ export async function syncToLocalDb(dbFunctions: {
|
|
|
393
181
|
nameservers?: string[];
|
|
394
182
|
}
|
|
395
183
|
) => unknown;
|
|
396
|
-
}, config?:
|
|
397
|
-
const
|
|
184
|
+
}, config?: ConnectorConfig): Promise<NamecheapSyncResult> {
|
|
185
|
+
const connector = createConnector(config);
|
|
398
186
|
const result: NamecheapSyncResult = { synced: 0, errors: [], domains: [] };
|
|
399
187
|
|
|
400
188
|
let ncDomains: NamecheapDomain[];
|
|
401
189
|
try {
|
|
402
|
-
ncDomains = await
|
|
190
|
+
ncDomains = await connector.domains.list();
|
|
403
191
|
} catch (error) {
|
|
404
192
|
throw new Error(`Failed to list Namecheap domains: ${error instanceof Error ? error.message : String(error)}`);
|
|
405
193
|
}
|
|
406
194
|
|
|
407
195
|
for (const ncDomain of ncDomains) {
|
|
408
196
|
try {
|
|
409
|
-
// Get detailed info
|
|
197
|
+
// Get detailed info via connector
|
|
410
198
|
let info: NamecheapDomainInfo;
|
|
411
199
|
try {
|
|
412
|
-
info = await
|
|
200
|
+
info = await connector.domains.getInfo(ncDomain.domain);
|
|
413
201
|
} catch {
|
|
414
202
|
// Fall back to basic info if getInfo fails
|
|
415
203
|
info = {
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"microservice-social": "./src/cli/index.ts",
|
|
8
|
-
"microservice-social-mcp": "./src/mcp/index.ts"
|
|
8
|
+
"microservice-social-mcp": "./src/mcp/index.ts",
|
|
9
|
+
"microservice-social-serve": "./src/server/index.ts"
|
|
9
10
|
},
|
|
10
11
|
"exports": {
|
|
11
12
|
".": "./src/index.ts"
|