@undefineds.co/xpod 0.2.13 → 0.2.15

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.
@@ -1 +1 @@
1
- {"version":3,"file":"SubdomainClient.js","sourceRoot":"","sources":["../../src/subdomain/SubdomainClient.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SubdomainClient - Local 模式子域名客户端\n * \n * Local 模式不持有 DNS/Tunnel 密钥,通过调用 Cloud API 来管理子域名。\n * 使用 Node Token 认证(与 Edge Node 心跳相同的认证方式)。\n */\n\nimport { getLoggerFor } from 'global-logger-factory';\n\nexport interface SubdomainClientOptions {\n /** Cloud API 端点 (如 https://center.example.com/v1/subdomain) */\n cloudApiEndpoint: string;\n \n /** 节点 ID */\n nodeId: string;\n \n /** 节点 Token */\n nodeToken: string;\n \n /** 请求超时 (ms) */\n timeoutMs?: number;\n}\n\nexport interface SubdomainCheckResult {\n subdomain: string;\n available: boolean;\n reason?: string;\n}\n\nexport interface SubdomainRegistrationResult {\n success: boolean;\n subdomain: string;\n fullDomain: string;\n mode: 'direct' | 'tunnel';\n ipv4?: string;\n tunnelProvider?: string;\n tunnelEndpoint?: string;\n registeredAt: string;\n message?: string;\n}\n\nexport interface SubdomainInfo {\n subdomain: string;\n fullDomain: string;\n mode: 'direct' | 'tunnel';\n ipv4?: string;\n tunnelProvider?: string;\n tunnelEndpoint?: string;\n registeredAt: string;\n ownerId?: string;\n}\n\nexport interface DdnsAllocationResult {\n success: boolean;\n subdomain: string;\n domain: string;\n fqdn: string;\n ipAddress?: string;\n ipv6Address?: string;\n createdAt: string;\n}\n\nexport interface DdnsUpdateResult {\n success: boolean;\n subdomain: string;\n domain: string;\n fqdn: string;\n ipAddress?: string;\n ipv6Address?: string;\n updatedAt: string;\n}\n\nexport interface DdnsRecordInfo {\n subdomain: string;\n domain: string;\n fqdn: string;\n ipAddress?: string;\n ipv6Address?: string;\n recordType: string;\n status: string;\n ttl: number;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * 子域名客户端 (Local 模式)\n * \n * 通过 HTTP 调用 Cloud 的子域名 API\n */\nexport class SubdomainClient {\n private readonly logger = getLoggerFor(this);\n private readonly cloudApiEndpoint: string;\n private readonly nodeId: string;\n private readonly nodeToken: string;\n private readonly timeoutMs: number;\n\n constructor(options: SubdomainClientOptions) {\n this.cloudApiEndpoint = options.cloudApiEndpoint.replace(/\\/$/, '');\n this.nodeId = options.nodeId;\n this.nodeToken = options.nodeToken;\n this.timeoutMs = options.timeoutMs ?? 30000;\n }\n\n /**\n * 检查子域名可用性\n */\n async checkAvailability(name: string): Promise<SubdomainCheckResult> {\n const url = `${this.cloudApiEndpoint}/check?name=${encodeURIComponent(name)}`;\n const response = await this.fetch(url, { method: 'GET' });\n return response as SubdomainCheckResult;\n }\n\n /**\n * 注册子域名\n */\n async register(options: {\n subdomain: string;\n localPort: number;\n ipv4?: string;\n }): Promise<SubdomainRegistrationResult> {\n const url = `${this.cloudApiEndpoint}/register`;\n const response = await this.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n subdomain: options.subdomain,\n localPort: options.localPort,\n ipv4: options.ipv4,\n nodeId: this.nodeId,\n }),\n });\n return response as SubdomainRegistrationResult;\n }\n\n /**\n * 获取子域名信息\n */\n async getInfo(name: string): Promise<SubdomainInfo | null> {\n const url = `${this.cloudApiEndpoint}/${encodeURIComponent(name)}`;\n try {\n const response = await this.fetch(url, { method: 'GET' });\n return response as SubdomainInfo;\n } catch (error) {\n if (error instanceof SubdomainClientError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * 列出所有子域名\n */\n async list(): Promise<{ registrations: SubdomainInfo[]; total: number }> {\n const url = this.cloudApiEndpoint;\n const response = await this.fetch(url, { method: 'GET' });\n return response as { registrations: SubdomainInfo[]; total: number };\n }\n\n /**\n * 释放子域名\n */\n async release(name: string): Promise<{ success: boolean; message: string }> {\n const url = `${this.cloudApiEndpoint}/${encodeURIComponent(name)}`;\n const response = await this.fetch(url, { method: 'DELETE' });\n return response as { success: boolean; message: string };\n }\n\n /**\n * 启动隧道\n */\n async startTunnel(name: string): Promise<{ success: boolean; message: string }> {\n const url = `${this.cloudApiEndpoint}/${encodeURIComponent(name)}/start`;\n const response = await this.fetch(url, { method: 'POST' });\n return response as { success: boolean; message: string };\n }\n\n /**\n * 停止隧道\n */\n async stopTunnel(name: string): Promise<{ success: boolean; message: string }> {\n const url = `${this.cloudApiEndpoint}/${encodeURIComponent(name)}/stop`;\n const response = await this.fetch(url, { method: 'POST' });\n return response as { success: boolean; message: string };\n }\n\n // ============ DDNS API ============\n\n /**\n * 分配 DDNS 子域名\n */\n async allocateDdns(options: {\n subdomain: string;\n ipAddress?: string;\n ipv6Address?: string;\n mode?: 'direct' | 'tunnel';\n tunnelProvider?: string;\n }): Promise<DdnsAllocationResult> {\n const url = `${this.cloudApiEndpoint}/api/v1/ddns/allocate`;\n const response = await this.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n subdomain: options.subdomain,\n nodeId: this.nodeId,\n ipAddress: options.ipAddress,\n ipv6Address: options.ipv6Address,\n mode: options.mode,\n tunnelProvider: options.tunnelProvider,\n }),\n });\n return response as DdnsAllocationResult;\n }\n\n /**\n * 更新 DDNS 记录\n */\n async updateDdns(subdomain: string, options: {\n ipAddress?: string;\n ipv6Address?: string;\n mode?: 'direct' | 'tunnel';\n tunnelProvider?: string;\n }): Promise<DdnsUpdateResult> {\n const url = `${this.cloudApiEndpoint}/api/v1/ddns/${encodeURIComponent(subdomain)}`;\n const response = await this.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n ip: options.ipAddress,\n ipv6Address: options.ipv6Address,\n mode: options.mode,\n tunnelProvider: options.tunnelProvider,\n }),\n });\n return response as DdnsUpdateResult;\n }\n\n /**\n * 获取 DDNS 记录\n */\n async getDdns(subdomain: string): Promise<DdnsRecordInfo | null> {\n const url = `${this.cloudApiEndpoint}/api/v1/ddns/${encodeURIComponent(subdomain)}`;\n try {\n const response = await this.fetch(url, { method: 'GET' });\n return response as DdnsRecordInfo;\n } catch (error) {\n if (error instanceof SubdomainClientError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n // ============ Private Methods ============\n\n private async fetch(url: string, options: {\n method: string;\n body?: string;\n }): Promise<unknown> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n // 使用 undici 的 fetch,禁用代理\n const { fetch: undiciFetch, Agent } = await import('undici');\n const agent = new Agent({\n connect: { timeout: this.timeoutMs },\n });\n\n const response = await undiciFetch(url, {\n method: options.method,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `XpodNode ${this.nodeId}:${this.nodeToken}`,\n },\n body: options.body,\n signal: controller.signal,\n dispatcher: agent,\n });\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = (data as any)?.error ?? 'Unknown error';\n throw new SubdomainClientError(error, response.status);\n }\n\n return data;\n } catch (error) {\n if (error instanceof SubdomainClientError) {\n throw error;\n }\n if (error instanceof Error && error.name === 'AbortError') {\n throw new SubdomainClientError('Request timeout', 408);\n }\n throw new SubdomainClientError(\n error instanceof Error ? error.message : 'Unknown error',\n 500,\n );\n } finally {\n clearTimeout(timeout);\n }\n }\n}\n\n/**\n * SubdomainClient 错误\n */\nexport class SubdomainClientError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = 'SubdomainClientError';\n }\n}\n"]}
1
+ {"version":3,"file":"SubdomainClient.js","sourceRoot":"","sources":["../../src/subdomain/SubdomainClient.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SubdomainClient - Local 模式子域名客户端\n * \n * Local 模式不持有 DNS/Tunnel 密钥,通过调用 Cloud API 来管理子域名。\n * 使用 Node Token 认证(与 Edge Node 心跳相同的认证方式)。\n */\n\nimport { getLoggerFor } from 'global-logger-factory';\n\nexport interface SubdomainClientOptions {\n /** Cloud API 端点 (如 https://center.example.com/v1/subdomain) */\n cloudApiEndpoint: string;\n \n /** 节点 ID */\n nodeId: string;\n \n /** 节点 Token */\n nodeToken: string;\n \n /** 请求超时 (ms) */\n timeoutMs?: number;\n}\n\nexport interface SubdomainCheckResult {\n subdomain: string;\n available: boolean;\n reason?: string;\n}\n\nexport interface SubdomainRegistrationResult {\n success: boolean;\n subdomain: string;\n fullDomain: string;\n mode: 'direct' | 'tunnel';\n ipv4?: string;\n tunnelProvider?: string;\n tunnelEndpoint?: string;\n registeredAt: string;\n message?: string;\n}\n\nexport interface SubdomainInfo {\n subdomain: string;\n fullDomain: string;\n mode: 'direct' | 'tunnel';\n ipv4?: string;\n tunnelProvider?: string;\n tunnelEndpoint?: string;\n registeredAt: string;\n ownerId?: string;\n}\n\nexport interface DdnsAllocationResult {\n success: boolean;\n subdomain: string;\n domain: string;\n fqdn: string;\n ipAddress?: string;\n ipv6Address?: string;\n tunnelProvider?: string;\n tunnelToken?: string;\n tunnelEndpoint?: string;\n createdAt: string;\n}\n\nexport interface DdnsUpdateResult {\n success: boolean;\n subdomain: string;\n domain: string;\n fqdn: string;\n ipAddress?: string;\n ipv6Address?: string;\n tunnelProvider?: string;\n tunnelToken?: string;\n tunnelEndpoint?: string;\n updatedAt: string;\n}\n\nexport interface DdnsRecordInfo {\n subdomain: string;\n domain: string;\n fqdn: string;\n ipAddress?: string;\n ipv6Address?: string;\n recordType: string;\n status: string;\n ttl: number;\n tunnelProvider?: string;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * 子域名客户端 (Local 模式)\n * \n * 通过 HTTP 调用 Cloud 的子域名 API\n */\nexport class SubdomainClient {\n private readonly logger = getLoggerFor(this);\n private readonly cloudApiEndpoint: string;\n private readonly nodeId: string;\n private readonly nodeToken: string;\n private readonly timeoutMs: number;\n\n constructor(options: SubdomainClientOptions) {\n this.cloudApiEndpoint = options.cloudApiEndpoint.replace(/\\/$/, '');\n this.nodeId = options.nodeId;\n this.nodeToken = options.nodeToken;\n this.timeoutMs = options.timeoutMs ?? 30000;\n }\n\n /**\n * 检查子域名可用性\n */\n async checkAvailability(name: string): Promise<SubdomainCheckResult> {\n const url = `${this.cloudApiEndpoint}/check?name=${encodeURIComponent(name)}`;\n const response = await this.fetch(url, { method: 'GET' });\n return response as SubdomainCheckResult;\n }\n\n /**\n * 注册子域名\n */\n async register(options: {\n subdomain: string;\n localPort: number;\n ipv4?: string;\n }): Promise<SubdomainRegistrationResult> {\n const url = `${this.cloudApiEndpoint}/register`;\n const response = await this.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n subdomain: options.subdomain,\n localPort: options.localPort,\n ipv4: options.ipv4,\n nodeId: this.nodeId,\n }),\n });\n return response as SubdomainRegistrationResult;\n }\n\n /**\n * 获取子域名信息\n */\n async getInfo(name: string): Promise<SubdomainInfo | null> {\n const url = `${this.cloudApiEndpoint}/${encodeURIComponent(name)}`;\n try {\n const response = await this.fetch(url, { method: 'GET' });\n return response as SubdomainInfo;\n } catch (error) {\n if (error instanceof SubdomainClientError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * 列出所有子域名\n */\n async list(): Promise<{ registrations: SubdomainInfo[]; total: number }> {\n const url = this.cloudApiEndpoint;\n const response = await this.fetch(url, { method: 'GET' });\n return response as { registrations: SubdomainInfo[]; total: number };\n }\n\n /**\n * 释放子域名\n */\n async release(name: string): Promise<{ success: boolean; message: string }> {\n const url = `${this.cloudApiEndpoint}/${encodeURIComponent(name)}`;\n const response = await this.fetch(url, { method: 'DELETE' });\n return response as { success: boolean; message: string };\n }\n\n /**\n * 启动隧道\n */\n async startTunnel(name: string): Promise<{ success: boolean; message: string }> {\n const url = `${this.cloudApiEndpoint}/${encodeURIComponent(name)}/start`;\n const response = await this.fetch(url, { method: 'POST' });\n return response as { success: boolean; message: string };\n }\n\n /**\n * 停止隧道\n */\n async stopTunnel(name: string): Promise<{ success: boolean; message: string }> {\n const url = `${this.cloudApiEndpoint}/${encodeURIComponent(name)}/stop`;\n const response = await this.fetch(url, { method: 'POST' });\n return response as { success: boolean; message: string };\n }\n\n // ============ DDNS API ============\n\n /**\n * 分配 DDNS 子域名\n */\n async allocateDdns(options: {\n subdomain: string;\n ipAddress?: string;\n ipv6Address?: string;\n mode?: 'direct' | 'tunnel';\n tunnelProvider?: string;\n localPort?: number;\n }): Promise<DdnsAllocationResult> {\n const url = `${this.cloudApiEndpoint}/api/v1/ddns/allocate`;\n const response = await this.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n subdomain: options.subdomain,\n nodeId: this.nodeId,\n ipAddress: options.ipAddress,\n ipv6Address: options.ipv6Address,\n mode: options.mode,\n tunnelProvider: options.tunnelProvider,\n localPort: options.localPort,\n }),\n });\n return response as DdnsAllocationResult;\n }\n\n /**\n * 更新 DDNS 记录\n */\n async updateDdns(subdomain: string, options: {\n ipAddress?: string;\n ipv6Address?: string;\n mode?: 'direct' | 'tunnel';\n tunnelProvider?: string;\n localPort?: number;\n }): Promise<DdnsUpdateResult> {\n const url = `${this.cloudApiEndpoint}/api/v1/ddns/${encodeURIComponent(subdomain)}`;\n const response = await this.fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n ip: options.ipAddress,\n ipv6Address: options.ipv6Address,\n mode: options.mode,\n tunnelProvider: options.tunnelProvider,\n localPort: options.localPort,\n }),\n });\n return response as DdnsUpdateResult;\n }\n\n /**\n * 获取 DDNS 记录\n */\n async getDdns(subdomain: string): Promise<DdnsRecordInfo | null> {\n const url = `${this.cloudApiEndpoint}/api/v1/ddns/${encodeURIComponent(subdomain)}`;\n try {\n const response = await this.fetch(url, { method: 'GET' });\n return response as DdnsRecordInfo;\n } catch (error) {\n if (error instanceof SubdomainClientError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n // ============ Private Methods ============\n\n private async fetch(url: string, options: {\n method: string;\n body?: string;\n }): Promise<unknown> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n // 使用 undici 的 fetch,禁用代理\n const { fetch: undiciFetch, Agent } = await import('undici');\n const agent = new Agent({\n connect: { timeout: this.timeoutMs },\n });\n\n const response = await undiciFetch(url, {\n method: options.method,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `XpodNode ${this.nodeId}:${this.nodeToken}`,\n },\n body: options.body,\n signal: controller.signal,\n dispatcher: agent,\n });\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = (data as any)?.error ?? 'Unknown error';\n throw new SubdomainClientError(error, response.status);\n }\n\n return data;\n } catch (error) {\n if (error instanceof SubdomainClientError) {\n throw error;\n }\n if (error instanceof Error && error.name === 'AbortError') {\n throw new SubdomainClientError('Request timeout', 408);\n }\n throw new SubdomainClientError(\n error instanceof Error ? error.message : 'Unknown error',\n 500,\n );\n } finally {\n clearTimeout(timeout);\n }\n }\n}\n\n/**\n * SubdomainClient 错误\n */\nexport class SubdomainClientError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = 'SubdomainClientError';\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/xpod",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Xpod is an extended Community Solid Server, offering rich-feature, production-level Solid Pod and identity management.",
5
5
  "repository": "https://github.com/undefinedsco/xpod",
6
6
  "author": "developer@undefineds.co",