@nospt/backstage-plugin-apigee-backend 0.1.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.
- package/README.md +91 -0
- package/config.d.ts +75 -0
- package/dist/index.cjs.js +22 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +431 -0
- package/dist/lib/api-hub-client.cjs.js +118 -0
- package/dist/lib/api-hub-client.cjs.js.map +1 -0
- package/dist/lib/apigee-client.cjs.js +40 -0
- package/dist/lib/apigee-client.cjs.js.map +1 -0
- package/dist/lib/apigee-stitching-processor.cjs.js +104 -0
- package/dist/lib/apigee-stitching-processor.cjs.js.map +1 -0
- package/dist/lib/entity-builder.cjs.js +253 -0
- package/dist/lib/entity-builder.cjs.js.map +1 -0
- package/dist/lib/entity-provider.cjs.js +371 -0
- package/dist/lib/entity-provider.cjs.js.map +1 -0
- package/dist/lib/fetch-utils.cjs.js +49 -0
- package/dist/lib/fetch-utils.cjs.js.map +1 -0
- package/dist/lib/sharedflow-client.cjs.js +21 -0
- package/dist/lib/sharedflow-client.cjs.js.map +1 -0
- package/dist/module.cjs.js +90 -0
- package/dist/module.cjs.js.map +1 -0
- package/dist/plugin.cjs.js +28 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/router.cjs.js +26 -0
- package/dist/router.cjs.js.map +1 -0
- package/package.json +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# @nospt/backstage-plugin-apigee-backend
|
|
2
|
+
|
|
3
|
+
Backend package for the bootstrap stage of the Backstage Apigee plugin.
|
|
4
|
+
|
|
5
|
+
## Included
|
|
6
|
+
|
|
7
|
+
- New Backend System plugin registration
|
|
8
|
+
- Minimal router mounted at `/api/apigee`
|
|
9
|
+
- Placeholder health endpoint at `/api/apigee/health`
|
|
10
|
+
|
|
11
|
+
## Development
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cd plugins/apigee-backend
|
|
15
|
+
yarn start
|
|
16
|
+
yarn test
|
|
17
|
+
yarn lint
|
|
18
|
+
yarn build
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Repository Stitching
|
|
22
|
+
|
|
23
|
+
A Backstage `CatalogProcessor` (`ApigeeStitchingProcessor`) links a backend
|
|
24
|
+
`Component` to its proxy `API` entity by emitting the native `providesApi` /
|
|
25
|
+
`apiProvidedBy` relations. This surfaces the standard **"Provided APIs"** card on
|
|
26
|
+
the component page and the **"Providers"** card on the API page — with zero custom
|
|
27
|
+
UI. A repository opts in by adding `nos.pt/apigee-*` annotations to its
|
|
28
|
+
`catalog-info.yaml`.
|
|
29
|
+
|
|
30
|
+
### Annotation styles
|
|
31
|
+
|
|
32
|
+
**Direct mapping (active in this release):**
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
apiVersion: backstage.io/v1alpha1
|
|
36
|
+
kind: Component
|
|
37
|
+
metadata:
|
|
38
|
+
name: orders-service
|
|
39
|
+
annotations:
|
|
40
|
+
nos.pt/apigee-api-name: my-proxy
|
|
41
|
+
nos.pt/apigee-project-id: apigee-x-public-p-123
|
|
42
|
+
spec:
|
|
43
|
+
type: service
|
|
44
|
+
owner: team-orders
|
|
45
|
+
lifecycle: production
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**TargetServer-based mapping (documented; resolution planned, not yet active):**
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
metadata:
|
|
52
|
+
annotations:
|
|
53
|
+
nos.pt/apigee-targetserver-hostname: backend.nos.pt
|
|
54
|
+
nos.pt/apigee-targetserver-port: "443"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Precedence rule
|
|
58
|
+
|
|
59
|
+
When both styles are present, the **TargetServer-based mapping is the preferred**
|
|
60
|
+
resolution path (STITCH-02). The direct API-name mapping is the **fallback**, used
|
|
61
|
+
when no TargetServer annotation is present or when TargetServer resolution is
|
|
62
|
+
ambiguous (for example, a generic load balancer shared by many proxies).
|
|
63
|
+
|
|
64
|
+
> **In this release only the direct-mapping path is implemented.** TargetServer
|
|
65
|
+
> resolution is planned but not yet active — no TargetServer data is captured by the
|
|
66
|
+
> entity provider yet (see `04-CONTEXT` D-01). The processor is structured around a
|
|
67
|
+
> resolution-strategy seam so the TargetServer branch slots in without rework.
|
|
68
|
+
|
|
69
|
+
### Apigee → Backstage mapping
|
|
70
|
+
|
|
71
|
+
| Apigee concept | Backstage entity |
|
|
72
|
+
|----------------|------------------|
|
|
73
|
+
| API proxy (implementation) | `kind: Component`, `spec.type: api-proxy` |
|
|
74
|
+
| API proxy (contract) | `kind: API`, `spec.type` from API Hub (default `other`) |
|
|
75
|
+
| Sharedflow | `kind: Component`, `spec.type: library` |
|
|
76
|
+
| Backend repo component ↔ proxy API | `providesApi` / `apiProvidedBy` relation |
|
|
77
|
+
|
|
78
|
+
### Resolution detail
|
|
79
|
+
|
|
80
|
+
The target API entity ref is deterministic:
|
|
81
|
+
`api:default/<slugify(nos.pt/apigee-api-name)>`. The processor reads the annotations,
|
|
82
|
+
synthesizes the ref, and emits the relation pair — no live catalog lookup is needed.
|
|
83
|
+
A partial annotation set (e.g. `nos.pt/apigee-api-name` without
|
|
84
|
+
`nos.pt/apigee-project-id`) or an empty/unresolvable value is skipped with a warning
|
|
85
|
+
(warn-and-skip), so no malformed relations are emitted.
|
|
86
|
+
|
|
87
|
+
### Example fixture
|
|
88
|
+
|
|
89
|
+
See [`examples/components.yaml`](./examples/components.yaml) for ready-to-register
|
|
90
|
+
sample `Component` entities exercising both annotation styles — useful for local
|
|
91
|
+
smoke testing of the stitching processor.
|
package/config.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
/** Apigee catalog module configuration */
|
|
3
|
+
apigee?: {
|
|
4
|
+
/**
|
|
5
|
+
* List of Apigee X organisations to sync.
|
|
6
|
+
* At least one entry is required; the module fails fast at startup if missing.
|
|
7
|
+
* @visibility backend
|
|
8
|
+
*/
|
|
9
|
+
orgs: Array<{
|
|
10
|
+
/** Human-readable label for this org */
|
|
11
|
+
name: string;
|
|
12
|
+
/** GCP project ID that owns this Apigee X organisation */
|
|
13
|
+
projectId: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional list of environments to include (e.g. ["prod", "staging"]).
|
|
16
|
+
* If omitted, all environments are synced.
|
|
17
|
+
* @visibility backend
|
|
18
|
+
*/
|
|
19
|
+
environments?: string[];
|
|
20
|
+
/**
|
|
21
|
+
* Optional GitHub organisation slug used to derive GitHub repo links
|
|
22
|
+
* when API Hub does not supply a repositoryUri (FR17).
|
|
23
|
+
* @visibility backend
|
|
24
|
+
*/
|
|
25
|
+
githubOrgSlug?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Explicit proxy-name -> API Hub apiId overrides for proxies whose slug
|
|
28
|
+
* does not match their API Hub apiId (D-01).
|
|
29
|
+
* @visibility backend
|
|
30
|
+
*/
|
|
31
|
+
apiHubMappings?: { [proxyName: string]: string };
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Catalog sync interval in minutes. Default: 60.
|
|
35
|
+
* @visibility backend
|
|
36
|
+
*/
|
|
37
|
+
syncIntervalMinutes?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Default spec.owner for API entities whose API Hub ownerTeam is absent.
|
|
40
|
+
* Must be a Backstage entity reference, e.g. "group:default/platform-team".
|
|
41
|
+
* @visibility backend
|
|
42
|
+
*/
|
|
43
|
+
defaultOwner?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Maximum inline spec size in bytes; specs larger than this are linked via
|
|
46
|
+
* apigee.com/spec-url instead of embedded. Default 512000 (500 KB).
|
|
47
|
+
* @visibility backend
|
|
48
|
+
*/
|
|
49
|
+
specMaxBytes?: number;
|
|
50
|
+
/**
|
|
51
|
+
* API Hub location (GCP region) to query. Defaults to "global".
|
|
52
|
+
* Use this when your API Hub instance is regional, e.g. "europe-west1".
|
|
53
|
+
* @visibility backend
|
|
54
|
+
*/
|
|
55
|
+
apiHubLocation?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Optional custom schedule for the catalog sync task.
|
|
58
|
+
* When provided, overrides syncIntervalMinutes.
|
|
59
|
+
* @visibility backend
|
|
60
|
+
*/
|
|
61
|
+
schedule?: {
|
|
62
|
+
/** How often to run the sync. */
|
|
63
|
+
frequency?: {
|
|
64
|
+
cron?: string;
|
|
65
|
+
minutes?: number;
|
|
66
|
+
hours?: number;
|
|
67
|
+
seconds?: number;
|
|
68
|
+
};
|
|
69
|
+
/** Maximum time allowed for a single sync run. */
|
|
70
|
+
timeout?: { minutes?: number; seconds?: number };
|
|
71
|
+
/** Delay before the first run after startup. */
|
|
72
|
+
initialDelay?: { minutes?: number; seconds?: number };
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var plugin = require('./plugin.cjs.js');
|
|
6
|
+
var module$1 = require('./module.cjs.js');
|
|
7
|
+
var apigeeClient = require('./lib/apigee-client.cjs.js');
|
|
8
|
+
var apiHubClient = require('./lib/api-hub-client.cjs.js');
|
|
9
|
+
var entityProvider = require('./lib/entity-provider.cjs.js');
|
|
10
|
+
var sharedflowClient = require('./lib/sharedflow-client.cjs.js');
|
|
11
|
+
var apigeeStitchingProcessor = require('./lib/apigee-stitching-processor.cjs.js');
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
exports.default = plugin.apigeePlugin;
|
|
16
|
+
exports.catalogModuleApigee = module$1.catalogModuleApigee;
|
|
17
|
+
exports.ApigeeClient = apigeeClient.ApigeeClient;
|
|
18
|
+
exports.ApiHubClient = apiHubClient.ApiHubClient;
|
|
19
|
+
exports.ApigeeEntityProvider = entityProvider.ApigeeEntityProvider;
|
|
20
|
+
exports.SharedflowClient = sharedflowClient.SharedflowClient;
|
|
21
|
+
exports.ApigeeStitchingProcessor = apigeeStitchingProcessor.ApigeeStitchingProcessor;
|
|
22
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
+
import { SchedulerServiceTaskRunner, LoggerService } from '@backstage/backend-plugin-api';
|
|
3
|
+
import { GoogleAuth } from 'google-auth-library';
|
|
4
|
+
import { EntityProvider, EntityProviderConnection, CatalogProcessor, LocationSpec, CatalogProcessorEmit } from '@backstage/plugin-catalog-node';
|
|
5
|
+
import { Entity } from '@backstage/catalog-model';
|
|
6
|
+
|
|
7
|
+
declare const apigeePlugin: _backstage_backend_plugin_api.BackendFeature;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Backstage catalog backend module for Apigee API discovery.
|
|
11
|
+
* Plugs into the catalog backend and registers Apigee proxies + API Hub
|
|
12
|
+
* definitions as Backstage API entities.
|
|
13
|
+
*/
|
|
14
|
+
declare const catalogModuleApigee: _backstage_backend_plugin_api.BackendFeature;
|
|
15
|
+
|
|
16
|
+
/** Represents a single Apigee API proxy entry from GET /organizations/{org}/apis */
|
|
17
|
+
interface ApigeeProxy {
|
|
18
|
+
/** Proxy name as registered in Apigee (may contain dots/underscores — slugify before use as metadata.name) */
|
|
19
|
+
name: string;
|
|
20
|
+
/** Array of revision numbers (strings), most recent last */
|
|
21
|
+
revision?: string[];
|
|
22
|
+
/** ISO 8601 creation timestamp */
|
|
23
|
+
createdAt?: string;
|
|
24
|
+
/** ISO 8601 last-modified timestamp */
|
|
25
|
+
lastModifiedAt?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Represents one environment deployment from GET /organizations/{org}/apis/{proxy}/deployments */
|
|
28
|
+
interface ApigeeDeployment {
|
|
29
|
+
/** Environment name (e.g. "prod", "staging") */
|
|
30
|
+
environment: string;
|
|
31
|
+
/** Deployed revision number */
|
|
32
|
+
apiRevision?: string;
|
|
33
|
+
/** Deployment state: READY | PROGRESSING | ERROR */
|
|
34
|
+
deploymentStatus?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Represents a single proxy revision detail from
|
|
38
|
+
* GET /organizations/{org}/apis/{proxy}/revisions/{rev}
|
|
39
|
+
*/
|
|
40
|
+
interface ApigeeProxyRevision {
|
|
41
|
+
name: string;
|
|
42
|
+
revision?: string;
|
|
43
|
+
/** Base paths declared in the proxy bundle (used for apigee.com/base-path annotation) */
|
|
44
|
+
basepaths?: string[];
|
|
45
|
+
description?: string;
|
|
46
|
+
/** Resource files attached to this revision */
|
|
47
|
+
resourceFiles?: {
|
|
48
|
+
resourceFile?: Array<{
|
|
49
|
+
name: string;
|
|
50
|
+
type: string;
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Read-only HTTP client for the Apigee Management API v1.
|
|
56
|
+
*
|
|
57
|
+
* Auth: uses GCP Application Default Credentials via the injected GoogleAuth
|
|
58
|
+
* instance. All calls are GET-only (AUTH-02: read-only IAM roles).
|
|
59
|
+
*
|
|
60
|
+
* Usage:
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const auth = new GoogleAuth({ scopes: ['https://www.googleapis.com/auth/cloud-platform'] });
|
|
63
|
+
* const client = new ApigeeClient(auth);
|
|
64
|
+
* const proxies = await client.listProxies('my-apigee-org');
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare class ApigeeClient {
|
|
68
|
+
private readonly auth;
|
|
69
|
+
constructor(auth: GoogleAuth);
|
|
70
|
+
/**
|
|
71
|
+
* Lists all API proxies in the given Apigee organisation.
|
|
72
|
+
* Calls: GET /organizations/{org}/apis
|
|
73
|
+
*/
|
|
74
|
+
listProxies(org: string): Promise<ApigeeProxy[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Lists all environment deployments for a given proxy.
|
|
77
|
+
* Calls: GET /organizations/{org}/apis/{proxy}/deployments
|
|
78
|
+
*/
|
|
79
|
+
listDeployments(org: string, proxy: string): Promise<ApigeeDeployment[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Fetches full detail for a specific proxy revision.
|
|
82
|
+
* Calls: GET /organizations/{org}/apis/{proxy}/revisions/{rev}
|
|
83
|
+
*/
|
|
84
|
+
getProxyRevision(org: string, proxy: string, rev: string): Promise<ApigeeProxyRevision>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Represents a single API definition from Cloud API Hub.
|
|
89
|
+
* GET /projects/{p}/locations/{l}/apis
|
|
90
|
+
*/
|
|
91
|
+
interface ApiHubApi {
|
|
92
|
+
/** Full resource name: projects/{p}/locations/{l}/apis/{id} */
|
|
93
|
+
name: string;
|
|
94
|
+
/** Human-readable display name */
|
|
95
|
+
displayName?: string;
|
|
96
|
+
/** Description from API Hub */
|
|
97
|
+
description?: string;
|
|
98
|
+
/** API Hub lifecycle state: DRAFT | ACTIVE | DEPRECATED | ARCHIVED */
|
|
99
|
+
businessUnit?: string;
|
|
100
|
+
/** Owner team name (maps to spec.owner in Backstage) */
|
|
101
|
+
owner?: {
|
|
102
|
+
displayName?: string;
|
|
103
|
+
email?: string;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* GitHub / source repo URI from API Hub metadata.
|
|
107
|
+
* Maps to metadata.links in Backstage (FR17 / META-10).
|
|
108
|
+
*/
|
|
109
|
+
sourceMetadata?: Array<{
|
|
110
|
+
sourceType?: string;
|
|
111
|
+
value?: string;
|
|
112
|
+
}>;
|
|
113
|
+
/** Array of category/tag IDs applied to this API in API Hub (META-09) */
|
|
114
|
+
categories?: string[];
|
|
115
|
+
/** API Hub catalog type (e.g. "openapi", "mcp") — maps to spec.type in Backstage */
|
|
116
|
+
apiType?: string;
|
|
117
|
+
/** ISO 8601 create/update timestamps */
|
|
118
|
+
createTime?: string;
|
|
119
|
+
updateTime?: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Represents one version of an API Hub API.
|
|
123
|
+
* GET /projects/{p}/locations/{l}/apis/{apiId}/versions
|
|
124
|
+
*/
|
|
125
|
+
interface ApiHubVersion {
|
|
126
|
+
/** Full resource name: .../apis/{id}/versions/{vid} */
|
|
127
|
+
name: string;
|
|
128
|
+
displayName?: string;
|
|
129
|
+
description?: string;
|
|
130
|
+
/** Version state: DRAFT | ACTIVE | DEPRECATED | ARCHIVED */
|
|
131
|
+
lifecycle?: {
|
|
132
|
+
stage?: string;
|
|
133
|
+
};
|
|
134
|
+
/** Spec IDs attached to this version */
|
|
135
|
+
specIds?: string[];
|
|
136
|
+
createTime?: string;
|
|
137
|
+
updateTime?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Represents a spec (OpenAPI document) attached to a version.
|
|
141
|
+
* GET /projects/{p}/locations/{l}/apis/{apiId}/versions/{versionId}/specs/{specId}
|
|
142
|
+
*/
|
|
143
|
+
interface ApiHubSpec {
|
|
144
|
+
/** Full resource name */
|
|
145
|
+
name: string;
|
|
146
|
+
/** MIME type (e.g. "application/json", "application/yaml") */
|
|
147
|
+
mimeType?: string;
|
|
148
|
+
/** File name (e.g. "openapi.yaml") */
|
|
149
|
+
filename?: string;
|
|
150
|
+
/** Hash of spec contents for deduplication */
|
|
151
|
+
hash?: string;
|
|
152
|
+
/** Size in bytes — used by spec size guard in Phase 3 */
|
|
153
|
+
sizeBytes?: number;
|
|
154
|
+
createTime?: string;
|
|
155
|
+
updateTime?: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Raw spec contents response from the :contents sub-resource.
|
|
159
|
+
* `contents` is base64-encoded (Cloud API Hub ApiSpecContents resource).
|
|
160
|
+
*/
|
|
161
|
+
interface ApiHubSpecContents {
|
|
162
|
+
mimeType?: string;
|
|
163
|
+
/** Base64-encoded spec file content */
|
|
164
|
+
contents?: string;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Read-only HTTP client for the Cloud API Hub REST v1 API.
|
|
168
|
+
*
|
|
169
|
+
* Mirrors ApigeeClient exactly (D-04): same constructor pattern, same
|
|
170
|
+
* fetchWithRetry delegation, same encodeURIComponent usage.
|
|
171
|
+
*
|
|
172
|
+
* Auth: uses the same GCP Application Default Credentials GoogleAuth instance
|
|
173
|
+
* that is shared with ApigeeClient (D-03).
|
|
174
|
+
*
|
|
175
|
+
* Usage:
|
|
176
|
+
* ```typescript
|
|
177
|
+
* const auth = new GoogleAuth({ scopes: ['https://www.googleapis.com/auth/cloud-platform'] });
|
|
178
|
+
* const client = new ApiHubClient(auth, 'my-gcp-project');
|
|
179
|
+
* const apis = await client.listApis();
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
declare class ApiHubClient {
|
|
183
|
+
private readonly auth;
|
|
184
|
+
private readonly projectId;
|
|
185
|
+
private readonly location;
|
|
186
|
+
/**
|
|
187
|
+
* @param auth - Shared GoogleAuth instance (D-03: injected by module.ts, not created here)
|
|
188
|
+
* @param projectId - GCP project that hosts the API Hub instance
|
|
189
|
+
* @param location - API Hub location (default: "global" — override if regional instance)
|
|
190
|
+
*/
|
|
191
|
+
constructor(auth: GoogleAuth, projectId?: string, location?: string);
|
|
192
|
+
/** Base path prefix shared by all API Hub resource URLs for this instance. */
|
|
193
|
+
private resourcePrefix;
|
|
194
|
+
/**
|
|
195
|
+
* Fetches every page of a paginated API Hub list endpoint, following
|
|
196
|
+
* `nextPageToken` until the collection is exhausted, and returns the
|
|
197
|
+
* concatenated items. API Hub caps list responses (commonly at 50 entries per
|
|
198
|
+
* page), so callers MUST page or risk silently truncating the catalogue.
|
|
199
|
+
*/
|
|
200
|
+
private fetchAllPages;
|
|
201
|
+
/**
|
|
202
|
+
* Lists all API definitions in this API Hub instance.
|
|
203
|
+
* Calls: GET /projects/{p}/locations/{l}/apis
|
|
204
|
+
*
|
|
205
|
+
* @param projectId - Optional override for the GCP project ID. When provided,
|
|
206
|
+
* overrides the instance-level projectId from the constructor. Allows a single
|
|
207
|
+
* ApiHubClient instance to serve multiple GCP projects (multi-org setups).
|
|
208
|
+
*
|
|
209
|
+
* Pages through all results, following nextPageToken until exhausted (API Hub
|
|
210
|
+
* caps list responses, commonly at 50 entries per page).
|
|
211
|
+
*/
|
|
212
|
+
listApis(projectId?: string): Promise<ApiHubApi[]>;
|
|
213
|
+
/**
|
|
214
|
+
* Lists all versions for a given API.
|
|
215
|
+
* Calls: GET /projects/{p}/locations/{l}/apis/{apiId}/versions
|
|
216
|
+
*
|
|
217
|
+
* @param apiId - Short API ID (last segment of the full resource name)
|
|
218
|
+
* @param projectId - Optional GCP project override for multi-org setups; defaults to the instance projectId.
|
|
219
|
+
*/
|
|
220
|
+
listVersions(apiId: string, projectId?: string): Promise<ApiHubVersion[]>;
|
|
221
|
+
/**
|
|
222
|
+
* Lists all specs attached to a given API version.
|
|
223
|
+
* Calls: GET /projects/{p}/locations/{l}/apis/{apiId}/versions/{versionId}/specs
|
|
224
|
+
*
|
|
225
|
+
* This is the authoritative source of spec IDs for a version. The versions
|
|
226
|
+
* list endpoint frequently returns version.specIds: null even when specs
|
|
227
|
+
* exist, so callers must enumerate specs here rather than trusting specIds.
|
|
228
|
+
*
|
|
229
|
+
* @param apiId - Short API ID (last segment of the full resource name)
|
|
230
|
+
* @param versionId - Short version ID (last segment of the version resource name)
|
|
231
|
+
* @param projectId - Optional GCP project override for multi-org setups; defaults to the instance projectId.
|
|
232
|
+
*/
|
|
233
|
+
listSpecs(apiId: string, versionId: string, projectId?: string): Promise<ApiHubSpec[]>;
|
|
234
|
+
/**
|
|
235
|
+
* Fetches the spec metadata for a given API version and spec ID.
|
|
236
|
+
* Calls: GET /projects/{p}/locations/{l}/apis/{apiId}/versions/{versionId}/specs/{specId}
|
|
237
|
+
*
|
|
238
|
+
* To retrieve the actual spec file content (base64), call getSpecContents() instead.
|
|
239
|
+
*
|
|
240
|
+
* @param projectId - Optional GCP project override for multi-org setups; defaults to the instance projectId.
|
|
241
|
+
*/
|
|
242
|
+
getSpec(apiId: string, versionId: string, specId: string, projectId?: string): Promise<ApiHubSpec>;
|
|
243
|
+
/**
|
|
244
|
+
* Fetches the raw spec file content for a given spec resource.
|
|
245
|
+
* Calls: GET .../specs/{specId}:contents
|
|
246
|
+
* Returns base64-encoded content in the `contents` field — caller must decode
|
|
247
|
+
* with Buffer.from(contents, 'base64').toString('utf-8').
|
|
248
|
+
*
|
|
249
|
+
* Used in Phase 3 for spec.definition population (with 500 KB size guard).
|
|
250
|
+
*
|
|
251
|
+
* @param projectId - Optional GCP project override for multi-org setups; defaults to the instance projectId.
|
|
252
|
+
*/
|
|
253
|
+
getSpecContents(apiId: string, versionId: string, specId: string, projectId?: string): Promise<ApiHubSpecContents>;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Minimal representation of an Apigee sharedflow as returned by
|
|
258
|
+
* GET /v1/organizations/{org}/sharedflows
|
|
259
|
+
*/
|
|
260
|
+
interface ApigeeSharedflow {
|
|
261
|
+
name: string;
|
|
262
|
+
latestRevisionId?: string;
|
|
263
|
+
metaData?: {
|
|
264
|
+
createdAt?: string;
|
|
265
|
+
lastModifiedAt?: string;
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Client for the Apigee Management API's sharedflow endpoints.
|
|
270
|
+
*/
|
|
271
|
+
declare class SharedflowClient {
|
|
272
|
+
private readonly auth;
|
|
273
|
+
constructor(auth: GoogleAuth);
|
|
274
|
+
/**
|
|
275
|
+
* Lists all sharedflows in the given Apigee organisation.
|
|
276
|
+
*/
|
|
277
|
+
listSharedflows(org: string): Promise<ApigeeSharedflow[]>;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Per-organisation data gathered during a sync run.
|
|
282
|
+
* Populated by ApigeeEntityProvider.run() before calling proxyToEntities().
|
|
283
|
+
*/
|
|
284
|
+
interface OrgSyncData {
|
|
285
|
+
/** Slugified org identifier (used as annotation key segment) */
|
|
286
|
+
slug: string;
|
|
287
|
+
/** Raw org name from config (e.g. "my-apigee-org") */
|
|
288
|
+
name: string;
|
|
289
|
+
/** GCP project ID owning this Apigee organisation */
|
|
290
|
+
projectId: string;
|
|
291
|
+
/** Names of environments this proxy is deployed to in this org */
|
|
292
|
+
environments: string[];
|
|
293
|
+
/** Resolved Backstage lifecycle for this org: production | experimental | deprecated */
|
|
294
|
+
lifecycle: string;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* A proxy that has been deduplicated across organisations (D-03).
|
|
298
|
+
* Multiple orgs may share the same proxy name — they are merged into one entity.
|
|
299
|
+
*/
|
|
300
|
+
interface MergedProxy {
|
|
301
|
+
/** Proxy data from the first org that declared this proxy */
|
|
302
|
+
proxy: ApigeeProxy;
|
|
303
|
+
/** Union of all base paths declared across all org revisions */
|
|
304
|
+
basePaths: string[];
|
|
305
|
+
/** All orgs that contain this proxy */
|
|
306
|
+
orgs: OrgSyncData[];
|
|
307
|
+
}
|
|
308
|
+
/** Options forwarded from plugin configuration. */
|
|
309
|
+
interface EntityBuildOptions {
|
|
310
|
+
/** Default spec.owner when not provided by API Hub. Must be a Backstage entity ref. */
|
|
311
|
+
defaultOwner?: string;
|
|
312
|
+
/** Inline spec size limit in bytes; default 512000 applied by the provider (D-03). */
|
|
313
|
+
specMaxBytes?: number;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Org configuration shape (matches config.d.ts apigee.orgs[n]) */
|
|
317
|
+
interface OrgConfig {
|
|
318
|
+
name: string;
|
|
319
|
+
projectId: string;
|
|
320
|
+
environments?: string[];
|
|
321
|
+
githubOrgSlug?: string;
|
|
322
|
+
/** proxyName → API Hub apiId override (D-01); set by module.ts from config. */
|
|
323
|
+
apiHubMappings?: Record<string, string>;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Entity provider that discovers Apigee API proxies and sharedflows across
|
|
327
|
+
* one or more organisations and registers them as Backstage entities.
|
|
328
|
+
*
|
|
329
|
+
* Registered with the catalog via `catalogProcessingExtensionPoint.addEntityProvider`.
|
|
330
|
+
* Scheduled via the `SchedulerServiceTaskRunner` injected at construction time.
|
|
331
|
+
*/
|
|
332
|
+
declare class ApigeeEntityProvider implements EntityProvider {
|
|
333
|
+
private readonly taskRunner;
|
|
334
|
+
private readonly logger;
|
|
335
|
+
private readonly orgsConfig;
|
|
336
|
+
private readonly apigeeClient;
|
|
337
|
+
private readonly apiHubClient;
|
|
338
|
+
private readonly sharedflowClient;
|
|
339
|
+
private readonly options;
|
|
340
|
+
private connection?;
|
|
341
|
+
constructor(taskRunner: SchedulerServiceTaskRunner, logger: LoggerService, orgsConfig: OrgConfig[], apigeeClient: ApigeeClient, apiHubClient: ApiHubClient, sharedflowClient: SharedflowClient, options: EntityBuildOptions);
|
|
342
|
+
/** Stable provider name — MUST NOT change; it links entities to this provider. */
|
|
343
|
+
getProviderName(): string;
|
|
344
|
+
/**
|
|
345
|
+
* Called once by the catalog on startup. Stores the connection and registers
|
|
346
|
+
* the recurring sync task with the scheduler.
|
|
347
|
+
*/
|
|
348
|
+
connect(connection: EntityProviderConnection): Promise<void>;
|
|
349
|
+
/**
|
|
350
|
+
* Executes one full catalog sync:
|
|
351
|
+
* 1. Fetch proxy / sharedflow / API-Hub data for all orgs in parallel.
|
|
352
|
+
* 2. Warn and skip any org that fails (error isolation per org).
|
|
353
|
+
* 3. Deduplicate proxies shared across multiple orgs (D-03).
|
|
354
|
+
* 4. Build entities and call applyMutation exactly once.
|
|
355
|
+
*/
|
|
356
|
+
run(): Promise<void>;
|
|
357
|
+
/**
|
|
358
|
+
* Maps `items` through `fn` with at most `limit` invocations in flight at
|
|
359
|
+
* once, preserving input order in the returned array. Used to parallelise
|
|
360
|
+
* per-API spec resolution without overwhelming the API Hub backend (WR-03).
|
|
361
|
+
*/
|
|
362
|
+
private mapWithConcurrency;
|
|
363
|
+
/**
|
|
364
|
+
* Fetches a spec's contents subject to the size guard (D-03).
|
|
365
|
+
*
|
|
366
|
+
* Two-stage guard:
|
|
367
|
+
* 1. Pre-fetch: if the spec metadata reports `sizeBytes > specMaxBytes`, skip
|
|
368
|
+
* the download entirely and return a `specUrl` link. NOTE: the API Hub spec
|
|
369
|
+
* metadata endpoint frequently reports `sizeBytes: 0`/undefined, so this
|
|
370
|
+
* stage often cannot fire and the contents are downloaded anyway.
|
|
371
|
+
* 2. Post-decode: enforce `specMaxBytes` against the actual decoded byte
|
|
372
|
+
* length — this is the guard that reliably bounds the *embedded* size.
|
|
373
|
+
*
|
|
374
|
+
* Because stage 1 is unreliable, `specMaxBytes` bounds the size of the spec
|
|
375
|
+
* that gets embedded, not necessarily the size downloaded into memory.
|
|
376
|
+
*/
|
|
377
|
+
private fetchSpecEmbed;
|
|
378
|
+
/**
|
|
379
|
+
* Resolves the spec for an API: lists versions, deterministically selects one
|
|
380
|
+
* (D-02), enumerates that version's specs (the versions endpoint does not
|
|
381
|
+
* reliably populate specIds), picks the lexicographically smallest spec ID,
|
|
382
|
+
* then fetches it with the size guard. Per-spec failures are isolated: any
|
|
383
|
+
* error is logged and `undefined` is returned so one bad spec never aborts
|
|
384
|
+
* the whole sync.
|
|
385
|
+
*/
|
|
386
|
+
private resolveSpecForApi;
|
|
387
|
+
/**
|
|
388
|
+
* Fetches all data for one org: proxies, their deployments + revisions,
|
|
389
|
+
* API Hub type map, and sharedflows.
|
|
390
|
+
*/
|
|
391
|
+
private fetchOrgData;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* A Backstage {@link CatalogProcessor} that links a backend `Component` to its
|
|
396
|
+
* proxy `API` entity by emitting the native `providesApi` / `apiProvidedBy`
|
|
397
|
+
* relation pair, surfacing the standard "Provided APIs" / "Providers" cards
|
|
398
|
+
* with zero custom UI (STITCH-01).
|
|
399
|
+
*
|
|
400
|
+
* Resolution dispatches through a strategy seam: a TargetServer-first path
|
|
401
|
+
* (deferred — STITCH-02, see 04-CONTEXT D-01) followed by the active
|
|
402
|
+
* direct-mapping path. The first strategy to return a target ref wins.
|
|
403
|
+
*/
|
|
404
|
+
declare class ApigeeStitchingProcessor implements CatalogProcessor {
|
|
405
|
+
private readonly logger;
|
|
406
|
+
constructor(logger: LoggerService);
|
|
407
|
+
getProcessorName(): string;
|
|
408
|
+
postProcessEntity(entity: Entity, _location: LocationSpec, emit: CatalogProcessorEmit): Promise<Entity>;
|
|
409
|
+
/**
|
|
410
|
+
* Strategy seam. Tries the TargetServer-preferred path first (deferred this
|
|
411
|
+
* phase), then falls back to the active direct-mapping path. First strategy
|
|
412
|
+
* to return a ref wins.
|
|
413
|
+
*/
|
|
414
|
+
private resolveTarget;
|
|
415
|
+
/**
|
|
416
|
+
* Deferred: TargetServer-preferred path (STITCH-02). See 04-CONTEXT D-01.
|
|
417
|
+
* No TargetServer data exists in the codebase yet, so this is the clean
|
|
418
|
+
* insertion point for the future branch and intentionally returns undefined.
|
|
419
|
+
*/
|
|
420
|
+
private resolveViaTargetServer;
|
|
421
|
+
/**
|
|
422
|
+
* Direct-mapping path. Requires BOTH the api-name and project-id annotations.
|
|
423
|
+
* The proxy API entity ref is deterministic — `api:default/<slugify(api-name)>` —
|
|
424
|
+
* so no live catalog lookup is needed (D-01). projectId is validated for
|
|
425
|
+
* presence to confirm intent but is not part of the deterministic ref.
|
|
426
|
+
*/
|
|
427
|
+
private resolveViaDirect;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export { ApiHubClient, ApigeeClient, ApigeeEntityProvider, ApigeeStitchingProcessor, SharedflowClient, catalogModuleApigee, apigeePlugin as default };
|
|
431
|
+
export type { ApiHubApi, ApiHubSpec, ApiHubSpecContents, ApiHubVersion, ApigeeDeployment, ApigeeProxy, ApigeeProxyRevision, ApigeeSharedflow, EntityBuildOptions, MergedProxy, OrgSyncData };
|