@undefineds.co/xpod 0.3.29 → 0.3.32

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 (167) hide show
  1. package/dist/api/auth/AuthContext.d.ts +3 -2
  2. package/dist/api/auth/AuthContext.js +2 -1
  3. package/dist/api/auth/AuthContext.js.map +1 -1
  4. package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +2 -12
  5. package/dist/api/auth/ClientCredentialsAuthenticator.js +4 -4
  6. package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
  7. package/dist/api/auth/ServiceTokenAuthenticator.d.ts +2 -2
  8. package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -1
  9. package/dist/api/container/business-token.d.ts +1 -1
  10. package/dist/api/container/business-token.js +5 -1
  11. package/dist/api/container/business-token.js.map +1 -1
  12. package/dist/api/container/common.js +14 -10
  13. package/dist/api/container/common.js.map +1 -1
  14. package/dist/api/container/routes.js +16 -3
  15. package/dist/api/container/routes.js.map +1 -1
  16. package/dist/api/container/types.d.ts +2 -4
  17. package/dist/api/container/types.js.map +1 -1
  18. package/dist/api/handlers/ChatHandler.d.ts +1 -1
  19. package/dist/api/handlers/ChatHandler.js +1 -1
  20. package/dist/api/handlers/ChatHandler.js.map +1 -1
  21. package/dist/api/handlers/EdgeNodeSignalHandler.js +3 -1
  22. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -1
  23. package/dist/api/handlers/PodManagementHandler.d.ts +2 -0
  24. package/dist/api/handlers/PodManagementHandler.js +114 -12
  25. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  26. package/dist/api/handlers/ProvisionHandler.d.ts +27 -0
  27. package/dist/api/handlers/ProvisionHandler.js +339 -32
  28. package/dist/api/handlers/ProvisionHandler.js.map +1 -1
  29. package/dist/api/handlers/QuotaHandler.js +0 -12
  30. package/dist/api/handlers/QuotaHandler.js.map +1 -1
  31. package/dist/api/handlers/index.d.ts +0 -1
  32. package/dist/api/handlers/index.js +0 -1
  33. package/dist/api/handlers/index.js.map +1 -1
  34. package/dist/api/runtime.js +3 -3
  35. package/dist/api/runtime.js.map +1 -1
  36. package/dist/authorization/PodAuthorizationResources.d.ts +1 -0
  37. package/dist/authorization/PodAuthorizationResources.js +36 -4
  38. package/dist/authorization/PodAuthorizationResources.js.map +1 -1
  39. package/dist/components/context.jsonld +12 -0
  40. package/dist/edge/EdgeNodeAgent.d.ts +1 -1
  41. package/dist/edge/EdgeNodeAgent.js +1 -1
  42. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  43. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -0
  44. package/dist/edge/EdgeNodeDnsCoordinator.js +9 -3
  45. package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
  46. package/dist/edge/EdgeNodeDnsCoordinator.jsonld +4 -0
  47. package/dist/edge/EdgeNodeHealthProbeService.d.ts +3 -0
  48. package/dist/edge/EdgeNodeHealthProbeService.js +22 -2
  49. package/dist/edge/EdgeNodeHealthProbeService.js.map +1 -1
  50. package/dist/edge/EdgeNodeHealthProbeService.jsonld +12 -0
  51. package/dist/http/ClusterIngressRouter.js +6 -3
  52. package/dist/http/ClusterIngressRouter.js.map +1 -1
  53. package/dist/http/ClusterWebSocketConfigurator.js +6 -2
  54. package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
  55. package/dist/http/EdgeNodeDirectDebugHttpHandler.d.ts +2 -0
  56. package/dist/http/EdgeNodeDirectDebugHttpHandler.js +18 -3
  57. package/dist/http/EdgeNodeDirectDebugHttpHandler.js.map +1 -1
  58. package/dist/http/EdgeNodeDirectDebugHttpHandler.jsonld +8 -0
  59. package/dist/http/EdgeNodeProxyHttpHandler.js +6 -2
  60. package/dist/http/EdgeNodeProxyHttpHandler.js.map +1 -1
  61. package/dist/http/cluster/PodMigrationHttpHandler.d.ts +2 -2
  62. package/dist/http/cluster/PodMigrationHttpHandler.js +2 -2
  63. package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
  64. package/dist/http/quota/QuotaAdminHttpHandler.js +27 -21
  65. package/dist/http/quota/QuotaAdminHttpHandler.js.map +1 -1
  66. package/dist/identity/drizzle/AccountRepository.d.ts +4 -22
  67. package/dist/identity/drizzle/AccountRepository.js +9 -113
  68. package/dist/identity/drizzle/AccountRepository.js.map +1 -1
  69. package/dist/identity/drizzle/AccountRoleRepository.d.ts +5 -5
  70. package/dist/identity/drizzle/AccountRoleRepository.js +204 -97
  71. package/dist/identity/drizzle/AccountRoleRepository.js.map +1 -1
  72. package/dist/identity/drizzle/DdnsRepository.d.ts +5 -20
  73. package/dist/identity/drizzle/DdnsRepository.js +13 -49
  74. package/dist/identity/drizzle/DdnsRepository.js.map +1 -1
  75. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +13 -6
  76. package/dist/identity/drizzle/EdgeNodeRepository.js +167 -66
  77. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  78. package/dist/identity/drizzle/PodLookupRepository.d.ts +7 -36
  79. package/dist/identity/drizzle/PodLookupRepository.js +103 -126
  80. package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
  81. package/dist/identity/drizzle/ServiceTokenRepository.d.ts +13 -1
  82. package/dist/identity/drizzle/ServiceTokenRepository.js +7 -0
  83. package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -1
  84. package/dist/identity/drizzle/db.d.ts +2 -1
  85. package/dist/identity/drizzle/db.js +173 -297
  86. package/dist/identity/drizzle/db.js.map +1 -1
  87. package/dist/identity/drizzle/schema.pg.d.ts +3 -11
  88. package/dist/identity/drizzle/schema.pg.js +10 -45
  89. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  90. package/dist/identity/drizzle/schema.sqlite.d.ts +88 -531
  91. package/dist/identity/drizzle/schema.sqlite.js +13 -46
  92. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  93. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +3 -0
  94. package/dist/identity/oidc/ScopedPickWebIdHandler.js +18 -6
  95. package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -1
  96. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +22 -0
  97. package/dist/provision/LocalPodProvisioningService.js +2 -0
  98. package/dist/provision/LocalPodProvisioningService.js.map +1 -1
  99. package/dist/provision/ProvisionCodeCodec.js +10 -1
  100. package/dist/provision/ProvisionCodeCodec.js.map +1 -1
  101. package/dist/provision/ProvisionPodCreator.d.ts +8 -2
  102. package/dist/provision/ProvisionPodCreator.js +136 -27
  103. package/dist/provision/ProvisionPodCreator.js.map +1 -1
  104. package/dist/provision/ProvisionPodCreator.jsonld +38 -3
  105. package/dist/quota/DrizzleQuotaService.d.ts +0 -4
  106. package/dist/quota/DrizzleQuotaService.js +1 -21
  107. package/dist/quota/DrizzleQuotaService.js.map +1 -1
  108. package/dist/quota/DrizzleQuotaService.jsonld +0 -16
  109. package/dist/quota/NoopQuotaService.d.ts +0 -4
  110. package/dist/quota/NoopQuotaService.js +0 -8
  111. package/dist/quota/NoopQuotaService.js.map +1 -1
  112. package/dist/quota/NoopQuotaService.jsonld +0 -16
  113. package/dist/quota/QuotaService.d.ts +0 -4
  114. package/dist/quota/QuotaService.js.map +1 -1
  115. package/dist/quota/QuotaService.jsonld +0 -16
  116. package/dist/service/EdgeNodeSignalClient.d.ts +0 -2
  117. package/dist/service/EdgeNodeSignalClient.js +0 -4
  118. package/dist/service/EdgeNodeSignalClient.js.map +1 -1
  119. package/dist/service/PodMigrationService.d.ts +2 -2
  120. package/dist/service/PodMigrationService.js +4 -4
  121. package/dist/service/PodMigrationService.js.map +1 -1
  122. package/dist/setup/LocalSetupServiceTokenRepository.d.ts +22 -0
  123. package/dist/setup/LocalSetupServiceTokenRepository.js +68 -0
  124. package/dist/setup/LocalSetupServiceTokenRepository.js.map +1 -0
  125. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  126. package/dist/storage/quota/PerAccountQuotaStrategy.js +2 -2
  127. package/dist/storage/quota/PerAccountQuotaStrategy.js.map +1 -1
  128. package/dist/storage/quota/UsageRepository.d.ts +10 -32
  129. package/dist/storage/quota/UsageRepository.js +84 -281
  130. package/dist/storage/quota/UsageRepository.js.map +1 -1
  131. package/dist/storage/rdf/PostgresRdfEngine.d.ts +12 -15
  132. package/dist/storage/rdf/PostgresRdfEngine.js +1040 -150
  133. package/dist/storage/rdf/PostgresRdfEngine.js.map +1 -1
  134. package/dist/storage/rdf/PostgresRdfEngine.jsonld +40 -52
  135. package/dist/storage/rdf/{RdfLocalQueryEngine.d.ts → RdfQueryExecutor.d.ts} +3 -3
  136. package/dist/storage/rdf/{RdfLocalQueryEngine.js → RdfQueryExecutor.js} +9 -9
  137. package/dist/storage/rdf/RdfQueryExecutor.js.map +1 -0
  138. package/dist/storage/rdf/RdfSparqlAdapter.d.ts +5 -5
  139. package/dist/storage/rdf/RdfSparqlAdapter.js +27 -27
  140. package/dist/storage/rdf/RdfSparqlAdapter.js.map +1 -1
  141. package/dist/storage/rdf/SolidRdfEngine.d.ts +2 -5
  142. package/dist/storage/rdf/SolidRdfEngine.js +6 -38
  143. package/dist/storage/rdf/SolidRdfEngine.js.map +1 -1
  144. package/dist/storage/rdf/SolidRdfEngine.jsonld +0 -12
  145. package/dist/storage/rdf/SolidRdfSparqlEngine.js.map +1 -1
  146. package/dist/storage/rdf/index.d.ts +3 -3
  147. package/dist/storage/rdf/index.js +6 -6
  148. package/dist/storage/rdf/index.js.map +1 -1
  149. package/dist/storage/rdf/models-benchmark.d.ts +9 -9
  150. package/dist/storage/rdf/models-benchmark.js +23 -23
  151. package/dist/storage/rdf/models-benchmark.js.map +1 -1
  152. package/dist/storage/rdf/types.d.ts +5 -5
  153. package/dist/storage/rdf/types.js.map +1 -1
  154. package/dist/subdomain/SubdomainService.d.ts +1 -1
  155. package/dist/subdomain/SubdomainService.js +1 -1
  156. package/dist/subdomain/SubdomainService.js.map +1 -1
  157. package/dist/subdomain/SubdomainService.jsonld +1 -1
  158. package/package.json +1 -1
  159. package/templates/pod/acp/profile/.acr +21 -0
  160. package/templates/pod/wac/profile/.acl.hbs +18 -0
  161. package/dist/api/handlers/ApiKeyHandler.d.ts +0 -15
  162. package/dist/api/handlers/ApiKeyHandler.js +0 -153
  163. package/dist/api/handlers/ApiKeyHandler.js.map +0 -1
  164. package/dist/api/store/DrizzleClientCredentialsStore.d.ts +0 -51
  165. package/dist/api/store/DrizzleClientCredentialsStore.js +0 -115
  166. package/dist/api/store/DrizzleClientCredentialsStore.js.map +0 -1
  167. package/dist/storage/rdf/RdfLocalQueryEngine.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"EdgeNodeRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/EdgeNodeRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes, randomUUID, createHash, timingSafeEqual } from 'node:crypto';\nimport { sql, eq } from 'drizzle-orm';\nimport type { IdentityDatabase } from './db';\nimport { executeStatement, executeQuery, toDbTimestamp, fromDbTimestamp } from './db';\nimport { edgeNodes } from './schema';\n\nexport interface EdgeNodeSummary {\n nodeId: string;\n displayName?: string;\n nodeType: 'center' | 'edge' | 'sp';\n podCount: number;\n createdAt?: string;\n updatedAt?: string;\n lastSeen?: string;\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface CreateEdgeNodeResult {\n nodeId: string;\n token: string;\n createdAt: string;\n}\n\nexport interface EdgeNodeSecret {\n nodeId: string;\n displayName?: string;\n tokenHash: string;\n nodeType: 'center' | 'edge' | 'sp';\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface CenterNodeInfo {\n nodeId: string;\n displayName?: string;\n internalIp: string;\n internalPort: number;\n connectivityStatus: 'unknown' | 'reachable' | 'unreachable';\n lastSeen?: Date;\n}\n\nexport interface CreateSpNodeResult {\n nodeId: string;\n nodeToken: string;\n serviceToken: string;\n createdAt: string;\n}\n\nexport interface SpNodeInfo {\n nodeId: string;\n displayName?: string;\n publicUrl: string;\n serviceTokenHash: string;\n lastSeen?: Date;\n}\n\nexport class EdgeNodeRepository {\n public constructor(private readonly db: IdentityDatabase) {}\n\n public async listNodes(): Promise<EdgeNodeSummary[]> {\n const result = await executeQuery(this.db, sql`\n SELECT en.id,\n en.display_name,\n en.node_type,\n en.created_at,\n en.updated_at,\n en.last_seen,\n en.metadata,\n COALESCE(pods.count, 0) AS pod_count\n FROM identity_edge_node en\n LEFT JOIN (\n SELECT node_id, COUNT(*) AS count\n FROM identity_edge_node_pod\n GROUP BY node_id\n ) pods ON pods.node_id = en.id\n ORDER BY en.created_at ASC\n `);\n\n return result.rows.map((row: any): EdgeNodeSummary => {\n const createdAt = fromDbTimestamp(row.created_at);\n const updatedAt = fromDbTimestamp(row.updated_at);\n const lastSeen = fromDbTimestamp(row.last_seen);\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n nodeType: (['center', 'edge', 'sp'].includes(row.node_type) ? row.node_type : 'edge') as 'center' | 'edge' | 'sp',\n podCount: Number(row.pod_count ?? 0),\n createdAt: createdAt?.toISOString(),\n updatedAt: updatedAt?.toISOString(),\n lastSeen: lastSeen?.toISOString(),\n metadata: typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata ?? null),\n };\n });\n }\n\n public async createNode(displayName?: string, _accountId?: string): Promise<CreateEdgeNodeResult> {\n const nodeId = randomUUID();\n const token = randomBytes(32).toString('base64url');\n const tokenHash = createHash('sha256').update(token).digest('hex');\n const now = new Date();\n const ts = toDbTimestamp(this.db, now);\n\n await executeStatement(this.db, sql`\n INSERT INTO identity_edge_node (id, display_name, token_hash, created_at, updated_at)\n VALUES (${nodeId}, ${displayName ?? null}, ${tokenHash}, ${ts}, ${ts})\n `);\n\n return {\n nodeId,\n token,\n createdAt: now.toISOString(),\n };\n }\n\n /**\n * Node/account 关系待产品化后单独建模;当前阶段不再在节点表上持久化账号归属。\n */\n public async getNodeOwner(_nodeId: string): Promise<string | undefined> {\n return undefined;\n }\n\n public async getNodeSecret(nodeId: string): Promise<EdgeNodeSecret | undefined> {\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, token_hash, node_type, metadata\n FROM identity_edge_node\n WHERE id = ${nodeId}\n LIMIT 1\n `);\n if (result.rows.length === 0) {\n return undefined;\n }\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n tokenHash: String(row.token_hash ?? ''),\n nodeType: (['center', 'edge', 'sp'].includes(row.node_type) ? row.node_type : 'edge') as 'center' | 'edge' | 'sp',\n metadata: typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata ?? null),\n };\n }\n\n public async updateNodeHeartbeat(nodeId: string, metadata: Record<string, unknown> | null, timestamp: Date): Promise<void> {\n const payload = metadata == null ? null : JSON.stringify(metadata);\n const ts = toDbTimestamp(this.db, timestamp);\n\n await executeStatement(this.db, sql`\n UPDATE identity_edge_node\n SET metadata = ${payload},\n last_seen = ${ts},\n updated_at = ${ts}\n WHERE id = ${nodeId}\n `);\n }\n\n public async updateNodeMode(nodeId: string, options: {\n accessMode: 'direct' | 'proxy';\n ipv4?: string;\n publicPort?: number;\n subdomain?: string;\n connectivityStatus?: 'unknown' | 'reachable' | 'unreachable';\n capabilities?: Record<string, unknown>;\n }): Promise<void> {\n const capabilitiesPayload = options.capabilities ? JSON.stringify(options.capabilities) : null;\n const now = new Date();\n const ts = toDbTimestamp(this.db, now);\n\n await executeStatement(this.db, sql`\n UPDATE identity_edge_node\n SET access_mode = ${options.accessMode},\n ipv4 = ${options.ipv4 ?? null},\n public_port = ${options.publicPort ?? null},\n subdomain = ${options.subdomain ?? null},\n connectivity_status = ${options.connectivityStatus ?? 'unknown'},\n capabilities = ${capabilitiesPayload},\n last_connectivity_check = ${ts},\n updated_at = ${ts}\n WHERE id = ${nodeId}\n `);\n }\n\n public async getNodeConnectivityInfo(nodeId: string): Promise<{\n nodeId: string;\n accessMode?: string;\n ipv4?: string;\n publicPort?: number;\n subdomain?: string;\n connectivityStatus?: string;\n lastConnectivityCheck?: Date;\n } | undefined> {\n const result = await executeQuery(this.db, sql`\n SELECT id, access_mode, ipv4, public_port, subdomain,\n connectivity_status, last_connectivity_check\n FROM identity_edge_node\n WHERE id = ${nodeId}\n LIMIT 1\n `);\n\n if (result.rows.length === 0) {\n return undefined;\n }\n\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n accessMode: row.access_mode ? String(row.access_mode) : undefined,\n ipv4: row.ipv4 ? String(row.ipv4) : undefined,\n publicPort: row.public_port ? Number(row.public_port) : undefined,\n subdomain: row.subdomain ? String(row.subdomain) : undefined,\n connectivityStatus: row.connectivity_status ? String(row.connectivity_status) : undefined,\n lastConnectivityCheck: fromDbTimestamp(row.last_connectivity_check),\n };\n }\n\n public async mergeNodeMetadata(nodeId: string, patch: Record<string, unknown>): Promise<void> {\n // Read current metadata\n const current = await this.getNodeMetadata(nodeId);\n if (!current) {\n throw new Error(`Node ${nodeId} not found`);\n }\n\n // Merge in application layer\n const merged = { ...(current.metadata ?? {}), ...patch };\n const payload = JSON.stringify(merged);\n const ts = toDbTimestamp(this.db, new Date());\n\n await executeStatement(this.db, sql`\n UPDATE identity_edge_node\n SET metadata = ${payload},\n updated_at = ${ts}\n WHERE id = ${nodeId}\n `);\n }\n\n public async getNodeMetadata(nodeId: string): Promise<{ nodeId: string; metadata: Record<string, unknown> | null; lastSeen?: Date } | undefined> {\n const result = await executeQuery(this.db, sql`\n SELECT id, metadata, last_seen\n FROM identity_edge_node\n WHERE id = ${nodeId}\n LIMIT 1\n `);\n if (result.rows.length === 0) {\n return undefined;\n }\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n metadata: typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata ?? null),\n lastSeen: fromDbTimestamp(row.last_seen),\n };\n }\n\n public async replaceNodePods(nodeId: string, pods: string[]): Promise<void> {\n await this.db.transaction(async (tx: IdentityDatabase) => {\n await tx.execute(sql`DELETE FROM identity_edge_node_pod WHERE node_id = ${nodeId}`);\n if (pods.length > 0) {\n const values = pods.map((baseUrl) => sql`(${nodeId}, ${baseUrl})`);\n await tx.execute(sql`\n INSERT INTO identity_edge_node_pod (node_id, base_url)\n VALUES ${sql.join(values, sql`, `)}\n ON CONFLICT DO NOTHING\n `);\n }\n });\n }\n\n public async findNodeByResourcePath(path: string): Promise<{ nodeId: string; baseUrl: string; accessMode?: string; metadata?: Record<string, unknown> | null } | undefined> {\n const result = await executeQuery(this.db, sql`\n SELECT en.id,\n en.access_mode,\n en.metadata,\n pods.base_url\n FROM identity_edge_node_pod pods\n JOIN identity_edge_node en ON en.id = pods.node_id\n WHERE ${path} LIKE pods.base_url || '%'\n ORDER BY length(pods.base_url) DESC\n LIMIT 1\n `);\n if (result.rows.length === 0) {\n return undefined;\n }\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n baseUrl: String(row.base_url),\n accessMode: row.access_mode ? String(row.access_mode) : undefined,\n metadata: row.metadata ?? null,\n };\n }\n\n public async findNodeBySubdomain(hostname: string): Promise<{ nodeId: string; accessMode?: string; metadata?: Record<string, unknown> | null; subdomain?: string } | undefined> {\n const normalized = hostname.trim().toLowerCase();\n if (normalized.length === 0) {\n return undefined;\n }\n const result = await executeQuery(this.db, sql`\n SELECT id, access_mode, metadata, subdomain\n FROM identity_edge_node\n WHERE subdomain = ${normalized}\n LIMIT 1\n `);\n if (result.rows.length === 0) {\n return undefined;\n }\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n accessMode: row.access_mode ? String(row.access_mode) : undefined,\n metadata: row.metadata ?? null,\n subdomain: row.subdomain ? String(row.subdomain) : undefined,\n };\n }\n\n public matchesToken(tokenHash: string, token: string): boolean {\n if (!tokenHash || typeof tokenHash !== 'string') {\n return false;\n }\n try {\n const expected = Buffer.from(tokenHash, 'hex');\n const actual = createHash('sha256').update(token).digest();\n if (expected.length !== actual.length) {\n return false;\n }\n return timingSafeEqual(expected, actual);\n } catch {\n return false;\n }\n }\n\n /**\n * Get node capabilities and related information for admin queries\n */\n public async getNodeCapabilities(nodeId: string): Promise<{\n nodeId: string;\n capabilities: Record<string, unknown> | null;\n stringCapabilities: string[] | null;\n accessMode: string | null;\n lastSeen: Date | null;\n connectivityStatus: string | null;\n } | undefined> {\n const row = await this.db\n .select({\n id: edgeNodes.id,\n capabilities: edgeNodes.capabilities,\n metadata: edgeNodes.metadata,\n accessMode: edgeNodes.accessMode,\n lastSeen: edgeNodes.lastSeen,\n connectivityStatus: edgeNodes.connectivityStatus,\n })\n .from(edgeNodes)\n .where(eq(edgeNodes.id, nodeId))\n .limit(1);\n\n if (row.length === 0) {\n return undefined;\n }\n\n const node = row[0];\n const metadata = node.metadata as Record<string, unknown> | null;\n \n return {\n nodeId: node.id,\n capabilities: node.capabilities as Record<string, unknown> | null,\n stringCapabilities: metadata?.capabilities as string[] ?? null,\n accessMode: node.accessMode,\n lastSeen: node.lastSeen,\n connectivityStatus: node.connectivityStatus,\n };\n }\n\n /**\n * List all nodes with their capability information\n */\n public async listNodeCapabilities(): Promise<Array<{\n nodeId: string;\n capabilities: Record<string, unknown> | null;\n stringCapabilities: string[] | null;\n accessMode: string | null;\n lastSeen: Date | null;\n connectivityStatus: string | null;\n }>> {\n const rows = await this.db\n .select({\n id: edgeNodes.id,\n capabilities: edgeNodes.capabilities,\n metadata: edgeNodes.metadata,\n accessMode: edgeNodes.accessMode,\n lastSeen: edgeNodes.lastSeen,\n connectivityStatus: edgeNodes.connectivityStatus,\n })\n .from(edgeNodes)\n .orderBy(edgeNodes.lastSeen);\n\n return rows.map((row: typeof rows[0]) => {\n const metadata = row.metadata as Record<string, unknown> | null;\n \n return {\n nodeId: row.id,\n capabilities: row.capabilities as Record<string, unknown> | null,\n stringCapabilities: metadata?.capabilities as string[] ?? null,\n accessMode: row.accessMode,\n lastSeen: row.lastSeen,\n connectivityStatus: row.connectivityStatus,\n };\n });\n }\n\n // ============ Center Node Methods ============\n\n /**\n * Register or update a center node in the cluster.\n * Center nodes use the same table as edge nodes but with nodeType='center'.\n */\n public async registerCenterNode(options: {\n nodeId: string;\n displayName?: string;\n internalIp: string;\n internalPort: number;\n }): Promise<{ nodeId: string; token: string }> {\n const token = randomBytes(32).toString('base64url');\n const tokenHash = createHash('sha256').update(token).digest('hex');\n const now = Math.floor(Date.now() / 1000); // Unix timestamp for SQLite compatibility\n\n // Use upsert pattern: INSERT ... ON CONFLICT UPDATE\n await executeStatement(this.db, sql`\n INSERT INTO identity_edge_node (\n id, display_name, token_hash, node_type, internal_ip, internal_port,\n connectivity_status, created_at, updated_at, last_seen\n )\n VALUES (\n ${options.nodeId}, ${options.displayName ?? null}, ${tokenHash}, 'center',\n ${options.internalIp}, ${options.internalPort}, 'unknown', ${now}, ${now}, ${now}\n )\n ON CONFLICT (id) DO UPDATE SET\n display_name = EXCLUDED.display_name,\n internal_ip = EXCLUDED.internal_ip,\n internal_port = EXCLUDED.internal_port,\n updated_at = EXCLUDED.updated_at,\n last_seen = EXCLUDED.last_seen\n `);\n\n return { nodeId: options.nodeId, token };\n }\n\n /**\n * Update center node heartbeat with internal endpoint info.\n */\n public async updateCenterNodeHeartbeat(\n nodeId: string,\n internalIp: string,\n internalPort: number,\n timestamp: Date,\n ): Promise<void> {\n const ts = Math.floor(timestamp.getTime() / 1000); // Unix timestamp for SQLite compatibility\n await executeStatement(this.db, sql`\n UPDATE identity_edge_node\n SET internal_ip = ${internalIp},\n internal_port = ${internalPort},\n last_seen = ${ts},\n updated_at = ${ts},\n connectivity_status = 'reachable'\n WHERE id = ${nodeId} AND node_type = 'center'\n `);\n }\n\n /**\n * List all center nodes in the cluster.\n */\n public async listCenterNodes(): Promise<CenterNodeInfo[]> {\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, internal_ip, internal_port, connectivity_status, last_seen\n FROM identity_edge_node\n WHERE node_type = 'center'\n ORDER BY created_at ASC\n `);\n\n return result.rows.map((row: any): CenterNodeInfo => ({\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n internalIp: String(row.internal_ip ?? ''),\n internalPort: Number(row.internal_port ?? 0),\n connectivityStatus: (row.connectivity_status ?? 'unknown') as 'unknown' | 'reachable' | 'unreachable',\n lastSeen: fromDbTimestamp(row.last_seen),\n }));\n }\n\n /**\n * Get a specific center node by ID.\n */\n public async getCenterNode(nodeId: string): Promise<CenterNodeInfo | undefined> {\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, internal_ip, internal_port, connectivity_status, last_seen\n FROM identity_edge_node\n WHERE id = ${nodeId} AND node_type = 'center'\n LIMIT 1\n `);\n\n if (result.rows.length === 0) {\n return undefined;\n }\n\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n internalIp: String(row.internal_ip ?? ''),\n internalPort: Number(row.internal_port ?? 0),\n connectivityStatus: (row.connectivity_status ?? 'unknown') as 'unknown' | 'reachable' | 'unreachable',\n lastSeen: fromDbTimestamp(row.last_seen),\n };\n }\n\n /**\n * Find a center node by its internal endpoint (for routing).\n */\n public async findCenterNodeByEndpoint(internalIp: string, internalPort: number): Promise<CenterNodeInfo | undefined> {\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, internal_ip, internal_port, connectivity_status, last_seen\n FROM identity_edge_node\n WHERE node_type = 'center' AND internal_ip = ${internalIp} AND internal_port = ${internalPort}\n LIMIT 1\n `);\n\n if (result.rows.length === 0) {\n return undefined;\n }\n\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n internalIp: String(row.internal_ip ?? ''),\n internalPort: Number(row.internal_port ?? 0),\n connectivityStatus: (row.connectivity_status ?? 'unknown') as 'unknown' | 'reachable' | 'unreachable',\n lastSeen: fromDbTimestamp(row.last_seen),\n };\n }\n\n /**\n * Mark a center node as unreachable (for health checks).\n */\n public async markCenterNodeUnreachable(nodeId: string): Promise<void> {\n const ts = toDbTimestamp(this.db, new Date());\n await executeStatement(this.db, sql`\n UPDATE identity_edge_node\n SET connectivity_status = 'unreachable',\n updated_at = ${ts}\n WHERE id = ${nodeId} AND node_type = 'center'\n `);\n }\n\n /**\n * Remove a center node from the cluster.\n */\n public async removeCenterNode(nodeId: string): Promise<boolean> {\n // Note: For SQLite, we can't easily get affected row count, so just execute and return true\n await executeStatement(this.db, sql`\n DELETE FROM identity_edge_node\n WHERE id = ${nodeId} AND node_type = 'center'\n `);\n return true;\n }\n\n // ============ Account-based Node Methods ============\n\n /**\n * List nodes owned by a specific account\n */\n public async listNodesByAccount(accountId: string): Promise<Array<{\n nodeId: string;\n displayName?: string;\n capabilities: Record<string, unknown> | null;\n stringCapabilities: string[] | null;\n accessMode: string | null;\n lastSeen: Date | null;\n connectivityStatus: string | null;\n }>> {\n void accountId;\n return [];\n }\n\n /**\n * Delete a node\n */\n public async deleteNode(nodeId: string): Promise<boolean> {\n // First delete associated pods\n await executeStatement(this.db, sql`\n DELETE FROM identity_edge_node_pod WHERE node_id = ${nodeId}\n `);\n\n // Then delete the node\n const result = await executeQuery(this.db, sql`\n DELETE FROM identity_edge_node\n WHERE id = ${nodeId}\n RETURNING id\n `);\n\n return result.rows.length > 0;\n }\n\n // ============ SP (Storage Provider) Node Methods ============\n\n /**\n * Register or update an SP node (UPSERT by nodeId).\n *\n * SP 本地生成 deviceId 作为 nodeId,注册时带上来。\n * 同一 nodeId 重复注册时更新 publicUrl、token 等,保留原记录。\n * 不传 nodeId 则 Cloud 随机分配。\n */\n public async registerSpNode(options: {\n publicUrl: string;\n displayName?: string;\n /** SP 提供的设备 ID,作为 nodeId(不传则随机生成) */\n nodeId?: string;\n /** SP 已保存的 nodeToken,重复注册时用于保留旧凭证 */\n nodeToken?: string;\n /** SP 提供的 serviceToken,不传则随机生成 */\n serviceToken?: string;\n }): Promise<CreateSpNodeResult> {\n const nodeId = options.nodeId || randomUUID();\n const nodeToken = options.nodeToken || randomBytes(32).toString('base64url');\n const nodeTokenHash = createHash('sha256').update(nodeToken).digest('hex');\n const serviceToken = options.serviceToken || randomBytes(32).toString('base64url');\n const now = new Date();\n const ts = toDbTimestamp(this.db, now);\n\n await executeStatement(this.db, sql`\n INSERT INTO identity_edge_node (\n id, display_name, token_hash, service_token_hash,\n node_type, public_url,\n connectivity_status, created_at, updated_at\n )\n VALUES (\n ${nodeId}, ${options.displayName ?? null}, ${nodeTokenHash}, ${serviceToken},\n 'sp', ${options.publicUrl}, 'unknown', ${ts}, ${ts}\n )\n ON CONFLICT (id) DO UPDATE SET\n display_name = EXCLUDED.display_name,\n token_hash = EXCLUDED.token_hash,\n service_token_hash = EXCLUDED.service_token_hash,\n public_url = EXCLUDED.public_url,\n updated_at = EXCLUDED.updated_at\n `);\n\n return {\n nodeId,\n nodeToken,\n serviceToken,\n createdAt: now.toISOString(),\n };\n }\n\n /**\n * Get SP node info by nodeId.\n */\n public async getSpNode(nodeId: string): Promise<SpNodeInfo | undefined> {\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, public_url, service_token_hash, last_seen\n FROM identity_edge_node\n WHERE id = ${nodeId} AND node_type = 'sp'\n LIMIT 1\n `);\n\n if (result.rows.length === 0) {\n return undefined;\n }\n\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n publicUrl: String(row.public_url ?? ''),\n serviceTokenHash: String(row.service_token_hash ?? ''),\n lastSeen: fromDbTimestamp(row.last_seen),\n };\n }\n}\n"]}
