@cat-factory/contracts 0.334.0 → 0.335.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.
Files changed (46) hide show
  1. package/dist/binary-generators.d.ts +4 -4
  2. package/dist/cache-policy.d.ts +22 -0
  3. package/dist/cache-policy.d.ts.map +1 -0
  4. package/dist/cache-policy.js +111 -0
  5. package/dist/cache-policy.js.map +1 -0
  6. package/dist/errors.d.ts +24 -2
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +27 -1
  9. package/dist/errors.js.map +1 -1
  10. package/dist/foundational-services.d.ts +16 -9
  11. package/dist/foundational-services.d.ts.map +1 -1
  12. package/dist/foundational-services.js +20 -1
  13. package/dist/foundational-services.js.map +1 -1
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/observability.d.ts +57 -0
  19. package/dist/observability.d.ts.map +1 -1
  20. package/dist/observability.js +19 -0
  21. package/dist/observability.js.map +1 -1
  22. package/dist/openrouter.d.ts +111 -4
  23. package/dist/openrouter.d.ts.map +1 -1
  24. package/dist/openrouter.js +39 -1
  25. package/dist/openrouter.js.map +1 -1
  26. package/dist/reserved-env-keys.d.ts.map +1 -1
  27. package/dist/reserved-env-keys.js +6 -0
  28. package/dist/reserved-env-keys.js.map +1 -1
  29. package/dist/routes/execution.d.ts +4 -0
  30. package/dist/routes/execution.d.ts.map +1 -1
  31. package/dist/routes/foundational-services.d.ts +8 -8
  32. package/dist/routes/index.d.ts +1 -0
  33. package/dist/routes/index.d.ts.map +1 -1
  34. package/dist/routes/index.js +1 -0
  35. package/dist/routes/index.js.map +1 -1
  36. package/dist/routes/openrouter.d.ts +16 -0
  37. package/dist/routes/openrouter.d.ts.map +1 -1
  38. package/dist/routes/service-catalog.d.ts +298 -0
  39. package/dist/routes/service-catalog.d.ts.map +1 -0
  40. package/dist/routes/service-catalog.js +77 -0
  41. package/dist/routes/service-catalog.js.map +1 -0
  42. package/dist/service-catalog.d.ts +223 -0
  43. package/dist/service-catalog.d.ts.map +1 -0
  44. package/dist/service-catalog.js +234 -0
  45. package/dist/service-catalog.js.map +1 -0
  46. package/package.json +1 -1
