dk-domain-agent-core 0.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 +5 -0
- package/dist/availability.d.ts +3 -0
- package/dist/availability.d.ts.map +1 -0
- package/dist/availability.js +75 -0
- package/dist/availability.js.map +1 -0
- package/dist/clock.d.ts +3 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +5 -0
- package/dist/clock.js.map +1 -0
- package/dist/file-cache.d.ts +17 -0
- package/dist/file-cache.d.ts.map +1 -0
- package/dist/file-cache.js +74 -0
- package/dist/file-cache.js.map +1 -0
- package/dist/file-lock.d.ts +9 -0
- package/dist/file-lock.d.ts.map +1 -0
- package/dist/file-lock.js +56 -0
- package/dist/file-lock.js.map +1 -0
- package/dist/file-rate-limiter.d.ts +14 -0
- package/dist/file-rate-limiter.d.ts.map +1 -0
- package/dist/file-rate-limiter.js +82 -0
- package/dist/file-rate-limiter.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-store.d.ts +12 -0
- package/dist/memory-store.d.ts.map +1 -0
- package/dist/memory-store.js +47 -0
- package/dist/memory-store.js.map +1 -0
- package/dist/normalize.d.ts +3 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +39 -0
- package/dist/normalize.js.map +1 -0
- package/dist/parser.d.ts +3 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +47 -0
- package/dist/parser.js.map +1 -0
- package/dist/result.d.ts +4 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +36 -0
- package/dist/result.js.map +1 -0
- package/dist/ttl.d.ts +3 -0
- package/dist/ttl.d.ts.map +1 -0
- package/dist/ttl.js +15 -0
- package/dist/ttl.js.map +1 -0
- package/dist/types.d.ts +62 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/whois-client.d.ts +8 -0
- package/dist/whois-client.d.ts.map +1 -0
- package/dist/whois-client.js +36 -0
- package/dist/whois-client.js.map +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"availability.d.ts","sourceRoot":"","sources":["../src/availability.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAoB,MAAM,YAAY,CAAC;AAM5F,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAmE7B"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { systemClock } from "./clock.js";
|
|
2
|
+
import { FileAvailabilityCache } from "./file-cache.js";
|
|
3
|
+
import { FileRateLimiter } from "./file-rate-limiter.js";
|
|
4
|
+
import { normalizeDkDomain } from "./normalize.js";
|
|
5
|
+
import { parsePunktumWhois } from "./parser.js";
|
|
6
|
+
import { availabilityResult, invalidResult } from "./result.js";
|
|
7
|
+
import { ttlForStatus } from "./ttl.js";
|
|
8
|
+
import { PunktumWhoisClient } from "./whois-client.js";
|
|
9
|
+
const DEFAULT_TIMEOUT_MS = 8000;
|
|
10
|
+
const DEFAULT_QUEUE_WAIT_MS = 10_000;
|
|
11
|
+
const PUNKTUM_WHOIS_INTERVAL_MS = 1000;
|
|
12
|
+
export async function checkDkDomainAvailability(input, options = {}) {
|
|
13
|
+
const clock = options.clock ?? systemClock;
|
|
14
|
+
const checkedAt = new Date(clock.now()).toISOString();
|
|
15
|
+
let normalized;
|
|
16
|
+
try {
|
|
17
|
+
normalized = normalizeDkDomain(input);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return invalidResult(input, checkedAt);
|
|
21
|
+
}
|
|
22
|
+
const cache = options.cache ?? new FileAvailabilityCache({ clock });
|
|
23
|
+
if (!options.bypassCache) {
|
|
24
|
+
const nowMs = clock.now();
|
|
25
|
+
const cached = await cache.get(normalized.asciiDomain, nowMs);
|
|
26
|
+
if (cached) {
|
|
27
|
+
return {
|
|
28
|
+
...cached.result,
|
|
29
|
+
cache: {
|
|
30
|
+
hit: true,
|
|
31
|
+
ttlSeconds: Math.max(0, Math.ceil((cached.expiresAtMs - nowMs) / 1000))
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const rateLimiter = options.rateLimiter ?? new FileRateLimiter({ clock });
|
|
37
|
+
const turn = await rateLimiter.waitForTurn({
|
|
38
|
+
intervalMs: PUNKTUM_WHOIS_INTERVAL_MS,
|
|
39
|
+
maxWaitMs: options.maxQueueWaitMs ?? DEFAULT_QUEUE_WAIT_MS,
|
|
40
|
+
clock
|
|
41
|
+
});
|
|
42
|
+
if (!turn.acquired) {
|
|
43
|
+
return availabilityResult(normalized.unicodeDomain, normalized.asciiDomain, {
|
|
44
|
+
available: null,
|
|
45
|
+
status: "rate_limited",
|
|
46
|
+
confidence: "unknown"
|
|
47
|
+
}, new Date(clock.now()).toISOString(), false, null);
|
|
48
|
+
}
|
|
49
|
+
const whoisClient = options.whoisClient ?? new PunktumWhoisClient();
|
|
50
|
+
const parsed = await queryAndParse(normalized.asciiDomain, whoisClient, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
51
|
+
const result = availabilityResult(normalized.unicodeDomain, normalized.asciiDomain, parsed, new Date(clock.now()).toISOString(), false, null);
|
|
52
|
+
const ttlSeconds = ttlForStatus(result.status);
|
|
53
|
+
await cache.set(normalized.asciiDomain, result, ttlSeconds, clock.now());
|
|
54
|
+
return {
|
|
55
|
+
...result,
|
|
56
|
+
cache: {
|
|
57
|
+
hit: false,
|
|
58
|
+
ttlSeconds
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async function queryAndParse(domain, whoisClient, timeoutMs) {
|
|
63
|
+
try {
|
|
64
|
+
const raw = await whoisClient.query(domain, timeoutMs);
|
|
65
|
+
return parsePunktumWhois(raw);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return {
|
|
69
|
+
available: null,
|
|
70
|
+
status: "unknown",
|
|
71
|
+
confidence: "unknown"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=availability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"availability.js","sourceRoot":"","sources":["../src/availability.ts"],"names":[],"mappings":"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"}
|
package/dist/clock.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../src/clock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,eAAO,MAAM,WAAW,EAAE,KAGzB,CAAC"}
|
package/dist/clock.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.js","sourceRoot":"","sources":["../src/clock.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAU;IAChC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;IACrB,KAAK,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;CACvE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AvailabilityCache, AvailabilityResult, CachedAvailability, Clock } from "./types.js";
|
|
2
|
+
export declare function defaultStateDir(): string;
|
|
3
|
+
export declare class FileAvailabilityCache implements AvailabilityCache {
|
|
4
|
+
private readonly stateFile;
|
|
5
|
+
private readonly lockDir;
|
|
6
|
+
private readonly clock;
|
|
7
|
+
constructor(options?: {
|
|
8
|
+
stateFile?: string;
|
|
9
|
+
clock?: Clock;
|
|
10
|
+
});
|
|
11
|
+
get(domain: string, nowMs: number): Promise<CachedAvailability | null>;
|
|
12
|
+
set(domain: string, result: AvailabilityResult, ttlSeconds: number, nowMs: number): Promise<void>;
|
|
13
|
+
clear(): Promise<void>;
|
|
14
|
+
private readState;
|
|
15
|
+
private writeState;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=file-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-cache.d.ts","sourceRoot":"","sources":["../src/file-cache.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAOnG,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,qBAAa,qBAAsB,YAAW,iBAAiB;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAA;KAAO;IASzD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAatE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAajG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAMd,SAAS;YAgBT,UAAU;CAMzB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { systemClock } from "./clock.js";
|
|
5
|
+
import { withFileLock } from "./file-lock.js";
|
|
6
|
+
export function defaultStateDir() {
|
|
7
|
+
return process.env.DK_DOMAIN_AGENT_STATE_DIR ?? path.join(os.homedir(), ".dk-domain-agent");
|
|
8
|
+
}
|
|
9
|
+
export class FileAvailabilityCache {
|
|
10
|
+
stateFile;
|
|
11
|
+
lockDir;
|
|
12
|
+
clock;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.stateFile =
|
|
15
|
+
options.stateFile ??
|
|
16
|
+
process.env.DK_DOMAIN_AGENT_CACHE_FILE ??
|
|
17
|
+
path.join(defaultStateDir(), "cache.json");
|
|
18
|
+
this.lockDir = `${this.stateFile}.lock`;
|
|
19
|
+
this.clock = options.clock ?? systemClock;
|
|
20
|
+
}
|
|
21
|
+
async get(domain, nowMs) {
|
|
22
|
+
return withFileLock(this.lockDir, { clock: this.clock }, async () => {
|
|
23
|
+
const state = await this.readState();
|
|
24
|
+
const cached = state.entries[domain];
|
|
25
|
+
if (!cached || cached.expiresAtMs <= nowMs) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return cached;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async set(domain, result, ttlSeconds, nowMs) {
|
|
32
|
+
if (ttlSeconds <= 0)
|
|
33
|
+
return;
|
|
34
|
+
await withFileLock(this.lockDir, { clock: this.clock }, async () => {
|
|
35
|
+
const state = await this.readState();
|
|
36
|
+
state.entries[domain] = {
|
|
37
|
+
result,
|
|
38
|
+
expiresAtMs: nowMs + ttlSeconds * 1000
|
|
39
|
+
};
|
|
40
|
+
await this.writeState(state);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async clear() {
|
|
44
|
+
await withFileLock(this.lockDir, { clock: this.clock }, async () => {
|
|
45
|
+
await this.writeState({ version: 1, entries: {} });
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async readState() {
|
|
49
|
+
try {
|
|
50
|
+
const raw = await fs.readFile(this.stateFile, "utf8");
|
|
51
|
+
const parsed = JSON.parse(raw);
|
|
52
|
+
return {
|
|
53
|
+
version: 1,
|
|
54
|
+
entries: parsed.entries ?? {}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (isMissingFile(error)) {
|
|
59
|
+
return { version: 1, entries: {} };
|
|
60
|
+
}
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async writeState(state) {
|
|
65
|
+
await fs.mkdir(path.dirname(this.stateFile), { recursive: true });
|
|
66
|
+
const tmpFile = `${this.stateFile}.${process.pid}.tmp`;
|
|
67
|
+
await fs.writeFile(tmpFile, JSON.stringify(state, null, 2));
|
|
68
|
+
await fs.rename(tmpFile, this.stateFile);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isMissingFile(error) {
|
|
72
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=file-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-cache.js","sourceRoot":"","sources":["../src/file-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Clock } from "./types.js";
|
|
2
|
+
export type FileLockOptions = {
|
|
3
|
+
staleMs?: number;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
retryMs?: number;
|
|
6
|
+
clock: Clock;
|
|
7
|
+
};
|
|
8
|
+
export declare function withFileLock<T>(lockDir: string, options: FileLockOptions, task: () => Promise<T>): Promise<T>;
|
|
9
|
+
//# sourceMappingURL=file-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.d.ts","sourceRoot":"","sources":["../src/file-lock.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAMF,wBAAsB,YAAY,CAAC,CAAC,EAClC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,CAAC,CAAC,CAkCZ"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const DEFAULT_STALE_MS = 30_000;
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 5_000;
|
|
5
|
+
const DEFAULT_RETRY_MS = 25;
|
|
6
|
+
export async function withFileLock(lockDir, options, task) {
|
|
7
|
+
const staleMs = options.staleMs ?? DEFAULT_STALE_MS;
|
|
8
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
9
|
+
const retryMs = options.retryMs ?? DEFAULT_RETRY_MS;
|
|
10
|
+
const startedAt = options.clock.now();
|
|
11
|
+
await fs.mkdir(path.dirname(lockDir), { recursive: true });
|
|
12
|
+
while (true) {
|
|
13
|
+
try {
|
|
14
|
+
await fs.mkdir(lockDir);
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (!isErrnoException(error) || error.code !== "EEXIST") {
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
if (await removeIfStale(lockDir, staleMs, options.clock.now())) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (options.clock.now() - startedAt >= timeoutMs) {
|
|
25
|
+
throw new Error(`Timed out waiting for lock: ${lockDir}`);
|
|
26
|
+
}
|
|
27
|
+
await options.clock.sleep(retryMs);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
return await task();
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await fs.rm(lockDir, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function removeIfStale(lockDir, staleMs, nowMs) {
|
|
38
|
+
try {
|
|
39
|
+
const stats = await fs.stat(lockDir);
|
|
40
|
+
if (nowMs - stats.mtimeMs < staleMs) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
await fs.rm(lockDir, { recursive: true, force: true });
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (isErrnoException(error) && error.code === "ENOENT") {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function isErrnoException(error) {
|
|
54
|
+
return error instanceof Error && "code" in error;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=file-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.js","sourceRoot":"","sources":["../src/file-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAU7B,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACjC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,OAAwB,EACxB,IAAsB;IAEtB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACpD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACpD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IAEtC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3D,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxB,MAAM;QACR,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACxD,MAAM,KAAK,CAAC;YACd,CAAC;YAED,IAAI,MAAM,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;gBAC/D,SAAS;YACX,CAAC;YAED,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,SAAS,EAAE,CAAC;gBACjD,MAAM,IAAI,KAAK,CAAC,+BAA+B,OAAO,EAAE,CAAC,CAAC;YAC5D,CAAC;YAED,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,OAAe,EAAE,KAAa;IAC1E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,gBAAgB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Clock, RateLimitRequest, RateLimitResult, RateLimiter } from "./types.js";
|
|
2
|
+
export declare class FileRateLimiter implements RateLimiter {
|
|
3
|
+
private readonly stateFile;
|
|
4
|
+
private readonly lockDir;
|
|
5
|
+
private readonly clock;
|
|
6
|
+
constructor(options?: {
|
|
7
|
+
stateFile?: string;
|
|
8
|
+
clock?: Clock;
|
|
9
|
+
});
|
|
10
|
+
waitForTurn(request: RateLimitRequest): Promise<RateLimitResult>;
|
|
11
|
+
private readState;
|
|
12
|
+
private writeState;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=file-rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-rate-limiter.d.ts","sourceRoot":"","sources":["../src/file-rate-limiter.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAOxF,qBAAa,eAAgB,YAAW,WAAW;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAA;KAAO;IASzD,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;YA8CxD,SAAS;YAgBT,UAAU;CAMzB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { systemClock } from "./clock.js";
|
|
4
|
+
import { defaultStateDir } from "./file-cache.js";
|
|
5
|
+
import { withFileLock } from "./file-lock.js";
|
|
6
|
+
export class FileRateLimiter {
|
|
7
|
+
stateFile;
|
|
8
|
+
lockDir;
|
|
9
|
+
clock;
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
this.stateFile =
|
|
12
|
+
options.stateFile ??
|
|
13
|
+
process.env.DK_DOMAIN_AGENT_RATE_LIMIT_FILE ??
|
|
14
|
+
path.join(defaultStateDir(), "rate-limit.json");
|
|
15
|
+
this.lockDir = `${this.stateFile}.lock`;
|
|
16
|
+
this.clock = options.clock ?? systemClock;
|
|
17
|
+
}
|
|
18
|
+
async waitForTurn(request) {
|
|
19
|
+
const clock = request.clock ?? this.clock;
|
|
20
|
+
const startedAt = clock.now();
|
|
21
|
+
while (true) {
|
|
22
|
+
const acquired = await withFileLock(this.lockDir, { clock }, async () => {
|
|
23
|
+
const state = await this.readState();
|
|
24
|
+
const now = clock.now();
|
|
25
|
+
if (state.nextAllowedMs > now) {
|
|
26
|
+
return {
|
|
27
|
+
acquired: false,
|
|
28
|
+
waitMs: state.nextAllowedMs - now
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
await this.writeState({
|
|
32
|
+
version: 1,
|
|
33
|
+
nextAllowedMs: now + request.intervalMs
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
acquired: true,
|
|
37
|
+
waitMs: 0
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
if (acquired.acquired) {
|
|
41
|
+
return {
|
|
42
|
+
acquired: true,
|
|
43
|
+
waitedMs: clock.now() - startedAt
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const elapsedMs = clock.now() - startedAt;
|
|
47
|
+
if (elapsedMs + acquired.waitMs > request.maxWaitMs) {
|
|
48
|
+
return {
|
|
49
|
+
acquired: false,
|
|
50
|
+
waitedMs: elapsedMs
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
await clock.sleep(acquired.waitMs);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async readState() {
|
|
57
|
+
try {
|
|
58
|
+
const raw = await fs.readFile(this.stateFile, "utf8");
|
|
59
|
+
const parsed = JSON.parse(raw);
|
|
60
|
+
return {
|
|
61
|
+
version: 1,
|
|
62
|
+
nextAllowedMs: parsed.nextAllowedMs ?? 0
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (isMissingFile(error)) {
|
|
67
|
+
return { version: 1, nextAllowedMs: 0 };
|
|
68
|
+
}
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async writeState(state) {
|
|
73
|
+
await fs.mkdir(path.dirname(this.stateFile), { recursive: true });
|
|
74
|
+
const tmpFile = `${this.stateFile}.${process.pid}.tmp`;
|
|
75
|
+
await fs.writeFile(tmpFile, JSON.stringify(state, null, 2));
|
|
76
|
+
await fs.rename(tmpFile, this.stateFile);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function isMissingFile(error) {
|
|
80
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=file-rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-rate-limiter.js","sourceRoot":"","sources":["../src/file-rate-limiter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { checkDkDomainAvailability } from "./availability.js";
|
|
2
|
+
export { systemClock } from "./clock.js";
|
|
3
|
+
export { FileAvailabilityCache, defaultStateDir } from "./file-cache.js";
|
|
4
|
+
export { FileRateLimiter } from "./file-rate-limiter.js";
|
|
5
|
+
export { MemoryAvailabilityCache, MemoryRateLimiter } from "./memory-store.js";
|
|
6
|
+
export { normalizeDkDomain } from "./normalize.js";
|
|
7
|
+
export { parsePunktumWhois } from "./parser.js";
|
|
8
|
+
export { availabilityResult, invalidResult } from "./result.js";
|
|
9
|
+
export { ttlForStatus } from "./ttl.js";
|
|
10
|
+
export { PunktumWhoisClient } from "./whois-client.js";
|
|
11
|
+
export type { AvailabilityCache, AvailabilityConfidence, AvailabilityOptions, AvailabilityResult, AvailabilityStatus, CachedAvailability, Clock, NormalizedDomain, RateLimiter, RateLimitRequest, RateLimitResult, WhoisClient, WhoisParseResult } from "./types.js";
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EACV,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,gBAAgB,EACjB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { checkDkDomainAvailability } from "./availability.js";
|
|
2
|
+
export { systemClock } from "./clock.js";
|
|
3
|
+
export { FileAvailabilityCache, defaultStateDir } from "./file-cache.js";
|
|
4
|
+
export { FileRateLimiter } from "./file-rate-limiter.js";
|
|
5
|
+
export { MemoryAvailabilityCache, MemoryRateLimiter } from "./memory-store.js";
|
|
6
|
+
export { normalizeDkDomain } from "./normalize.js";
|
|
7
|
+
export { parsePunktumWhois } from "./parser.js";
|
|
8
|
+
export { availabilityResult, invalidResult } from "./result.js";
|
|
9
|
+
export { ttlForStatus } from "./ttl.js";
|
|
10
|
+
export { PunktumWhoisClient } from "./whois-client.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AvailabilityCache, AvailabilityResult, CachedAvailability, RateLimitRequest, RateLimitResult, RateLimiter } from "./types.js";
|
|
2
|
+
export declare class MemoryAvailabilityCache implements AvailabilityCache {
|
|
3
|
+
private readonly cache;
|
|
4
|
+
get(domain: string, nowMs: number): Promise<CachedAvailability | null>;
|
|
5
|
+
set(domain: string, result: AvailabilityResult, ttlSeconds: number, nowMs: number): Promise<void>;
|
|
6
|
+
clear(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare class MemoryRateLimiter implements RateLimiter {
|
|
9
|
+
private nextAllowedMs;
|
|
10
|
+
waitForTurn(request: RateLimitRequest): Promise<RateLimitResult>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=memory-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../src/memory-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,uBAAwB,YAAW,iBAAiB;IAC/D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyC;IAEzD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAQtE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAED,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,aAAa,CAAK;IAEpB,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;CA2BvE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export class MemoryAvailabilityCache {
|
|
2
|
+
cache = new Map();
|
|
3
|
+
async get(domain, nowMs) {
|
|
4
|
+
const cached = this.cache.get(domain);
|
|
5
|
+
if (!cached || cached.expiresAtMs <= nowMs) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
return cached;
|
|
9
|
+
}
|
|
10
|
+
async set(domain, result, ttlSeconds, nowMs) {
|
|
11
|
+
if (ttlSeconds <= 0)
|
|
12
|
+
return;
|
|
13
|
+
this.cache.set(domain, {
|
|
14
|
+
result,
|
|
15
|
+
expiresAtMs: nowMs + ttlSeconds * 1000
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async clear() {
|
|
19
|
+
this.cache.clear();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class MemoryRateLimiter {
|
|
23
|
+
nextAllowedMs = 0;
|
|
24
|
+
async waitForTurn(request) {
|
|
25
|
+
const startedAt = request.clock.now();
|
|
26
|
+
while (true) {
|
|
27
|
+
const now = request.clock.now();
|
|
28
|
+
if (this.nextAllowedMs <= now) {
|
|
29
|
+
this.nextAllowedMs = now + request.intervalMs;
|
|
30
|
+
return {
|
|
31
|
+
acquired: true,
|
|
32
|
+
waitedMs: now - startedAt
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const waitMs = this.nextAllowedMs - now;
|
|
36
|
+
const elapsedMs = now - startedAt;
|
|
37
|
+
if (elapsedMs + waitMs > request.maxWaitMs) {
|
|
38
|
+
return {
|
|
39
|
+
acquired: false,
|
|
40
|
+
waitedMs: elapsedMs
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
await request.clock.sleep(waitMs);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=memory-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../src/memory-store.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,uBAAuB;IACjB,KAAK,GAAG,IAAI,GAAG,EAA8B,CAAC;IAE/D,KAAK,CAAC,GAAG,CAAC,MAAc,EAAE,KAAa;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,WAAW,IAAI,KAAK,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAc,EAAE,MAA0B,EAAE,UAAkB,EAAE,KAAa;QACrF,IAAI,UAAU,IAAI,CAAC;YAAE,OAAO;QAC5B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE;YACrB,MAAM;YACN,WAAW,EAAE,KAAK,GAAG,UAAU,GAAG,IAAI;SACvC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAED,MAAM,OAAO,iBAAiB;IACpB,aAAa,GAAG,CAAC,CAAC;IAE1B,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAEtC,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YAEhC,IAAI,IAAI,CAAC,aAAa,IAAI,GAAG,EAAE,CAAC;gBAC9B,IAAI,CAAC,aAAa,GAAG,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;gBAC9C,OAAO;oBACL,QAAQ,EAAE,IAAI;oBACd,QAAQ,EAAE,GAAG,GAAG,SAAS;iBAC1B,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC;YACxC,MAAM,SAAS,GAAG,GAAG,GAAG,SAAS,CAAC;YAElC,IAAI,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC3C,OAAO;oBACL,QAAQ,EAAE,KAAK;oBACf,QAAQ,EAAE,SAAS;iBACpB,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAKnD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CA6BjE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { domainToASCII, domainToUnicode } from "node:url";
|
|
2
|
+
const DK_SUFFIX = ".dk";
|
|
3
|
+
const LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
|
|
4
|
+
export function normalizeDkDomain(input) {
|
|
5
|
+
const trimmed = input.trim().replace(/\.$/, "");
|
|
6
|
+
if (!trimmed) {
|
|
7
|
+
throw new Error("Domain is required.");
|
|
8
|
+
}
|
|
9
|
+
if (trimmed.includes(".") && !trimmed.toLowerCase().endsWith(DK_SUFFIX)) {
|
|
10
|
+
throw new Error("Only .dk domains are supported.");
|
|
11
|
+
}
|
|
12
|
+
const candidate = trimmed.toLowerCase().endsWith(DK_SUFFIX)
|
|
13
|
+
? trimmed.toLowerCase()
|
|
14
|
+
: `${trimmed.toLowerCase()}${DK_SUFFIX}`;
|
|
15
|
+
const asciiDomain = domainToASCII(candidate);
|
|
16
|
+
const unicodeDomain = domainToUnicode(asciiDomain);
|
|
17
|
+
if (!asciiDomain || !asciiDomain.endsWith(DK_SUFFIX)) {
|
|
18
|
+
throw new Error("Only .dk domains are supported.");
|
|
19
|
+
}
|
|
20
|
+
validateAsciiDomain(asciiDomain);
|
|
21
|
+
return {
|
|
22
|
+
input,
|
|
23
|
+
asciiDomain,
|
|
24
|
+
unicodeDomain
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function validateAsciiDomain(domain) {
|
|
28
|
+
if (domain.length > 253) {
|
|
29
|
+
throw new Error("Domain is too long.");
|
|
30
|
+
}
|
|
31
|
+
const labels = domain.split(".");
|
|
32
|
+
if (labels.length !== 2 || labels[1] !== "dk") {
|
|
33
|
+
throw new Error("Only second-level .dk domains are supported.");
|
|
34
|
+
}
|
|
35
|
+
if (!LABEL_PATTERN.test(labels[0])) {
|
|
36
|
+
throw new Error("Invalid .dk domain label.");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG1D,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,aAAa,GAAG,yCAAyC,CAAC;AAEhE,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEhD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QACzD,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE;QACvB,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,EAAE,CAAC;IAE3C,MAAM,WAAW,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAEnD,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAEjC,OAAO;QACL,KAAK;QACL,WAAW;QACX,aAAa;KACd,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAc;IACzC,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEjC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAOnD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAwC/D"}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const NOT_FOUND = /No entries found for the selected source\./i;
|
|
2
|
+
const DOMAIN_FIELD = /^Domain:\s+/im;
|
|
3
|
+
const WAITING_LIST = /(waiting list|offered to waiting list|Status:\s*Offered)/i;
|
|
4
|
+
const RATE_LIMIT = /(rate limit|temporar(?:y|ily)|ban|abuse|too many)/i;
|
|
5
|
+
export function parsePunktumWhois(raw) {
|
|
6
|
+
const text = raw.trim();
|
|
7
|
+
if (!text) {
|
|
8
|
+
return unknown();
|
|
9
|
+
}
|
|
10
|
+
if (RATE_LIMIT.test(text)) {
|
|
11
|
+
return {
|
|
12
|
+
available: null,
|
|
13
|
+
status: "rate_limited",
|
|
14
|
+
confidence: "unknown"
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (NOT_FOUND.test(text)) {
|
|
18
|
+
return {
|
|
19
|
+
available: true,
|
|
20
|
+
status: "probably_available",
|
|
21
|
+
confidence: "whois_inferred"
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (WAITING_LIST.test(text)) {
|
|
25
|
+
return {
|
|
26
|
+
available: false,
|
|
27
|
+
status: "offered_to_waiting_list",
|
|
28
|
+
confidence: "public_registry_lookup"
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (DOMAIN_FIELD.test(text)) {
|
|
32
|
+
return {
|
|
33
|
+
available: false,
|
|
34
|
+
status: "registered",
|
|
35
|
+
confidence: "public_registry_lookup"
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return unknown();
|
|
39
|
+
}
|
|
40
|
+
function unknown() {
|
|
41
|
+
return {
|
|
42
|
+
available: null,
|
|
43
|
+
status: "unknown",
|
|
44
|
+
confidence: "unknown"
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,6CAA6C,CAAC;AAChE,MAAM,YAAY,GAAG,eAAe,CAAC;AACrC,MAAM,YAAY,GAAG,2DAA2D,CAAC;AACjF,MAAM,UAAU,GAAG,oDAAoD,CAAC;AAExE,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAExB,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,cAAc;YACtB,UAAU,EAAE,SAAS;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,oBAAoB;YAC5B,UAAU,EAAE,gBAAgB;SAC7B,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,yBAAyB;YACjC,UAAU,EAAE,wBAAwB;SACrC,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,YAAY;YACpB,UAAU,EAAE,wBAAwB;SACrC,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED,SAAS,OAAO;IACd,OAAO;QACL,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,SAAS;QACjB,UAAU,EAAE,SAAS;KACtB,CAAC;AACJ,CAAC"}
|
package/dist/result.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AvailabilityResult, WhoisParseResult } from "./types.js";
|
|
2
|
+
export declare function invalidResult(input: string, checkedAt: string): AvailabilityResult;
|
|
3
|
+
export declare function availabilityResult(unicodeDomain: string, asciiDomain: string, parsed: WhoisParseResult, checkedAt: string, cacheHit: boolean, ttlSeconds: number | null): AvailabilityResult;
|
|
4
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAkBlF;AAED,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,kBAAkB,CAgBpB"}
|
package/dist/result.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function invalidResult(input, checkedAt) {
|
|
2
|
+
const domain = input.trim();
|
|
3
|
+
return {
|
|
4
|
+
domain,
|
|
5
|
+
unicodeDomain: domain,
|
|
6
|
+
asciiDomain: domain,
|
|
7
|
+
available: null,
|
|
8
|
+
status: "invalid",
|
|
9
|
+
confidence: "unknown",
|
|
10
|
+
source: "punktum_whois",
|
|
11
|
+
registrationRequiredForConfirmation: true,
|
|
12
|
+
checkedAt,
|
|
13
|
+
cache: {
|
|
14
|
+
hit: false,
|
|
15
|
+
ttlSeconds: null
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function availabilityResult(unicodeDomain, asciiDomain, parsed, checkedAt, cacheHit, ttlSeconds) {
|
|
20
|
+
return {
|
|
21
|
+
domain: unicodeDomain,
|
|
22
|
+
unicodeDomain,
|
|
23
|
+
asciiDomain,
|
|
24
|
+
available: parsed.available,
|
|
25
|
+
status: parsed.status,
|
|
26
|
+
confidence: parsed.confidence,
|
|
27
|
+
source: "punktum_whois",
|
|
28
|
+
registrationRequiredForConfirmation: true,
|
|
29
|
+
checkedAt,
|
|
30
|
+
cache: {
|
|
31
|
+
hit: cacheHit,
|
|
32
|
+
ttlSeconds
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,SAAiB;IAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE5B,OAAO;QACL,MAAM;QACN,aAAa,EAAE,MAAM;QACrB,WAAW,EAAE,MAAM;QACnB,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,SAAS;QACjB,UAAU,EAAE,SAAS;QACrB,MAAM,EAAE,eAAe;QACvB,mCAAmC,EAAE,IAAI;QACzC,SAAS;QACT,KAAK,EAAE;YACL,GAAG,EAAE,KAAK;YACV,UAAU,EAAE,IAAI;SACjB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,aAAqB,EACrB,WAAmB,EACnB,MAAwB,EACxB,SAAiB,EACjB,QAAiB,EACjB,UAAyB;IAEzB,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,aAAa;QACb,WAAW;QACX,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,eAAe;QACvB,mCAAmC,EAAE,IAAI;QACzC,SAAS;QACT,KAAK,EAAE;YACL,GAAG,EAAE,QAAQ;YACb,UAAU;SACX;KACF,CAAC;AACJ,CAAC"}
|
package/dist/ttl.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ttl.d.ts","sourceRoot":"","sources":["../src/ttl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAa/D"}
|
package/dist/ttl.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function ttlForStatus(status) {
|
|
2
|
+
switch (status) {
|
|
3
|
+
case "registered":
|
|
4
|
+
case "offered_to_waiting_list":
|
|
5
|
+
return 60 * 60 * 12;
|
|
6
|
+
case "probably_available":
|
|
7
|
+
return 60 * 10;
|
|
8
|
+
case "unknown":
|
|
9
|
+
case "rate_limited":
|
|
10
|
+
return 60 * 2;
|
|
11
|
+
case "invalid":
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=ttl.js.map
|
package/dist/ttl.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ttl.js","sourceRoot":"","sources":["../src/ttl.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAAC,MAA0B;IACrD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,YAAY,CAAC;QAClB,KAAK,yBAAyB;YAC5B,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QACtB,KAAK,oBAAoB;YACvB,OAAO,EAAE,GAAG,EAAE,CAAC;QACjB,KAAK,SAAS,CAAC;QACf,KAAK,cAAc;YACjB,OAAO,EAAE,GAAG,CAAC,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export type AvailabilityStatus = "probably_available" | "registered" | "offered_to_waiting_list" | "invalid" | "rate_limited" | "unknown";
|
|
2
|
+
export type AvailabilityConfidence = "whois_inferred" | "public_registry_lookup" | "unknown";
|
|
3
|
+
export type AvailabilityResult = {
|
|
4
|
+
domain: string;
|
|
5
|
+
unicodeDomain: string;
|
|
6
|
+
asciiDomain: string;
|
|
7
|
+
available: boolean | null;
|
|
8
|
+
status: AvailabilityStatus;
|
|
9
|
+
confidence: AvailabilityConfidence;
|
|
10
|
+
source: "punktum_whois";
|
|
11
|
+
registrationRequiredForConfirmation: true;
|
|
12
|
+
checkedAt: string;
|
|
13
|
+
cache: {
|
|
14
|
+
hit: boolean;
|
|
15
|
+
ttlSeconds: number | null;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export type NormalizedDomain = {
|
|
19
|
+
input: string;
|
|
20
|
+
unicodeDomain: string;
|
|
21
|
+
asciiDomain: string;
|
|
22
|
+
};
|
|
23
|
+
export type WhoisParseResult = Pick<AvailabilityResult, "available" | "status" | "confidence">;
|
|
24
|
+
export type AvailabilityOptions = {
|
|
25
|
+
bypassCache?: boolean;
|
|
26
|
+
timeoutMs?: number;
|
|
27
|
+
maxQueueWaitMs?: number;
|
|
28
|
+
clock?: Clock;
|
|
29
|
+
cache?: AvailabilityCache;
|
|
30
|
+
rateLimiter?: RateLimiter;
|
|
31
|
+
whoisClient?: WhoisClient;
|
|
32
|
+
};
|
|
33
|
+
export type WhoisClient = {
|
|
34
|
+
query(domain: string, timeoutMs: number): Promise<string>;
|
|
35
|
+
};
|
|
36
|
+
export type CachedAvailability = {
|
|
37
|
+
result: AvailabilityResult;
|
|
38
|
+
expiresAtMs: number;
|
|
39
|
+
};
|
|
40
|
+
export type AvailabilityCache = {
|
|
41
|
+
get(domain: string, nowMs: number): Promise<CachedAvailability | null>;
|
|
42
|
+
set(domain: string, result: AvailabilityResult, ttlSeconds: number, nowMs: number): Promise<void>;
|
|
43
|
+
clear(): Promise<void>;
|
|
44
|
+
close?(): void;
|
|
45
|
+
};
|
|
46
|
+
export type Clock = {
|
|
47
|
+
now(): number;
|
|
48
|
+
sleep(ms: number): Promise<void>;
|
|
49
|
+
};
|
|
50
|
+
export type RateLimitRequest = {
|
|
51
|
+
intervalMs: number;
|
|
52
|
+
maxWaitMs: number;
|
|
53
|
+
clock: Clock;
|
|
54
|
+
};
|
|
55
|
+
export type RateLimitResult = {
|
|
56
|
+
acquired: boolean;
|
|
57
|
+
waitedMs: number;
|
|
58
|
+
};
|
|
59
|
+
export type RateLimiter = {
|
|
60
|
+
waitForTurn(request: RateLimitRequest): Promise<RateLimitResult>;
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAC1B,oBAAoB,GACpB,YAAY,GACZ,yBAAyB,GACzB,SAAS,GACT,cAAc,GACd,SAAS,CAAC;AAEd,MAAM,MAAM,sBAAsB,GAC9B,gBAAgB,GAChB,wBAAwB,GACxB,SAAS,CAAC;AAEd,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,eAAe,CAAC;IACxB,mCAAmC,EAAE,IAAI,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QACL,GAAG,EAAE,OAAO,CAAC;QACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,kBAAkB,EAClB,WAAW,GAAG,QAAQ,GAAG,YAAY,CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3D,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;IACvE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,KAAK,CAAC,IAAI,IAAI,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,IAAI,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAClE,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { WhoisClient } from "./types.js";
|
|
2
|
+
export declare class PunktumWhoisClient implements WhoisClient {
|
|
3
|
+
private readonly host;
|
|
4
|
+
private readonly port;
|
|
5
|
+
constructor(host?: string, port?: number);
|
|
6
|
+
query(domain: string, timeoutMs: number): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=whois-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whois-client.d.ts","sourceRoot":"","sources":["../src/whois-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,qBAAa,kBAAmB,YAAW,WAAW;IACxC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAuB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAhD,IAAI,SAAqB,EAAmB,IAAI,SAAK;IAElF,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CA6B1D"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import net from "node:net";
|
|
2
|
+
export class PunktumWhoisClient {
|
|
3
|
+
host;
|
|
4
|
+
port;
|
|
5
|
+
constructor(host = "whois.punktum.dk", port = 43) {
|
|
6
|
+
this.host = host;
|
|
7
|
+
this.port = port;
|
|
8
|
+
}
|
|
9
|
+
query(domain, timeoutMs) {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
const socket = net.createConnection({ host: this.host, port: this.port });
|
|
12
|
+
const chunks = [];
|
|
13
|
+
let finished = false;
|
|
14
|
+
const finish = (error) => {
|
|
15
|
+
if (finished)
|
|
16
|
+
return;
|
|
17
|
+
finished = true;
|
|
18
|
+
socket.destroy();
|
|
19
|
+
if (error) {
|
|
20
|
+
reject(error);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
24
|
+
};
|
|
25
|
+
socket.setTimeout(timeoutMs);
|
|
26
|
+
socket.on("connect", () => {
|
|
27
|
+
socket.write(`${domain}\r\n`);
|
|
28
|
+
});
|
|
29
|
+
socket.on("data", chunk => chunks.push(Buffer.from(chunk)));
|
|
30
|
+
socket.on("end", () => finish());
|
|
31
|
+
socket.on("timeout", () => finish(new Error("WHOIS query timed out.")));
|
|
32
|
+
socket.on("error", error => finish(error));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=whois-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whois-client.js","sourceRoot":"","sources":["../src/whois-client.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAG3B,MAAM,OAAO,kBAAkB;IACA;IAA4C;IAAzE,YAA6B,OAAO,kBAAkB,EAAmB,OAAO,EAAE;QAArD,SAAI,GAAJ,IAAI,CAAqB;QAAmB,SAAI,GAAJ,IAAI,CAAK;IAAG,CAAC;IAEtF,KAAK,CAAC,MAAc,EAAE,SAAiB;QACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAC1E,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,IAAI,QAAQ,GAAG,KAAK,CAAC;YAErB,MAAM,MAAM,GAAG,CAAC,KAAa,EAAQ,EAAE;gBACrC,IAAI,QAAQ;oBAAE,OAAO;gBACrB,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM,CAAC,OAAO,EAAE,CAAC;gBAEjB,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,CAAC,KAAK,CAAC,CAAC;oBACd,OAAO;gBACT,CAAC;gBAED,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YAClD,CAAC,CAAC;YAEF,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAC7B,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;gBACxB,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC;YAChC,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;YACjC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;YACxE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dk-domain-agent-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core .dk WHOIS availability inference library.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"keywords": [
|
|
12
|
+
"dk",
|
|
13
|
+
"domain",
|
|
14
|
+
"whois",
|
|
15
|
+
"availability",
|
|
16
|
+
"punktum"
|
|
17
|
+
],
|
|
18
|
+
"main": "dist/index.js",
|
|
19
|
+
"types": "dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
28
|
+
"build": "npm run clean && tsc -p tsconfig.json",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {}
|
|
33
|
+
}
|