1
+ {"version":3,"file":"EdgeNodeRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/EdgeNodeRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes, randomUUID, createHash, timingSafeEqual } from 'node:crypto';\nimport { sql, eq } from 'drizzle-orm';\nimport type { IdentityDatabase } from './db';\nimport { ensureCloudClusterTables, executeStatement, executeQuery, toDbTimestamp, fromDbTimestamp } from './db';\nimport { edgeNodes } from './schema';\n\nexport interface EdgeNodeRepositoryOptions {\n ensureClusterTables?: boolean;\n}\n\nexport interface EdgeNodeSummary {\n nodeId: string;\n displayName?: string;\n nodeType: 'center' | 'edge' | 'sp';\n podCount: number;\n createdAt?: string;\n updatedAt?: string;\n lastSeen?: string;\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface CreateEdgeNodeResult {\n nodeId: string;\n token: string;\n createdAt: string;\n}\n\nexport interface EdgeNodeSecret {\n nodeId: string;\n displayName?: string;\n tokenHash: string;\n nodeType: 'center' | 'edge' | 'sp';\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface CenterNodeInfo {\n nodeId: string;\n displayName?: string;\n internalIp: string;\n internalPort: number;\n connectivityStatus: 'unknown' | 'reachable' | 'unreachable';\n lastSeen?: Date;\n}\n\nexport interface CreateSpNodeResult {\n nodeId: string;\n nodeToken: string;\n serviceToken: string;\n createdAt: string;\n}\n\nexport interface SpNodeInfo {\n nodeId: string;\n displayName?: string;\n publicUrl: string;\n serviceTokenHash: string;\n lastSeen?: Date;\n}\n\nexport class EdgeNodeRepository {\n private readonly ready: Promise<void>;\n\n public constructor(\n private readonly db: IdentityDatabase,\n options: EdgeNodeRepositoryOptions = {},\n ) {\n this.ready = options.ensureClusterTables === false\n ? Promise.resolve()\n : ensureCloudClusterTables(db);\n }\n\n public async listNodes(): Promise<EdgeNodeSummary[]> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT en.id,\n en.display_name,\n en.node_type,\n en.created_at,\n en.updated_at,\n en.last_seen,\n en.metadata,\n en.pod_base_urls\n FROM cluster_node en\n ORDER BY en.created_at ASC\n `);\n\n return result.rows.map((row: any): EdgeNodeSummary => {\n const createdAt = fromDbTimestamp(row.created_at);\n const updatedAt = fromDbTimestamp(row.updated_at);\n const lastSeen = fromDbTimestamp(row.last_seen);\n const podBaseUrls = parsePodBaseUrls(row.pod_base_urls);\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n nodeType: (['center', 'edge', 'sp'].includes(row.node_type) ? row.node_type : 'edge') as 'center' | 'edge' | 'sp',\n podCount: podBaseUrls.length,\n createdAt: createdAt?.toISOString(),\n updatedAt: updatedAt?.toISOString(),\n lastSeen: lastSeen?.toISOString(),\n metadata: typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata ?? null),\n };\n });\n }\n\n public async createNode(displayName?: string): Promise<CreateEdgeNodeResult> {\n await this.ready;\n const nodeId = randomUUID();\n const token = randomBytes(32).toString('base64url');\n const tokenHash = createHash('sha256').update(token).digest('hex');\n const now = new Date();\n const ts = toDbTimestamp(this.db, now);\n\n await executeStatement(this.db, sql`\n INSERT INTO cluster_node (id, display_name, token_hash, created_at, updated_at)\n VALUES (${nodeId}, ${displayName ?? null}, ${tokenHash}, ${ts}, ${ts})\n `);\n\n return {\n nodeId,\n token,\n createdAt: now.toISOString(),\n };\n }\n\n public async getNodeSecret(nodeId: string): Promise<EdgeNodeSecret | undefined> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, token_hash, node_type, metadata\n FROM cluster_node\n WHERE id = ${nodeId}\n LIMIT 1\n `);\n if (result.rows.length === 0) {\n return undefined;\n }\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n tokenHash: String(row.token_hash ?? ''),\n nodeType: (['center', 'edge', 'sp'].includes(row.node_type) ? row.node_type : 'edge') as 'center' | 'edge' | 'sp',\n metadata: typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata ?? null),\n };\n }\n\n public async updateNodeHeartbeat(nodeId: string, metadata: Record<string, unknown> | null, timestamp: Date): Promise<void> {\n await this.ready;\n const payload = metadata == null ? null : JSON.stringify(metadata);\n const ts = toDbTimestamp(this.db, timestamp);\n\n await executeStatement(this.db, sql`\n UPDATE cluster_node\n SET metadata = ${payload},\n last_seen = ${ts},\n updated_at = ${ts}\n WHERE id = ${nodeId}\n `);\n }\n\n public async updateNodeMode(nodeId: string, options: {\n accessMode: 'direct' | 'proxy';\n ipv4?: string;\n publicPort?: number;\n subdomain?: string;\n connectivityStatus?: 'unknown' | 'reachable' | 'unreachable';\n capabilities?: Record<string, unknown>;\n }): Promise<void> {\n await this.ready;\n const capabilitiesPayload = options.capabilities ? JSON.stringify(options.capabilities) : null;\n const now = new Date();\n const ts = toDbTimestamp(this.db, now);\n\n await executeStatement(this.db, sql`\n UPDATE cluster_node\n SET access_mode = ${options.accessMode},\n ipv4 = ${options.ipv4 ?? null},\n public_port = ${options.publicPort ?? null},\n subdomain = ${options.subdomain ?? null},\n connectivity_status = ${options.connectivityStatus ?? 'unknown'},\n capabilities = ${capabilitiesPayload},\n last_connectivity_check = ${ts},\n updated_at = ${ts}\n WHERE id = ${nodeId}\n `);\n }\n\n public async getNodeConnectivityInfo(nodeId: string): Promise<{\n nodeId: string;\n accessMode?: string;\n ipv4?: string;\n publicPort?: number;\n publicUrl?: string;\n subdomain?: string;\n connectivityStatus?: string;\n lastConnectivityCheck?: Date;\n } | undefined> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT id, access_mode, ipv4, public_port, public_url, subdomain,\n connectivity_status, last_connectivity_check\n FROM cluster_node\n WHERE id = ${nodeId}\n LIMIT 1\n `);\n\n if (result.rows.length === 0) {\n return undefined;\n }\n\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n accessMode: row.access_mode ? String(row.access_mode) : undefined,\n ipv4: row.ipv4 ? String(row.ipv4) : undefined,\n publicPort: row.public_port ? Number(row.public_port) : undefined,\n publicUrl: row.public_url ? String(row.public_url) : undefined,\n subdomain: row.subdomain ? String(row.subdomain) : undefined,\n connectivityStatus: row.connectivity_status ? String(row.connectivity_status) : undefined,\n lastConnectivityCheck: fromDbTimestamp(row.last_connectivity_check),\n };\n }\n\n public async mergeNodeMetadata(nodeId: string, patch: Record<string, unknown>): Promise<void> {\n await this.ready;\n // Read current metadata\n const current = await this.getNodeMetadata(nodeId);\n if (!current) {\n throw new Error(`Node ${nodeId} not found`);\n }\n\n // Merge in application layer\n const merged = { ...(current.metadata ?? {}), ...patch };\n const payload = JSON.stringify(merged);\n const ts = toDbTimestamp(this.db, new Date());\n\n await executeStatement(this.db, sql`\n UPDATE cluster_node\n SET metadata = ${payload},\n updated_at = ${ts}\n WHERE id = ${nodeId}\n `);\n }\n\n public async getNodeMetadata(nodeId: string): Promise<{ nodeId: string; metadata: Record<string, unknown> | null; lastSeen?: Date } | undefined> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT id, metadata, last_seen\n FROM cluster_node\n WHERE id = ${nodeId}\n LIMIT 1\n `);\n if (result.rows.length === 0) {\n return undefined;\n }\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n metadata: typeof row.metadata === 'string' ? JSON.parse(row.metadata) : (row.metadata ?? null),\n lastSeen: fromDbTimestamp(row.last_seen),\n };\n }\n\n public async replaceNodePods(nodeId: string, pods: string[]): Promise<void> {\n await this.ready;\n const targetPods = uniquePodBaseUrls(pods);\n await this.updateNodePodBaseUrls(nodeId, targetPods);\n await this.removePodBaseUrlsFromOtherNodes(nodeId, targetPods);\n }\n\n public async assignPodToNode(nodeId: string, baseUrl: string): Promise<void> {\n await this.ready;\n const normalizedBaseUrl = normalizePodBaseUrl(baseUrl);\n if (!normalizedBaseUrl) {\n return;\n }\n\n const rows = await this.getNodePodRows();\n for (const row of rows) {\n const current = parsePodBaseUrls(row.pod_base_urls);\n const next = row.id === nodeId\n ? uniquePodBaseUrls([ ...current, normalizedBaseUrl ])\n : current.filter((value) => value !== normalizedBaseUrl);\n if (!arraysEqual(current, next)) {\n await this.updateNodePodBaseUrls(row.id, next);\n }\n }\n }\n\n public async findNodeByResourcePath(path: string): Promise<{ nodeId: string; baseUrl: string; accessMode?: string; publicUrl?: string; metadata?: Record<string, unknown> | null } | undefined> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT id, access_mode, public_url, metadata, pod_base_urls\n FROM cluster_node\n WHERE pod_base_urls IS NOT NULL AND pod_base_urls <> ''\n `);\n\n let bestMatch: { row: any; baseUrl: string } | undefined;\n for (const row of result.rows as any[]) {\n for (const baseUrl of parsePodBaseUrls(row.pod_base_urls)) {\n if (path.startsWith(baseUrl) && baseUrl.length > (bestMatch?.baseUrl.length ?? 0)) {\n bestMatch = { row, baseUrl };\n }\n }\n }\n\n if (!bestMatch) {\n return undefined;\n }\n\n return {\n nodeId: String(bestMatch.row.id),\n baseUrl: bestMatch.baseUrl,\n accessMode: bestMatch.row.access_mode ? String(bestMatch.row.access_mode) : undefined,\n publicUrl: bestMatch.row.public_url ? String(bestMatch.row.public_url) : undefined,\n metadata: parseJsonRecord(bestMatch.row.metadata),\n };\n }\n\n public async findNodeBySubdomain(hostname: string): Promise<{ nodeId: string; accessMode?: string; publicUrl?: string; metadata?: Record<string, unknown> | null; subdomain?: string } | undefined> {\n await this.ready;\n const normalized = hostname.trim().toLowerCase();\n if (normalized.length === 0) {\n return undefined;\n }\n const result = await executeQuery(this.db, sql`\n SELECT id, access_mode, public_url, metadata, subdomain\n FROM cluster_node\n WHERE subdomain = ${normalized}\n LIMIT 1\n `);\n if (result.rows.length === 0) {\n return undefined;\n }\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n accessMode: row.access_mode ? String(row.access_mode) : undefined,\n publicUrl: row.public_url ? String(row.public_url) : undefined,\n metadata: row.metadata ?? null,\n subdomain: row.subdomain ? String(row.subdomain) : undefined,\n };\n }\n\n public matchesToken(tokenHash: string, token: string): boolean {\n if (!tokenHash || typeof tokenHash !== 'string') {\n return false;\n }\n try {\n const expected = Buffer.from(tokenHash, 'hex');\n const actual = createHash('sha256').update(token).digest();\n if (expected.length !== actual.length) {\n return false;\n }\n return timingSafeEqual(expected, actual);\n } catch {\n return false;\n }\n }\n\n /**\n * Get node capabilities and related information for admin queries\n */\n public async getNodeCapabilities(nodeId: string): Promise<{\n nodeId: string;\n capabilities: Record<string, unknown> | null;\n stringCapabilities: string[] | null;\n accessMode: string | null;\n lastSeen: Date | null;\n connectivityStatus: string | null;\n } | undefined> {\n await this.ready;\n const row = await this.db\n .select({\n id: edgeNodes.id,\n capabilities: edgeNodes.capabilities,\n metadata: edgeNodes.metadata,\n accessMode: edgeNodes.accessMode,\n lastSeen: edgeNodes.lastSeen,\n connectivityStatus: edgeNodes.connectivityStatus,\n })\n .from(edgeNodes)\n .where(eq(edgeNodes.id, nodeId))\n .limit(1);\n\n if (row.length === 0) {\n return undefined;\n }\n\n const node = row[0];\n const metadata = node.metadata as Record<string, unknown> | null;\n \n return {\n nodeId: node.id,\n capabilities: node.capabilities as Record<string, unknown> | null,\n stringCapabilities: metadata?.capabilities as string[] ?? null,\n accessMode: node.accessMode,\n lastSeen: node.lastSeen,\n connectivityStatus: node.connectivityStatus,\n };\n }\n\n /**\n * List all nodes with their capability information\n */\n public async listNodeCapabilities(): Promise<Array<{\n nodeId: string;\n capabilities: Record<string, unknown> | null;\n stringCapabilities: string[] | null;\n accessMode: string | null;\n lastSeen: Date | null;\n connectivityStatus: string | null;\n }>> {\n await this.ready;\n const rows = await this.db\n .select({\n id: edgeNodes.id,\n capabilities: edgeNodes.capabilities,\n metadata: edgeNodes.metadata,\n accessMode: edgeNodes.accessMode,\n lastSeen: edgeNodes.lastSeen,\n connectivityStatus: edgeNodes.connectivityStatus,\n })\n .from(edgeNodes)\n .orderBy(edgeNodes.lastSeen);\n\n return rows.map((row: typeof rows[0]) => {\n const metadata = row.metadata as Record<string, unknown> | null;\n \n return {\n nodeId: row.id,\n capabilities: row.capabilities as Record<string, unknown> | null,\n stringCapabilities: metadata?.capabilities as string[] ?? null,\n accessMode: row.accessMode,\n lastSeen: row.lastSeen,\n connectivityStatus: row.connectivityStatus,\n };\n });\n }\n\n // ============ Center Node Methods ============\n\n /**\n * Register or update a center node in the cluster.\n * Center nodes use the same table as edge nodes but with nodeType='center'.\n */\n public async registerCenterNode(options: {\n nodeId: string;\n displayName?: string;\n internalIp: string;\n internalPort: number;\n }): Promise<{ nodeId: string; token: string }> {\n await this.ready;\n const token = randomBytes(32).toString('base64url');\n const tokenHash = createHash('sha256').update(token).digest('hex');\n const now = Math.floor(Date.now() / 1000); // Unix timestamp for SQLite compatibility\n\n // Use upsert pattern: INSERT ... ON CONFLICT UPDATE\n await executeStatement(this.db, sql`\n INSERT INTO cluster_node (\n id, display_name, token_hash, node_type, internal_ip, internal_port,\n connectivity_status, created_at, updated_at, last_seen\n )\n VALUES (\n ${options.nodeId}, ${options.displayName ?? null}, ${tokenHash}, 'center',\n ${options.internalIp}, ${options.internalPort}, 'unknown', ${now}, ${now}, ${now}\n )\n ON CONFLICT (id) DO UPDATE SET\n display_name = EXCLUDED.display_name,\n internal_ip = EXCLUDED.internal_ip,\n internal_port = EXCLUDED.internal_port,\n updated_at = EXCLUDED.updated_at,\n last_seen = EXCLUDED.last_seen\n `);\n\n return { nodeId: options.nodeId, token };\n }\n\n /**\n * Update center node heartbeat with internal endpoint info.\n */\n public async updateCenterNodeHeartbeat(\n nodeId: string,\n internalIp: string,\n internalPort: number,\n timestamp: Date,\n ): Promise<void> {\n await this.ready;\n const ts = Math.floor(timestamp.getTime() / 1000); // Unix timestamp for SQLite compatibility\n await executeStatement(this.db, sql`\n UPDATE cluster_node\n SET internal_ip = ${internalIp},\n internal_port = ${internalPort},\n last_seen = ${ts},\n updated_at = ${ts},\n connectivity_status = 'reachable'\n WHERE id = ${nodeId} AND node_type = 'center'\n `);\n }\n\n /**\n * List all center nodes in the cluster.\n */\n public async listCenterNodes(): Promise<CenterNodeInfo[]> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, internal_ip, internal_port, connectivity_status, last_seen\n FROM cluster_node\n WHERE node_type = 'center'\n ORDER BY created_at ASC\n `);\n\n return result.rows.map((row: any): CenterNodeInfo => ({\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n internalIp: String(row.internal_ip ?? ''),\n internalPort: Number(row.internal_port ?? 0),\n connectivityStatus: (row.connectivity_status ?? 'unknown') as 'unknown' | 'reachable' | 'unreachable',\n lastSeen: fromDbTimestamp(row.last_seen),\n }));\n }\n\n /**\n * Get a specific center node by ID.\n */\n public async getCenterNode(nodeId: string): Promise<CenterNodeInfo | undefined> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, internal_ip, internal_port, connectivity_status, last_seen\n FROM cluster_node\n WHERE id = ${nodeId} AND node_type = 'center'\n LIMIT 1\n `);\n\n if (result.rows.length === 0) {\n return undefined;\n }\n\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n internalIp: String(row.internal_ip ?? ''),\n internalPort: Number(row.internal_port ?? 0),\n connectivityStatus: (row.connectivity_status ?? 'unknown') as 'unknown' | 'reachable' | 'unreachable',\n lastSeen: fromDbTimestamp(row.last_seen),\n };\n }\n\n /**\n * Find a center node by its internal endpoint (for routing).\n */\n public async findCenterNodeByEndpoint(internalIp: string, internalPort: number): Promise<CenterNodeInfo | undefined> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, internal_ip, internal_port, connectivity_status, last_seen\n FROM cluster_node\n WHERE node_type = 'center' AND internal_ip = ${internalIp} AND internal_port = ${internalPort}\n LIMIT 1\n `);\n\n if (result.rows.length === 0) {\n return undefined;\n }\n\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n internalIp: String(row.internal_ip ?? ''),\n internalPort: Number(row.internal_port ?? 0),\n connectivityStatus: (row.connectivity_status ?? 'unknown') as 'unknown' | 'reachable' | 'unreachable',\n lastSeen: fromDbTimestamp(row.last_seen),\n };\n }\n\n /**\n * Mark a center node as unreachable (for health checks).\n */\n public async markCenterNodeUnreachable(nodeId: string): Promise<void> {\n await this.ready;\n const ts = toDbTimestamp(this.db, new Date());\n await executeStatement(this.db, sql`\n UPDATE cluster_node\n SET connectivity_status = 'unreachable',\n updated_at = ${ts}\n WHERE id = ${nodeId} AND node_type = 'center'\n `);\n }\n\n /**\n * Remove a center node from the cluster.\n */\n public async removeCenterNode(nodeId: string): Promise<boolean> {\n await this.ready;\n // Note: For SQLite, we can't easily get affected row count, so just execute and return true\n await executeStatement(this.db, sql`\n DELETE FROM cluster_node\n WHERE id = ${nodeId} AND node_type = 'center'\n `);\n return true;\n }\n\n // ============ Account-based Node Methods ============\n\n /**\n * List nodes owned by a specific account\n */\n public async listNodesByAccount(accountId: string): Promise<Array<{\n nodeId: string;\n displayName?: string;\n capabilities: Record<string, unknown> | null;\n stringCapabilities: string[] | null;\n accessMode: string | null;\n lastSeen: Date | null;\n connectivityStatus: string | null;\n }>> {\n await this.ready;\n void accountId;\n return [];\n }\n\n /**\n * Delete a node\n */\n public async deleteNode(nodeId: string): Promise<boolean> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n DELETE FROM cluster_node\n WHERE id = ${nodeId}\n RETURNING id\n `);\n\n return result.rows.length > 0;\n }\n\n private async getNodePodRows(): Promise<Array<{ id: string; pod_base_urls?: unknown }>> {\n const result = await executeQuery(this.db, sql`\n SELECT id, pod_base_urls\n FROM cluster_node\n `);\n return result.rows.map((row: any) => ({\n id: String(row.id),\n pod_base_urls: row.pod_base_urls,\n }));\n }\n\n private async updateNodePodBaseUrls(nodeId: string, pods: string[]): Promise<void> {\n const payload = pods.length > 0 ? JSON.stringify(pods) : null;\n const ts = toDbTimestamp(this.db, new Date());\n await executeStatement(this.db, sql`\n UPDATE cluster_node\n SET pod_base_urls = ${payload},\n updated_at = ${ts}\n WHERE id = ${nodeId}\n `);\n }\n\n private async removePodBaseUrlsFromOtherNodes(nodeId: string, pods: string[]): Promise<void> {\n if (pods.length === 0) {\n return;\n }\n const podSet = new Set(pods);\n const rows = await this.getNodePodRows();\n for (const row of rows) {\n if (row.id === nodeId) {\n continue;\n }\n const current = parsePodBaseUrls(row.pod_base_urls);\n const next = current.filter((value) => !podSet.has(value));\n if (!arraysEqual(current, next)) {\n await this.updateNodePodBaseUrls(row.id, next);\n }\n }\n }\n\n // ============ SP (Storage Provider) Node Methods ============\n\n /**\n * Register or update an SP node (UPSERT by nodeId).\n *\n * SP 本地生成 deviceId 作为 nodeId,注册时带上来。\n * 同一 nodeId 重复注册时更新 publicUrl、token 等,保留原记录。\n * 不传 nodeId 则 Cloud 随机分配。\n */\n public async registerSpNode(options: {\n publicUrl: string;\n displayName?: string;\n /** SP 提供的设备 ID,作为 nodeId(不传则随机生成) */\n nodeId?: string;\n /** SP 已保存的 nodeToken,重复注册时用于保留旧凭证 */\n nodeToken?: string;\n /** SP 提供的 serviceToken,不传则随机生成 */\n serviceToken?: string;\n }): Promise<CreateSpNodeResult> {\n await this.ready;\n const nodeId = options.nodeId || randomUUID();\n const nodeToken = options.nodeToken || randomBytes(32).toString('base64url');\n const nodeTokenHash = createHash('sha256').update(nodeToken).digest('hex');\n const serviceToken = options.serviceToken || randomBytes(32).toString('base64url');\n const now = new Date();\n const ts = toDbTimestamp(this.db, now);\n\n await executeStatement(this.db, sql`\n INSERT INTO cluster_node (\n id, display_name, token_hash, service_token_hash,\n node_type, public_url,\n connectivity_status, created_at, updated_at\n )\n VALUES (\n ${nodeId}, ${options.displayName ?? null}, ${nodeTokenHash}, ${serviceToken},\n 'sp', ${options.publicUrl}, 'unknown', ${ts}, ${ts}\n )\n ON CONFLICT (id) DO UPDATE SET\n display_name = EXCLUDED.display_name,\n token_hash = EXCLUDED.token_hash,\n service_token_hash = EXCLUDED.service_token_hash,\n public_url = EXCLUDED.public_url,\n updated_at = EXCLUDED.updated_at\n `);\n\n return {\n nodeId,\n nodeToken,\n serviceToken,\n createdAt: now.toISOString(),\n };\n }\n\n /**\n * Get SP node info by nodeId.\n */\n public async getSpNode(nodeId: string): Promise<SpNodeInfo | undefined> {\n await this.ready;\n const result = await executeQuery(this.db, sql`\n SELECT id, display_name, public_url, service_token_hash, last_seen\n FROM cluster_node\n WHERE id = ${nodeId} AND node_type = 'sp'\n LIMIT 1\n `);\n\n if (result.rows.length === 0) {\n return undefined;\n }\n\n const row = result.rows[0] as any;\n return {\n nodeId: String(row.id),\n displayName: row.display_name == null ? undefined : String(row.display_name),\n publicUrl: String(row.public_url ?? ''),\n serviceTokenHash: String(row.service_token_hash ?? ''),\n lastSeen: fromDbTimestamp(row.last_seen),\n };\n }\n}\n\nfunction parsePodBaseUrls(value: unknown): string[] {\n if (Array.isArray(value)) {\n return uniquePodBaseUrls(value);\n }\n if (typeof value !== 'string' || value.length === 0) {\n return [];\n }\n try {\n const parsed = JSON.parse(value) as unknown;\n return Array.isArray(parsed) ? uniquePodBaseUrls(parsed) : [];\n } catch {\n return [];\n }\n}\n\nfunction normalizePodBaseUrl(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction uniquePodBaseUrls(values: unknown[]): string[] {\n return [...new Set(values.map(normalizePodBaseUrl).filter((value): value is string => Boolean(value)))];\n}\n\nfunction arraysEqual(left: string[], right: string[]): boolean {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n}\n\nfunction parseJsonRecord(value: unknown): Record<string, unknown> | null {\n if (!value) {\n return null;\n }\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value) as unknown;\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : null;\n } catch {\n return null;\n }\n }\n return typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : null;\n}\n"]}
@@ -9,25 +9,16 @@ export interface PodLookupResult {
9
9
  nodeId?: string;
10
10
  edgeNodeId?: string;
11
11
  }
