@peterhauge/apiops-cli 0.1.3-alpha.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 (199) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +135 -0
  3. package/dist/cli/extract-command.d.ts +12 -0
  4. package/dist/cli/extract-command.d.ts.map +1 -0
  5. package/dist/cli/extract-command.js +157 -0
  6. package/dist/cli/extract-command.js.map +1 -0
  7. package/dist/cli/index.d.ts +7 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +74 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/init-command.d.ts +11 -0
  12. package/dist/cli/init-command.d.ts.map +1 -0
  13. package/dist/cli/init-command.js +87 -0
  14. package/dist/cli/init-command.js.map +1 -0
  15. package/dist/cli/publish-command.d.ts +12 -0
  16. package/dist/cli/publish-command.d.ts.map +1 -0
  17. package/dist/cli/publish-command.js +159 -0
  18. package/dist/cli/publish-command.js.map +1 -0
  19. package/dist/clients/apim-client.d.ts +110 -0
  20. package/dist/clients/apim-client.d.ts.map +1 -0
  21. package/dist/clients/apim-client.js +586 -0
  22. package/dist/clients/apim-client.js.map +1 -0
  23. package/dist/clients/artifact-store.d.ts +23 -0
  24. package/dist/clients/artifact-store.d.ts.map +1 -0
  25. package/dist/clients/artifact-store.js +188 -0
  26. package/dist/clients/artifact-store.js.map +1 -0
  27. package/dist/clients/iapim-client.d.ts +52 -0
  28. package/dist/clients/iapim-client.d.ts.map +1 -0
  29. package/dist/clients/iapim-client.js +6 -0
  30. package/dist/clients/iapim-client.js.map +1 -0
  31. package/dist/clients/iartifact-store.d.ts +50 -0
  32. package/dist/clients/iartifact-store.d.ts.map +1 -0
  33. package/dist/clients/iartifact-store.js +6 -0
  34. package/dist/clients/iartifact-store.js.map +1 -0
  35. package/dist/lib/auto-generated.d.ts +27 -0
  36. package/dist/lib/auto-generated.d.ts.map +1 -0
  37. package/dist/lib/auto-generated.js +34 -0
  38. package/dist/lib/auto-generated.js.map +1 -0
  39. package/dist/lib/cloud-config.d.ts +29 -0
  40. package/dist/lib/cloud-config.d.ts.map +1 -0
  41. package/dist/lib/cloud-config.js +60 -0
  42. package/dist/lib/cloud-config.js.map +1 -0
  43. package/dist/lib/config-loader.d.ts +21 -0
  44. package/dist/lib/config-loader.d.ts.map +1 -0
  45. package/dist/lib/config-loader.js +131 -0
  46. package/dist/lib/config-loader.js.map +1 -0
  47. package/dist/lib/dependency-graph.d.ts +43 -0
  48. package/dist/lib/dependency-graph.d.ts.map +1 -0
  49. package/dist/lib/dependency-graph.js +163 -0
  50. package/dist/lib/dependency-graph.js.map +1 -0
  51. package/dist/lib/exit-codes.d.ts +27 -0
  52. package/dist/lib/exit-codes.d.ts.map +1 -0
  53. package/dist/lib/exit-codes.js +33 -0
  54. package/dist/lib/exit-codes.js.map +1 -0
  55. package/dist/lib/logger.d.ts +39 -0
  56. package/dist/lib/logger.d.ts.map +1 -0
  57. package/dist/lib/logger.js +128 -0
  58. package/dist/lib/logger.js.map +1 -0
  59. package/dist/lib/parallel-runner.d.ts +38 -0
  60. package/dist/lib/parallel-runner.d.ts.map +1 -0
  61. package/dist/lib/parallel-runner.js +70 -0
  62. package/dist/lib/parallel-runner.js.map +1 -0
  63. package/dist/lib/resource-path.d.ts +205 -0
  64. package/dist/lib/resource-path.d.ts.map +1 -0
  65. package/dist/lib/resource-path.js +401 -0
  66. package/dist/lib/resource-path.js.map +1 -0
  67. package/dist/lib/resource-uri.d.ts +40 -0
  68. package/dist/lib/resource-uri.d.ts.map +1 -0
  69. package/dist/lib/resource-uri.js +86 -0
  70. package/dist/lib/resource-uri.js.map +1 -0
  71. package/dist/lib/user-agent.d.ts +2 -0
  72. package/dist/lib/user-agent.d.ts.map +1 -0
  73. package/dist/lib/user-agent.js +5 -0
  74. package/dist/lib/user-agent.js.map +1 -0
  75. package/dist/models/config.d.ts +83 -0
  76. package/dist/models/config.d.ts.map +1 -0
  77. package/dist/models/config.js +6 -0
  78. package/dist/models/config.js.map +1 -0
  79. package/dist/models/resource-types.d.ts +66 -0
  80. package/dist/models/resource-types.d.ts.map +1 -0
  81. package/dist/models/resource-types.js +243 -0
  82. package/dist/models/resource-types.js.map +1 -0
  83. package/dist/models/types.d.ts +47 -0
  84. package/dist/models/types.d.ts.map +1 -0
  85. package/dist/models/types.js +6 -0
  86. package/dist/models/types.js.map +1 -0
  87. package/dist/services/api-extractor.d.ts +36 -0
  88. package/dist/services/api-extractor.d.ts.map +1 -0
  89. package/dist/services/api-extractor.js +319 -0
  90. package/dist/services/api-extractor.js.map +1 -0
  91. package/dist/services/api-publisher.d.ts +18 -0
  92. package/dist/services/api-publisher.d.ts.map +1 -0
  93. package/dist/services/api-publisher.js +290 -0
  94. package/dist/services/api-publisher.js.map +1 -0
  95. package/dist/services/delete-unmatched-service.d.ts +17 -0
  96. package/dist/services/delete-unmatched-service.d.ts.map +1 -0
  97. package/dist/services/delete-unmatched-service.js +143 -0
  98. package/dist/services/delete-unmatched-service.js.map +1 -0
  99. package/dist/services/dry-run-reporter.d.ts +30 -0
  100. package/dist/services/dry-run-reporter.d.ts.map +1 -0
  101. package/dist/services/dry-run-reporter.js +111 -0
  102. package/dist/services/dry-run-reporter.js.map +1 -0
  103. package/dist/services/extract-service.d.ts +47 -0
  104. package/dist/services/extract-service.d.ts.map +1 -0
  105. package/dist/services/extract-service.js +374 -0
  106. package/dist/services/extract-service.js.map +1 -0
  107. package/dist/services/filter-service.d.ts +29 -0
  108. package/dist/services/filter-service.d.ts.map +1 -0
  109. package/dist/services/filter-service.js +143 -0
  110. package/dist/services/filter-service.js.map +1 -0
  111. package/dist/services/git-diff-service.d.ts +23 -0
  112. package/dist/services/git-diff-service.d.ts.map +1 -0
  113. package/dist/services/git-diff-service.js +135 -0
  114. package/dist/services/git-diff-service.js.map +1 -0
  115. package/dist/services/identity-guide-service.d.ts +11 -0
  116. package/dist/services/identity-guide-service.d.ts.map +1 -0
  117. package/dist/services/identity-guide-service.js +227 -0
  118. package/dist/services/identity-guide-service.js.map +1 -0
  119. package/dist/services/init-service.d.ts +16 -0
  120. package/dist/services/init-service.d.ts.map +1 -0
  121. package/dist/services/init-service.js +304 -0
  122. package/dist/services/init-service.js.map +1 -0
  123. package/dist/services/keyvault-checker.d.ts +58 -0
  124. package/dist/services/keyvault-checker.d.ts.map +1 -0
  125. package/dist/services/keyvault-checker.js +390 -0
  126. package/dist/services/keyvault-checker.js.map +1 -0
  127. package/dist/services/override-merger.d.ts +20 -0
  128. package/dist/services/override-merger.d.ts.map +1 -0
  129. package/dist/services/override-merger.js +102 -0
  130. package/dist/services/override-merger.js.map +1 -0
  131. package/dist/services/product-extractor.d.ts +26 -0
  132. package/dist/services/product-extractor.d.ts.map +1 -0
  133. package/dist/services/product-extractor.js +141 -0
  134. package/dist/services/product-extractor.js.map +1 -0
  135. package/dist/services/product-publisher.d.ts +15 -0
  136. package/dist/services/product-publisher.d.ts.map +1 -0
  137. package/dist/services/product-publisher.js +113 -0
  138. package/dist/services/product-publisher.js.map +1 -0
  139. package/dist/services/prompt-service.d.ts +13 -0
  140. package/dist/services/prompt-service.d.ts.map +1 -0
  141. package/dist/services/prompt-service.js +69 -0
  142. package/dist/services/prompt-service.js.map +1 -0
  143. package/dist/services/publish-service.d.ts +31 -0
  144. package/dist/services/publish-service.d.ts.map +1 -0
  145. package/dist/services/publish-service.js +445 -0
  146. package/dist/services/publish-service.js.map +1 -0
  147. package/dist/services/resource-extractor.d.ts +52 -0
  148. package/dist/services/resource-extractor.d.ts.map +1 -0
  149. package/dist/services/resource-extractor.js +168 -0
  150. package/dist/services/resource-extractor.js.map +1 -0
  151. package/dist/services/resource-publisher.d.ts +23 -0
  152. package/dist/services/resource-publisher.d.ts.map +1 -0
  153. package/dist/services/resource-publisher.js +349 -0
  154. package/dist/services/resource-publisher.js.map +1 -0
  155. package/dist/services/secret-redactor.d.ts +20 -0
  156. package/dist/services/secret-redactor.d.ts.map +1 -0
  157. package/dist/services/secret-redactor.js +45 -0
  158. package/dist/services/secret-redactor.js.map +1 -0
  159. package/dist/services/transitive-resolver.d.ts +45 -0
  160. package/dist/services/transitive-resolver.d.ts.map +1 -0
  161. package/dist/services/transitive-resolver.js +177 -0
  162. package/dist/services/transitive-resolver.js.map +1 -0
  163. package/dist/services/workspace-extractor.d.ts +34 -0
  164. package/dist/services/workspace-extractor.d.ts.map +1 -0
  165. package/dist/services/workspace-extractor.js +120 -0
  166. package/dist/services/workspace-extractor.js.map +1 -0
  167. package/dist/templates/azure-devops/extract-pipeline.d.ts +9 -0
  168. package/dist/templates/azure-devops/extract-pipeline.d.ts.map +1 -0
  169. package/dist/templates/azure-devops/extract-pipeline.js +95 -0
  170. package/dist/templates/azure-devops/extract-pipeline.js.map +1 -0
  171. package/dist/templates/azure-devops/publish-pipeline.d.ts +10 -0
  172. package/dist/templates/azure-devops/publish-pipeline.d.ts.map +1 -0
  173. package/dist/templates/azure-devops/publish-pipeline.js +100 -0
  174. package/dist/templates/azure-devops/publish-pipeline.js.map +1 -0
  175. package/dist/templates/configs/filter-config.d.ts +6 -0
  176. package/dist/templates/configs/filter-config.d.ts.map +1 -0
  177. package/dist/templates/configs/filter-config.js +51 -0
  178. package/dist/templates/configs/filter-config.js.map +1 -0
  179. package/dist/templates/configs/override-config.d.ts +6 -0
  180. package/dist/templates/configs/override-config.d.ts.map +1 -0
  181. package/dist/templates/configs/override-config.js +45 -0
  182. package/dist/templates/configs/override-config.js.map +1 -0
  183. package/dist/templates/configs/package-json.d.ts +10 -0
  184. package/dist/templates/configs/package-json.d.ts.map +1 -0
  185. package/dist/templates/configs/package-json.js +19 -0
  186. package/dist/templates/configs/package-json.js.map +1 -0
  187. package/dist/templates/copilot/identity-setup-prompt.d.ts +13 -0
  188. package/dist/templates/copilot/identity-setup-prompt.d.ts.map +1 -0
  189. package/dist/templates/copilot/identity-setup-prompt.js +279 -0
  190. package/dist/templates/copilot/identity-setup-prompt.js.map +1 -0
  191. package/dist/templates/github-actions/extract-workflow.d.ts +9 -0
  192. package/dist/templates/github-actions/extract-workflow.d.ts.map +1 -0
  193. package/dist/templates/github-actions/extract-workflow.js +126 -0
  194. package/dist/templates/github-actions/extract-workflow.js.map +1 -0
  195. package/dist/templates/github-actions/publish-workflow.d.ts +10 -0
  196. package/dist/templates/github-actions/publish-workflow.d.ts.map +1 -0
  197. package/dist/templates/github-actions/publish-workflow.js +105 -0
  198. package/dist/templates/github-actions/publish-workflow.js.map +1 -0
  199. package/package.json +65 -0
