@astrogate/sdk 0.1.0 → 0.2.0

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.
@@ -0,0 +1,35 @@
1
+ import type { ManagementOptions } from "./management.js";
2
+ import type { components } from "./wire.gen.js";
3
+ type Schemas = components["schemas"];
4
+ export type AdmissionPolicy = Schemas["AdmissionPolicy"];
5
+ export type AdmissionState = Schemas["AdmissionState"];
6
+ export type AdmissionUsagePage = Schemas["AdmissionUsagePage"];
7
+ export interface UsageQuery {
8
+ from: string;
9
+ until: string;
10
+ limit: number;
11
+ project?: string;
12
+ environment?: string;
13
+ workload?: "application" | "database" | "identity" | "storage" | "jobs" | "builds" | "realtime";
14
+ subject?: string;
15
+ after?: string;
16
+ }
17
+ export declare function admissionState(value: unknown): value is AdmissionState;
18
+ export declare function admissionUsage(value: unknown): value is AdmissionUsagePage;
19
+ export declare function admissionClient(options: ManagementOptions, endpoint: URL, base: string): {
20
+ get: (signal?: AbortSignal) => Promise<{
21
+ policy: components["schemas"]["AdmissionPolicy"];
22
+ occupancy: components["schemas"]["AdmissionOccupancy"][];
23
+ storageCredits: components["schemas"]["TenantStorageCredit"][];
24
+ }>;
25
+ assign: (input: Schemas["AssignAdmissionPolicy"], signal?: AbortSignal) => Promise<{
26
+ revision: number;
27
+ profile: components["schemas"]["AdmissionProfile"];
28
+ assignedAt: string;
29
+ }>;
30
+ usage: (query: UsageQuery, signal?: AbortSignal) => Promise<{
31
+ points: components["schemas"]["AdmissionUsagePoint"][];
32
+ next?: string;
33
+ }>;
34
+ };
35
+ export {};
@@ -0,0 +1,112 @@
1
+ import { AstrogateError, object, requestJSON } from "./http.js";
2
+ function count(value) {
3
+ return Number.isSafeInteger(value) && Number(value) >= 0;
4
+ }
5
+ function date(value) {
6
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
7
+ }
8
+ function positive(value) {
9
+ return count(value) && value > 0;
10
+ }
11
+ function rule(value) {
12
+ return (object(value) &&
13
+ typeof value.requestsPerSecond === "number" &&
14
+ Number.isFinite(value.requestsPerSecond) &&
15
+ value.requestsPerSecond > 0 &&
16
+ ["burst", "concurrent", "executionMs"].every((key) => positive(value[key])) &&
17
+ ["pending", "pendingBytes", "waitMs"].every((key) => count(value[key])));
18
+ }
19
+ function validRetention(value) {
20
+ return (object(value) &&
21
+ positive(value.rawLogsSeconds) &&
22
+ positive(value.usageSeconds) &&
23
+ count(value.subjectSeconds) &&
24
+ value.subjectSeconds <= value.usageSeconds);
25
+ }
26
+ function policy(value) {
27
+ if (!object(value) ||
28
+ !positive(value.revision) ||
29
+ !date(value.assignedAt) ||
30
+ !object(value.profile))
31
+ return false;
32
+ const p = value.profile;
33
+ return (typeof p.id === "string" &&
34
+ p.id.length > 0 &&
35
+ typeof p.evidence === "string" &&
36
+ p.evidence.length > 0 &&
37
+ positive(p.durableBytes) &&
38
+ validRetention(p.retention) &&
39
+ object(p.rules) &&
40
+ object(p.rules.all) &&
41
+ Object.entries(p.rules).every(([kind, value]) => [
42
+ "all",
43
+ "application",
44
+ "database",
45
+ "identity",
46
+ "storage",
47
+ "jobs",
48
+ "builds",
49
+ "realtime",
50
+ ].includes(kind) &&
51
+ object(value) &&
52
+ rule(value.tenant) &&
53
+ rule(value.application)));
54
+ }
55
+ export function admissionState(value) {
56
+ return (object(value) &&
57
+ policy(value.policy) &&
58
+ Array.isArray(value.occupancy) &&
59
+ value.occupancy.every((o) => object(o) &&
60
+ typeof o.projectId === "string" &&
61
+ typeof o.workload === "string" &&
62
+ ["running", "unacknowledged", "pending", "pendingBytes"].every((key) => count(o[key])) &&
63
+ (o.oldest === undefined || date(o.oldest))) &&
64
+ Array.isArray(value.storageCredits) &&
65
+ value.storageCredits.every((c) => object(c) &&
66
+ ["projectId", "environmentId", "block", "owner"].every((key) => typeof c[key] === "string") &&
67
+ count(c.bytes) &&
68
+ count(c.epoch)));
69
+ }
70
+ export function admissionUsage(value) {
71
+ return (object(value) &&
72
+ (value.next === undefined || date(value.next)) &&
73
+ Array.isArray(value.points) &&
74
+ value.points.every((p) => object(p) &&
75
+ date(p.hour) &&
76
+ typeof p.workload === "string" &&
77
+ typeof p.outcome === "string" &&
78
+ ["requests", "bytes", "elapsedMs"].every((key) => count(p[key]))));
79
+ }
80
+ // This namespace uses the same authority and transport as the management client.
81
+ // A profile reference is the only writable entitlement, never arbitrary limits.
82
+ export function admissionClient(options, endpoint, base) {
83
+ const headers = { authorization: `Bearer ${options.token}` };
84
+ return {
85
+ get: (signal) => requestJSON(new URL(base + "/admission", endpoint), options, { headers }, admissionState, signal),
86
+ assign: (input, signal) => {
87
+ if (!input.profileId || !count(input.expectedRevision))
88
+ throw new AstrogateError("invalid_policy_assignment", 0, "", false);
89
+ // A lost response to CAS needs a read/reconciliation, not a blind replay.
90
+ return requestJSON(new URL(base + "/admission", endpoint), { ...options, maxAttempts: 1 }, {
91
+ method: "POST",
92
+ headers: { ...headers, "content-type": "application/json" },
93
+ body: JSON.stringify(input),
94
+ }, policy, signal);
95
+ },
96
+ usage: (query, signal) => {
97
+ if (!date(query.from) ||
98
+ !date(query.until) ||
99
+ Date.parse(query.from) >= Date.parse(query.until) ||
100
+ !count(query.limit) ||
101
+ query.limit === 0 ||
102
+ (query.environment && !query.project) ||
103
+ (query.after && !date(query.after)))
104
+ throw new AstrogateError("invalid_usage_query", 0, "", false);
105
+ const url = new URL(base + "/usage", endpoint);
106
+ for (const [key, value] of Object.entries(query))
107
+ if (value !== undefined)
108
+ url.searchParams.set(key, String(value));
109
+ return requestJSON(url, options, { headers }, admissionUsage, signal);
110
+ },
111
+ };
112
+ }
package/dist/http.d.ts CHANGED
@@ -1,9 +1,12 @@
1
+ import type { components } from "./wire.gen.js";
2
+ export type FailureDetails = Pick<components["schemas"]["Error"], "message" | "scope" | "dimension" | "reason">;
1
3
  export declare class AstrogateError extends Error {
2
4
  readonly code: string;
3
5
  readonly status: number;
4
6
  readonly requestId: string;
5
7
  readonly retryable: boolean;
6
- constructor(code: string, status: number, requestId: string, retryable: boolean);
8
+ readonly details?: Partial<FailureDetails> | undefined;
9
+ constructor(code: string, status: number, requestId: string, retryable: boolean, details?: Partial<FailureDetails> | undefined);
7
10
  }