12
- export interface PodMigrationStatus {
13
- podId: string;
14
- nodeId?: string;
15
- migrationStatus?: 'syncing' | 'done' | null;
16
- migrationTargetNode?: string;
17
- migrationProgress?: number;
18
- }
19
12
  /**
20
13
  * Repository for Pod lookup operations.
21
14
  *
22
- * Reads Pod data from CSS's internal_kv table where account data is stored.
23
- * CSS stores account data at key "accounts/data/{accountId}" with Pod info
24
- * nested in the "**pod**" field.
15
+ * Reads Pod facts from the canonical identity_store table and from CSS
16
+ * WrappedIndexedStorage rows when that storage backend is active.
25
17
  */
26
18
  export declare class PodLookupRepository {
27
19
  private readonly db;
28
20
  private readonly kvTableName;
29
21
  private readonly indexedStoreTableName;
30
- private readonly usageTableName;
31
22
  constructor(db: IdentityDatabase, kvTableName?: string);
32
23
  /**
33
24
  * Find Pod by resource path (matches longest canonical storage/base URL prefix).
@@ -61,34 +52,16 @@ export declare class PodLookupRepository {
61
52
  * List Pods for a specific account.
62
53
  */
63
54
  listByAccountId(accountId: string): Promise<PodLookupResult[]>;
64
- /**
65
- * Set the canonical storage URL for a Pod in identity_pod_usage.
66
- */
67
- setStorageUrl(podId: string, accountId: string, storageUrl: string): Promise<void>;
68
- /**
69
- * Get migration status for a Pod from identity_pod_usage table.
70
- */
71
- getMigrationStatus(podId: string): Promise<PodMigrationStatus | undefined>;
72
- /**
73
- * Set the nodeId for a Pod in identity_pod_usage table.
74
- */
75
- setNodeId(podId: string, nodeId: string): Promise<void>;
76
- /**
77
- * Update migration status for a Pod in identity_pod_usage table.
78
- */
79
- setMigrationStatus(podId: string, status: 'syncing' | 'done' | null, targetNode?: string | null, progress?: number | null): Promise<void>;
80
55
  /**
81
56
  * List all pods.
82
57
  */
83
58
  listAllPods(): Promise<PodLookupResult[]>;
84
59
  /**
85
- * Extract all pods from CSS's internal_kv storage.
86
- *
87
- * It keeps backward compatibility with legacy rows that already expose
88
- * id/account_id/base_url columns (used by some unit tests and older schemas).
60
+ * Extract all pods from the configured CSS identity storage.
89
61
  */
90
62
  private getAllPods;
91
- private getUsageByPodId;
63
+ private getAccountRowsFromKv;
64
+ private getNodeAssignments;
92
65
  /**
93
66
  * Fast path for CSS WrappedIndexedStorage. WebID indexes point to the root
94
67
  * account id, so a single indexed key plus account data row can resolve the
@@ -100,10 +73,8 @@ export declare class PodLookupRepository {
100
73
  private readKvValue;
101
74
  private extractPodsFromAccountData;
102
75
  /**
103
- * Older Xpod/CSS deployments may have used the IndexedStorage-compatible
104
- * identity_store table instead of CSS's WrappedIndexedStorage JSON tree in
105
- * internal_kv. Keep this as a read-only compatibility source so hosted WebID
106
- * profile lookup still works after storage implementation changes.
76
+ * DrizzleIndexedStorage stores CSS identity facts as typed rows in
77
+ * identity_store; this is the canonical clustered identity source.
107
78
  */
108
79
  private getPodsFromIndexedStore;
109
80
  }
