feat(pages): pull latest by project and keep a single edge release

Agents now treat pages_project_id as the stable anchor and fetch the
control-plane active package via project latest APIs, so activating a
deployment updates edges without republishing main config. Local roots use
projects/{id}/current, only the newest release is retained after a successful
switch, hash/package races retry, and per-project failures no longer block
siblings.
This commit is contained in:
ryan
2026-07-17 17:43:40 +08:00
parent a0fcf9f627
commit ce736e2de4
21 changed files with 871 additions and 219 deletions
+8
View File
@@ -220,3 +220,11 @@ type PagesDeploymentHashResponse struct {
DeploymentID uint `json:"deployment_id"`
Hash string `json:"hash"`
}
// PagesProjectLatestHashResponse is the hash of a project's currently active Pages deployment.
// Agents poll this like a "latest" pointer without caring about historical deployment IDs.
type PagesProjectLatestHashResponse struct {
ProjectID uint `json:"project_id"`
DeploymentID uint `json:"deployment_id"`
Hash string `json:"hash"`
}
+2 -2
View File
@@ -345,7 +345,7 @@ func TestRenderRouteConfigPagesWithoutSPAFallbackServesRoot(t *testing.T) {
UpstreamType: "pages",
EnableHTTPS: false,
PagesDeployment: &PagesDeployment{
LocalRoot: "/data/var/lib/openflare/pages/deployments/1/current",
LocalRoot: "/data/var/lib/openflare/pages/projects/1/current",
EntryFile: "index.html",
SPAFallbackEnabled: false,
},
@@ -378,7 +378,7 @@ func TestRenderRouteConfigPagesWithSPAFallbackServesRoot(t *testing.T) {
UpstreamType: "pages",
EnableHTTPS: false,
PagesDeployment: &PagesDeployment{
LocalRoot: "/data/var/lib/openflare/pages/deployments/1/current",
LocalRoot: "/data/var/lib/openflare/pages/projects/1/current",
EntryFile: "index.html",
SPAFallbackEnabled: true,
SPAFallbackPath: "/index.html",
+16 -1
View File
@@ -1,6 +1,9 @@
package openresty
import "encoding/json"
import (
"encoding/json"
"fmt"
)
// Placeholder constants used as sentinel values in rendered OpenResty config
// files; the deploy process replaces them with real paths before reload.
@@ -163,6 +166,10 @@ type Route struct {
// PagesDeployment holds the static-site deployment parameters for a Pages-type
// route, including local root, entry file, SPA fallback, and API proxy options.
//
// LocalRoot is anchored on ProjectID (projects/{id}/current), not a specific
// deployment ID, so Agents can switch active packages without re-publishing
// main config / reloading OpenResty root paths.
type PagesDeployment struct {
ProjectID uint `json:"project_id"`
ProjectSlug string `json:"project_slug"`
@@ -179,6 +186,14 @@ type PagesDeployment struct {
LocalRoot string `json:"local_root"`
}
// PagesProjectLocalRoot returns the Agent-local root for a Pages project.
func PagesProjectLocalRoot(projectID uint) string {
if projectID == 0 {
return PagesDirPlaceholder
}
return fmt.Sprintf("%s/projects/%d/current", PagesDirPlaceholder, projectID)
}
// WAFRuleGraph is the compact graph executed by the OpenResty WAF runtime.
type WAFRuleGraph struct {
Entry string `json:"entry"`