8
11
  export interface TransportBudget {
9
12
  deadlineMs: number;
package/dist/http.js CHANGED
@@ -1,42 +1,85 @@
1
- // Shared owned HTTP behavior. Native database/auth clients retain their own
2
- // return values and transport semantics.
3
1
  export class AstrogateError extends Error {
4
2
  code;
5
3
  status;
6
4
  requestId;
7
5
  retryable;
8
- constructor(code, status, requestId, retryable) {
9
- super(code);
6
+ details;
7
+ constructor(code, status, requestId, retryable, details) {
8
+ super(details?.message ?? code);
10
9
  this.code = code;
11
10
  this.status = status;
12
11
  this.requestId = requestId;
13
12
  this.retryable = retryable;
13
+ this.details = details;
14
14
  this.name = "AstrogateError";
15
15
  }
16
16
  }
17
- export function object(value) { return typeof value === "object" && value !== null && !Array.isArray(value); }
18
- export function identifier(value) { if (!/^[A-Za-z0-9_-]+$/.test(value))
19
- throw new AstrogateError("invalid_resource_reference", 0, "", false); return value; }
20
- export function validateBudget(options) { if (!Number.isSafeInteger(options.deadlineMs) || options.deadlineMs <= 0 || !Number.isSafeInteger(options.maxAttempts) || options.maxAttempts < 1)
21
- throw new AstrogateError("explicit_transport_budget_required", 0, "", false); }
22
- function delay(ms, signal) { return new Promise((resolve, reject) => { if (signal.aborted) {
23
- reject(signal.reason);
24
- return;
25
- } const abort = () => { clearTimeout(timer); reject(signal.reason); }; const timer = setTimeout(() => { signal.removeEventListener("abort", abort); resolve(); }, ms); signal.addEventListener("abort", abort, { once: true }); }); }
17
+ export function object(value) {
18
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19
+ }
20
+ export function identifier(value) {
21
+ if (!/^[A-Za-z0-9_-]+$/.test(value))
22
+ throw new AstrogateError("invalid_resource_reference", 0, "", false);
23
+ return value;
24
+ }
25
+ export function validateBudget(options) {
26
+ if (!Number.isSafeInteger(options.deadlineMs) ||
27
+ options.deadlineMs <= 0 ||
28
+ options.deadlineMs > timerMaximumMs ||
29
+ !Number.isSafeInteger(options.maxAttempts) ||
30
+ options.maxAttempts < 1)
31
+ throw new AstrogateError("explicit_transport_budget_required", 0, "", false);
32
+ }
33
+ // Native browser/Node timers use signed 32-bit millisecond delays. Durable
34
+ // operations outlive transport calls and are polled instead of held for days.
35
+ const timerMaximumMs = 2 ** 31 - 1;
36
+ function optionalText(value, key) {
37
+ const field = value[key];
38
+ if (field !== undefined && typeof field !== "string")
39
+ throw new AstrogateError("invalid_error_response", 0, "", false);
40
+ return field;
41
+ }
42
+ function delay(ms, signal) {
43
+ return new Promise((resolve, reject) => {
44
+ if (signal.aborted) {
45
+ reject(signal.reason);
46
+ return;
47
+ }
48
+ const abort = () => {
49
+ clearTimeout(timer);
50
+ reject(signal.reason);
51
+ };
52
+ const timer = setTimeout(() => {
53
+ signal.removeEventListener("abort", abort);
54
+ resolve();
55
+ }, ms);
56
+ signal.addEventListener("abort", abort, { once: true });
57
+ });
58
+ }
26
59
  export async function requestResponse(url, options, input, signal) {
27
60
  validateBudget(options);
28
- const combined = signal ? AbortSignal.any([AbortSignal.timeout(options.deadlineMs), signal]) : AbortSignal.timeout(options.deadlineMs);
61
+ const combined = signal
62
+ ? AbortSignal.any([AbortSignal.timeout(options.deadlineMs), signal])
63
+ : AbortSignal.timeout(options.deadlineMs);
29
64
  let last;
30
65
  for (let attempt = 0; attempt < options.maxAttempts; attempt++) {
31
66
  let retryAfter = 0;
32
67
  try {
33
- const response = await fetch(url, { ...input, signal: combined, redirect: "error", cache: "no-store" });
68
+ const response = await fetch(url, {
69
+ ...input,
70
+ signal: combined,
71
+ redirect: "error",
72
+ cache: "no-store",
73
+ });
34
74
  if (response.ok)
35
75
  return response;
36
76
  const after = response.headers.get("retry-after");
37
77
  if (after) {
38
78
  const seconds = Number(after);
39
- retryAfter = Number.isFinite(seconds) ? Math.max(0, seconds * 1000) : Math.max(0, Date.parse(after) - Date.now());
79
+ const parsed = Number.isFinite(seconds)
80
+ ? seconds * 1000
81
+ : Date.parse(after) - Date.now();
82
+ retryAfter = Number.isFinite(parsed) ? Math.max(0, parsed) : 0;
40
83
  }
41
84
  let value;
42
85
  try {
@@ -45,9 +88,17 @@ export async function requestResponse(url, options, input, signal) {
45
88
  catch {
46
89
  throw new AstrogateError("invalid_error_response", response.status, "", false);
47
90
  }
48
- if (!object(value) || typeof value.code !== "string" || typeof value.requestId !== "string" || typeof value.retryable !== "boolean")
91
+ if (!object(value) ||
92
+ typeof value.code !== "string" ||
93
+ typeof value.requestId !== "string" ||
94
+ typeof value.retryable !== "boolean")
49
95
  throw new AstrogateError("invalid_error_response", response.status, "", false);
50
- throw new AstrogateError(value.code, response.status, value.requestId, value.retryable);
96
+ throw new AstrogateError(value.code, response.status, value.requestId, value.retryable, {
97
+ message: optionalText(value, "message"),
98
+ scope: optionalText(value, "scope"),
99
+ dimension: optionalText(value, "dimension"),
100
+ reason: optionalText(value, "reason"),
101
+ });
51
102
  }
52
103
  catch (error) {
53
104
  if (combined.aborted)
@@ -57,7 +108,7 @@ export async function requestResponse(url, options, input, signal) {
57
108
  throw error;
58
109
  if (attempt + 1 === options.maxAttempts)
59
110
  break;
60
- await delay(Math.max(retryAfter, 100 * 2 ** attempt * (0.5 + Math.random())), combined);
111
+ await delay(Math.min(options.deadlineMs, Math.max(retryAfter, 100 * 2 ** attempt * (0.5 + Math.random()))), combined);
61
112
  }
62
113
  }
63
114
  if (last instanceof AstrogateError)
@@ -83,7 +134,14 @@ export function managementAuthority(options) {
83
134
  if (typeof window !== "undefined")
84
135
  throw new AstrogateError("server_only_entrypoint", 0, "", false);
85
136
  const endpoint = new URL(options.endpoint);
86
- if ((endpoint.protocol !== "https:" && !(endpoint.protocol === "http:" && ["127.0.0.1", "[::1]", "localhost"].includes(endpoint.hostname))) || endpoint.username || endpoint.password || endpoint.search || endpoint.hash || endpoint.pathname !== "/")
137
+ if ((endpoint.protocol !== "https:" &&
138
+ !(endpoint.protocol === "http:" &&
139
+ ["127.0.0.1", "[::1]", "localhost"].includes(endpoint.hostname))) ||
140
+ endpoint.username ||
141
+ endpoint.password ||
142
+ endpoint.search ||
143
+ endpoint.hash ||
144
+ endpoint.pathname !== "/")
87
145
  throw new AstrogateError("unsafe_management_authority", 0, "", false);
88
146
  validateBudget(options);
89
147
  if (!options.token)
package/dist/inventory.js CHANGED
@@ -6,6 +6,8 @@ export function listQuery(options) {
6
6
  throw new AstrogateError("invalid_page_limit", 0, "", false);
7
7
  query.set("limit", String(options.limit));
8
8
  }
9
+ if (options.search !== undefined)
10
+ query.set("search", options.search);
9
11
  if (options.cursor !== undefined)
10
12
  query.set("cursor", options.cursor);
11
13
  return query.size ? `?${query}` : "";
@@ -1,4 +1,5 @@
1
1
  import { type PageOptions } from "./inventory.js";
2
+ export type { AdmissionPolicy, AdmissionState, AdmissionUsagePage, UsageQuery } from "./admission.js";
2
3
  export { AstrogateError } from "./http.js";
3
4
  import type { components } from "./wire.gen.js";
4
5
  type Schemas = components["schemas"];
@@ -47,6 +48,25 @@ export interface ManagementOptions {
47
48
  maxAttempts: number;
48
49
  }
49
50
  export declare function createManagement(options: ManagementOptions): {
51
+ admission: {
52
+ get: (signal?: AbortSignal) => Promise<{
53
+ policy: components["schemas"]["AdmissionPolicy"];
54
+ occupancy: components["schemas"]["AdmissionOccupancy"][];
55
+ storageCredits: components["schemas"]["TenantStorageCredit"][];
56
+ }>;
57
+ assign: (input: {
58
+ profileId: string;
59
+ expectedRevision: number;
60
+ }, signal?: AbortSignal) => Promise<{
61
+ revision: number;
62
+ profile: components["schemas"]["AdmissionProfile"];
63
+ assignedAt: string;
64
+ }>;
65
+ usage: (query: import("./admission.js").UsageQuery, signal?: AbortSignal) => Promise<{
66
+ points: components["schemas"]["AdmissionUsagePoint"][];
67
+ next?: string;
68
+ }>;
69
+ };
50
70
  projects: {
51
71
  create: (input: CreateProject, controls: RequestOptions) => Promise<{
52
72
  operationId: string;
@@ -3,6 +3,7 @@ import { project, environment, placementState, placementLocations, operation, op
3
3
  import { listQuery, pageOf } from "./inventory.js";
4
4
  import { managementAuthority } from "./http.js";
5
5
  import { serviceBindings } from "./services.js";
6
+ import { admissionClient } from "./admission.js";
6
7
  export { AstrogateError } from "./http.js";
7
8
  function object(value) {
8
9
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -66,6 +67,7 @@ export function createManagement(options) {
66
67
  return requestJSON(new URL(base + path, endpoint), options, { method: method ?? (body === undefined ? "GET" : "POST"), headers, body }, validate, controls?.signal ?? signal);
67
68
  }
68
69
  return {
70
+ admission: admissionClient(options, endpoint, base),
69
71
  projects: { create: (input, controls) => request(`/projects`, accepted, input, controls), list: (page = {}, signal) => request(`/projects${listQuery(page)}`, pageOf(project), undefined, undefined, signal), get: (resource, signal) => request(`/projects/${id(resource)}`, project, undefined, undefined, signal) },
70
72
  repositories: {
71
73
  create: (project, input, controls) => request(`/projects/${id(project)}/repository`, accepted, input, controls),
@@ -0,0 +1,8 @@
1
+ import type { components } from "./wire.gen.js";
2
+ export type ResourceSummary = components["schemas"]["ResourceSummary"];
3
+ export type ResourceRelationships = components["schemas"]["ResourceRelationships"];
4
+ export type ResourceNode = components["schemas"]["ResourceNode"];
5
+ export type ResourceRelationship = components["schemas"]["ResourceRelationship"];
6
+ export type ResourceSummaryPage = components["schemas"]["ResourceSummaryPage"];
7
+ export declare function resourceSummary(value: unknown): value is ResourceSummary;
8
+ export declare function resourceRelationships(value: unknown): value is ResourceRelationships;
@@ -0,0 +1,73 @@
1
+ import { object } from "./http.js";
2
+ function strings(value, fields) {
3
+ return object(value) && fields.every((key) => typeof value[key] === "string");
4
+ }
5
+ export function resourceSummary(value) {
6
+ return strings(value, [
7
+ "product",
8
+ "tenant",
9
+ "project",
10
+ "projectName",
11
+ "environment",
12
+ "environmentName",
13
+ "environmentKind",
14
+ "cell",
15
+ "location",
16
+ "phase",
17
+ ]);
18
+ }
19
+ function dateOrNull(value) {
20
+ return (value === null ||
21
+ (typeof value === "string" && Number.isFinite(Date.parse(value))));
22
+ }
23
+ export function resourceRelationships(value) {
24
+ if (!object(value) ||
25
+ !resourceSummary(value.resource) ||
26
+ !Number.isSafeInteger(value.epoch) ||
27
+ !dateOrNull(value.observedAt) ||
28
+ !dateOrNull(value.validUntil) ||
29
+ typeof value.fresh !== "boolean")
30
+ return false;
31
+ if (!Array.isArray(value.nodes) ||
32
+ !value.nodes.every((node) => strings(node, [
33
+ "id",
34
+ "kind",
35
+ "label",
36
+ "resourceId",
37
+ "providerId",
38
+ "cell",
39
+ "location",
40
+ "state",
41
+ "allocation",
42
+ "evidence",
43
+ "operationId",
44
+ ])))
45
+ return false;
46
+ const ids = new Set(value.nodes.map((node) => node.id));
47
+ if (ids.size !== value.nodes.length ||
48
+ !Array.isArray(value.relationships) ||
49
+ !value.relationships.every((edge) => strings(edge, ["id", "source", "target", "kind", "evidence"]) &&
50
+ object(edge) &&
51
+ ids.has(edge.source) &&
52
+ ids.has(edge.target)))
53
+ return false;
54
+ if (!object(value.recovery) ||
55
+ !strings(value.recovery, [
56
+ "protection",
57
+ "targetCell",
58
+ "targetLocation",
59
+ "automaticFailover",
60
+ ]) ||
61
+ value.recovery.automaticFailover !== "not-established" ||
62
+ !dateOrNull(value.recovery.checkpointAt))
63
+ return false;
64
+ const test = value.recovery.latestTest;
65
+ if (test !== null &&
66
+ (!strings(test, ["operationId", "state", "recordedAt"]) ||
67
+ !object(test) ||
68
+ typeof test.recordedAt !== "string" ||
69
+ !Number.isFinite(Date.parse(test.recordedAt))))
70
+ return false;
71
+ return (Array.isArray(value.notes) &&
72
+ value.notes.every((note) => typeof note === "string"));
73
+ }
@@ -1,4 +1,7 @@
1
1
  import { type TransportBudget } from "./http.js";
2
+ import { type UsageQuery } from "./admission.js";
3
+ export type { AdmissionState, AdmissionPolicy, AdmissionUsagePage, UsageQuery } from "./admission.js";
4
+ export type { ResourceSummary, ResourceRelationships, ResourceNode, ResourceRelationship, ResourceSummaryPage } from "./operator-resources.js";
2
5
  import { type PageOptions } from "./inventory.js";
3
6
  import type { components } from "./wire.gen.js";
4
7
  export { AstrogateError } from "./http.js";
@@ -9,6 +12,54 @@ export type OperatorOptions = TransportBudget & {
9
12
  export type { PageOptions } from "./inventory.js";
10
13
  type EnvironmentTopology = components["schemas"]["EnvironmentTopology"];
11
14
  export declare function createOperator(options: OperatorOptions): {
15
+ admission: {
16
+ get: (product: string, tenant: string, signal?: AbortSignal) => Promise<{
17
+ policy: components["schemas"]["AdmissionPolicy"];
18
+ occupancy: components["schemas"]["AdmissionOccupancy"][];
19
+ storageCredits: components["schemas"]["TenantStorageCredit"][];
20
+ }>;
21
+ usage: (product: string, tenant: string, query: UsageQuery, signal?: AbortSignal) => Promise<{
22
+ points: components["schemas"]["AdmissionUsagePoint"][];
23
+ next?: string;
24
+ }>;
25
+ };
26
+ resources: {
27
+ list: (product: string, tenant: string, page?: PageOptions, signal?: AbortSignal) => Promise<import("./inventory.js").InventoryPage<{
28
+ product: string;
29
+ tenant: string;
30
+ project: string;
31
+ projectName: string;
32
+ environment: string;
33
+ environmentName: string;
34
+ environmentKind: string;
35
+ cell: string;
36
+ location: string;
37
+ phase: string;
38
+ }>>;
39
+ relationships: (product: string, tenant: string, project: string, environment: string, signal?: AbortSignal) => Promise<{
40
+ resource: components["schemas"]["ResourceSummary"];
41
+ epoch: number;
42
+ observedAt: string | null;
43
+ validUntil: string | null;
44
+ fresh: boolean;
45
+ nodes: components["schemas"]["ResourceNode"][];
46
+ relationships: components["schemas"]["ResourceRelationship"][];
47
+ recovery: components["schemas"]["ResourceRecovery"];
48
+ notes: string[];
49
+ }>;
50
+ forHost: (providerId: string, page?: PageOptions, signal?: AbortSignal) => Promise<import("./inventory.js").InventoryPage<{
51
+ product: string;
52
+ tenant: string;
53
+ project: string;
54
+ projectName: string;
55
+ environment: string;
56
+ environmentName: string;
57
+ environmentKind: string;
58
+ cell: string;
59
+ location: string;
60
+ phase: string;
61
+ }>>;
62
+ };
12
63
  products: {
13
64
  list: (page?: PageOptions, signal?: AbortSignal) => Promise<import("./inventory.js").InventoryPage<{
14
65
  id: string;
package/dist/operator.js CHANGED
@@ -2,6 +2,8 @@
2
2
  // authenticate here. Issuance and mutation remain installation-owned.
3
3
  import { identifier, managementAuthority, object, requestJSON, } from "./http.js";
4
4
  import { project, environment, placementState, operation, operationLog, operatorOperationDetail, buildingBlock, hostnameBinding } from "./management-read.js";
5
+ import { admissionState, admissionUsage } from "./admission.js";
6
+ import { resourceSummary, resourceRelationships } from "./operator-resources.js";
5
7
  import { listQuery, pageOf } from "./inventory.js";
6
8
  export { AstrogateError } from "./http.js";
7
9
  function catalogEntry(value) {
@@ -14,13 +16,32 @@ function environmentTopology(value) {
14
16
  }
15
17
  export function createOperator(options) {
16
18
  const endpoint = managementAuthority(options);
17
- function read(path, validate, signal) {
18
- return requestJSON(new URL(`/v1/operator/products${path}`, endpoint), options, { method: "GET", headers: { authorization: `Bearer ${options.token}` } }, validate, signal);
19
+ function read(path, validate, signal, root = "/v1/operator/products") {
20
+ return requestJSON(new URL(`${root}${path}`, endpoint), options, { method: "GET", headers: { authorization: `Bearer ${options.token}` } }, validate, signal);
19
21
  }
20
22
  const scope = (product, tenant) => `/${identifier(product)}/tenants/${identifier(tenant)}`;
21
23
  const projectPath = (product, tenant, id) => `${scope(product, tenant)}/projects/${identifier(id)}`;
22
24
  const environmentPath = (product, tenant, project, id) => `${projectPath(product, tenant, project)}/environments/${identifier(id)}`;
23
25
  return {
26
+ admission: {
27
+ get: (product, tenant, signal) => read(`${scope(product, tenant)}/admission`, admissionState, signal),
28
+ usage: (product, tenant, query, signal) => {
29
+ const parameters = new URLSearchParams();
30
+ for (const [key, value] of Object.entries(query))
31
+ if (value !== undefined)
32
+ parameters.set(key, String(value));
33
+ return read(`${scope(product, tenant)}/usage?${parameters}`, admissionUsage, signal);
34
+ },
35
+ },
36
+ resources: {
37
+ list: (product, tenant, page = {}, signal) => read(`${scope(product, tenant)}/resources${listQuery(page)}`, pageOf(resourceSummary), signal),
38
+ relationships: (product, tenant, project, environment, signal) => read(`${environmentPath(product, tenant, project, environment)}/relationships`, resourceRelationships, signal),
39
+ forHost: (providerId, page = {}, signal) => {
40
+ const query = new URLSearchParams(listQuery(page));
41
+ query.set("providerId", providerId);
42
+ return read(`?${query}`, pageOf(resourceSummary), signal, "/v1/operator/host-environments");
43
+ },
44
+ },
24
45
  products: {
25
46
  list: (page = {}, signal) => read(listQuery(page), pageOf(catalogEntry), signal),
26
47
  },
@@ -1037,6 +1037,119 @@ export interface paths {
1037
1037
  patch?: never;
1038
1038
  trace?: never;
1039
1039
  };
1040
+ "/v1/operator/products/{productId}/tenants/{tenantId}/resources": {
1041
+ parameters: {
1042
+ query?: never;
1043
+ header?: never;
1044
+ path?: never;
1045
+ cookie?: never;
1046
+ };
1047
+ get: operations["listOperatorResources"];
1048
+ put?: never;
1049
+ post?: never;
1050
+ delete?: never;
1051
+ options?: never;
1052
+ head?: never;
1053
+ patch?: never;
1054
+ trace?: never;
1055
+ };
1056
+ "/v1/operator/host-environments": {
1057
+ parameters: {
1058
+ query?: never;
1059
+ header?: never;
1060
+ path?: never;
1061
+ cookie?: never;
1062
+ };
1063
+ get: operations["listOperatorHostEnvironments"];
1064
+ put?: never;
1065
+ post?: never;
1066
+ delete?: never;
1067
+ options?: never;
1068
+ head?: never;
1069
+ patch?: never;
1070
+ trace?: never;
1071
+ };
1072
+ "/v1/operator/products/{productId}/tenants/{tenantId}/projects/{projectId}/environments/{environmentId}/relationships": {
1073
+ parameters: {
1074
+ query?: never;
1075
+ header?: never;
1076
+ path?: never;
1077
+ cookie?: never;
1078
+ };
1079
+ get: operations["getOperatorResourceRelationships"];
1080
+ put?: never;
1081
+ post?: never;
1082
+ delete?: never;
1083
+ options?: never;
1084
+ head?: never;
1085
+ patch?: never;
1086
+ trace?: never;
1087
+ };
1088
+ "/v1/tenants/{tenant}/admission": {
1089
+ parameters: {
1090
+ query?: never;
1091
+ header?: never;
1092
+ path?: never;
1093
+ cookie?: never;
1094
+ };
1095
+ get: operations["getAdmissionState"];
1096
+ put?: never;
1097
+ /** @description Requires policy.assign and an installation-registered profile grant. Revision compare-and-set does not auto-retry an uncertain response. Read current state before deciding whether to submit another change. */
1098
+ post: operations["assignAdmissionPolicy"];
1099
+ delete?: never;
1100
+ options?: never;
1101
+ head?: never;
1102
+ patch?: never;
1103
+ trace?: never;
1104
+ };
1105
+ "/v1/tenants/{tenant}/usage": {
1106
+ parameters: {
1107
+ query?: never;
1108
+ header?: never;
1109
+ path?: never;
1110
+ cookie?: never;
1111
+ };
1112
+ get: operations["getAdmissionUsage"];
1113
+ put?: never;
1114
+ post?: never;
1115
+ delete?: never;
1116
+ options?: never;
1117
+ head?: never;
1118
+ patch?: never;
1119
+ trace?: never;
1120
+ };
1121
+ "/v1/operator/products/{product}/tenants/{tenant}/admission": {
1122
+ parameters: {
1123
+ query?: never;
1124
+ header?: never;
1125
+ path?: never;
1126
+ cookie?: never;
1127
+ };
1128
+ get: operations["operatorAdmission"];
1129
+ put?: never;
1130
+ post?: never;
1131
+ delete?: never;
1132
+ options?: never;
1133
+ head?: never;
1134
+ patch?: never;
1135
+ trace?: never;
1136
+ };
1137
+ "/v1/operator/products/{product}/tenants/{tenant}/usage": {
1138
+ parameters: {
1139
+ query?: never;
1140
+ header?: never;
1141
+ path?: never;
1142
+ cookie?: never;
1143
+ };
1144
+ get: operations["operatorUsage"];
1145
+ put?: never;
1146
+ post?: never;
1147
+ delete?: never;
1148
+ options?: never;
1149
+ head?: never;
1150
+ patch?: never;
1151
+ trace?: never;
1152
+ };
1040
1153
  }
1041
1154
  export type webhooks = Record<string, never>;
1042
1155
  export interface components {
@@ -1064,6 +1177,10 @@ export interface components {
1064
1177
  message: string;
1065
1178
  requestId: string;
1066
1179
  retryable: boolean;
1180
+ scope?: string;
1181
+ dimension?: string;
1182
+ reason?: string;
1183
+ error?: string;
1067
1184
  };
1068
1185
  CreateDeployment: {
1069
1186
  releaseId: string;
@@ -1562,6 +1679,168 @@ export interface components {
1562
1679
  items: components["schemas"]["HostnameBinding"][];
1563
1680
  nextCursor: string;
1564
1681
  };
1682
+ ResourceSummary: {
1683
+ product: string;
1684
+ tenant: string;
1685
+ project: string;
1686
+ projectName: string;
1687
+ environment: string;
1688
+ environmentName: string;
1689
+ environmentKind: string;
1690
+ cell: string;
1691
+ location: string;
1692
+ phase: string;
1693
+ };
1694
+ ResourceSummaryPage: {
1695
+ items: components["schemas"]["ResourceSummary"][];
1696
+ nextCursor: string;
1697
+ };
1698
+ ResourceNode: {
1699
+ id: string;
1700
+ kind: string;
1701
+ label: string;
1702
+ resourceId: string;
1703
+ providerId: string;
1704
+ cell: string;
1705
+ location: string;
1706
+ state: string;
1707
+ allocation: string;
1708
+ evidence: string;
1709
+ operationId: string;
1710
+ };
1711
+ ResourceRelationship: {
1712
+ id: string;
1713
+ source: string;
1714
+ target: string;
1715
+ kind: string;
1716
+ evidence: string;
1717
+ };
1718
+ ResourceRecoveryTest: {
1719
+ operationId: string;
1720
+ state: string;
1721
+ /** Format: date-time */
1722
+ recordedAt: string;
1723
+ };
1724
+ ResourceRecovery: {
1725
+ protection: string;
1726
+ targetCell: string;
1727
+ targetLocation: string;
1728
+ /** Format: date-time */
1729
+ checkpointAt: string | null;
1730
+ latestTest: components["schemas"]["ResourceRecoveryTest"] | null;
1731
+ /** @enum {string} */
1732
+ automaticFailover: "not-established";
1733
+ };
1734
+ ResourceRelationships: {
1735
+ resource: components["schemas"]["ResourceSummary"];
1736
+ /** Format: int64 */
1737
+ epoch: number;
1738
+ /** Format: date-time */
1739
+ observedAt: string | null;
1740
+ /** Format: date-time */
1741
+ validUntil: string | null;
1742
+ fresh: boolean;
1743
+ nodes: components["schemas"]["ResourceNode"][];
1744
+ relationships: components["schemas"]["ResourceRelationship"][];
1745
+ recovery: components["schemas"]["ResourceRecovery"];
1746
+ notes: string[];
1747
+ };
1748
+ AdmissionRule: {
1749
+ /** Format: double */
1750
+ requestsPerSecond: number;
1751
+ /** Format: int64 */
1752
+ burst: number;
1753
+ /** Format: int64 */
1754
+ concurrent: number;
1755
+ /** Format: int64 */
1756
+ pending: number;
1757
+ /** Format: int64 */
1758
+ pendingBytes: number;
1759
+ /** Format: int64 */
1760
+ waitMs: number;
1761
+ /** Format: int64 */
1762
+ executionMs: number;
1763
+ };
1764
+ WorkloadRule: {
1765
+ tenant: components["schemas"]["AdmissionRule"];
1766
+ application: components["schemas"]["AdmissionRule"];
1767
+ };
1768
+ AdmissionRetention: {
1769
+ /** Format: int64 */
1770
+ rawLogsSeconds: number;
1771
+ /** Format: int64 */
1772
+ usageSeconds: number;
1773
+ /** Format: int64 */
1774
+ subjectSeconds: number;
1775
+ };
1776
+ AdmissionProfile: {
1777
+ id: string;
1778
+ evidence: string;
1779
+ rules: {
1780
+ [key: string]: components["schemas"]["WorkloadRule"];
1781
+ };
1782
+ /** Format: int64 */
1783
+ durableBytes: number;
1784
+ retention: components["schemas"]["AdmissionRetention"];
1785
+ };
1786
+ AdmissionPolicy: {
1787
+ /** Format: int64 */
1788
+ revision: number;
1789
+ profile: components["schemas"]["AdmissionProfile"];
1790
+ /** Format: date-time */
1791
+ assignedAt: string;
1792
+ };
1793
+ AssignAdmissionPolicy: {
1794
+ profileId: string;
1795
+ /** Format: int64 */
1796
+ expectedRevision: number;
1797
+ };
1798
+ AdmissionOccupancy: {
1799
+ projectId: string;
1800
+ workload: string;
1801
+ /** Format: int64 */
1802
+ running: number;
1803
+ /** Format: int64 */
1804
+ unacknowledged: number;
1805
+ /** Format: int64 */
1806
+ pending: number;
1807
+ /** Format: int64 */
1808
+ pendingBytes: number;
1809
+ /** Format: date-time */
1810
+ oldest?: string;
1811
+ };
1812
+ TenantStorageCredit: {
1813
+ projectId: string;
1814
+ environmentId: string;
1815
+ block: string;
1816
+ owner: string;
1817
+ /** Format: int64 */
1818
+ bytes: number;
1819
+ /** Format: int64 */
1820
+ epoch: number;
1821
+ };
1822
+ AdmissionState: {
1823
+ policy: components["schemas"]["AdmissionPolicy"];
1824
+ occupancy: components["schemas"]["AdmissionOccupancy"][];
1825
+ storageCredits: components["schemas"]["TenantStorageCredit"][];
1826
+ };
1827
+ AdmissionUsagePoint: {
1828
+ /** Format: date-time */
1829
+ hour: string;
1830
+ workload: string;
1831
+ outcome: string;
1832
+ /** Format: int64 */
1833
+ requests: number;
1834
+ /** Format: int64 */
1835
+ bytes: number;
1836
+ /** Format: int64 */
1837
+ elapsedMs: number;
1838
+ };
1839
+ AdmissionUsagePage: {
1840
+ points: components["schemas"]["AdmissionUsagePoint"][];
1841
+ /** Format: date-time */
1842
+ next?: string;
1843
+ };
1565
1844
  };
1566
1845
  responses: never;
1567
1846
  parameters: never;
@@ -1576,6 +1855,8 @@ export interface operations {
1576
1855
  query?: {
1577
1856
  limit?: number;
1578
1857
  cursor?: string;
1858
+ /** @description Case-insensitive literal substring over registered IDs and available names, applied before pagination. Cursors bind the search. */
1859
+ search?: string;
1579
1860
  };
1580
1861
  header?: never;
1581
1862
  path: {
@@ -5494,6 +5775,8 @@ export interface operations {
5494
5775
  query?: {
5495
5776
  limit?: number;
5496
5777
  cursor?: string;
5778
+ /** @description Case-insensitive literal substring over registered IDs and available names, applied before pagination. Cursors bind the search. */
5779
+ search?: string;
5497
5780
  };
5498
5781
  header?: never;
5499
5782
  path: {
@@ -5565,6 +5848,8 @@ export interface operations {
5565
5848
  query?: {
5566
5849
  limit?: number;
5567
5850
  cursor?: string;
5851
+ /** @description Case-insensitive literal substring over registered IDs and available names, applied before pagination. Cursors bind the search. */
5852
+ search?: string;
5568
5853
  };
5569
5854
  header?: never;
5570
5855
  path?: never;
@@ -5633,6 +5918,8 @@ export interface operations {
5633
5918
  query?: {
5634
5919
  limit?: number;
5635
5920
  cursor?: string;
5921
+ /** @description Case-insensitive literal substring over registered IDs and available names, applied before pagination. Cursors bind the search. */
5922
+ search?: string;
5636
5923
  };
5637
5924
  header?: never;
5638
5925
  path: {
@@ -5703,6 +5990,8 @@ export interface operations {
5703
5990
  query?: {
5704
5991
  limit?: number;
5705
5992
  cursor?: string;
5993
+ /** @description Case-insensitive literal substring over registered IDs and available names, applied before pagination. Cursors bind the search. */
5994
+ search?: string;
5706
5995
  };
5707
5996
  header?: never;
5708
5997
  path: {
@@ -5774,6 +6063,8 @@ export interface operations {
5774
6063
  query?: {
5775
6064
  limit?: number;
5776
6065
  cursor?: string;
6066
+ /** @description Case-insensitive literal substring over registered IDs and available names, applied before pagination. Cursors bind the search. */
6067
+ search?: string;
5777
6068
  };
5778
6069
  header?: never;
5779
6070
  path: {
@@ -7104,4 +7395,398 @@ export interface operations {
7104
7395
  };
7105
7396
  };
7106
7397
  };
7398
+ listOperatorResources: {
7399
+ parameters: {
7400
+ query?: {
7401
+ limit?: number;
7402
+ cursor?: string;
7403
+ /** @description Case-insensitive literal substring over registered IDs and available names, applied before pagination. Cursors bind the search. */
7404
+ search?: string;
7405
+ };
7406
+ header?: never;
7407
+ path: {
7408
+ productId: string;
7409
+ tenantId: string;
7410
+ };
7411
+ cookie?: never;
7412
+ };
7413
+ requestBody?: never;
7414
+ responses: {
7415
+ /** @description Authorized stable keyset page. Empty nextCursor marks the end. */
7416
+ 200: {
7417
+ headers: {
7418
+ [name: string]: unknown;
7419
+ };
7420
+ content: {
7421
+ "application/json": components["schemas"]["ResourceSummaryPage"];
7422
+ };
7423
+ };
7424
+ /** @description Rejected request or unavailable dependency */
7425
+ 400: {
7426
+ headers: {
7427
+ [name: string]: unknown;
7428
+ };
7429
+ content: {
7430
+ "application/json": components["schemas"]["Error"];
7431
+ };
7432
+ };
7433
+ /** @description Rejected request or unavailable dependency */
7434
+ 401: {
7435
+ headers: {
7436
+ [name: string]: unknown;
7437
+ };
7438
+ content: {
7439
+ "application/json": components["schemas"]["Error"];
7440
+ };
7441
+ };
7442
+ /** @description Rejected request or unavailable dependency */
7443
+ 403: {
7444
+ headers: {
7445
+ [name: string]: unknown;
7446
+ };
7447
+ content: {
7448
+ "application/json": components["schemas"]["Error"];
7449
+ };
7450
+ };
7451
+ /** @description Rejected request or unavailable dependency */
7452
+ 404: {
7453
+ headers: {
7454
+ [name: string]: unknown;
7455
+ };
7456
+ content: {
7457
+ "application/json": components["schemas"]["Error"];
7458
+ };
7459
+ };
7460
+ /** @description Rejected request or unavailable dependency */
7461
+ 503: {
7462
+ headers: {
7463
+ [name: string]: unknown;
7464
+ };
7465
+ content: {
7466
+ "application/json": components["schemas"]["Error"];
7467
+ };
7468
+ };
7469
+ };
7470
+ };
7471
+ listOperatorHostEnvironments: {
7472
+ parameters: {
7473
+ query: {
7474
+ limit?: number;
7475
+ cursor?: string;
7476
+ /** @description Case-insensitive literal substring over registered IDs and available names, applied before pagination. Cursors bind the search. */
7477
+ search?: string;
7478
+ /** @description Exact native provider identity, never a server name. */
7479
+ providerId: string;
7480
+ };
7481
+ header?: never;
7482
+ path?: never;
7483
+ cookie?: never;
7484
+ };
7485
+ requestBody?: never;
7486
+ responses: {
7487
+ /** @description Authorized stable keyset page. Empty nextCursor marks the end. */
7488
+ 200: {
7489
+ headers: {
7490
+ [name: string]: unknown;
7491
+ };
7492
+ content: {
7493
+ "application/json": components["schemas"]["ResourceSummaryPage"];
7494
+ };
7495
+ };
7496
+ /** @description Rejected request or unavailable dependency */
7497
+ 400: {
7498
+ headers: {
7499
+ [name: string]: unknown;
7500
+ };
7501
+ content: {
7502
+ "application/json": components["schemas"]["Error"];
7503
+ };
7504
+ };
7505
+ /** @description Rejected request or unavailable dependency */
7506
+ 401: {
7507
+ headers: {
7508
+ [name: string]: unknown;
7509
+ };
7510
+ content: {
7511
+ "application/json": components["schemas"]["Error"];
7512
+ };
7513
+ };
7514
+ /** @description Rejected request or unavailable dependency */
7515
+ 403: {
7516
+ headers: {
7517
+ [name: string]: unknown;
7518
+ };
7519
+ content: {
7520
+ "application/json": components["schemas"]["Error"];
7521
+ };
7522
+ };
7523
+ /** @description Rejected request or unavailable dependency */
7524
+ 404: {
7525
+ headers: {
7526
+ [name: string]: unknown;
7527
+ };
7528
+ content: {
7529
+ "application/json": components["schemas"]["Error"];
7530
+ };
7531
+ };
7532
+ /** @description Rejected request or unavailable dependency */
7533
+ 503: {
7534
+ headers: {
7535
+ [name: string]: unknown;
7536
+ };
7537
+ content: {
7538
+ "application/json": components["schemas"]["Error"];
7539
+ };
7540
+ };
7541
+ };
7542
+ };
7543
+ getOperatorResourceRelationships: {
7544
+ parameters: {
7545
+ query?: never;
7546
+ header?: never;
7547
+ path: {
7548
+ productId: string;
7549
+ tenantId: string;
7550
+ projectId: string;
7551
+ environmentId: string;
7552
+ };
7553
+ cookie?: never;
7554
+ };
7555
+ requestBody?: never;
7556
+ responses: {
7557
+ /** @description Authorized stable keyset page. Empty nextCursor marks the end. */
7558
+ 200: {
7559
+ headers: {
7560
+ [name: string]: unknown;
7561
+ };
7562
+ content: {
7563
+ "application/json": components["schemas"]["ResourceRelationships"];
7564
+ };
7565
+ };
7566
+ /** @description Rejected request or unavailable dependency */
7567
+ 400: {
7568
+ headers: {
7569
+ [name: string]: unknown;
7570
+ };
7571
+ content: {
7572
+ "application/json": components["schemas"]["Error"];
7573
+ };
7574
+ };
7575
+ /** @description Rejected request or unavailable dependency */
7576
+ 401: {
7577
+ headers: {
7578
+ [name: string]: unknown;
7579
+ };
7580
+ content: {
7581
+ "application/json": components["schemas"]["Error"];
7582
+ };
7583
+ };
7584
+ /** @description Rejected request or unavailable dependency */
7585
+ 403: {
7586
+ headers: {
7587
+ [name: string]: unknown;
7588
+ };
7589
+ content: {
7590
+ "application/json": components["schemas"]["Error"];
7591
+ };
7592
+ };
7593
+ /** @description Rejected request or unavailable dependency */
7594
+ 404: {
7595
+ headers: {
7596
+ [name: string]: unknown;
7597
+ };
7598
+ content: {
7599
+ "application/json": components["schemas"]["Error"];
7600
+ };
7601
+ };
7602
+ /** @description Rejected request or unavailable dependency */
7603
+ 503: {
7604
+ headers: {
7605
+ [name: string]: unknown;
7606
+ };
7607
+ content: {
7608
+ "application/json": components["schemas"]["Error"];
7609
+ };
7610
+ };
7611
+ };
7612
+ };
7613
+ getAdmissionState: {
7614
+ parameters: {
7615
+ query?: never;
7616
+ header?: never;
7617
+ path: {
7618
+ tenant: string;
7619
+ };
7620
+ cookie?: never;
7621
+ };
7622
+ requestBody?: never;
7623
+ responses: {
7624
+ /** @description Authorized tenant projection */
7625
+ 200: {
7626
+ headers: {
7627
+ [name: string]: unknown;
7628
+ };
7629
+ content: {
7630
+ "application/json": components["schemas"]["AdmissionState"];
7631
+ };
7632
+ };
7633
+ /** @description Scoped API error */
7634
+ default: {
7635
+ headers: {
7636
+ [name: string]: unknown;
7637
+ };
7638
+ content: {
7639
+ "application/json": components["schemas"]["Error"];
7640
+ };
7641
+ };
7642
+ };
7643
+ };
7644
+ assignAdmissionPolicy: {
7645
+ parameters: {
7646
+ query?: never;
7647
+ header?: never;
7648
+ path: {
7649
+ tenant: string;
7650
+ };
7651
+ cookie?: never;
7652
+ };
7653
+ requestBody: {
7654
+ content: {
7655
+ "application/json": components["schemas"]["AssignAdmissionPolicy"];
7656
+ };
7657
+ };
7658
+ responses: {
7659
+ /** @description Authorized tenant projection */
7660
+ 200: {
7661
+ headers: {
7662
+ [name: string]: unknown;
7663
+ };
7664
+ content: {
7665
+ "application/json": components["schemas"]["AdmissionPolicy"];
7666
+ };
7667
+ };
7668
+ /** @description Scoped API error */
7669
+ default: {
7670
+ headers: {
7671
+ [name: string]: unknown;
7672
+ };
7673
+ content: {
7674
+ "application/json": components["schemas"]["Error"];
7675
+ };
7676
+ };
7677
+ };
7678
+ };
7679
+ getAdmissionUsage: {
7680
+ parameters: {
7681
+ query: {
7682
+ project?: string;
7683
+ environment?: string;
7684
+ workload?: string;
7685
+ subject?: string;
7686
+ from: string;
7687
+ until: string;
7688
+ after?: string;
7689
+ limit: number;
7690
+ };
7691
+ header?: never;
7692
+ path: {
7693
+ tenant: string;
7694
+ };
7695
+ cookie?: never;
7696
+ };
7697
+ requestBody?: never;
7698
+ responses: {
7699
+ /** @description Authorized tenant projection */
7700
+ 200: {
7701
+ headers: {
7702
+ [name: string]: unknown;
7703
+ };
7704
+ content: {
7705
+ "application/json": components["schemas"]["AdmissionUsagePage"];
7706
+ };
7707
+ };
7708
+ /** @description Scoped API error */
7709
+ default: {
7710
+ headers: {
7711
+ [name: string]: unknown;
7712
+ };
7713
+ content: {
7714
+ "application/json": components["schemas"]["Error"];
7715
+ };
7716
+ };
7717
+ };
7718
+ };
7719
+ operatorAdmission: {
7720
+ parameters: {
7721
+ query?: never;
7722
+ header?: never;
7723
+ path: {
7724
+ product: string;
7725
+ tenant: string;
7726
+ };
7727
+ cookie?: never;
7728
+ };
7729
+ requestBody?: never;
7730
+ responses: {
7731
+ /** @description Authorized tenant projection */
7732
+ 200: {
7733
+ headers: {
7734
+ [name: string]: unknown;
7735
+ };
7736
+ content: {
7737
+ "application/json": components["schemas"]["AdmissionState"];
7738
+ };
7739
+ };
7740
+ /** @description Scoped API error */
7741
+ default: {
7742
+ headers: {
7743
+ [name: string]: unknown;
7744
+ };
7745
+ content: {
7746
+ "application/json": components["schemas"]["Error"];
7747
+ };
7748
+ };
7749
+ };
7750
+ };
7751
+ operatorUsage: {
7752
+ parameters: {
7753
+ query: {
7754
+ project?: string;
7755
+ environment?: string;
7756
+ workload?: string;
7757
+ subject?: string;
7758
+ from: string;
7759
+ until: string;
7760
+ after?: string;
7761
+ limit: number;
7762
+ };
7763
+ header?: never;
7764
+ path: {
7765
+ product: string;
7766
+ tenant: string;
7767
+ };
7768
+ cookie?: never;
7769
+ };
7770
+ requestBody?: never;
7771
+ responses: {
7772
+ /** @description Authorized tenant projection */
7773
+ 200: {
7774
+ headers: {
7775
+ [name: string]: unknown;
7776
+ };
7777
+ content: {
7778
+ "application/json": components["schemas"]["AdmissionUsagePage"];
7779
+ };
7780
+ };
7781
+ /** @description Scoped API error */
7782
+ default: {
7783
+ headers: {
7784
+ [name: string]: unknown;
7785
+ };
7786
+ content: {
7787
+ "application/json": components["schemas"]["Error"];
7788
+ };
7789
+ };
7790
+ };
7791
+ };
7107
7792
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrogate/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Scoped Astrogate application and infrastructure clients",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
package/release.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astrogate/sdk",
3
- "version": "0.1.0",
4
- "sourceRevision": "7656f3ba660807af684bdca6880f2e0ed6d661e6",
3
+ "version": "0.2.0",
4
+ "sourceRevision": "f5fdbfd8322cc353cddda48d89e35ee8b2c4c16a",
5
5
  "cleanSource": true,
6
6
  "sdkLockSHA256": "18c62b4e44914fefcd3a06c72121bac03545170d6a77d9d6333dfab276382990",
7
7
  "nativeLockSHA256": "747051f0cdb1b0c493967c480c1bef111cde7661cdf66eb2d132803c11bd8d3a",