@@ -6,16 +6,14 @@ const db_1 = require("./db");
6
6
  /**
7
7
  * Repository for Pod lookup operations.
8
8
  *
9
- * Reads Pod data from CSS's internal_kv table where account data is stored.
10
- * CSS stores account data at key "accounts/data/{accountId}" with Pod info
11
- * nested in the "**pod**" field.
9
+ * Reads Pod facts from the canonical identity_store table and from CSS
10
+ * WrappedIndexedStorage rows when that storage backend is active.
12
11
  */
13
12
  class PodLookupRepository {
14
13
  constructor(db, kvTableName) {
15
14
  this.db = db;
16
15
  this.kvTableName = kvTableName ?? 'internal_kv';
17
16
  this.indexedStoreTableName = 'identity_store';
18
- this.usageTableName = 'identity_pod_usage';
19
17
  }
20
18
  /**
21
19
  * Find Pod by resource path (matches longest canonical storage/base URL prefix).
@@ -80,10 +78,8 @@ class PodLookupRepository {
80
78
  if (!indexed) {
81
79
  return [];
82
80
  }
83
- const usage = await this.getUsageByPodId();
84
81
  return [{
85
82
  ...indexed,
86
- storageUrl: indexed.storageUrl ?? usage.get(indexed.podId)?.storageUrl,
87
83
  }];
88
84
  }
89
85
  /**
@@ -117,11 +113,7 @@ class PodLookupRepository {
117
113
  }
118
114
  const indexed = await this.findByWebIdIndex(normalized);
119
115
  if (indexed) {
120
- const usage = await this.getUsageByPodId();
121
- results.push({
122
- ...indexed,
123
- storageUrl: indexed.storageUrl ?? usage.get(indexed.podId)?.storageUrl,
124
- });
116
+ results.push(indexed);
125
117
  }
126
118
  }
127
119
  }
@@ -134,73 +126,6 @@ class PodLookupRepository {
134
126
  const pods = await this.getAllPods();
135
127
  return pods.filter((pod) => pod.accountId === accountId);
136
128
  }
137
- /**
138
- * Set the canonical storage URL for a Pod in identity_pod_usage.
139
- */
140
- async setStorageUrl(podId, accountId, storageUrl) {
141
- const tableId = drizzle_orm_1.sql.identifier([this.usageTableName]);
142
- await (0, db_1.executeStatement)(this.db, (0, drizzle_orm_1.sql) `
143
- INSERT INTO ${tableId} (pod_id, account_id, storage_url)
144
- VALUES (${podId}, ${accountId}, ${storageUrl})
145
- ON CONFLICT (pod_id) DO UPDATE SET
146
- account_id = ${accountId},
147
- storage_url = ${storageUrl}
148
- `);
149
- }
150
- /**
151
- * Get migration status for a Pod from identity_pod_usage table.
152
- */
153
- async getMigrationStatus(podId) {
154
- try {
155
- const tableId = drizzle_orm_1.sql.identifier([this.usageTableName]);
156
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
157
- SELECT pod_id, node_id, migration_status, migration_target_node, migration_progress
158
- FROM ${tableId}
159
- WHERE pod_id = ${podId}
160
- LIMIT 1
161
- `);
162
- if (result.rows.length === 0) {
163
- return undefined;
164
- }
165
- const row = result.rows[0];
166
- return {
167
- podId: row.pod_id ?? row.id ?? podId,
168
- nodeId: row.node_id ?? undefined,
169
- migrationStatus: row.migration_status,
170
- migrationTargetNode: row.migration_target_node ?? undefined,
171
- migrationProgress: row.migration_progress ?? undefined,
172
- };
173
- }
174
- catch {
175
- // Table might not exist.
176
- return undefined;
177
- }
178
- }
179
- /**
180
- * Set the nodeId for a Pod in identity_pod_usage table.
181
- */
182
- async setNodeId(podId, nodeId) {
183
- const tableId = drizzle_orm_1.sql.identifier([this.usageTableName]);
184
- await (0, db_1.executeStatement)(this.db, (0, drizzle_orm_1.sql) `
185
- INSERT INTO ${tableId} (pod_id, account_id, node_id)
186
- VALUES (${podId}, '', ${nodeId})
187
- ON CONFLICT (pod_id) DO UPDATE SET node_id = ${nodeId}
188
- `);
189
- }
190
- /**
191
- * Update migration status for a Pod in identity_pod_usage table.
192
- */
193
- async setMigrationStatus(podId, status, targetNode, progress) {
194
- const tableId = drizzle_orm_1.sql.identifier([this.usageTableName]);
195
- await (0, db_1.executeStatement)(this.db, (0, drizzle_orm_1.sql) `
196
- INSERT INTO ${tableId} (pod_id, account_id, migration_status, migration_target_node, migration_progress)
197
- VALUES (${podId}, '', ${status}, ${targetNode ?? null}, ${progress ?? 0})
198
- ON CONFLICT (pod_id) DO UPDATE SET
199
- migration_status = ${status},
200
- migration_target_node = ${targetNode ?? null},
201
- migration_progress = ${progress ?? 0}
202
- `);
203
- }
204
129
  /**
205
130
  * List all pods.
206
131
  */
@@ -208,32 +133,13 @@ class PodLookupRepository {
208
133
  return this.getAllPods();
209
134
  }
210
135
  /**
211
- * Extract all pods from CSS's internal_kv storage.
212
- *
213
- * It keeps backward compatibility with legacy rows that already expose
214
- * id/account_id/base_url columns (used by some unit tests and older schemas).
136
+ * Extract all pods from the configured CSS identity storage.
215
137
  */
216
138
  async getAllPods() {
217
- const kvTableId = drizzle_orm_1.sql.identifier([this.kvTableName]);
218
- const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
219
- SELECT key, value FROM ${kvTableId}
220
- WHERE key LIKE 'accounts/data/%'
221
- OR key LIKE '/.internal/accounts/data/%'
222
- `);
223
- const usageByPodId = await this.getUsageByPodId();
139
+ const result = await this.getAccountRowsFromKv();
140
+ const nodeAssignments = await this.getNodeAssignments();
224
141
  const pods = [];
225
- for (const row of result?.rows ?? []) {
226
- if (row.id && row.account_id && row.base_url) {
227
- pods.push({
228
- podId: String(row.id),
229
- accountId: String(row.account_id),
230
- baseUrl: String(row.base_url),
231
- storageUrl: row.storage_url ? String(row.storage_url) : undefined,
232
- nodeId: row.node_id ? String(row.node_id) : undefined,
233
- edgeNodeId: row.edge_node_id ? String(row.edge_node_id) : undefined,
234
- });
235
- continue;
236
- }
142
+ for (const row of result) {
237
143
  if (!row.key || row.value === undefined) {
238
144
  continue;
239
145
  }
@@ -248,7 +154,7 @@ class PodLookupRepository {
248
154
  for (const [podId, podData] of Object.entries(podMap)) {
249
155
  const pod = podData;
250
156
  if (pod.baseUrl && typeof pod.baseUrl === 'string') {
251
- const usage = usageByPodId.get(podId);
157
+ const storageUrl = stringValue(pod.storageUrl) ?? stringValue(pod.storage);
252
158
  const podWebIds = [
253
159
  typeof pod.webId === 'string' ? pod.webId : undefined,
254
160
  ...extractPodOwnerWebIds(pod),
@@ -258,10 +164,10 @@ class PodLookupRepository {
258
164
  podId,
259
165
  accountId,
260
166
  baseUrl: pod.baseUrl,
261
- storageUrl: stringValue(pod.storageUrl) ?? usage?.storageUrl,
167
+ storageUrl,
262
168
  webId: dedupeStrings(podWebIds)[0],
263
169
  ...webIdsProperty(podWebIds),
264
- nodeId: typeof pod.nodeId === 'string' ? pod.nodeId : undefined,
170
+ nodeId: typeof pod.nodeId === 'string' ? pod.nodeId : findNodeIdForPod(nodeAssignments, [storageUrl, pod.baseUrl]),
265
171
  edgeNodeId: typeof pod.edgeNodeId === 'string' ? pod.edgeNodeId : undefined,
266
172
  });
267
173
  }
@@ -273,28 +179,42 @@ class PodLookupRepository {
273
179
  }
274
180
  return mergePodLookupResults([
275
181
  ...pods,
276
- ...await this.getPodsFromIndexedStore(),
182
+ ...await this.getPodsFromIndexedStore(nodeAssignments),
277
183
  ]);
278
184
  }
279
- async getUsageByPodId() {
280
- const tableId = drizzle_orm_1.sql.identifier([this.usageTableName]);
185
+ async getAccountRowsFromKv() {
186
+ const kvTableId = drizzle_orm_1.sql.identifier([this.kvTableName]);
281
187
  try {
282
188
  const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
283
- SELECT pod_id, storage_url FROM ${tableId}
189
+ SELECT key, value FROM ${kvTableId}
190
+ WHERE key LIKE 'accounts/data/%'
191
+ OR key LIKE '/.internal/accounts/data/%'
284
192
  `);
285
- const byPodId = new Map();
286
- for (const row of result.rows) {
287
- if (!row.pod_id) {
288
- continue;
193
+ return result?.rows ?? [];
194
+ }
195
+ catch {
196
+ return [];
197
+ }
198
+ }
199
+ async getNodeAssignments() {
200
+ try {
201
+ const tableId = drizzle_orm_1.sql.identifier(['cluster_node']);
202
+ const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
203
+ SELECT id, pod_base_urls FROM ${tableId}
204
+ WHERE pod_base_urls IS NOT NULL AND pod_base_urls <> ''
205
+ `);
206
+ return result.rows.flatMap((row) => {
207
+ if (!row.id) {
208
+ return [];
289
209
  }
290
- byPodId.set(row.pod_id, {
291
- storageUrl: row.storage_url ?? undefined,
292
- });
293
- }
294
- return byPodId;
210
+ return parsePodBaseUrls(row.pod_base_urls).map((baseUrl) => ({
211
+ node_id: row.id,
212
+ base_url: baseUrl,
213
+ }));
214
+ });
295
215
  }
296
216
  catch {
297
- return new Map();
217
+ return [];
298
218
  }
299
219
  }
300
220
  /**
@@ -365,6 +285,7 @@ class PodLookupRepository {
365
285
  for (const [podId, podData] of Object.entries(podMap)) {
366
286
  const pod = podData;
367
287
  if (pod.baseUrl && typeof pod.baseUrl === 'string') {
288
+ const storageUrl = stringValue(pod.storageUrl) ?? stringValue(pod.storage);
368
289
  const podWebIds = [
369
290
  typeof pod.webId === 'string' ? pod.webId : undefined,
370
291
  ...extractPodOwnerWebIds(pod),
@@ -374,7 +295,7 @@ class PodLookupRepository {
374
295
  podId,
375
296
  accountId,
376
297
  baseUrl: pod.baseUrl,
377
- storageUrl: stringValue(pod.storageUrl),
298
+ storageUrl,
378
299
  webId: dedupeStrings(podWebIds)[0],
379
300
  ...webIdsProperty(podWebIds),
380
301
  nodeId: typeof pod.nodeId === 'string' ? pod.nodeId : undefined,
@@ -385,12 +306,10 @@ class PodLookupRepository {
385
306
  return pods;
386
307
  }
387
308
  /**
388
- * Older Xpod/CSS deployments may have used the IndexedStorage-compatible
389
- * identity_store table instead of CSS's WrappedIndexedStorage JSON tree in
390
- * internal_kv. Keep this as a read-only compatibility source so hosted WebID
391
- * profile lookup still works after storage implementation changes.
309
+ * DrizzleIndexedStorage stores CSS identity facts as typed rows in
310
+ * identity_store; this is the canonical clustered identity source.
392
311
  */
393
- async getPodsFromIndexedStore() {
312
+ async getPodsFromIndexedStore(nodeAssignments = []) {
394
313
  const storeTableId = drizzle_orm_1.sql.identifier([this.indexedStoreTableName]);
395
314
  let result;
396
315
  try {
@@ -445,14 +364,15 @@ class PodLookupRepository {
445
364
  ...(ownerWebIdsByPodId.get(podId) ?? []),
446
365
  ...(webIdsByAccountId.get(accountId) ?? []),
447
366
  ].filter((value) => typeof value === 'string'));
367
+ const storageUrl = stringValue(pod.storageUrl) ?? stringValue(pod.storage);
448
368
  pods.push({
449
369
  podId,
450
370
  accountId,
451
371
  baseUrl,
452
- storageUrl: stringValue(pod.storageUrl),
372
+ storageUrl,
453
373
  webId: podWebIds[0],
454
374
  ...webIdsProperty(podWebIds),
455
- nodeId: stringValue(pod.nodeId),
375
+ nodeId: stringValue(pod.nodeId) ?? findNodeIdForPod(nodeAssignments, [storageUrl, baseUrl]),
456
376
  edgeNodeId: stringValue(pod.edgeNodeId),
457
377
  });
458
378
  }
@@ -514,6 +434,21 @@ function normalizeWebId(webId) {
514
434
  return webId;
515
435
  }
516
436
  }
437
+ function normalizeUrlRoot(url) {
438
+ if (!url) {
439
+ return undefined;
440
+ }
441
+ try {
442
+ const parsed = new URL(url);
443
+ parsed.pathname = parsed.pathname.replace(/\/+$/u, '') || '/';
444
+ parsed.search = '';
445
+ parsed.hash = '';
446
+ return parsed.toString();
447
+ }
448
+ catch {
449
+ return url;
450
+ }
451
+ }
517
452
  function dedupeStrings(values) {
518
453
  return [...new Set(values)];
519
454
  }
@@ -594,4 +529,46 @@ function appendMapValue(map, key, value) {
594
529
  values.push(value);
595
530
  map.set(key, values);
596
531
  }
532
+ function parsePodBaseUrls(value) {
533
+ if (Array.isArray(value)) {
534
+ return dedupeStrings(value.filter((entry) => typeof entry === 'string' && entry.length > 0));
535
+ }
536
+ if (typeof value !== 'string' || value.length === 0) {
537
+ return [];
538
+ }
539
+ try {
540
+ const parsed = JSON.parse(value);
541
+ return Array.isArray(parsed)
542
+ ? dedupeStrings(parsed.filter((entry) => typeof entry === 'string' && entry.length > 0))
543
+ : [];
544
+ }
545
+ catch {
546
+ return [];
547
+ }
548
+ }
549
+ function findNodeIdForPod(assignments, urls) {
550
+ const normalizedUrls = urls.map(normalizeUrlRoot).filter((value) => Boolean(value));
551
+ if (normalizedUrls.length === 0) {
552
+ return undefined;
553
+ }
554
+ let bestMatch;
555
+ for (const assignment of assignments) {
556
+ if (!assignment.node_id || !assignment.base_url) {
557
+ continue;
558
+ }
559
+ const assignedBase = normalizeUrlRoot(assignment.base_url);
560
+ if (!assignedBase) {
561
+ continue;
562
+ }
563
+ for (const url of normalizedUrls) {
564
+ if (url.startsWith(assignedBase) && assignedBase.length > (bestMatch?.length ?? 0)) {
565
+ bestMatch = {
566
+ nodeId: assignment.node_id,
567
+ length: assignedBase.length,
568
+ };
569
+ }
570
+ }
571
+ }
572
+ return bestMatch?.nodeId;
573
+ }
597
574
  //# sourceMappingURL=PodLookupRepository.js.map