@@ -0,0 +1,319 @@
1
+ /**
2
+ * T022: API-specific extraction logic
3
+ * API revisions, API specifications, operations & operation policies,
4
+ * GraphQL resolvers & resolver policies, API tags, diagnostics, schemas,
5
+ * releases, tag descriptions, wikis.
6
+ */
7
+ import { ResourceType } from '../models/resource-types.js';
8
+ import { shouldIncludeResource } from './filter-service.js';
9
+ import { extractResourceType } from './resource-extractor.js';
10
+ import { logger } from '../lib/logger.js';
11
+ import { buildResourceLabel } from '../lib/resource-uri.js';
12
+ import { getNamePart } from '../lib/resource-path.js';
13
+ /**
14
+ * Extract all API-specific resources for a single API.
15
+ * This includes revisions, specifications, operations, policies, etc.
16
+ */
17
+ export async function extractApiResources(client, store, context, apiDescriptor, apiJson, outputDir, filter, workspace) {
18
+ const apiName = getNamePart(apiDescriptor.nameParts, 0);
19
+ const result = {
20
+ apiName,
21
+ revisions: [],
22
+ specification: false,
23
+ operations: [],
24
+ operationPolicies: [],
25
+ tags: [],
26
+ diagnostics: [],
27
+ schemas: [],
28
+ releases: [],
29
+ tagDescriptions: [],
30
+ wiki: false,
31
+ resolvers: [],
32
+ resolverPolicies: [],
33
+ policies: [],
34
+ };
35
+ // Extract API revisions
36
+ result.revisions = await extractApiRevisions(client, store, context, apiName, outputDir, filter, workspace);
37
+ // Extract API schemas FIRST. For synthetic GraphQL APIs the SDL lives in an
38
+ // ApiSchema resource; by extracting schemas first we can detect that case
39
+ // from the results and skip the (failing) spec export — avoiding a redundant
40
+ // `list schemas` probe per GraphQL-typed API at scale.
41
+ const schemaResult = await extractResourceType(client, store, context, ResourceType.ApiSchema, outputDir, filter, apiDescriptor, workspace);
42
+ result.schemas = schemaResult.extracted;
43
+ // Extract API specification (uses already-extracted schemas to detect
44
+ // synthetic GraphQL without a second list call).
45
+ result.specification = await extractApiSpecification(client, store, context, apiDescriptor, apiJson, outputDir, result.schemas);
46
+ // Extract API policy
47
+ const policyContent = await extractApiPolicy(client, store, context, apiDescriptor, outputDir);
48
+ if (policyContent) {
49
+ result.policies.push(policyContent);
50
+ }
51
+ // Extract operations and their policies
52
+ const opsResult = await extractApiOperations(client, store, context, apiDescriptor, outputDir, filter, workspace);
53
+ result.operations = opsResult.operations;
54
+ result.operationPolicies = opsResult.operationPolicies;
55
+ result.policies.push(...opsResult.policies);
56
+ // Extract API tags
57
+ const tagsResult = await extractResourceType(client, store, context, ResourceType.ApiTag, outputDir, filter, apiDescriptor, workspace);
58
+ result.tags = tagsResult.extracted;
59
+ // Extract API diagnostics
60
+ const diagResult = await extractResourceType(client, store, context, ResourceType.ApiDiagnostic, outputDir, filter, apiDescriptor, workspace);
61
+ result.diagnostics = diagResult.extracted;
62
+ // Extract API releases
63
+ const releaseResult = await extractResourceType(client, store, context, ResourceType.ApiRelease, outputDir, filter, apiDescriptor, workspace);
64
+ result.releases = releaseResult.extracted;
65
+ // Extract API tag descriptions
66
+ const tagDescResult = await extractResourceType(client, store, context, ResourceType.ApiTagDescription, outputDir, filter, apiDescriptor, workspace);
67
+ result.tagDescriptions = tagDescResult.extracted;
68
+ // Extract API wiki
69
+ result.wiki = await extractApiWiki(client, store, context, apiDescriptor, outputDir);
70
+ // Extract GraphQL resolvers and their policies
71
+ const resolverResult = await extractGraphQLResolvers(client, store, context, apiDescriptor, apiJson, outputDir, filter, workspace);
72
+ result.resolvers = resolverResult.resolvers;
73
+ result.resolverPolicies = resolverResult.resolverPolicies;
74
+ result.policies.push(...resolverResult.policies);
75
+ return result;
76
+ }
77
+ /**
78
+ * Extract API revisions.
79
+ * Lists revisions and extracts each as a sub-folder with ;rev=N naming.
80
+ */
81
+ async function extractApiRevisions(client, store, context, apiName, outputDir, filter, workspace) {
82
+ const results = [];
83
+ try {
84
+ const revisions = client.listApiRevisions(context, apiName);
85
+ for await (const revision of revisions) {
86
+ try {
87
+ const revNumber = (revision.apiRevision ?? revision.revisionNumber);
88
+ if (!revNumber || revNumber === '1') {
89
+ // Skip revision 1 — it's the main API
90
+ continue;
91
+ }
92
+ const revName = `${apiName};rev=${revNumber}`;
93
+ const descriptor = {
94
+ type: ResourceType.Api,
95
+ nameParts: [revName],
96
+ workspace,
97
+ };
98
+ // Check filter — use root API name for matching
99
+ if (!shouldIncludeResource(descriptor, filter)) {
100
+ continue;
101
+ }
102
+ // Get full revision resource
103
+ const revJson = await client.getResource(context, descriptor);
104
+ if (revJson) {
105
+ await store.writeResource(outputDir, descriptor, revJson);
106
+ results.push({ descriptor, json: revJson, status: 'success' });
107
+ logger.info(`Extracted revision ${buildResourceLabel(descriptor)}`);
108
+ }
109
+ }
110
+ catch (error) {
111
+ const errorMessage = error instanceof Error ? error.message : String(error);
112
+ logger.warn(`Failed to extract revision: ${errorMessage}`);
113
+ results.push({
114
+ descriptor: { type: ResourceType.Api, nameParts: [`${apiName};rev=?`] },
115
+ json: {},
116
+ status: 'error',
117
+ error: errorMessage,
118
+ });
119
+ }
120
+ }
121
+ }
122
+ catch (error) {
123
+ logger.warn(`Failed to list revisions for API "${apiName}": ${error.message}`);
124
+ }
125
+ return results;
126
+ }
127
+ /**
128
+ * Extract API specification (OpenAPI/GraphQL/WSDL/WADL).
129
+ * WebSocket APIs do not have an OpenAPI specification — skip with a debug log.
130
+ * Synthetic GraphQL APIs (schema stored as an ApiSchema, no external SDL blob)
131
+ * are detected by inspecting already-extracted schemas and skipped here —
132
+ * their schema is captured by the ApiSchema extraction step. Pass-through
133
+ * GraphQL APIs (linked to an external GraphQL server) export their SDL via
134
+ * the graphql-link format.
135
+ */
136
+ async function extractApiSpecification(client, store, context, apiDescriptor, apiJson, outputDir, extractedSchemas) {
137
+ const properties = apiJson.properties;
138
+ const apiType = properties?.type;
139
+ if (apiType?.toLowerCase() === 'websocket') {
140
+ logger.debug(`OpenAPI does not apply to WebSocket APIs`);
141
+ return false;
142
+ }
143
+ if (apiType?.toLowerCase() === 'graphql' && hasGraphQLSchema(extractedSchemas)) {
144
+ logger.debug(`Skipping spec export for synthetic GraphQL API "${getNamePart(apiDescriptor.nameParts, 0)}" — schema is captured via ApiSchema`);
145
+ return false;
146
+ }
147
+ try {
148
+ const spec = await client.getApiSpecification(context, getNamePart(apiDescriptor.nameParts, 0), apiType);
149
+ if (!spec) {
150
+ logger.debug(`No specification found for API "${getNamePart(apiDescriptor.nameParts, 0)}"`);
151
+ return false;
152
+ }
153
+ await store.writeContent(outputDir, apiDescriptor, spec.content, 'specification', spec.format);
154
+ logger.info(`Extracted specification ${buildResourceLabel(apiDescriptor)} (${spec.format})`);
155
+ return true;
156
+ }
157
+ catch (error) {
158
+ const errorMessage = error instanceof Error ? error.message : String(error);
159
+ logger.warn(`Failed to extract specification ${buildResourceLabel(apiDescriptor)}: ${errorMessage}`);
160
+ return false;
161
+ }
162
+ }
163
+ /**
164
+ * Returns true if any already-extracted ApiSchema resource has a contentType
165
+ * indicating a GraphQL schema. Used to distinguish synthetic GraphQL APIs
166
+ * (schema stored in APIM) from pass-through GraphQL APIs (schema fetched from
167
+ * backend). Inspects schemas that were extracted prior to spec export, so no
168
+ * extra list call is required.
169
+ */
170
+ function hasGraphQLSchema(schemas) {
171
+ for (const schema of schemas) {
172
+ const props = schema.json.properties;
173
+ const contentType = props?.contentType?.toLowerCase() ?? '';
174
+ if (contentType.includes('graphql')) {
175
+ return true;
176
+ }
177
+ }
178
+ return false;
179
+ }
180
+ /**
181
+ * Extract API-level policy.
182
+ */
183
+ async function extractApiPolicy(client, store, context, apiDescriptor, outputDir) {
184
+ const policyDescriptor = {
185
+ type: ResourceType.ApiPolicy,
186
+ nameParts: [...apiDescriptor.nameParts],
187
+ workspace: apiDescriptor.workspace,
188
+ };
189
+ const policyJson = await client.getResource(context, policyDescriptor);
190
+ if (!policyJson) {
191
+ return undefined;
192
+ }
193
+ const properties = policyJson.properties;
194
+ const policyContent = properties?.value;
195
+ if (policyContent) {
196
+ await store.writeContent(outputDir, policyDescriptor, policyContent, 'policy');
197
+ logger.debug(`Extracted ${buildResourceLabel(policyDescriptor)}`);
198
+ return policyContent;
199
+ }
200
+ return undefined;
201
+ }
202
+ /**
203
+ * Extract API operations and their policies.
204
+ */
205
+ async function extractApiOperations(client, store, context, apiDescriptor, outputDir, filter, workspace) {
206
+ const operations = [];
207
+ const operationPolicies = [];
208
+ const policies = [];
209
+ // Extract operations
210
+ const opsResult = await extractResourceType(client, store, context, ResourceType.ApiOperation, outputDir, filter, apiDescriptor, workspace);
211
+ operations.push(...opsResult.extracted);
212
+ // Extract operation policies for each operation
213
+ for (const op of opsResult.extracted) {
214
+ if (op.status !== 'success')
215
+ continue;
216
+ const opPolicyDescriptor = {
217
+ type: ResourceType.ApiOperationPolicy,
218
+ nameParts: [...op.descriptor.nameParts],
219
+ workspace,
220
+ };
221
+ const policyJson = await client.getResource(context, opPolicyDescriptor);
222
+ if (!policyJson)
223
+ continue;
224
+ const properties = policyJson.properties;
225
+ const policyContent = properties?.value;
226
+ if (policyContent) {
227
+ await store.writeContent(outputDir, opPolicyDescriptor, policyContent, 'policy');
228
+ operationPolicies.push({
229
+ descriptor: opPolicyDescriptor,
230
+ json: policyJson,
231
+ status: 'success',
232
+ });
233
+ policies.push(policyContent);
234
+ logger.debug(`Extracted ${buildResourceLabel(opPolicyDescriptor)}`);
235
+ }
236
+ }
237
+ return { operations, operationPolicies, policies };
238
+ }
239
+ /**
240
+ * Extract API wiki content.
241
+ */
242
+ async function extractApiWiki(client, store, context, apiDescriptor, outputDir) {
243
+ const wikiDescriptor = {
244
+ type: ResourceType.ApiWiki,
245
+ nameParts: [...apiDescriptor.nameParts],
246
+ workspace: apiDescriptor.workspace,
247
+ };
248
+ try {
249
+ const wikiJson = await client.getResource(context, wikiDescriptor);
250
+ if (!wikiJson) {
251
+ return false;
252
+ }
253
+ // Extract markdown content from wiki JSON
254
+ const properties = wikiJson.properties;
255
+ const documents = properties?.documents;
256
+ if (documents) {
257
+ // Write wiki info as markdown — use writeResource (not writeContent with 'policy')
258
+ // since there is no dedicated 'wiki' content type in IArtifactStore
259
+ const content = documents.map((d) => `# ${d.title}\n\n${d.documentationId}`).join('\n\n');
260
+ const markdownJson = { ...wikiJson, _markdownContent: content };
261
+ await store.writeResource(outputDir, wikiDescriptor, markdownJson);
262
+ }
263
+ else {
264
+ // Write the raw JSON
265
+ await store.writeResource(outputDir, wikiDescriptor, wikiJson);
266
+ }
267
+ logger.info(`Extracted ${buildResourceLabel(wikiDescriptor)}`);
268
+ return true;
269
+ }
270
+ catch (error) {
271
+ const errorMessage = error instanceof Error ? error.message : String(error);
272
+ logger.debug(`No wiki ${buildResourceLabel(wikiDescriptor)}: ${errorMessage}`);
273
+ return false;
274
+ }
275
+ }
276
+ /**
277
+ * Extract GraphQL resolvers and their policies.
278
+ */
279
+ async function extractGraphQLResolvers(client, store, context, apiDescriptor, apiJson, outputDir, filter, workspace) {
280
+ const resolvers = [];
281
+ const resolverPolicies = [];
282
+ const policies = [];
283
+ // Only extract resolvers for GraphQL APIs — use the already-fetched apiJson
284
+ const properties = apiJson.properties;
285
+ const apiType = properties?.type;
286
+ if (apiType?.toLowerCase() !== 'graphql') {
287
+ return { resolvers, resolverPolicies, policies };
288
+ }
289
+ // Extract resolvers
290
+ const resolverResult = await extractResourceType(client, store, context, ResourceType.GraphQLResolver, outputDir, filter, apiDescriptor, workspace);
291
+ resolvers.push(...resolverResult.extracted);
292
+ // Extract resolver policies
293
+ for (const resolver of resolverResult.extracted) {
294
+ if (resolver.status !== 'success')
295
+ continue;
296
+ const resolverPolicyDescriptor = {
297
+ type: ResourceType.GraphQLResolverPolicy,
298
+ nameParts: [...resolver.descriptor.nameParts],
299
+ workspace,
300
+ };
301
+ const policyJson = await client.getResource(context, resolverPolicyDescriptor);
302
+ if (!policyJson)
303
+ continue;
304
+ const props = policyJson.properties;
305
+ const policyContent = props?.value;
306
+ if (policyContent) {
307
+ await store.writeContent(outputDir, resolverPolicyDescriptor, policyContent, 'policy');
308
+ resolverPolicies.push({
309
+ descriptor: resolverPolicyDescriptor,
310
+ json: policyJson,
311
+ status: 'success',
312
+ });
313
+ policies.push(policyContent);
314
+ logger.debug(`Extracted ${buildResourceLabel(resolverPolicyDescriptor)}`);
315
+ }
316
+ }
317
+ return { resolvers, resolverPolicies, policies };
318
+ }
319
+ //# sourceMappingURL=api-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-extractor.js","sourceRoot":"","sources":["../../src/services/api-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * T032: API publisher with revision handling
3
+ * Create root API first, then revisions in numeric order with forced revision numbers.
4
+ * Publish operations, policies, schemas, releases, resolvers, tag descriptions, wikis per FR-024.
5
+ * Handle SOAP/WSDL import via ?import=true&format=wsdl-link query parameter.
6
+ */
7
+ import type { IApimClient } from '../clients/iapim-client.js';
8
+ import type { IArtifactStore } from '../clients/iartifact-store.js';
9
+ import type { ApimServiceContext, ResourceDescriptor } from '../models/types.js';
10
+ import type { PublishConfig } from '../models/config.js';
11
+ import { type ResourcePublishResult } from './resource-publisher.js';
12
+ /**
13
+ * Publish an API with all its revisions and child resources.
14
+ * Creates root API first, then revisions in numeric order.
15
+ * Handles SOAP/WSDL import via ?import=true&format=wsdl-link.
16
+ */
17
+ export declare function publishApi(client: IApimClient, store: IArtifactStore, context: ApimServiceContext, descriptor: ResourceDescriptor, config: PublishConfig): Promise<ResourcePublishResult>;
18
+ //# sourceMappingURL=api-publisher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-publisher.d.ts","sourceRoot":"","sources":["../../src/services/api-publisher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAwBtF;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,kBAAkB,EAC3B,UAAU,EAAE,kBAAkB,EAC9B,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,qBAAqB,CAAC,CA4BhC"}
@@ -0,0 +1,290 @@
1
+ /**
2
+ * T032: API publisher with revision handling
3
+ * Create root API first, then revisions in numeric order with forced revision numbers.
4
+ * Publish operations, policies, schemas, releases, resolvers, tag descriptions, wikis per FR-024.
5
+ * Handle SOAP/WSDL import via ?import=true&format=wsdl-link query parameter.
6
+ */
7
+ import { ResourceType } from '../models/resource-types.js';
8
+ import { publishResource } from './resource-publisher.js';
9
+ import { runParallel } from '../lib/parallel-runner.js';
10
+ import { applyOverrides } from './override-merger.js';
11
+ import { logger } from '../lib/logger.js';
12
+ import { getNamePart, getPublishTier } from '../lib/resource-path.js';
13
+ import { isAutoGeneratedId } from '../lib/auto-generated.js';
14
+ /**
15
+ * API child resource types that should be published after the API itself
16
+ */
17
+ const API_CHILD_TYPES = [
18
+ ResourceType.ApiPolicy,
19
+ ResourceType.ApiTag,
20
+ ResourceType.ApiDiagnostic,
21
+ ResourceType.ApiOperation,
22
+ ResourceType.ApiOperationPolicy,
23
+ ResourceType.ApiSchema,
24
+ ResourceType.ApiRelease,
25
+ ResourceType.ApiTagDescription,
26
+ ResourceType.ApiWiki,
27
+ ResourceType.GraphQLResolver,
28
+ ResourceType.GraphQLResolverPolicy,
29
+ ];
30
+ /**
31
+ * Publish an API with all its revisions and child resources.
32
+ * Creates root API first, then revisions in numeric order.
33
+ * Handles SOAP/WSDL import via ?import=true&format=wsdl-link.
34
+ */
35
+ export async function publishApi(client, store, context, descriptor, config) {
36
+ try {
37
+ // Step 1: Publish root API (with spec import if available)
38
+ const rootResult = await publishRootApi(client, store, context, descriptor, config);
39
+ if (rootResult.status !== 'success') {
40
+ return rootResult;
41
+ }
42
+ // Step 2: Find and publish revisions in numeric order
43
+ await publishApiRevisions(client, store, context, descriptor, config);
44
+ // Step 3: Publish child resources in parallel
45
+ // When a spec was imported, operations and schemas are auto-created by APIM
46
+ await publishApiChildren(client, store, context, descriptor, config, rootResult.specImported);
47
+ return {
48
+ descriptor,
49
+ status: 'success',
50
+ action: 'put',
51
+ };
52
+ }
53
+ catch (error) {
54
+ return {
55
+ descriptor,
56
+ status: 'failed',
57
+ action: 'noop',
58
+ error: error instanceof Error ? error : new Error(String(error)),
59
+ };
60
+ }
61
+ }
62
+ /**
63
+ * Maps spec file format to APIM ContentFormat for inline import.
64
+ */
65
+ function getImportFormat(specFormat, _apiType) {
66
+ switch (specFormat) {
67
+ case 'yaml':
68
+ return 'openapi';
69
+ case 'json':
70
+ // Swagger 2.0 uses swagger-json, OpenAPI 3.x uses openapi+json.
71
+ // Default to openapi+json as the more modern format — APIM accepts both.
72
+ return 'openapi+json';
73
+ case 'wsdl':
74
+ return 'wsdl';
75
+ case 'wadl':
76
+ return 'wadl-xml';
77
+ case 'graphql':
78
+ // GraphQL schemas are managed via the ApiSchema resource, not via
79
+ // the import properties. Return undefined so we skip injection.
80
+ return undefined;
81
+ default:
82
+ return undefined;
83
+ }
84
+ }
85
+ /**
86
+ * Publish the root API (apiInformation.json).
87
+ * When a specification file exists alongside the API metadata, injects
88
+ * `properties.format` and `properties.value` into the PUT body so APIM
89
+ * imports the spec and auto-creates operations + schemas.
90
+ */
91
+ async function publishRootApi(client, store, context, descriptor, config) {
92
+ let json = await store.readResource(config.sourceDir, descriptor);
93
+ if (!json) {
94
+ return {
95
+ descriptor,
96
+ status: 'skipped',
97
+ action: 'noop',
98
+ specImported: false,
99
+ };
100
+ }
101
+ // Apply overrides
102
+ json = applyOverrides(descriptor, json, config.overrides);
103
+ // Try to read the specification file for this API
104
+ let specImported = false;
105
+ const specResult = await store.readContent(config.sourceDir, descriptor, 'specification');
106
+ if (specResult) {
107
+ const properties = json.properties;
108
+ const apiType = properties?.type;
109
+ const importFormat = getImportFormat(specResult.format ?? 'yaml', apiType);
110
+ if (importFormat) {
111
+ // Strip null-valued properties that cause validation errors in
112
+ // APIM's spec-import mode (e.g. "backendId": null → HTTP 400).
113
+ const cleanProps = {};
114
+ for (const [key, val] of Object.entries(properties ?? {})) {
115
+ if (val !== null) {
116
+ cleanProps[key] = val;
117
+ }
118
+ }
119
+ // The `type` property from GET is read-only and ignored on PUT.
120
+ // APIM uses `apiType` to determine the API kind during spec import.
121
+ // Always set it explicitly (valid values: http, soap, websocket, graphql, odata, grpc, mcp).
122
+ if (apiType) {
123
+ cleanProps.apiType = apiType;
124
+ }
125
+ // Inject the spec into the PUT body for APIM to import
126
+ json = {
127
+ ...json,
128
+ properties: {
129
+ ...cleanProps,
130
+ format: importFormat,
131
+ value: specResult.content,
132
+ },
133
+ };
134
+ specImported = true;
135
+ logger.info(`Including ${specResult.format} specification in API import for "${getNamePart(descriptor.nameParts, 0)}"`);
136
+ }
137
+ }
138
+ // PUT the API resource to APIM
139
+ await client.putResource(context, descriptor, json);
140
+ return {
141
+ descriptor,
142
+ status: 'success',
143
+ action: 'put',
144
+ specImported,
145
+ };
146
+ }
147
+ /**
148
+ * Find and publish API revisions in numeric order
149
+ */
150
+ async function publishApiRevisions(client, store, context, apiDescriptor, config) {
151
+ // List all resources from store
152
+ const allDescriptors = await store.listResources(config.sourceDir);
153
+ // Find revision descriptors for this API
154
+ const revisionDescriptors = allDescriptors.filter((d) => d.type === ResourceType.Api &&
155
+ getNamePart(d.nameParts, 0).startsWith(`${getNamePart(apiDescriptor.nameParts, 0)};rev=`));
156
+ // Sort revisions by revision number
157
+ const sortedRevisions = revisionDescriptors.sort((a, b) => {
158
+ const revA = extractRevisionNumber(getNamePart(a.nameParts, 0));
159
+ const revB = extractRevisionNumber(getNamePart(b.nameParts, 0));
160
+ return revA - revB;
161
+ });
162
+ // Publish each revision in order
163
+ for (const revDescriptor of sortedRevisions) {
164
+ await publishResource(client, store, context, revDescriptor, config);
165
+ }
166
+ }
167
+ /**
168
+ * Resource types that are auto-created by APIM when importing a spec.
169
+ * Both ApiOperation and ApiSchema are initially excluded, but we selectively
170
+ * re-add: operations with schema references, and explicitly named schemas
171
+ * (non-auto-generated 24-char hex IDs).
172
+ */
173
+ const SPEC_MANAGED_CHILD_TYPES = new Set([
174
+ ResourceType.ApiOperation,
175
+ ResourceType.ApiSchema,
176
+ ]);
177
+ /**
178
+ * Publish all child resources of an API in parallel.
179
+ * When specImported is true, skips ApiSchema and ApiOperation since APIM
180
+ * auto-creates those from the imported specification. However:
181
+ * - Operations with schema references are re-PUT explicitly so APIM preserves those links
182
+ * - Explicitly named schemas (non-24-char-hex IDs) are also re-published
183
+ */
184
+ async function publishApiChildren(client, store, context, apiDescriptor, config, specImported = false) {
185
+ // List all resources from store
186
+ const allDescriptors = await store.listResources(config.sourceDir);
187
+ // Find child descriptors for this API
188
+ let childDescriptors = allDescriptors.filter((d) => API_CHILD_TYPES.includes(d.type) &&
189
+ getNamePart(d.nameParts, 0) === getNamePart(apiDescriptor.nameParts, 0) &&
190
+ !(specImported && SPEC_MANAGED_CHILD_TYPES.has(d.type)));
191
+ // When a spec was imported, APIM auto-creates operations and schemas but loses
192
+ // schemaId/typeName references in representations. Re-include operations that
193
+ // carry such references so those links are explicitly restored via PUT.
194
+ if (specImported) {
195
+ const operationDescriptors = allDescriptors.filter((d) => d.type === ResourceType.ApiOperation &&
196
+ getNamePart(d.nameParts, 0) === getNamePart(apiDescriptor.nameParts, 0));
197
+ const schemaRefOps = await filterOperationsWithSchemaRefs(store, config.sourceDir, operationDescriptors);
198
+ if (schemaRefOps.length > 0) {
199
+ logger.debug(`Re-publishing ${schemaRefOps.length} operation(s) with schema references after spec import for "${getNamePart(apiDescriptor.nameParts, 0)}"`);
200
+ childDescriptors = [...childDescriptors, ...schemaRefOps];
201
+ }
202
+ // Re-include explicitly named schemas (non-auto-generated IDs).
203
+ // Auto-generated schemas have 24-char hex names and are recreated by spec import.
204
+ // Explicitly named schemas (like "src-rest-schema-item") must be published.
205
+ const explicitSchemas = allDescriptors.filter((d) => d.type === ResourceType.ApiSchema &&
206
+ getNamePart(d.nameParts, 0) === getNamePart(apiDescriptor.nameParts, 0) &&
207
+ !isAutoGeneratedId(getNamePart(d.nameParts, 1)));
208
+ if (explicitSchemas.length > 0) {
209
+ logger.debug(`Re-publishing ${explicitSchemas.length} explicit schema(s) after spec import for "${getNamePart(apiDescriptor.nameParts, 0)}"`);
210
+ childDescriptors = [...childDescriptors, ...explicitSchemas];
211
+ }
212
+ }
213
+ // Group resources by publish tier for dependency ordering.
214
+ // Lower tiers are published first (parents before children, operations before policies).
215
+ // Resources in the same tier can be published in parallel.
216
+ const tierMap = new Map();
217
+ for (const d of childDescriptors) {
218
+ const tier = getPublishTier(d.type);
219
+ const existing = tierMap.get(tier) ?? [];
220
+ existing.push(d);
221
+ tierMap.set(tier, existing);
222
+ }
223
+ // Publish each tier in order (lowest to highest)
224
+ const sortedTiers = [...tierMap.keys()].sort((a, b) => a - b);
225
+ for (const tier of sortedTiers) {
226
+ const descriptors = tierMap.get(tier) ?? [];
227
+ if (descriptors.length > 0) {
228
+ const tasks = descriptors.map((descriptor) => () => publishResource(client, store, context, descriptor, config));
229
+ await runParallel(tasks, 5);
230
+ }
231
+ }
232
+ }
233
+ /**
234
+ * Returns the subset of operation descriptors whose stored artifact contains
235
+ * at least one representation with a schemaId or typeName property.
236
+ * These operations must be re-PUT after a spec import so APIM retains the
237
+ * schema linkage that the import path discards.
238
+ */
239
+ async function filterOperationsWithSchemaRefs(store, sourceDir, operationDescriptors) {
240
+ const result = [];
241
+ for (const descriptor of operationDescriptors) {
242
+ const json = await store.readResource(sourceDir, descriptor);
243
+ if (json && operationHasSchemaRefs(json)) {
244
+ result.push(descriptor);
245
+ }
246
+ }
247
+ return result;
248
+ }
249
+ /**
250
+ * Returns true if the operation JSON contains at least one representation
251
+ * (in request or any response) that has a schemaId or typeName property.
252
+ */
253
+ function operationHasSchemaRefs(json) {
254
+ const props = json.properties;
255
+ if (!props)
256
+ return false;
257
+ const representationGroups = [];
258
+ const request = props.request;
259
+ if (request?.representations) {
260
+ representationGroups.push(request.representations);
261
+ }
262
+ const responses = props.responses;
263
+ if (Array.isArray(responses)) {
264
+ for (const response of responses) {
265
+ const r = response;
266
+ if (r.representations) {
267
+ representationGroups.push(r.representations);
268
+ }
269
+ }
270
+ }
271
+ for (const group of representationGroups) {
272
+ if (!Array.isArray(group))
273
+ continue;
274
+ for (const rep of group) {
275
+ const r = rep;
276
+ if (r.schemaId != null || r.typeName != null) {
277
+ return true;
278
+ }
279
+ }
280
+ }
281
+ return false;
282
+ }
283
+ /**
284
+ * Extract revision number from API name (e.g., "my-api;rev=2" -> 2)
285
+ */
286
+ function extractRevisionNumber(apiName) {
287
+ const match = /;rev=(\d+)/.exec(apiName);
288
+ return match ? parseInt(match[1], 10) : 0;
289
+ }
290
+ //# sourceMappingURL=api-publisher.js.map