{
  "@context": [
    "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld",
    "https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld",
    "https://linkedsoftwaredependencies.org/bundles/npm/asynchronous-handlers/^1.0.0/components/context.jsonld"
  ],
  "@graph": [
    {
      "comment": "Optional ingress IP for proxy edge nodes.",
      "@id": "urn:solid-server:default:variable:clusterIngressIp",
      "@type": "Variable"
    },
    {
      "comment": "Identifier strategy that allows cluster root host and node subdomains.",
      "@id": "urn:undefineds:xpod:ClusterIdentifierStrategy",
      "@type": "npmd:@undefineds.co/xpod/^0.0.0/dist/util/identifiers/ClusterIdentifierStrategy.jsonld#ClusterIdentifierStrategy",
      "npmd:@undefineds.co/xpod/^0.0.0/dist/util/identifiers/ClusterIdentifierStrategy.jsonld#ClusterIdentifierStrategy_options_baseUrl": {
        "@id": "urn:solid-server:default:variable:baseUrl",
        "@type": "Variable"
      },
      "npmd:@undefineds.co/xpod/^0.0.0/dist/util/identifiers/ClusterIdentifierStrategy.jsonld#ClusterIdentifierStrategy_options_allowedHosts": {
        "@id": "urn:solid-server:default:variable:allowedHosts",
        "@type": "Variable"
      }
    },
    {
      "comment": "Allow requests for cluster domain and any node subdomain.",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:IdentifierStrategy"
      },
      "overrideParameters": {
        "@id": "urn:undefineds:xpod:ClusterIdentifierStrategy"
      }
    },
    {
      "comment": "Cluster ingress domain for node routing.",
      "@id": "urn:solid-server:default:variable:clusterIngressDomain",
      "@type": "Variable"
    },
    {
      "comment": "Persist /.internal key/value records in PostgreSQL for clustered deployments.",
      "@id": "urn:undefineds:xpod:PostgresInternalKeyValueStorage",
      "@type": "PostgresKeyValueStorage",
      "connectionString": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      },
      "tableName": "internal_kv",
      "namespace": "/.internal/"
    },
    {
      "comment": "Route core key/value storage through PostgreSQL.",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:KeyValueStorage"
      },
      "overrideParameters": {
        "@id": "urn:undefineds:xpod:PostgresInternalKeyValueStorage"
      }
    },
    {
      "comment": "Redis-backed adapter storage for OIDC tokens.",
      "@id": "urn:undefineds:xpod:RedisInternalKeyValueStorage",
      "@type": "RedisKeyValueStorage",
      "client": {
        "@id": "urn:solid-server:default:variable:redisClient",
        "@type": "Variable"
      },
      "username": {
        "@id": "urn:solid-server:default:variable:redisUsername",
        "@type": "Variable"
      },
      "password": {
        "@id": "urn:solid-server:default:variable:redisPassword",
        "@type": "Variable"
      },
      "namespace": "/.internal/",
      "scanCount": 500
    },
    {
      "comment": "Expose the Redis key/value storage under the expected /.internal/idp/adapter/ path.",
      "@id": "urn:undefineds:xpod:IdpAdapterContainerStorage",
      "@type": "ContainerPathStorage",
      "relativePath": "/idp/adapter/",
      "source": {
        "@id": "urn:undefineds:xpod:RedisInternalKeyValueStorage"
      }
    },
    {
      "comment": "Redis-backed container for forgot password tokens.",
      "@id": "urn:undefineds:xpod:ForgotPasswordRedisStorage",
      "@type": "ContainerPathStorage",
      "relativePath": "/accounts/forgot-password/",
      "source": {
        "@id": "urn:undefineds:xpod:RedisInternalKeyValueStorage"
      }
    },
    {
      "comment": "Redis-backed container for account cookies.",
      "@id": "urn:undefineds:xpod:CookieRedisContainerStorage",
      "@type": "ContainerPathStorage",
      "relativePath": "/accounts/cookies/",
      "source": {
        "@id": "urn:undefineds:xpod:RedisInternalKeyValueStorage"
      }
    },
    {
      "comment": "Store forgot password tokens in Redis with TTL cleanup.",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:ForgotPasswordStorage"
      },
      "overrideParameters": {
        "@type": "WrappedExpiringStorage",
        "source": {
          "@id": "urn:undefineds:xpod:ForgotPasswordRedisStorage"
        }
      }
    },
    {
      "comment": "Store account cookies in Redis with TTL cleanup.",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:CookieStorage"
      },
      "overrideParameters": {
        "@type": "WrappedExpiringStorage",
        "source": {
          "@id": "urn:undefineds:xpod:CookieRedisContainerStorage"
        }
      }
    },
    {
      "comment": "Store OIDC adapter state in Redis while keeping the default wrapping behaviour.",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:IdpAdapterFactory"
      },
      "overrideParameters": {
        "@type": "ClientCredentialsAdapterFactory",
        "webIdStore": {
          "@id": "urn:solid-server:default:WebIdStore"
        },
        "clientCredentialsStore": {
          "@id": "urn:solid-server:default:ClientCredentialsStore"
        },
        "source": {
          "@type": "LoopbackClientIdAdapterFactory",
          "@id": "urn:undefineds:xpod:LoopbackClientIdAdapterFactory",
          "converter": {
            "@id": "urn:solid-server:default:RepresentationConverter"
          },
          "source": {
            "@type": "ExpiringAdapterFactory",
            "@id": "urn:undefineds:xpod:ExpiringAdapterFactory",
            "storage": {
              "@type": "WrappedExpiringStorage",
              "@id": "urn:undefineds:xpod:WrappedExpiringAdapterStorage",
              "source": {
                "@id": "urn:undefineds:xpod:IdpAdapterContainerStorage"
              }
            }
          }
        }
      }
    },
    {
      "comment": "Tencent DNS provider for edge node automation",
      "@id": "urn:undefineds:xpod:TencentDnsProvider",
      "@type": "TencentDnsProvider",
      "tokenId": {
        "@id": "urn:solid-server:default:variable:tencentDnsTokenId",
        "@type": "Variable"
      },
      "token": {
        "@id": "urn:solid-server:default:variable:tencentDnsToken",
        "@type": "Variable"
      },
      "baseUrl": {
        "@id": "urn:solid-server:default:variable:tencentDnsBaseUrl",
        "@type": "Variable"
      },
      "defaultLineId": {
        "@id": "urn:solid-server:default:variable:tencentDnsDefaultLineId",
        "@type": "Variable"
      },
      "userAgent": {
        "@value": "Xpod-Cluster"
      }
    },
    {
      "comment": "Coordinates DNS records for edge nodes",
      "@id": "urn:undefineds:xpod:EdgeNodeDnsCoordinator",
      "@type": "EdgeNodeDnsCoordinator",
      "provider": {
        "@id": "urn:undefineds:xpod:TencentDnsProvider"
      },
      "rootDomain": {
        "@id": "urn:solid-server:default:variable:baseStorageDomain",
        "@type": "Variable"
      },
      "ttl": {
        "@id": "urn:solid-server:default:variable:dnsRecordTtl",
        "@type": "Variable"
      }
    },
    {
      "comment": "Writes DNS-01 TXT records for certificate challenges",
      "@id": "urn:undefineds:xpod:Dns01CertificateProvisioner",
      "@type": "Dns01CertificateProvisioner",
      "provider": {
        "@id": "urn:undefineds:xpod:TencentDnsProvider"
      },
      "rootDomain": {
        "@id": "urn:solid-server:default:variable:baseUrl",
        "@type": "Variable"
      },
      "ttl": {
        "@id": "urn:solid-server:default:variable:dnsRecordTtl",
        "@type": "Variable"
      }
    },
    {
      "comment": "FRP-based tunnel manager for edge nodes",
      "@id": "urn:undefineds:xpod:EdgeNodeTunnelManager",
      "@type": "FrpTunnelManager",
      "serverHost": {
        "@id": "urn:solid-server:default:variable:frpServerHost",
        "@type": "Variable"
      },
      "serverPort": {
        "@id": "urn:solid-server:default:variable:frpServerPort",
        "@type": "Variable"
      },
      "token": {
        "@id": "urn:solid-server:default:variable:frpToken",
        "@type": "Variable"
      },
      "protocol": {
        "@id": "urn:solid-server:default:variable:frpProtocol",
        "@type": "Variable"
      }
    },
    {
      "comment": "Health probe service for edge nodes",
      "@id": "urn:undefineds:xpod:EdgeNodeHealthProbeService",
      "@type": "EdgeNodeHealthProbeService",
      "identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      },
      "enabled": {
        "@id": "urn:solid-server:default:variable:edgeHealthProbesEnabled",
        "@type": "Variable"
      },
      "timeoutMs": {
        "@id": "urn:solid-server:default:variable:edgeHealthProbeTimeout",
        "@type": "Variable"
      }
    },
    {
      "comment": "Cluster ingress router for unified entry point",
      "@type": "ClusterIngressRouter", 
      "@id": "urn:undefineds:xpod:ClusterIngressRouter",
      "identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      },
      "edgeNodesEnabled": {
        "@id": "urn:solid-server:default:variable:edgeNodesEnabled", 
        "@type": "Variable"
      },
      "clusterIngressDomain": {
        "@id": "urn:solid-server:default:variable:baseUrl",
        "@type": "Variable"
      }
    },
    {
      "comment": "Redirects pod traffic to registered edge nodes (Debug Only)",
      "@type": "EdgeNodeDirectDebugHttpHandler",
      "@id": "urn:undefineds:xpod:EdgeNodeDirectDebugHttpHandler",
      "identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      },
      "edgeNodesEnabled": {
        "@id": "urn:solid-server:default:variable:edgeNodesEnabled",
        "@type": "Variable"
      }
    },
    {
      "comment": "Center node registration service for multi-node deployment",
      "@id": "urn:undefineds:xpod:CenterNodeRegistrationService",
      "@type": "CenterNodeRegistrationService",
      "npmd:@undefineds.co/xpod/^0.0.0/dist/identity/CenterNodeRegistrationService.jsonld#CenterNodeRegistrationService_config_enabled": {
        "@id": "urn:solid-server:default:variable:centerRegistrationEnabled",
        "@type": "Variable"
      },
      "config_identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      },
      "config_port": {
        "@id": "urn:solid-server:default:variable:port",
        "@type": "Variable"
      },
      "config_rootFilePath": {
        "@id": "urn:solid-server:default:variable:rootFilePath",
        "@type": "Variable"
      },
      "config_nodeId": {
        "@id": "urn:solid-server:default:variable:nodeId",
        "@type": "Variable"
      },
      "config_heartbeatInterval": {
        "@id": "urn:solid-server:default:variable:nodeHeartbeatInterval",
        "@type": "Variable"
      }
    },
    {
      "comment": "Add CenterNodeRegistrationService to initialization sequence",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:PrimarySequenceInitializer"
      },
      "overrideParameters": {
        "@type": "SequenceHandler",
        "https://linkedsoftwaredependencies.org/bundles/npm/asynchronous-handlers/^1.0.0/components/WaterfallHandler.jsonld#WaterfallHandler_handlers": [
          { "@id": "urn:solid-server:default:CleanupInitializer" },
          { "@id": "urn:solid-server:default:MigrationInitializer" },
          { "@id": "urn:solid-server:default:BaseUrlVerifier" },
          { "@id": "urn:solid-server:default:PrimaryParallelInitializer" },
          { "@id": "urn:solid-server:default:ModuleVersionVerifier" },
          { "@id": "urn:solid-server:default:WorkerManager" },
          { "@id": "urn:solid-server:default:SeededAccountInitializer" },
          { "@id": "urn:undefineds:xpod:CenterNodeRegistrationService" }
        ]
      }
    },
    {
      "comment": "Pod routing handler for cross-node request forwarding",
      "@id": "urn:undefineds:xpod:PodRoutingHttpHandler",
      "@type": "PodRoutingHttpHandler",
      "options_identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      },
      "options_nodeId": {
        "@id": "urn:solid-server:default:variable:nodeId",
        "@type": "Variable"
      },
      "options_enabled": {
        "@id": "urn:solid-server:default:variable:podRoutingEnabled",
        "@type": "Variable"
      }
    },
    {
      "comment": "Pod migration API handler (/.cluster/pods)",
      "@id": "urn:undefineds:xpod:PodMigrationHttpHandler",
      "@type": "PodMigrationHttpHandler",
      "options_identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      }
    },
    {
      "comment": "Define MainHttpHandler with tracing middleware.",
      "@id": "urn:undefineds:xpod:MainHttpHandler",
      "@type": "https://linkedsoftwaredependencies.org/bundles/npm/asynchronous-handlers/^1.0.0/components/ChainedHttpHandler.jsonld#ChainedHttpHandler",
      "https://linkedsoftwaredependencies.org/bundles/npm/asynchronous-handlers/^1.0.0/components/ChainedHttpHandler.jsonld#ChainedHttpHandler_handlers": [
        { "@id": "urn:undefineds:xpod:TracingMiddleware" },
        { "@id": "urn:solid-server:default:HttpHandler" }
      ]
    }
  ]
}