@@ -0,0 +1,223 @@
1
+ import * as v from 'valibot';
2
+ /**
3
+ * Which developer-portal product a connection talks to.
4
+ *
5
+ * A picklist with one member rather than a bare literal, because the read surface, the SPA and
6
+ * the stored row all name it: adding Port / Cortex / OpsLevel later is a member plus an adapter,
7
+ * and every `Record<ServiceCatalogProvider, …>` fails to compile until it is mapped. The
8
+ * platform-neutral vocabulary below (`ServiceCatalogEntry` in the kernel) is what the importer
9
+ * consumes, so nothing downstream of the adapter knows the word "Backstage".
10
+ */
11
+ export declare const serviceCatalogProviderSchema: v.PicklistSchema<["backstage"], undefined>;
12
+ export type ServiceCatalogProvider = v.InferOutput<typeof serviceCatalogProviderSchema>;
13
+ /**
14
+ * How the platform authenticates to a SELF-HOSTED portal.
15
+ *
16
+ * These are the shapes organisations actually run Backstage behind, and each needs a different
17
+ * request built, which is why this is a closed vocabulary rather than a free-form header bag:
18
+ *
19
+ * - `none`: no auth on the catalog API. Real, and common on an instance reachable only inside a
20
+ * VPN. It is admissible ONLY because the base URL is held to the deployment's
21
+ * `UrlSafetyPolicy`, so reaching a private host is an operator decision already made.
22
+ * - `static-token`: a service-to-service token from Backstage's `backend.auth.externalAccess`
23
+ * (`type: static`), sent as `Authorization: Bearer <token>`. The vendor's own recommended
24
+ * way for an external system to read the catalog.
25
+ * - `legacy-shared-secret`: the older external-access route, still what a great many
26
+ * self-hosted instances are configured for: a short-lived HS256 JWT signed with a secret
27
+ * from `backend.auth.keys[]`. The platform MINTS the token per request rather than storing
28
+ * one, which is why the stored credential is the secret and not a bearer value.
29
+ * - `oauth2-client-credentials`: the portal sits behind an IdP or an identity-aware proxy
30
+ * (Keycloak, Okta, Entra, Google IAP). The platform exchanges a client id/secret at the
31
+ * token endpoint and sends the result as a bearer token.
32
+ * - `basic`: HTTP Basic, i.e. a reverse proxy in front of the portal.
33
+ * - `headers`: an explicit header list, for a gateway that authenticates on its own header
34
+ * names. A LIST rather than one pair because the common case needs two (a Cloudflare Access
35
+ * service token is `CF-Access-Client-Id` plus `CF-Access-Client-Secret`), and a single-pair
36
+ * shape would have sent half a credential.
37
+ */
38
+ export declare const serviceCatalogAuthModeSchema: v.PicklistSchema<["none", "static-token", "legacy-shared-secret", "oauth2-client-credentials", "basic", "headers"], undefined>;
39
+ export type ServiceCatalogAuthMode = v.InferOutput<typeof serviceCatalogAuthModeSchema>;
40
+ /** The credential half of a connection, discriminated by the auth mode it belongs to. */
41
+ export declare const serviceCatalogAuthSchema: v.VariantSchema<"mode", [v.ObjectSchema<{
42
+ readonly mode: v.LiteralSchema<"none", undefined>;
43
+ }, undefined>, v.ObjectSchema<{
44
+ readonly mode: v.LiteralSchema<"static-token", undefined>;
45
+ readonly token: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
46
+ }, undefined>, v.ObjectSchema<{
47
+ readonly mode: v.LiteralSchema<"legacy-shared-secret", undefined>;
48
+ readonly sharedSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
49
+ }, undefined>, v.ObjectSchema<{
50
+ readonly mode: v.LiteralSchema<"oauth2-client-credentials", undefined>;
51
+ /** The IdP's token endpoint. Held to the same URL policy as the portal's own base URL. */
52
+ readonly tokenUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
53
+ readonly clientId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
54
+ readonly clientSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
55
+ /** Optional `scope` / `audience` request parameters some IdPs require. */
56
+ readonly scope: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
57
+ readonly audience: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
58
+ }, undefined>, v.ObjectSchema<{
59
+ readonly mode: v.LiteralSchema<"basic", undefined>;
60
+ readonly username: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
61
+ readonly password: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
62
+ }, undefined>, v.ObjectSchema<{
63
+ readonly mode: v.LiteralSchema<"headers", undefined>;
64
+ readonly headers: v.SchemaWithPipe<readonly [v.ArraySchema<v.ObjectSchema<{
65
+ readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.RegexAction<string, "must be a valid HTTP header name">]>;
66
+ readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>, v.RegexAction<string, "must not contain a line break">]>;
67
+ }, undefined>, undefined>, v.MinLengthAction<{
68
+ name: string;
69
+ value: string;
70
+ }[], 1, undefined>, v.MaxLengthAction<{
71
+ name: string;
72
+ value: string;
73
+ }[], 5, undefined>]>;
74
+ }, undefined>], undefined>;
75
+ export type ServiceCatalogAuth = v.InferOutput<typeof serviceCatalogAuthSchema>;
76
+ /**
77
+ * The default filter, applied when a connection names none: the portal's SERVICE-like
78
+ * components.
79
+ *
80
+ * A default rather than a required field, because the honest alternative is worse in both
81
+ * directions. Importing the WHOLE catalog would fold a thousand-entity estate into every
82
+ * design prompt (the exact cost ADR 0031 split the catalog and contract reads to avoid), while
83
+ * refusing to import without a filter makes the first connection fail on a vendor query language
84
+ * the operator has no reason to know yet. `kind=component` is the one term that is right for
85
+ * every Backstage instance, and a narrower estate (a tag, a system, an owner) is one term more.
86
+ */
87
+ export declare const DEFAULT_SERVICE_CATALOG_FILTER: readonly string[];
88
+ /** How many services ONE import may bring in, and the ceiling on that number. */
89
+ export declare const DEFAULT_MAX_CATALOG_SERVICES = 200;
90
+ export declare const MAX_CATALOG_SERVICES_CEILING = 1000;
91
+ /** Connect (or re-connect) the workspace's service catalog. Replaces any prior connection. */
92
+ export declare const connectServiceCatalogSchema: v.ObjectSchema<{
93
+ readonly provider: v.OptionalSchema<v.PicklistSchema<["backstage"], undefined>, undefined>;
94
+ /** The portal's base URL, e.g. `https://backstage.corp.internal`. */
95
+ readonly baseUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
96
+ readonly auth: v.VariantSchema<"mode", [v.ObjectSchema<{
97
+ readonly mode: v.LiteralSchema<"none", undefined>;
98
+ }, undefined>, v.ObjectSchema<{
99
+ readonly mode: v.LiteralSchema<"static-token", undefined>;
100
+ readonly token: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
101
+ }, undefined>, v.ObjectSchema<{
102
+ readonly mode: v.LiteralSchema<"legacy-shared-secret", undefined>;
103
+ readonly sharedSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
104
+ }, undefined>, v.ObjectSchema<{
105
+ readonly mode: v.LiteralSchema<"oauth2-client-credentials", undefined>;
106
+ /** The IdP's token endpoint. Held to the same URL policy as the portal's own base URL. */
107
+ readonly tokenUrl: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 500, undefined>]>;
108
+ readonly clientId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
109
+ readonly clientSecret: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
110
+ /** Optional `scope` / `audience` request parameters some IdPs require. */
111
+ readonly scope: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
112
+ readonly audience: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 500, undefined>]>, undefined>;
113
+ }, undefined>, v.ObjectSchema<{
114
+ readonly mode: v.LiteralSchema<"basic", undefined>;
115
+ readonly username: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
116
+ readonly password: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>]>;
117
+ }, undefined>, v.ObjectSchema<{
118
+ readonly mode: v.LiteralSchema<"headers", undefined>;
119
+ readonly headers: v.SchemaWithPipe<readonly [v.ArraySchema<v.ObjectSchema<{
120
+ readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.RegexAction<string, "must be a valid HTTP header name">]>;
121
+ readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 8000, undefined>, v.RegexAction<string, "must not contain a line break">]>;
122
+ }, undefined>, undefined>, v.MinLengthAction<{
123
+ name: string;
124
+ value: string;
125
+ }[], 1, undefined>, v.MaxLengthAction<{
126
+ name: string;
127
+ value: string;
128
+ }[], 5, undefined>]>;
129
+ }, undefined>], undefined>;
130
+ /**
131
+ * Portal-side filter terms, ANDed. Empty/absent ⇒ {@link DEFAULT_SERVICE_CATALOG_FILTER}.
132
+ * Filtering AT THE PORTAL rather than after the fetch is what keeps a large estate from being
133
+ * paged through in full on every refresh.
134
+ */
135
+ readonly entityFilter: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 3, undefined>, v.MaxLengthAction<string, 200, undefined>, v.RegexAction<string, "must be a single `key=value` term (letters, digits and `_.-:/@`)">]>, undefined>, v.MaxLengthAction<string[], 10, undefined>]>, undefined>;
136
+ /**
137
+ * Whether to import the API definitions each service publishes (`spec.providesApis`).
138
+ * Defaults to true, being the half of the ask that lets a consumer call a shared service
139
+ * rather than merely know it exists.
140
+ */
141
+ readonly includeApis: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
142
+ /** Cap on imported services. Defaults to {@link DEFAULT_MAX_CATALOG_SERVICES}. */
143
+ readonly maxServices: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>, v.MaxValueAction<number, 1000, undefined>]>, undefined>;
144
+ }, undefined>;
145
+ export type ConnectServiceCatalogInput = v.InferOutput<typeof connectServiceCatalogSchema>;
146
+ /**
147
+ * How much of the portal's matching estate one import covered.
148
+ *
149
+ * Three states rather than a count, for the reason the repo-source `folderScan` coverage has
150
+ * three: each needs a different fix from the person who connected it, and `truncated` must never
151
+ * read as `complete`. An importer that reported only "42 services" would leave an operator with
152
+ * a 300-service estate believing the catalog is the estate.
153
+ */
154
+ export declare const serviceCatalogCoverageSchema: v.PicklistSchema<["complete", "truncated", "empty"], undefined>;
155
+ export type ServiceCatalogCoverage = v.InferOutput<typeof serviceCatalogCoverageSchema>;
156
+ /** What the LAST import concluded, as the management surface reports it. */
157
+ export declare const serviceCatalogSyncStatusSchema: v.PicklistSchema<["ok", "partial", "failed"], undefined>;
158
+ export type ServiceCatalogSyncStatus = v.InferOutput<typeof serviceCatalogSyncStatusSchema>;
159
+ /**
160
+ * The connection as the management surface sees it: never a credential, not even a masked one.
161
+ *
162
+ * `authMode` is here because it is the one part of the credential that is configuration rather
163
+ * than secret, because the operator has to see WHICH scheme a stored connection uses to know whether
164
+ * it still matches how the portal is deployed.
165
+ */
166
+ export declare const serviceCatalogConnectionSchema: v.ObjectSchema<{
167
+ readonly provider: v.PicklistSchema<["backstage"], undefined>;
168
+ readonly baseUrl: v.StringSchema<undefined>;
169
+ readonly authMode: v.PicklistSchema<["none", "static-token", "legacy-shared-secret", "oauth2-client-credentials", "basic", "headers"], undefined>;
170
+ readonly entityFilter: v.ArraySchema<v.StringSchema<undefined>, undefined>;
171
+ readonly includeApis: v.BooleanSchema<undefined>;
172
+ readonly maxServices: v.NumberSchema<undefined>;
173
+ readonly lastSyncedAt: v.NullableSchema<v.NumberSchema<undefined>, undefined>;
174
+ readonly lastSyncStatus: v.NullableSchema<v.PicklistSchema<["ok", "partial", "failed"], undefined>, undefined>;
175
+ /**
176
+ * What the last import wants a human to know: the truncation, the unreadable definitions, or
177
+ * the transport failure. Null when the last pass had nothing to report, which is the only
178
+ * state that needs no sentence.
179
+ */
180
+ readonly lastSyncMessage: v.NullableSchema<v.StringSchema<undefined>, undefined>;
181
+ readonly connectedAt: v.NumberSchema<undefined>;
182
+ }, undefined>;
183
+ export type ServiceCatalogConnection = v.InferOutput<typeof serviceCatalogConnectionSchema>;
184
+ /** Outcome of one import: what changed in the catalog, and what the pass could not do. */
185
+ export declare const serviceCatalogSyncResultSchema: v.ObjectSchema<{
186
+ readonly upserted: v.NumberSchema<undefined>;
187
+ /** Services this connection produced before and the portal no longer offers. */
188
+ readonly tombstoned: v.NumberSchema<undefined>;
189
+ readonly unchanged: v.NumberSchema<undefined>;
190
+ /** API definitions stored across every imported service. */
191
+ readonly contracts: v.NumberSchema<undefined>;
192
+ readonly coverage: v.PicklistSchema<["complete", "truncated", "empty"], undefined>;
193
+ /**
194
+ * Entities the filter matched that did NOT become a service: no usable identity, or a name
195
+ * that yields no slug. Zero and "nothing matched" are told apart by {@link coverage}, and a
196
+ * non-zero value here is the only thing that explains a catalog thinner than the portal's
197
+ * own entity count.
198
+ */
199
+ readonly skippedServices: v.NumberSchema<undefined>;
200
+ /**
201
+ * Portal services this pass REFUSED to write because the workspace already registers a service
202
+ * under that id by another route (an upload, a linked repo).
203
+ *
204
+ * Its own count rather than folded into {@link skippedServices}, because the two name opposite
205
+ * faults with opposite remedies: a skipped service is an entity the PORTAL describes in a way
206
+ * this platform cannot use, and this is a collision between two things the workspace itself
207
+ * did. Refusing is the only safe disposition, since overwriting would silently replace a
208
+ * hand-authored service (and its uploaded contracts, and any platform capability it was granted)
209
+ * with the portal's row, and disconnecting would then tombstone the original.
210
+ */
211
+ readonly skippedConflicts: v.NumberSchema<undefined>;
212
+ /**
213
+ * API definitions a service DECLARES that this pass could not store: a type the platform
214
+ * serves no format for, an entity the portal would not return, an empty or oversized
215
+ * definition, or an id that collides with another interface of the same service. Reported
216
+ * rather than dropped, because a service listed with no interface reads to an agent as a
217
+ * service that publishes none.
218
+ */
219
+ readonly skippedApis: v.NumberSchema<undefined>;
220
+ readonly status: v.PicklistSchema<["ok", "partial", "failed"], undefined>;
221
+ }, undefined>;
222
+ export type ServiceCatalogSyncResult = v.InferOutput<typeof serviceCatalogSyncResultSchema>;
223
+ //# sourceMappingURL=service-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-catalog.d.ts","sourceRoot":"","sources":["../src/service-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAqB5B;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,4CAA4B,CAAA;AACrE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,4BAA4B,CAAC,CAAA;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,4BAA4B,gIAOvC,CAAA;AACF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,4BAA4B,CAAC,CAAA;AA0BvF,yFAAyF;AACzF,eAAO,MAAM,wBAAwB;;;;;;;;;;IAMjC,0FAA0F;;;;IAI1F,0EAA0E;;;;;;;;;;;;;;;;;;;0BAa5E,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAqB/E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS,MAAM,EAAuB,CAAA;AAEnF,iFAAiF;AACjF,eAAO,MAAM,4BAA4B,MAAM,CAAA;AAC/C,eAAO,MAAM,4BAA4B,OAAQ,CAAA;AAEjD,8FAA8F;AAC9F,eAAO,MAAM,2BAA2B;;IAEtC,qEAAqE;;;;;;;;;;;;QA3DnE,0FAA0F;;;;QAI1F,0EAA0E;;;;;;;;;;;;;;;;;;;;IA0D5E;;;;OAIG;;IAEH;;;;OAIG;;IAEH,kFAAkF;;aAIlF,CAAA;AACF,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,iEAWvC,CAAA;AACF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,4BAA4B,CAAC,CAAA;AAEvF,4EAA4E;AAC5E,eAAO,MAAM,8BAA8B,0DAWzC,CAAA;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,8BAA8B,CAAC,CAAA;AAE3F;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;IASzC;;;;OAIG;;;aAGH,CAAA;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,8BAA8B,CAAC,CAAA;AAE3F,0FAA0F;AAC1F,eAAO,MAAM,8BAA8B;;IAEzC,gFAAgF;;;IAGhF,4DAA4D;;;IAG5D;;;;;OAKG;;IAEH;;;;;;;;;;OAUG;;IAEH;;;;;;OAMG;;;aAGH,CAAA;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,8BAA8B,CAAC,CAAA"}
@@ -0,0 +1,234 @@
1
+ import * as v from 'valibot';
2
+ // ---------------------------------------------------------------------------
3
+ // Wire contracts for the SERVICE CATALOG connection: a workspace points the platform at the
4
+ // developer portal its organisation already runs (Backstage today) and the platform imports
5
+ // that portal's services (identity, ownership, and the API definitions each one publishes)
6
+ // into the FOUNDATIONAL SERVICES catalog agents already read
7
+ // (backend/docs/adr/0031-foundational-services.md).
8
+ //
9
+ // It is a THIRD supply route beside direct upload and a linked git repo, deliberately not a
10
+ // second agent-facing catalog: an agent that was told about a service twice, once per
11
+ // mechanism, is the accretion this reuse avoids. What the import produces is ordinary
12
+ // `workspace`-tier foundational services, so the tiered merge, the suppression sub-resource,
13
+ // the lazily-read contract documents and the injected `.cat-context/` files all work unchanged.
14
+ //
15
+ // Scoped to a WORKSPACE, like every other sealed vendor connection (observability, tracker,
16
+ // document sources). That is also what makes it work on a mothership-mode node: the credential
17
+ // bag travels as ciphertext and is opened by naming the row over the secret delegation, which
18
+ // is workspace-keyed by construction.
19
+ // ---------------------------------------------------------------------------
20
+ /**
21
+ * Which developer-portal product a connection talks to.
22
+ *
23
+ * A picklist with one member rather than a bare literal, because the read surface, the SPA and
24
+ * the stored row all name it: adding Port / Cortex / OpsLevel later is a member plus an adapter,
25
+ * and every `Record<ServiceCatalogProvider, …>` fails to compile until it is mapped. The
26
+ * platform-neutral vocabulary below (`ServiceCatalogEntry` in the kernel) is what the importer
27
+ * consumes, so nothing downstream of the adapter knows the word "Backstage".
28
+ */
29
+ export const serviceCatalogProviderSchema = v.picklist(['backstage']);
30
+ /**
31
+ * How the platform authenticates to a SELF-HOSTED portal.
32
+ *
33
+ * These are the shapes organisations actually run Backstage behind, and each needs a different
34
+ * request built, which is why this is a closed vocabulary rather than a free-form header bag:
35
+ *
36
+ * - `none`: no auth on the catalog API. Real, and common on an instance reachable only inside a
37
+ * VPN. It is admissible ONLY because the base URL is held to the deployment's
38
+ * `UrlSafetyPolicy`, so reaching a private host is an operator decision already made.
39
+ * - `static-token`: a service-to-service token from Backstage's `backend.auth.externalAccess`
40
+ * (`type: static`), sent as `Authorization: Bearer <token>`. The vendor's own recommended
41
+ * way for an external system to read the catalog.
42
+ * - `legacy-shared-secret`: the older external-access route, still what a great many
43
+ * self-hosted instances are configured for: a short-lived HS256 JWT signed with a secret
44
+ * from `backend.auth.keys[]`. The platform MINTS the token per request rather than storing
45
+ * one, which is why the stored credential is the secret and not a bearer value.
46
+ * - `oauth2-client-credentials`: the portal sits behind an IdP or an identity-aware proxy
47
+ * (Keycloak, Okta, Entra, Google IAP). The platform exchanges a client id/secret at the
48
+ * token endpoint and sends the result as a bearer token.
49
+ * - `basic`: HTTP Basic, i.e. a reverse proxy in front of the portal.
50
+ * - `headers`: an explicit header list, for a gateway that authenticates on its own header
51
+ * names. A LIST rather than one pair because the common case needs two (a Cloudflare Access
52
+ * service token is `CF-Access-Client-Id` plus `CF-Access-Client-Secret`), and a single-pair
53
+ * shape would have sent half a credential.
54
+ */
55
+ export const serviceCatalogAuthModeSchema = v.picklist([
56
+ 'none',
57
+ 'static-token',
58
+ 'legacy-shared-secret',
59
+ 'oauth2-client-credentials',
60
+ 'basic',
61
+ 'headers',
62
+ ]);
63
+ const secretValue = v.pipe(v.string(), v.trim(), v.minLength(1), v.maxLength(8_000));
64
+ const shortText = v.pipe(v.string(), v.trim(), v.minLength(1), v.maxLength(200));
65
+ const url = v.pipe(v.string(), v.trim(), v.minLength(1), v.maxLength(500));
66
+ /**
67
+ * A header name a gateway may authenticate on. Restricted to the RFC 7230 token characters this
68
+ * platform will emit, so a stored credential can never inject a second header or a request line
69
+ * (the value is checked the same way below, because a `\r\n` in either half is the same split).
70
+ */
71
+ const headerName = v.pipe(v.string(), v.trim(), v.minLength(1), v.maxLength(100), v.regex(/^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/, 'must be a valid HTTP header name'));
72
+ const headerValue = v.pipe(v.string(), v.minLength(1), v.maxLength(8_000), v.regex(/^[^\r\n]+$/, 'must not contain a line break'));
73
+ /** The credential half of a connection, discriminated by the auth mode it belongs to. */
74
+ export const serviceCatalogAuthSchema = v.variant('mode', [
75
+ v.object({ mode: v.literal('none') }),
76
+ v.object({ mode: v.literal('static-token'), token: secretValue }),
77
+ v.object({ mode: v.literal('legacy-shared-secret'), sharedSecret: secretValue }),
78
+ v.object({
79
+ mode: v.literal('oauth2-client-credentials'),
80
+ /** The IdP's token endpoint. Held to the same URL policy as the portal's own base URL. */
81
+ tokenUrl: url,
82
+ clientId: shortText,
83
+ clientSecret: secretValue,
84
+ /** Optional `scope` / `audience` request parameters some IdPs require. */
85
+ scope: v.optional(v.pipe(v.string(), v.trim(), v.maxLength(500))),
86
+ audience: v.optional(v.pipe(v.string(), v.trim(), v.maxLength(500))),
87
+ }),
88
+ v.object({ mode: v.literal('basic'), username: shortText, password: secretValue }),
89
+ v.object({
90
+ mode: v.literal('headers'),
91
+ headers: v.pipe(v.array(v.object({ name: headerName, value: headerValue })), v.minLength(1), v.maxLength(5)),
92
+ }),
93
+ ]);
94
+ /**
95
+ * One term of the portal-side entity filter, `key=value`.
96
+ *
97
+ * The charset is deliberately tight: these terms are serialised into the vendor's query string,
98
+ * so admitting `&` or `=` beyond the first would let a stored filter add query parameters the
99
+ * platform never meant to send (a `limit`, a second `filter`, a `fields` projection that drops
100
+ * the fields the importer reads). One `=`, no separators, no whitespace.
101
+ */
102
+ const entityFilterTerm = v.pipe(v.string(), v.trim(), v.minLength(3), v.maxLength(200), v.regex(/^[A-Za-z0-9_.-]+=[A-Za-z0-9_.:/@-]+$/, 'must be a single `key=value` term (letters, digits and `_.-:/@`)'));
103
+ /**
104
+ * The default filter, applied when a connection names none: the portal's SERVICE-like
105
+ * components.
106
+ *
107
+ * A default rather than a required field, because the honest alternative is worse in both
108
+ * directions. Importing the WHOLE catalog would fold a thousand-entity estate into every
109
+ * design prompt (the exact cost ADR 0031 split the catalog and contract reads to avoid), while
110
+ * refusing to import without a filter makes the first connection fail on a vendor query language
111
+ * the operator has no reason to know yet. `kind=component` is the one term that is right for
112
+ * every Backstage instance, and a narrower estate (a tag, a system, an owner) is one term more.
113
+ */
114
+ export const DEFAULT_SERVICE_CATALOG_FILTER = ['kind=component'];
115
+ /** How many services ONE import may bring in, and the ceiling on that number. */
116
+ export const DEFAULT_MAX_CATALOG_SERVICES = 200;
117
+ export const MAX_CATALOG_SERVICES_CEILING = 1_000;
118
+ /** Connect (or re-connect) the workspace's service catalog. Replaces any prior connection. */
119
+ export const connectServiceCatalogSchema = v.object({
120
+ provider: v.optional(serviceCatalogProviderSchema),
121
+ /** The portal's base URL, e.g. `https://backstage.corp.internal`. */
122
+ baseUrl: url,
123
+ auth: serviceCatalogAuthSchema,
124
+ /**
125
+ * Portal-side filter terms, ANDed. Empty/absent ⇒ {@link DEFAULT_SERVICE_CATALOG_FILTER}.
126
+ * Filtering AT THE PORTAL rather than after the fetch is what keeps a large estate from being
127
+ * paged through in full on every refresh.
128
+ */
129
+ entityFilter: v.optional(v.pipe(v.array(entityFilterTerm), v.maxLength(10))),
130
+ /**
131
+ * Whether to import the API definitions each service publishes (`spec.providesApis`).
132
+ * Defaults to true, being the half of the ask that lets a consumer call a shared service
133
+ * rather than merely know it exists.
134
+ */
135
+ includeApis: v.optional(v.boolean()),
136
+ /** Cap on imported services. Defaults to {@link DEFAULT_MAX_CATALOG_SERVICES}. */
137
+ maxServices: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1), v.maxValue(MAX_CATALOG_SERVICES_CEILING))),
138
+ });
139
+ /**
140
+ * How much of the portal's matching estate one import covered.
141
+ *
142
+ * Three states rather than a count, for the reason the repo-source `folderScan` coverage has
143
+ * three: each needs a different fix from the person who connected it, and `truncated` must never
144
+ * read as `complete`. An importer that reported only "42 services" would leave an operator with
145
+ * a 300-service estate believing the catalog is the estate.
146
+ */
147
+ export const serviceCatalogCoverageSchema = v.picklist([
148
+ /** Every matching entity was imported. */
149
+ 'complete',
150
+ /** The `maxServices` cap stopped the paging short, so the catalog is a PREFIX of the estate. */
151
+ 'truncated',
152
+ /**
153
+ * The filter matched nothing at all. Kept apart from `complete` because zero services is
154
+ * never a healthy `complete`: it is a filter that names a kind, tag or system the portal does
155
+ * not use, and the remedy is editing the filter rather than waiting for a sync.
156
+ */
157
+ 'empty',
158
+ ]);
159
+ /** What the LAST import concluded, as the management surface reports it. */
160
+ export const serviceCatalogSyncStatusSchema = v.picklist([
161
+ /** Everything the filter matched arrived, with nothing dropped. */
162
+ 'ok',
163
+ /**
164
+ * The import ran and is INCOMPLETE: truncated by the cap, or with entities/definitions it
165
+ * could not use. Distinct from `failed`: the catalog holds real services, it just does not
166
+ * hold all of them, and only naming that keeps a partial estate from reading as the estate.
167
+ */
168
+ 'partial',
169
+ /** The import could not read the portal at all; whatever the catalog holds is from before. */
170
+ 'failed',
171
+ ]);
172
+ /**
173
+ * The connection as the management surface sees it: never a credential, not even a masked one.
174
+ *
175
+ * `authMode` is here because it is the one part of the credential that is configuration rather
176
+ * than secret, because the operator has to see WHICH scheme a stored connection uses to know whether
177
+ * it still matches how the portal is deployed.
178
+ */
179
+ export const serviceCatalogConnectionSchema = v.object({
180
+ provider: serviceCatalogProviderSchema,
181
+ baseUrl: v.string(),
182
+ authMode: serviceCatalogAuthModeSchema,
183
+ entityFilter: v.array(v.string()),
184
+ includeApis: v.boolean(),
185
+ maxServices: v.number(),
186
+ lastSyncedAt: v.nullable(v.number()),
187
+ lastSyncStatus: v.nullable(serviceCatalogSyncStatusSchema),
188
+ /**
189
+ * What the last import wants a human to know: the truncation, the unreadable definitions, or
190
+ * the transport failure. Null when the last pass had nothing to report, which is the only
191
+ * state that needs no sentence.
192
+ */
193
+ lastSyncMessage: v.nullable(v.string()),
194
+ connectedAt: v.number(),
195
+ });
196
+ /** Outcome of one import: what changed in the catalog, and what the pass could not do. */
197
+ export const serviceCatalogSyncResultSchema = v.object({
198
+ upserted: v.number(),
199
+ /** Services this connection produced before and the portal no longer offers. */
200
+ tombstoned: v.number(),
201
+ unchanged: v.number(),
202
+ /** API definitions stored across every imported service. */
203
+ contracts: v.number(),
204
+ coverage: serviceCatalogCoverageSchema,
205
+ /**
206
+ * Entities the filter matched that did NOT become a service: no usable identity, or a name
207
+ * that yields no slug. Zero and "nothing matched" are told apart by {@link coverage}, and a
208
+ * non-zero value here is the only thing that explains a catalog thinner than the portal's
209
+ * own entity count.
210
+ */
211
+ skippedServices: v.number(),
212
+ /**
213
+ * Portal services this pass REFUSED to write because the workspace already registers a service
214
+ * under that id by another route (an upload, a linked repo).
215
+ *
216
+ * Its own count rather than folded into {@link skippedServices}, because the two name opposite
217
+ * faults with opposite remedies: a skipped service is an entity the PORTAL describes in a way
218
+ * this platform cannot use, and this is a collision between two things the workspace itself
219
+ * did. Refusing is the only safe disposition, since overwriting would silently replace a
220
+ * hand-authored service (and its uploaded contracts, and any platform capability it was granted)
221
+ * with the portal's row, and disconnecting would then tombstone the original.
222
+ */
223
+ skippedConflicts: v.number(),
224
+ /**
225
+ * API definitions a service DECLARES that this pass could not store: a type the platform
226
+ * serves no format for, an entity the portal would not return, an empty or oversized
227
+ * definition, or an id that collides with another interface of the same service. Reported
228
+ * rather than dropped, because a service listed with no interface reads to an agent as a
229
+ * service that publishes none.
230
+ */
231
+ skippedApis: v.number(),
232
+ status: serviceCatalogSyncStatusSchema,
233
+ });
234
+ //# sourceMappingURL=service-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-catalog.js","sourceRoot":"","sources":["../src/service-catalog.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/contracts",
3
- "version": "0.334.0",
3
+ "version": "0.335.0",
4
4
  "description": "Valibot wire contract shared between the Agent Architecture Board frontend and backend.",
5
5
  "repository": {
6
6
  "type": "git",