@jant/core 0.6.6 → 0.6.7

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.
@@ -72,6 +72,11 @@ export interface ManageManagedSiteDomainInput {
72
72
  makePrimary?: boolean;
73
73
  }
74
74
 
75
+ export interface RenameManagedSiteInput {
76
+ key: string;
77
+ primaryHost: string;
78
+ }
79
+
75
80
  export interface ExportManagedSiteDeps {
76
81
  env: Bindings;
77
82
  storage?: StorageDriver | null;
@@ -130,6 +135,20 @@ export interface SiteAdminService {
130
135
  ): Promise<ManagedSitePostCountResult[]>;
131
136
  suspendManagedSite(siteId: string): Promise<Site>;
132
137
  resumeManagedSite(siteId: string): Promise<Site>;
138
+ /**
139
+ * Atomically rename a managed site: change `sites.key` and rewrite the
140
+ * existing primary domain's host. The primary domain row keeps its id, so
141
+ * downstream projections that key off the domain id (e.g. the control
142
+ * plane's `cloud_site_domain` projection) stay stable across the rename.
143
+ *
144
+ * Throws ConflictError if the new key or primary host collide with another
145
+ * site (or with a non-primary domain on the same site). No-ops when the new
146
+ * key and host both match the current values.
147
+ */
148
+ renameManagedSite(
149
+ siteId: string,
150
+ input: RenameManagedSiteInput,
151
+ ): Promise<ManagedSiteResult>;
133
152
  deleteManagedSite(
134
153
  siteId: string,
135
154
  deps?: DeleteManagedSiteDeps,
@@ -1024,5 +1043,107 @@ export function createSiteAdminService(
1024
1043
  .where(eq(siteDomains.id, normalizedDomainId));
1025
1044
  });
1026
1045
  },
1046
+ async renameManagedSite(siteId, input) {
1047
+ assertManagedSiteOperationsEnabled();
1048
+ const normalizedSiteId = siteId.trim();
1049
+ if (!normalizedSiteId) {
1050
+ throw new NotFoundError("Site");
1051
+ }
1052
+
1053
+ const newKey = input.key.trim();
1054
+ const newPrimaryHost = input.primaryHost.trim().toLowerCase();
1055
+ if (!newKey) {
1056
+ throw new ConflictError("Site key is required.");
1057
+ }
1058
+ if (!newPrimaryHost) {
1059
+ throw new ConflictError("Primary host is required.");
1060
+ }
1061
+
1062
+ async function performRename(
1063
+ targetDb: Database,
1064
+ ): Promise<ManagedSiteResult> {
1065
+ const siteRow = await requireSiteRow(targetDb, normalizedSiteId);
1066
+
1067
+ const primaryRows = await targetDb
1068
+ .select()
1069
+ .from(siteDomains)
1070
+ .where(
1071
+ and(
1072
+ eq(siteDomains.siteId, normalizedSiteId),
1073
+ eq(siteDomains.kind, "primary"),
1074
+ ),
1075
+ )
1076
+ .limit(1);
1077
+ const primaryRow = primaryRows[0];
1078
+ if (!primaryRow) {
1079
+ throw new NotFoundError("Site primary domain");
1080
+ }
1081
+
1082
+ if (siteRow.key === newKey && primaryRow.host === newPrimaryHost) {
1083
+ return {
1084
+ domain: toSiteDomain(primaryRow),
1085
+ site: toSite(siteRow),
1086
+ };
1087
+ }
1088
+
1089
+ if (siteRow.key !== newKey) {
1090
+ const conflictingSite = await targetDb
1091
+ .select({ id: sites.id })
1092
+ .from(sites)
1093
+ .where(eq(sites.key, newKey))
1094
+ .limit(1);
1095
+ if (conflictingSite[0]) {
1096
+ throw new ConflictError("Site key is already in use.");
1097
+ }
1098
+ }
1099
+
1100
+ if (primaryRow.host !== newPrimaryHost) {
1101
+ const conflictingDomain = await targetDb
1102
+ .select({ id: siteDomains.id, siteId: siteDomains.siteId })
1103
+ .from(siteDomains)
1104
+ .where(eq(siteDomains.host, newPrimaryHost))
1105
+ .limit(1);
1106
+ if (conflictingDomain[0]) {
1107
+ throw new ConflictError("Primary host is already in use.");
1108
+ }
1109
+ }
1110
+
1111
+ const timestamp = now();
1112
+ const updatedSiteRow = (
1113
+ await targetDb
1114
+ .update(sites)
1115
+ .set({ key: newKey, updatedAt: timestamp })
1116
+ .where(eq(sites.id, normalizedSiteId))
1117
+ .returning()
1118
+ )[0];
1119
+ if (!updatedSiteRow) {
1120
+ throw new NotFoundError("Site");
1121
+ }
1122
+
1123
+ const updatedDomainRow = (
1124
+ await targetDb
1125
+ .update(siteDomains)
1126
+ .set({ host: newPrimaryHost, updatedAt: timestamp })
1127
+ .where(eq(siteDomains.id, primaryRow.id))
1128
+ .returning()
1129
+ )[0];
1130
+ if (!updatedDomainRow) {
1131
+ throw new NotFoundError("Site primary domain");
1132
+ }
1133
+
1134
+ return {
1135
+ domain: toSiteDomain(updatedDomainRow),
1136
+ site: toSite(updatedSiteRow),
1137
+ };
1138
+ }
1139
+
1140
+ if (supportsDrizzleTransaction(db, databaseDialect)) {
1141
+ return db.transaction(async (tx) =>
1142
+ performRename(tx as unknown as Database),
1143
+ );
1144
+ }
1145
+
1146
+ return performRename(db);
1147
+ },
1027
1148
  };
1028
1149
  }