{
  "@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"
  ],
  "import": [
    "./main.json",
    "./xpod.base.json"
  ],
  "@graph": [
    {
      "comment": "Redis-based locker with expiration wrapper for clustered deployments",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:ResourceLocker"
      },
      "overrideParameters": {
        "@type": "WrappedExpiringReadWriteLocker",
        "locker": {
          "@type": "UrlAwareRedisLocker",
          "redisClient": {
            "@id": "urn:solid-server:default:variable:redisClient",
            "@type": "Variable"
          }
        },
        "expiration": 6000
      }
    },
    {
      "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": "Redefine PrimarySequenceInitializer to include CenterNodeRegistrationService",
      "@id": "urn:solid-server:default:PrimarySequenceInitializer",
      "@type": "SequenceHandler",
      "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/SequenceHandler.jsonld#SequenceHandler_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": "Quota service backed by identity DB, falls back to env defaults then unlimited",
      "@id": "urn:undefineds:xpod:QuotaService",
      "@type": "DrizzleQuotaService",
      "DrizzleQuotaService:_options_identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl"
      }
    },
    {
      "comment": "Persist CSS account identity records in the clustered identity DB. LoginMethodGuardStorage keeps the last-login-method deletion guard while allowing SP-linked accounts to exist without passwords.",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:AccountStorage"
      },
      "overrideParameters": {
        "@type": "LoginMethodGuardStorage",
        "storage": {
          "@type": "DrizzleIndexedStorage",
          "connectionString": {
            "@id": "urn:solid-server:default:variable:identityDbUrl",
            "@type": "Variable"
          }
        }
      }
    },
    {
      "comment": "The settings of your email server.",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:EmailSender"
      },
      "overrideParameters": {
        "@type": "BaseEmailSender",
        "senderName": "Undefineds Support Team <support@undefineds.co>",
        "emailConfig_host": {
          "@id": "urn:solid-server:default:variable:emailConfigHost",
          "@type": "Variable"
        },
        "emailConfig_port": {
          "@id": "urn:solid-server:default:variable:emailConfigPort",
          "@type": "Variable"
        },
        "emailConfig_auth_user": {
          "@id": "urn:solid-server:default:variable:emailConfigAuthUser",
          "@type": "Variable"
        },
        "emailConfig_auth_pass": {
          "@id": "urn:solid-server:default:variable:emailConfigAuthPass",
          "@type": "Variable"
        }
      }
    },
    {
      "@id": "urn:undefineds:xpod:MixDataAccessor",
      "@type": "MixDataAccessor",
      "structuredDataAccessor": {
        "@id": "urn:undefineds:xpod:SolidRdfDataAccessor"
      },
      "unstructuredDataAccessor": {
        "@id": "urn:undefineds:xpod:RemoteDataAccessor"
      },
      "presignedRedirectEnabled": false,
      "textSearchIndexingEnabled": true,
      "rdfSearchIntentSink": {
        "@id": "urn:undefineds:xpod:RdfSearchIntentSink"
      },
      "rdfFileDataAccessor": {
        "@id": "urn:solid-server:default:FileDataAccessor"
      }
    },
    {
      "comment": "Default structured RDF data accessor backed directly by SolidRdfEngine.",
      "@id": "urn:undefineds:xpod:SolidRdfDataAccessor",
      "@type": "SolidRdfDataAccessor",
      "rdfEngine": {
        "@id": "urn:undefineds:xpod:SolidRdfEngine"
      },
      "identifierStrategy": {
        "@id": "urn:solid-server:default:IdentifierStrategy"
      }
    },
    {
      "comment": "PostgreSQL-backed text search index sharing the RDF database.",
      "@id": "urn:undefineds:xpod:PostgresRdfTextIndex",
      "@type": "PostgresRdfTextIndex",
      "options_driver": "pg",
      "options_textSearchBackend": "pg-native-fts",
      "options_connectionString": {
        "@id": "urn:solid-server:default:variable:sparqlEndpoint",
        "@type": "Variable"
      }
    },
    {
      "comment": "PostgreSQL-backed vector search index sharing the RDF database.",
      "@id": "urn:undefineds:xpod:PostgresRdfVectorIndex",
      "@type": "PostgresRdfVectorIndex",
      "options_driver": "pg",
      "options_backend": "component",
      "options_connectionString": {
        "@id": "urn:solid-server:default:variable:sparqlEndpoint",
        "@type": "Variable"
      },
      "options_defaultMetric": "cosine"
    },
    {
      "comment": "RDF facts engine backed by PostgreSQL facts and PG search indexes.",
      "@id": "urn:undefineds:xpod:SolidRdfEngine",
      "@type": "PostgresRdfEngine",
      "options_driver": "pg",
      "options_connectionString": {
        "@id": "urn:solid-server:default:variable:sparqlEndpoint",
        "@type": "Variable"
      },
      "options_textIndex": {
        "@id": "urn:undefineds:xpod:PostgresRdfTextIndex"
      },
      "options_vectorIndex": {
        "@id": "urn:undefineds:xpod:PostgresRdfVectorIndex"
      },
      "options_rdfAccelerationProfile": "pg-hot-operators",
      "options_autoOpen": true,
      "options_maintenanceIntervalMs": 60000,
      "options_maintenanceSourceBatchSize": 256
    },
    {
      "comment": "Default SPARQL engine for public Cloud: evaluate SPARQL algebra with Comunica over the PostgreSQL RDF facts engine; no native QLever or per-request fallback.",
      "@id": "urn:undefineds:xpod:DefaultSparqlEngine",
      "@type": "RdfQuerySparqlEngine",
      "rdfEngine": {
        "@id": "urn:undefineds:xpod:SolidRdfEngine"
      }
    },
    {
      "comment": "Terminal Sidecar HTTP Handler - manages PTY sessions for trusted AI agents",
      "@id": "urn:undefineds:xpod:TerminalHttpHandler",
      "@type": "TerminalHttpHandler",
      "sidecarPath": "/-/terminal",
      "credentialsExtractor": {
        "@id": "urn:solid-server:default:CredentialsExtractor"
      },
      "maxSessionsPerUser": 5,
      "maxTotalSessions": 100,
      "defaultTimeout": 3600,
      "maxTimeout": 86400,
      "defaultWorkdir": "/workspace",
      "sparqlEngine": {
        "@id": "urn:undefineds:xpod:DefaultSparqlEngine"
      }
    },
    {
      "@id": "urn:undefineds:xpod:RemoteDataAccessor",
      "@type": "MinioDataAccessor",
      "resourceMapper": {
        "@id": "urn:solid-server:default:FileIdentifierMapper"
      },
      "accessKey": {
        "@id": "urn:solid-server:default:variable:minioAccessKey",
        "@type": "Variable"
      },
      "secretKey": {
        "@id": "urn:solid-server:default:variable:minioSecretKey",
        "@type": "Variable"
      },
      "endpoint": {
        "@id": "urn:solid-server:default:variable:minioEndpoint",
        "@type": "Variable"
      },
      "bucketName": {
        "@id": "urn:solid-server:default:variable:minioBucketName",
        "@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"
    },
    {
      "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"
              }
            }
          }
        }
      }
    },
    {
      "@id": "urn:undefineds:xpod:SparqlResourceStoreBackend",
      "@type": "SparqlUpdateResourceStore",
      "identifierStrategy": { "@id": "urn:solid-server:default:IdentifierStrategy" },
      "auxiliaryStrategy": { "@id": "urn:solid-server:default:AuxiliaryStrategy" },
      "metadataStrategy": { "@id": "urn:solid-server:default:MetadataStrategy" },
      "accessor": { "@id": "urn:undefineds:xpod:MixDataAccessor" }
    },
    {
      "@id": "urn:undefineds:xpod:TrackedResourceStore",
      "@type": "UsageTrackingStore",
      "UsageTrackingStore:_source": { "@id": "urn:undefineds:xpod:SparqlResourceStoreBackend" },
      "options_identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      },
      "options_defaultAccountBandwidthLimitBps": {
        "@type": "Literal",
        "value": 10485760
      }
    },
    {
      "comment": "等位替换: 保留资源变更通知；FTS 在 MixDataAccessor 提交，VEC 由 durable reconciliation 补齐",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:ResourceStore_Backend"
      },
      "overrideParameters": {
        "@type": "ObservableResourceStore",
        "source": { "@id": "urn:undefineds:xpod:TrackedResourceStore" }
      }
    },
    {
      "comment": "等位替换: 用 RepresentationPartialConvertingStore 替换 Converting 层，只转换 RDF 类型",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:ResourceStore_Converting"
      },
      "overrideParameters": {
        "@type": "RepresentationPartialConvertingStore",
        "source": {
          "@id": "urn:solid-server:default:ResourceStore_Backend"
        },
        "metadataStrategy": {
          "@id": "urn:solid-server:default:MetadataStrategy"
        },
        "options_inConverter": {
          "@id": "urn:solid-server:default:RepresentationConverter"
        },
        "options_outConverter": {
          "@id": "urn:solid-server:default:RepresentationConverter"
        },
        "options_inPreferences_type": {
          "RepresentationPartialConvertingStore:_options_inPreferences_type_key": "internal/quads",
          "RepresentationPartialConvertingStore:_options_inPreferences_type_value": 1
        }
      }
    },
    {
      "comment": "Apply bandwidth limits to SPARQL responses in server profile",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:undefineds:xpod:SubgraphSparqlHttpHandler"
      },
      "overrideParameters": {
        "@type": "SubgraphSparqlHttpHandler",
        "options_defaultAccountBandwidthLimitBps": {
          "@type": "Literal",
          "value": 10485760
        }
      }
    },
    {
      "comment": "Enforce per-account quota via default quota service",
      "@id": "urn:solid-server:default:QuotaStrategy",
      "@type": "PerAccountQuotaStrategy",
      "PerAccountQuotaStrategy:_options_identityDbUrl": {
        "@id": "urn:solid-server:default:variable:identityDbUrl",
        "@type": "Variable"
      },
      "PerAccountQuotaStrategy:_options_defaultAccountQuotaBytes": {
        "@type": "Literal",
        "value": 10737418240
      },
      "PerAccountQuotaStrategy:_options_quotaService": {
        "@id": "urn:undefineds:xpod:QuotaService"
      },
      "PerAccountQuotaStrategy:_reporter": {
        "@id": "urn:solid-server:default:SizeReporter"
      }
    },
    {
      "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": "Compose server HTTP pipeline (simplified, no cluster-specific handlers)",
      "@type": "Override",
      "overrideInstance": {
        "@id": "urn:solid-server:default:BaseHttpHandler"
      },
      "overrideParameters": {
        "@type": "StatusWaterfallHandler",
        "handlers": [
          {
            "@id": "urn:undefineds:xpod:InternalPodDataHttpHandler"
          },
          {
            "@id": "urn:undefineds:xpod:SubgraphSparqlHttpHandler"
          },
          {
            "@id": "urn:undefineds:xpod:TerminalHttpHandler"
          },
          {
            "@id": "urn:undefineds:xpod:AppStaticAssetHandler"
          },
          {
            "@id": "urn:solid-server:default:StaticAssetHandler"
          },
          {
            "@id": "urn:solid-server:default:OidcHandler"
          },
          {
            "@id": "urn:solid-server:default:NotificationHttpHandler"
          },
          {
            "@id": "urn:solid-server:default:StorageDescriptionHandler"
          },
          {
            "@id": "urn:solid-server:default:AuthResourceHttpHandler"
          },
          {
            "@id": "urn:solid-server:default:IdentityProviderHandler"
          },
          {
            "@id": "urn:solid-server:default:LdpHandler"
          }
        ]
      }
    }
  ]
}
