@treeseed/sdk 0.13.0-rc.71 → 0.13.0-rc.73

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.
@@ -27,6 +27,14 @@ const resourceProviderKinds = {
27
27
  };
28
28
  const sensitiveKey = /(?:credential|password|private.?key|registration.?code|secret|token)/iu;
29
29
  const personalPath = /(?:^|[\s'"`:=])(?:\/home\/[^/\s]+|\/Users\/[^/\s]+|[A-Za-z]:\\Users\\[^\\\s]+)/u;
30
+ const hostedResourceDeclarationSchema = z.object({
31
+ id: identifier,
32
+ provider: hostedProviderSchema,
33
+ kind: hostedResourceKindSchema,
34
+ dependsOn: z.array(identifier).default([]),
35
+ parameters: z.record(identifier, parameterSchema).default({}),
36
+ adoption: z.object({ mode: z.literal("adopt-or-create"), externalIdInput: identifier.optional(), replacement: z.literal("forbidden") }).strict()
37
+ }).strict();
30
38
  const hostedTopologyDeclarationSchema = z.object({
31
39
  schemaVersion: z.literal("treeseed.hosted-topology/v1"),
32
40
  id: identifier,
@@ -35,14 +43,7 @@ const hostedTopologyDeclarationSchema = z.object({
35
43
  platform: z.object({ repository: z.literal("treeseed-ai/platform"), commit: gitCommit }).strict(),
36
44
  providerConnections: z.record(hostedProviderSchema, z.object({ connectionRef: identifier }).strict()),
37
45
  artifacts: z.record(identifier, z.object({ digest, source: z.string().url() }).strict()),
38
- resources: z.array(z.object({
39
- id: identifier,
40
- provider: hostedProviderSchema,
41
- kind: hostedResourceKindSchema,
42
- dependsOn: z.array(identifier).default([]),
43
- parameters: z.record(identifier, parameterSchema).default({}),
44
- adoption: z.object({ mode: z.literal("adopt-or-create"), externalIdInput: identifier.optional(), replacement: z.literal("forbidden") }).strict()
45
- }).strict()).min(1)
46
+ resources: z.array(hostedResourceDeclarationSchema).min(1)
46
47
  }).strict().superRefine((declaration, context) => {
47
48
  const ids = declaration.resources.map(({ id }) => id);
48
49
  if (new Set(ids).size !== ids.length) context.addIssue({ code: z.ZodIssueCode.custom, path: ["resources"], message: "Hosted topology resource identities must be unique." });
@@ -63,7 +64,7 @@ const hostedResourceObservationSchema = z.object({
63
64
  observedDigest: digest.nullable(),
64
65
  observedAt: timestamp
65
66
  }).strict();
66
- const hostedTopologyPlanSchema = z.object({
67
+ const hostedTopologyPlanShape = {
67
68
  schemaVersion: z.literal("treeseed.hosted-topology-plan/v1"),
68
69
  planId: z.string().regex(/^topology-plan-[a-f0-9]{16}$/u),
69
70
  planDigest: digest,
@@ -76,6 +77,7 @@ const hostedTopologyPlanSchema = z.object({
76
77
  provider: hostedProviderSchema,
77
78
  kind: hostedResourceKindSchema,
78
79
  action: z.enum(["create", "adopt", "update", "noop"]),
80
+ desiredResource: hostedResourceDeclarationSchema,
79
81
  desiredDigest: digest,
80
82
  previousDigest: digest.nullable(),
81
83
  providerResourceId: z.string().min(1).max(512).nullable()
@@ -83,7 +85,28 @@ const hostedTopologyPlanSchema = z.object({
83
85
  blockers: z.array(z.object({ code: z.enum(["connection-unavailable", "dependency-cycle", "observation-unhealthy", "adoption-drift"]), resourceId: identifier.optional(), message: z.string().min(1) }).strict()),
84
86
  approvalRequired: z.boolean(),
85
87
  executable: z.literal(false)
86
- }).strict();
88
+ };
89
+ function verifyPlanBinding(plan, context) {
90
+ for (const [index, action] of plan.actions.entries()) {
91
+ const desired = hostedResourceDeclarationSchema.parse(action.desiredResource);
92
+ if (desired.id !== action.resourceId || desired.provider !== action.provider || desired.kind !== action.kind)
93
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["actions", index, "desiredResource"], message: "Hosted plan action identity must match its desired resource specification." });
94
+ if (deploymentDigest(desired) !== action.desiredDigest)
95
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["actions", index, "desiredDigest"], message: "Hosted plan desired digest must bind its complete desired resource specification." });
96
+ }
97
+ const core = {
98
+ declarationDigest: plan.declarationDigest,
99
+ topologyId: plan.topologyId,
100
+ environment: plan.environment,
101
+ platformCommit: plan.platformCommit,
102
+ actions: plan.actions,
103
+ blockers: plan.blockers
104
+ };
105
+ const expected = deploymentDigest(core);
106
+ if (expected !== plan.planDigest || plan.planId !== `topology-plan-${expected.slice(7, 23)}`)
107
+ context.addIssue({ code: z.ZodIssueCode.custom, path: ["planDigest"], message: "Hosted topology plan identity must bind the exact canonical plan." });
108
+ }
109
+ const hostedTopologyPlanSchema = z.object(hostedTopologyPlanShape).strict().superRefine(verifyPlanBinding);
87
110
  const hostedTopologyApprovalSchema = z.object({
88
111
  schemaVersion: z.literal("treeseed.hosted-topology-approval/v1"),
89
112
  planDigest: digest,
@@ -92,10 +115,11 @@ const hostedTopologyApprovalSchema = z.object({
92
115
  approvedBy: z.string().min(1).max(256),
93
116
  approvedAt: timestamp
94
117
  }).strict();
95
- const authorizedHostedTopologyPlanSchema = hostedTopologyPlanSchema.extend({
118
+ const authorizedHostedTopologyPlanSchema = z.object({
119
+ ...hostedTopologyPlanShape,
96
120
  executable: z.literal(true),
97
121
  approval: hostedTopologyApprovalSchema.nullable()
98
- }).omit({ approvalRequired: true });
122
+ }).strict().omit({ approvalRequired: true }).superRefine(verifyPlanBinding);
99
123
  const hostedTopologyReceiptSchema = z.object({
100
124
  schemaVersion: z.literal("treeseed.hosted-topology-receipt/v1"),
101
125
  receiptId: z.string().regex(/^topology-receipt-[a-f0-9]{16}$/u),
@@ -113,6 +137,7 @@ const hostedTopologyRollbackSchema = z.object({
113
137
  schemaVersion: z.literal("treeseed.hosted-topology-rollback/v1"),
114
138
  rollbackId: z.string().regex(/^topology-rollback-[a-f0-9]{16}$/u),
115
139
  sourceReceiptId: z.string().regex(/^topology-receipt-[a-f0-9]{16}$/u),
140
+ environment: z.enum(["staging", "production"]),
116
141
  operations: z.array(z.object({
117
142
  resourceId: identifier,
118
143
  action: z.enum(["restore", "delete-created", "noop"]),
@@ -121,6 +146,14 @@ const hostedTopologyRollbackSchema = z.object({
121
146
  }).strict()),
122
147
  rollbackDigest: digest
123
148
  }).strict();
149
+ const hostedTopologyRollbackApprovalSchema = z.object({
150
+ schemaVersion: z.literal("treeseed.hosted-topology-rollback-approval/v1"),
151
+ rollbackDigest: digest,
152
+ environment: z.enum(["staging", "production"]),
153
+ decision: z.literal("approved"),
154
+ approvedBy: z.string().min(1).max(256),
155
+ approvedAt: timestamp
156
+ }).strict();
124
157
  function observationMap(items, declaration) {
125
158
  const resources = new Map(declaration.resources.map((resource) => [resource.id, resource]));
126
159
  const observations = /* @__PURE__ */ new Map();
@@ -173,7 +206,16 @@ function planHostedTopology(input) {
173
206
  else if (observation.managedBy === "external") blockers.push({ code: "adoption-drift", resourceId: resource.id, message: `External resource ${resource.id} differs from the declaration and cannot be replaced.` });
174
207
  else action = "update";
175
208
  }
176
- return { resourceId: resource.id, provider: resource.provider, kind: resource.kind, action, desiredDigest, previousDigest: observation?.observedDigest ?? null, providerResourceId: observation?.providerResourceId ?? null };
209
+ return {
210
+ resourceId: resource.id,
211
+ provider: resource.provider,
212
+ kind: resource.kind,
213
+ action,
214
+ desiredResource: resource,
215
+ desiredDigest,
216
+ previousDigest: observation?.observedDigest ?? null,
217
+ providerResourceId: observation?.providerResourceId ?? null
218
+ };
177
219
  });
178
220
  const declarationDigest = deploymentDigest(normalizedDeclaration);
179
221
  const core = { declarationDigest, topologyId: declaration.id, environment: declaration.environment, platformCommit: declaration.platform.commit, actions, blockers };
@@ -211,10 +253,16 @@ function planHostedTopologyRollback(receiptInput) {
211
253
  return { resourceId: resource.resourceId, action: !prior || prior.state === "missing" ? "delete-created" : prior.observedDigest === resource.observedDigest ? "noop" : "restore", providerResourceId: resource.providerResourceId, targetDigest: prior?.observedDigest ?? null };
212
254
  }).sort((left, right) => left.resourceId.localeCompare(right.resourceId));
213
255
  const rollbackDigest = deploymentDigest({ sourceReceiptId: receipt.receiptId, operations });
214
- return hostedTopologyRollbackSchema.parse({ schemaVersion: "treeseed.hosted-topology-rollback/v1", rollbackId: `topology-rollback-${rollbackDigest.slice(7, 23)}`, sourceReceiptId: receipt.receiptId, operations, rollbackDigest });
256
+ return hostedTopologyRollbackSchema.parse({ schemaVersion: "treeseed.hosted-topology-rollback/v1", rollbackId: `topology-rollback-${rollbackDigest.slice(7, 23)}`, sourceReceiptId: receipt.receiptId, environment: receipt.environment, operations, rollbackDigest });
257
+ }
258
+ function authorizeHostedTopologyRollback(rollbackInput, approvalInput) {
259
+ const rollback = hostedTopologyRollbackSchema.parse(rollbackInput), approval = hostedTopologyRollbackApprovalSchema.parse(approvalInput);
260
+ if (approval.rollbackDigest !== rollback.rollbackDigest || approval.environment !== rollback.environment) throw new Error("Hosted topology rollback approval does not bind the exact rollback and environment.");
261
+ return { rollback, approval };
215
262
  }
216
263
  export {
217
264
  authorizeHostedTopologyPlan,
265
+ authorizeHostedTopologyRollback,
218
266
  authorizedHostedTopologyPlanSchema,
219
267
  hostedProviderSchema,
220
268
  hostedResourceKindSchema,
@@ -223,6 +271,7 @@ export {
223
271
  hostedTopologyDeclarationSchema,
224
272
  hostedTopologyPlanSchema,
225
273
  hostedTopologyReceiptSchema,
274
+ hostedTopologyRollbackApprovalSchema,
226
275
  hostedTopologyRollbackSchema,
227
276
  planHostedTopology,
228
277
  planHostedTopologyRollback,
@@ -34,6 +34,10 @@ const operationBindings = {
34
34
  "platform verify": local("local.platform.verify"),
35
35
  "platform workset": local("local.platform.workset"),
36
36
  "platform project create": local("local.platform.project.create"),
37
+ "platform topology plan": local("local.platform.topology.plan"),
38
+ "platform topology apply": local("local.platform.topology.apply"),
39
+ "platform topology status": local("local.platform.topology.status"),
40
+ "platform topology rollback": local("local.platform.topology.rollback"),
37
41
  "host status": local("local.host.status"),
38
42
  "host doctor": local("local.host.doctor"),
39
43
  "host plan": local("local.host.plan"),
@@ -358,6 +362,12 @@ const commandTree = {
358
362
  { nodeType: "leaf", segment: "workset", description: "Plan or safely materialize exact primary source checkouts beneath packages/.", kind: "mutation", options: [planOption, { name: "--apply", description: "Apply the frozen workset plan.", type: "boolean" }, { name: "--yes", description: "Confirm the planned checkout mutations.", type: "boolean" }, { name: "--profile", description: "Composable source profile; repeat to union profiles.", type: "string[]" }, { name: "--project", description: "Explicit project slug; repeat to select projects.", type: "string[]" }, { name: "--exclude", description: "Project slug to exclude; repeat as needed.", type: "string[]" }, { name: "--json", description: "Emit the stable command-result envelope.", type: "boolean" }], authorization: { capability: "development.workset", confirmation: "never" }, resultSchemaId: "treeseed.platform-workset-result/v1", execution: local("local.platform.workset") },
359
363
  branch("project", [
360
364
  { nodeType: "leaf", segment: "create", description: "Plan or reconcile a project, repository, template, library binding, and live inventory without writing application source into Platform Git.", kind: "mutation", arguments: [{ name: "slug", description: "Portable project slug.", required: true }], options: [planOption, { name: "--apply", description: "Apply the accepted creation plan.", type: "boolean" }, { name: "--yes", description: "Confirm authority-bearing project creation.", type: "boolean" }, { name: "--template", description: "Published template identity.", type: "string", required: true }, { name: "--json", description: "Emit the stable command-result envelope.", type: "boolean" }], authorization: { capability: "projects.create", confirmation: "authority" }, resultSchemaId: "treeseed.platform-project-create-result/v1", execution: local("local.platform.project.create") }
365
+ ]),
366
+ branch("topology", [
367
+ { nodeType: "leaf", segment: "plan", description: "Plan Cloudflare and Railway reconciliation from a portable hosted-topology declaration.", kind: "read", arguments: [{ name: "file", description: "Hosted topology YAML or JSON declaration.", required: true }], resultSchemaId: "treeseed.hosted-topology-plan/v1", execution: local("local.platform.topology.plan") },
368
+ { nodeType: "leaf", segment: "apply", description: "Apply an exact reviewed hosted-topology plan through the operations runner.", kind: "mutation", arguments: [{ name: "plan", description: "Exact plan JSON file.", required: true }], options: [planOption, { name: "--approval", description: "Exact environment approval JSON file.", type: "string", required: true }, { name: "--yes", description: "Confirm the authority-bearing mutation.", type: "boolean" }], authorization: { capability: "infrastructure.write", confirmation: "authority" }, resultSchemaId: "treeseed.platform-operation/v1", execution: local("local.platform.topology.apply") },
369
+ { nodeType: "leaf", segment: "status", description: "Read the latest hosted-topology operation and known-good receipt.", kind: "read", resultSchemaId: "treeseed.infrastructure.topology.status.output/v1", execution: local("local.platform.topology.status") },
370
+ { nodeType: "leaf", segment: "rollback", description: "Restore exact prior hosted-topology state from a known-good receipt.", kind: "mutation", arguments: [{ name: "rollback", description: "Exact rollback JSON file.", required: true }], options: [planOption, { name: "--approval", description: "Exact rollback approval JSON file.", type: "string", required: true }, { name: "--yes", description: "Confirm the destructive rollback.", type: "boolean" }], authorization: { capability: "infrastructure.write", confirmation: "destructive" }, resultSchemaId: "treeseed.platform-operation/v1", execution: local("local.platform.topology.rollback") }
361
371
  ])
362
372
  ]),
363
373
  branch("dev", [
@@ -0,0 +1,214 @@
1
+ export declare const HOSTED_TOPOLOGY_OPERATIONS: {
2
+ readonly plan: import("../control-plane-operation.js").ControlPlaneOperationBinding<{
3
+ teamId: string;
4
+ }, {}, {
5
+ declaration: {
6
+ schemaVersion: "treeseed.hosted-topology/v1";
7
+ resources: {
8
+ id: string;
9
+ kind: "admin-application" | "dns-record" | "tls-policy" | "api-proxy" | "control-plane-api" | "postgresql" | "operations-runner" | "treedx-service";
10
+ provider: "cloudflare" | "railway";
11
+ adoption: {
12
+ mode: "adopt-or-create";
13
+ replacement: "forbidden";
14
+ externalIdInput?: string | undefined;
15
+ };
16
+ dependsOn?: string[] | undefined;
17
+ parameters?: Record<string, {
18
+ input: string;
19
+ } | {
20
+ artifact: string;
21
+ } | {
22
+ resourceOutput: {
23
+ resourceId: string;
24
+ output: string;
25
+ };
26
+ } | {
27
+ literal: string | number | boolean;
28
+ }> | undefined;
29
+ }[];
30
+ id: string;
31
+ platform: {
32
+ repository: "treeseed-ai/platform";
33
+ commit: string;
34
+ };
35
+ mutation: "approval-required";
36
+ environment: "production" | "staging";
37
+ artifacts: Record<string, {
38
+ digest: string;
39
+ source: string;
40
+ }>;
41
+ providerConnections: Partial<Record<"cloudflare" | "railway", {
42
+ connectionRef: string;
43
+ }>>;
44
+ };
45
+ }, {
46
+ schemaVersion: "treeseed.hosted-topology-plan/v1";
47
+ blockers: {
48
+ code: "connection-unavailable" | "dependency-cycle" | "observation-unhealthy" | "adoption-drift";
49
+ message: string;
50
+ resourceId?: string | undefined;
51
+ }[];
52
+ planDigest: string;
53
+ actions: {
54
+ action: "noop" | "create" | "adopt" | "update";
55
+ resourceId: string;
56
+ kind: "admin-application" | "dns-record" | "tls-policy" | "api-proxy" | "control-plane-api" | "postgresql" | "operations-runner" | "treedx-service";
57
+ provider: "cloudflare" | "railway";
58
+ providerResourceId: string | null;
59
+ desiredResource: {
60
+ id: string;
61
+ kind: "admin-application" | "dns-record" | "tls-policy" | "api-proxy" | "control-plane-api" | "postgresql" | "operations-runner" | "treedx-service";
62
+ provider: "cloudflare" | "railway";
63
+ adoption: {
64
+ mode: "adopt-or-create";
65
+ replacement: "forbidden";
66
+ externalIdInput?: string | undefined;
67
+ };
68
+ dependsOn?: string[] | undefined;
69
+ parameters?: Record<string, {
70
+ input: string;
71
+ } | {
72
+ artifact: string;
73
+ } | {
74
+ resourceOutput: {
75
+ resourceId: string;
76
+ output: string;
77
+ };
78
+ } | {
79
+ literal: string | number | boolean;
80
+ }> | undefined;
81
+ };
82
+ desiredDigest: string;
83
+ previousDigest: string | null;
84
+ }[];
85
+ environment: "production" | "staging";
86
+ executable: false;
87
+ planId: string;
88
+ declarationDigest: string;
89
+ topologyId: string;
90
+ platformCommit: string;
91
+ approvalRequired: boolean;
92
+ }>;
93
+ readonly apply: import("../control-plane-operation.js").ControlPlaneOperationBinding<{
94
+ teamId: string;
95
+ }, {}, {
96
+ approval: {
97
+ schemaVersion: "treeseed.hosted-topology-approval/v1";
98
+ planDigest: string;
99
+ environment: "production" | "staging";
100
+ decision: "approved";
101
+ approvedBy: string;
102
+ approvedAt: string;
103
+ };
104
+ plan: {
105
+ schemaVersion: "treeseed.hosted-topology-plan/v1";
106
+ blockers: {
107
+ code: "connection-unavailable" | "dependency-cycle" | "observation-unhealthy" | "adoption-drift";
108
+ message: string;
109
+ resourceId?: string | undefined;
110
+ }[];
111
+ planDigest: string;
112
+ actions: {
113
+ action: "noop" | "create" | "adopt" | "update";
114
+ resourceId: string;
115
+ kind: "admin-application" | "dns-record" | "tls-policy" | "api-proxy" | "control-plane-api" | "postgresql" | "operations-runner" | "treedx-service";
116
+ provider: "cloudflare" | "railway";
117
+ providerResourceId: string | null;
118
+ desiredResource: {
119
+ id: string;
120
+ kind: "admin-application" | "dns-record" | "tls-policy" | "api-proxy" | "control-plane-api" | "postgresql" | "operations-runner" | "treedx-service";
121
+ provider: "cloudflare" | "railway";
122
+ adoption: {
123
+ mode: "adopt-or-create";
124
+ replacement: "forbidden";
125
+ externalIdInput?: string | undefined;
126
+ };
127
+ dependsOn?: string[] | undefined;
128
+ parameters?: Record<string, {
129
+ input: string;
130
+ } | {
131
+ artifact: string;
132
+ } | {
133
+ resourceOutput: {
134
+ resourceId: string;
135
+ output: string;
136
+ };
137
+ } | {
138
+ literal: string | number | boolean;
139
+ }> | undefined;
140
+ };
141
+ desiredDigest: string;
142
+ previousDigest: string | null;
143
+ }[];
144
+ environment: "production" | "staging";
145
+ executable: false;
146
+ planId: string;
147
+ declarationDigest: string;
148
+ topologyId: string;
149
+ platformCommit: string;
150
+ approvalRequired: boolean;
151
+ };
152
+ }, Record<string, unknown>>;
153
+ readonly status: import("../control-plane-operation.js").ControlPlaneOperationBinding<{
154
+ teamId: string;
155
+ }, {}, undefined, {
156
+ operation: Record<string, unknown> | null;
157
+ receipt: {
158
+ schemaVersion: "treeseed.hosted-topology-receipt/v1";
159
+ resources: {
160
+ state: "missing" | "degraded" | "healthy";
161
+ resourceId: string;
162
+ kind: "admin-application" | "dns-record" | "tls-policy" | "api-proxy" | "control-plane-api" | "postgresql" | "operations-runner" | "treedx-service";
163
+ provider: "cloudflare" | "railway";
164
+ providerResourceId: string | null;
165
+ managedBy: "external" | "treeseed" | null;
166
+ observedDigest: string | null;
167
+ observedAt: string;
168
+ }[];
169
+ planDigest: string;
170
+ state: "known-good";
171
+ environment: "production" | "staging";
172
+ completedAt: string;
173
+ receiptId: string;
174
+ declarationDigest: string;
175
+ topologyId: string;
176
+ platformCommit: string;
177
+ previousResources: {
178
+ state: "missing" | "degraded" | "healthy";
179
+ resourceId: string;
180
+ kind: "admin-application" | "dns-record" | "tls-policy" | "api-proxy" | "control-plane-api" | "postgresql" | "operations-runner" | "treedx-service";
181
+ provider: "cloudflare" | "railway";
182
+ providerResourceId: string | null;
183
+ managedBy: "external" | "treeseed" | null;
184
+ observedDigest: string | null;
185
+ observedAt: string;
186
+ }[];
187
+ } | null;
188
+ }>;
189
+ readonly rollback: import("../control-plane-operation.js").ControlPlaneOperationBinding<{
190
+ teamId: string;
191
+ }, {}, {
192
+ rollback: {
193
+ schemaVersion: "treeseed.hosted-topology-rollback/v1";
194
+ environment: "production" | "staging";
195
+ operations: {
196
+ action: "noop" | "restore" | "delete-created";
197
+ resourceId: string;
198
+ providerResourceId: string;
199
+ targetDigest: string | null;
200
+ }[];
201
+ rollbackId: string;
202
+ sourceReceiptId: string;
203
+ rollbackDigest: string;
204
+ };
205
+ approval: {
206
+ schemaVersion: "treeseed.hosted-topology-rollback-approval/v1";
207
+ environment: "production" | "staging";
208
+ decision: "approved";
209
+ approvedBy: string;
210
+ approvedAt: string;
211
+ rollbackDigest: string;
212
+ };
213
+ }, Record<string, unknown>>;
214
+ };
@@ -0,0 +1,77 @@
1
+ import { z } from "zod";
2
+ import { hostedTopologyApprovalSchema, hostedTopologyDeclarationSchema, hostedTopologyPlanSchema, hostedTopologyReceiptSchema, hostedTopologyRollbackApprovalSchema, hostedTopologyRollbackSchema } from "../../deployment/hosted-topology.js";
3
+ import { defineOperation } from "../operation-builder.js";
4
+ const teamPath = z.object({ teamId: z.string().min(1) }).strict();
5
+ const empty = z.object({}).strict();
6
+ const none = z.undefined();
7
+ const operationReceipt = z.record(z.unknown());
8
+ const HOSTED_TOPOLOGY_OPERATIONS = {
9
+ plan: defineOperation({
10
+ operationId: "infrastructure.topology.plan",
11
+ description: "Plan exact hosted topology reconciliation from authoritative provider observations.",
12
+ rest: { method: "POST", path: "/v1/teams/{teamId}/infrastructure/topology/plan" },
13
+ parameters: "treeseed.infrastructure.topology.plan.parameters/v1",
14
+ capability: "infrastructure.read",
15
+ authentication: "oauth",
16
+ oauthScopes: ["treeseed:read"],
17
+ kind: "read",
18
+ riskClass: "ordinary",
19
+ confirmation: "never",
20
+ surfaces: ["rest", "cli"],
21
+ cacheScope: "none",
22
+ pagination: "none",
23
+ idempotencyRequired: false
24
+ }, { path: teamPath, query: empty, body: z.object({ declaration: hostedTopologyDeclarationSchema }).strict(), output: hostedTopologyPlanSchema }),
25
+ apply: defineOperation({
26
+ operationId: "infrastructure.topology.apply",
27
+ description: "Apply an exact approved hosted topology plan through the operations runner.",
28
+ rest: { method: "POST", path: "/v1/teams/{teamId}/infrastructure/topology/apply" },
29
+ parameters: "treeseed.infrastructure.topology.apply.parameters/v1",
30
+ capability: "infrastructure.write",
31
+ authentication: "oauth",
32
+ oauthScopes: ["treeseed:admin"],
33
+ kind: "mutation",
34
+ riskClass: "authority",
35
+ confirmation: "input_required",
36
+ surfaces: ["rest", "cli"],
37
+ cacheScope: "none",
38
+ pagination: "none",
39
+ concurrencyRequired: true,
40
+ redactedPaths: ["body.approval.approvedBy"]
41
+ }, { path: teamPath, query: empty, body: z.object({ plan: hostedTopologyPlanSchema, approval: hostedTopologyApprovalSchema }).strict(), output: operationReceipt }),
42
+ status: defineOperation({
43
+ operationId: "infrastructure.topology.status",
44
+ description: "Read the latest authoritative hosted topology receipt and operation state.",
45
+ rest: { method: "GET", path: "/v1/teams/{teamId}/infrastructure/topology" },
46
+ parameters: "treeseed.infrastructure.topology.status.parameters/v1",
47
+ capability: "infrastructure.read",
48
+ authentication: "oauth",
49
+ oauthScopes: ["treeseed:read"],
50
+ kind: "read",
51
+ riskClass: "ordinary",
52
+ confirmation: "never",
53
+ surfaces: ["rest", "cli"],
54
+ cacheScope: "principal",
55
+ pagination: "none"
56
+ }, { path: teamPath, query: empty, body: none, output: z.object({ receipt: hostedTopologyReceiptSchema.nullable(), operation: operationReceipt.nullable() }).strict() }),
57
+ rollback: defineOperation({
58
+ operationId: "infrastructure.topology.rollback",
59
+ description: "Restore exact prior hosted topology lineage from a known-good receipt.",
60
+ rest: { method: "POST", path: "/v1/teams/{teamId}/infrastructure/topology/rollback" },
61
+ parameters: "treeseed.infrastructure.topology.rollback.parameters/v1",
62
+ capability: "infrastructure.write",
63
+ authentication: "oauth",
64
+ oauthScopes: ["treeseed:admin"],
65
+ kind: "mutation",
66
+ riskClass: "destructive",
67
+ confirmation: "input_required",
68
+ surfaces: ["rest", "cli"],
69
+ cacheScope: "none",
70
+ pagination: "none",
71
+ concurrencyRequired: true,
72
+ redactedPaths: ["body.approval.approvedBy"]
73
+ }, { path: teamPath, query: empty, body: z.object({ rollback: hostedTopologyRollbackSchema, approval: hostedTopologyRollbackApprovalSchema }).strict(), output: operationReceipt })
74
+ };
75
+ export {
76
+ HOSTED_TOPOLOGY_OPERATIONS
77
+ };