@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,131 @@
1
+ /**
2
+ * T015: YAML config loader with validation
3
+ * Parse filter YAML, override YAML, and OTel config files
4
+ */
5
+ import * as fs from 'node:fs/promises';
6
+ import * as yaml from 'js-yaml';
7
+ import { logger } from './logger.js';
8
+ /**
9
+ * Assert that a value is an array of strings. Throws on type mismatch.
10
+ */
11
+ function assertStringArray(value, fieldName) {
12
+ if (!Array.isArray(value)) {
13
+ throw new Error(`${fieldName} must be an array, got ${typeof value}`);
14
+ }
15
+ for (let i = 0; i < value.length; i++) {
16
+ if (typeof value[i] !== 'string') {
17
+ throw new Error(`${fieldName}[${i}] must be a string, got ${typeof value[i]}`);
18
+ }
19
+ }
20
+ return value;
21
+ }
22
+ /**
23
+ * Load and parse a filter configuration YAML file.
24
+ * Returns undefined if file doesn't exist.
25
+ */
26
+ export async function loadFilterConfig(filePath) {
27
+ try {
28
+ const content = await fs.readFile(filePath, 'utf-8');
29
+ const parsed = yaml.load(content);
30
+ // Validate structure — each field must be an array of strings
31
+ const config = {};
32
+ if (parsed.apiNames !== undefined) {
33
+ config.apiNames = assertStringArray(parsed.apiNames, 'apiNames');
34
+ }
35
+ if (parsed.backendNames !== undefined) {
36
+ config.backendNames = assertStringArray(parsed.backendNames, 'backendNames');
37
+ }
38
+ if (parsed.productNames !== undefined) {
39
+ config.productNames = assertStringArray(parsed.productNames, 'productNames');
40
+ }
41
+ if (parsed.namedValueNames !== undefined) {
42
+ config.namedValueNames = assertStringArray(parsed.namedValueNames, 'namedValueNames');
43
+ }
44
+ if (parsed.loggerNames !== undefined) {
45
+ config.loggerNames = assertStringArray(parsed.loggerNames, 'loggerNames');
46
+ }
47
+ if (parsed.diagnosticNames !== undefined) {
48
+ config.diagnosticNames = assertStringArray(parsed.diagnosticNames, 'diagnosticNames');
49
+ }
50
+ if (parsed.tagNames !== undefined) {
51
+ config.tagNames = assertStringArray(parsed.tagNames, 'tagNames');
52
+ }
53
+ if (parsed.policyFragmentNames !== undefined) {
54
+ config.policyFragmentNames = assertStringArray(parsed.policyFragmentNames, 'policyFragmentNames');
55
+ }
56
+ if (parsed.gatewayNames !== undefined) {
57
+ config.gatewayNames = assertStringArray(parsed.gatewayNames, 'gatewayNames');
58
+ }
59
+ if (parsed.versionSetNames !== undefined) {
60
+ config.versionSetNames = assertStringArray(parsed.versionSetNames, 'versionSetNames');
61
+ }
62
+ if (parsed.groupNames !== undefined) {
63
+ config.groupNames = assertStringArray(parsed.groupNames, 'groupNames');
64
+ }
65
+ if (parsed.subscriptionNames !== undefined) {
66
+ config.subscriptionNames = assertStringArray(parsed.subscriptionNames, 'subscriptionNames');
67
+ }
68
+ if (parsed.schemaNames !== undefined) {
69
+ config.schemaNames = assertStringArray(parsed.schemaNames, 'schemaNames');
70
+ }
71
+ if (parsed.policyRestrictionNames !== undefined) {
72
+ config.policyRestrictionNames = assertStringArray(parsed.policyRestrictionNames, 'policyRestrictionNames');
73
+ }
74
+ if (parsed.documentationNames !== undefined) {
75
+ config.documentationNames = assertStringArray(parsed.documentationNames, 'documentationNames');
76
+ }
77
+ if (parsed.workspaceNames !== undefined) {
78
+ config.workspaceNames = assertStringArray(parsed.workspaceNames, 'workspaceNames');
79
+ }
80
+ logger.debug(`Loaded filter config from ${filePath}`);
81
+ return config;
82
+ }
83
+ catch (error) {
84
+ if (error.code === 'ENOENT') {
85
+ logger.debug(`Filter config file not found: ${filePath}`);
86
+ return undefined;
87
+ }
88
+ throw new Error(`Failed to load filter config from ${filePath}: ${error.message}`, { cause: error });
89
+ }
90
+ }
91
+ /**
92
+ * Load and parse an override configuration YAML file.
93
+ * Returns undefined if file doesn't exist.
94
+ */
95
+ export async function loadOverrideConfig(filePath) {
96
+ try {
97
+ const content = await fs.readFile(filePath, 'utf-8');
98
+ const parsed = yaml.load(content);
99
+ // Return as-is; validation will happen during publish when applied
100
+ const config = parsed;
101
+ logger.debug(`Loaded override config from ${filePath}`);
102
+ return config;
103
+ }
104
+ catch (error) {
105
+ if (error.code === 'ENOENT') {
106
+ logger.debug(`Override config file not found: ${filePath}`);
107
+ return undefined;
108
+ }
109
+ throw new Error(`Failed to load override config from ${filePath}: ${error.message}`, { cause: error });
110
+ }
111
+ }
112
+ /**
113
+ * Load and parse an OpenTelemetry configuration YAML file.
114
+ * Returns undefined if file doesn't exist.
115
+ */
116
+ export async function loadOTelConfig(filePath) {
117
+ try {
118
+ const content = await fs.readFile(filePath, 'utf-8');
119
+ const parsed = yaml.load(content);
120
+ logger.debug(`Loaded OTel config from ${filePath}`);
121
+ return parsed;
122
+ }
123
+ catch (error) {
124
+ if (error.code === 'ENOENT') {
125
+ logger.debug(`OTel config file not found: ${filePath}`);
126
+ return undefined;
127
+ }
128
+ throw new Error(`Failed to load OTel config from ${filePath}: ${error.message}`, { cause: error });
129
+ }
130
+ }
131
+ //# sourceMappingURL=config-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/lib/config-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * T011: Static dependency graph implementation
3
+ * 33 resource types, 4 tiers, topological sort, cycle-detection assertion
4
+ */
5
+ import { ResourceType } from '../models/resource-types.js';
6
+ import { DependencyEdge } from '../models/types.js';
7
+ /**
8
+ * Static dependency edges between resource types.
9
+ *
10
+ * Note: This dependency graph is resource-type-based and does not account for
11
+ * workspace-specific dependency variations. All resource types have the same
12
+ * dependency rules regardless of workspace context. This is correct for the
13
+ * current APIM API (2024-05-01) where workspace scoping does not introduce
14
+ * different dependency relationships.
15
+ */
16
+ export declare const DEPENDENCY_EDGES: DependencyEdge[];
17
+ export declare const TIER_1_RESOURCES: ResourceType[];
18
+ export declare const TIER_2_RESOURCES: ResourceType[];
19
+ export declare const TIER_3_RESOURCES: ResourceType[];
20
+ export declare const TIER_4_RESOURCES: ResourceType[];
21
+ /**
22
+ * Returns all resource types in topological order (dependencies first).
23
+ * This is the order in which resources should be extracted and published.
24
+ */
25
+ export declare function getTopologicalOrder(): ResourceType[];
26
+ /**
27
+ * Returns the tier number (1-4) for a given resource type.
28
+ */
29
+ export declare function getResourceTier(type: ResourceType): number;
30
+ /**
31
+ * Returns all dependencies for a given resource type.
32
+ */
33
+ export declare function getDependencies(type: ResourceType): DependencyEdge[];
34
+ /**
35
+ * Returns all resource types that depend on a given resource type.
36
+ */
37
+ export declare function getDependents(type: ResourceType): ResourceType[];
38
+ /**
39
+ * Validates that the dependency graph is acyclic.
40
+ * Throws an error if a cycle is detected.
41
+ */
42
+ export declare function assertAcyclic(): void;
43
+ //# sourceMappingURL=dependency-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-graph.d.ts","sourceRoot":"","sources":["../../src/lib/dependency-graph.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAAc,EAuC5C,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,YAAY,EAY1C,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,YAAY,EAK1C,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,YAAY,EAiB1C,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,YAAY,EAG1C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,EAAE,CAOpD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAM1D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,EAAE,CAEpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,EAAE,CAIhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CA8BpC"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * T011: Static dependency graph implementation
3
+ * 33 resource types, 4 tiers, topological sort, cycle-detection assertion
4
+ */
5
+ import { ResourceType } from '../models/resource-types.js';
6
+ /**
7
+ * Static dependency edges between resource types.
8
+ *
9
+ * Note: This dependency graph is resource-type-based and does not account for
10
+ * workspace-specific dependency variations. All resource types have the same
11
+ * dependency rules regardless of workspace context. This is correct for the
12
+ * current APIM API (2024-05-01) where workspace scoping does not introduce
13
+ * different dependency relationships.
14
+ */
15
+ export const DEPENDENCY_EDGES = [
16
+ // Tier 1 -> Tier 2 dependencies
17
+ { from: ResourceType.Diagnostic, to: ResourceType.Logger, required: false },
18
+ { from: ResourceType.ServicePolicy, to: ResourceType.NamedValue, required: false },
19
+ { from: ResourceType.ServicePolicy, to: ResourceType.PolicyFragment, required: false },
20
+ { from: ResourceType.Api, to: ResourceType.VersionSet, required: false },
21
+ // Tier 2 -> Tier 3 dependencies
22
+ { from: ResourceType.ProductPolicy, to: ResourceType.Product, required: true },
23
+ { from: ResourceType.ProductGroup, to: ResourceType.Product, required: true },
24
+ { from: ResourceType.ProductGroup, to: ResourceType.Group, required: true },
25
+ { from: ResourceType.ProductTag, to: ResourceType.Product, required: true },
26
+ { from: ResourceType.ProductTag, to: ResourceType.Tag, required: true },
27
+ { from: ResourceType.ProductApi, to: ResourceType.Product, required: true },
28
+ { from: ResourceType.ProductApi, to: ResourceType.Api, required: true },
29
+ { from: ResourceType.ProductWiki, to: ResourceType.Product, required: true },
30
+ { from: ResourceType.ApiPolicy, to: ResourceType.Api, required: true },
31
+ { from: ResourceType.ApiTag, to: ResourceType.Api, required: true },
32
+ { from: ResourceType.ApiTag, to: ResourceType.Tag, required: true },
33
+ { from: ResourceType.ApiDiagnostic, to: ResourceType.Api, required: true },
34
+ { from: ResourceType.ApiDiagnostic, to: ResourceType.Logger, required: false },
35
+ { from: ResourceType.ApiOperation, to: ResourceType.Api, required: true },
36
+ { from: ResourceType.ApiSchema, to: ResourceType.Api, required: true },
37
+ { from: ResourceType.ApiRelease, to: ResourceType.Api, required: true },
38
+ { from: ResourceType.ApiTagDescription, to: ResourceType.Api, required: true },
39
+ { from: ResourceType.ApiTagDescription, to: ResourceType.Tag, required: true },
40
+ { from: ResourceType.ApiWiki, to: ResourceType.Api, required: true },
41
+ { from: ResourceType.GraphQLResolver, to: ResourceType.Api, required: true },
42
+ { from: ResourceType.GatewayApi, to: ResourceType.Gateway, required: true },
43
+ { from: ResourceType.GatewayApi, to: ResourceType.Api, required: true },
44
+ { from: ResourceType.Subscription, to: ResourceType.Product, required: false },
45
+ { from: ResourceType.Subscription, to: ResourceType.Api, required: false },
46
+ // Tier 3 -> Tier 4 dependencies
47
+ { from: ResourceType.ApiOperationPolicy, to: ResourceType.ApiOperation, required: true },
48
+ { from: ResourceType.GraphQLResolverPolicy, to: ResourceType.GraphQLResolver, required: true },
49
+ ];
50
+ export const TIER_1_RESOURCES = [
51
+ ResourceType.NamedValue,
52
+ ResourceType.Tag,
53
+ ResourceType.Gateway,
54
+ ResourceType.VersionSet,
55
+ ResourceType.Backend,
56
+ ResourceType.Logger,
57
+ ResourceType.Group,
58
+ ResourceType.PolicyFragment,
59
+ ResourceType.GlobalSchema,
60
+ ResourceType.PolicyRestriction,
61
+ ResourceType.Documentation,
62
+ ];
63
+ export const TIER_2_RESOURCES = [
64
+ ResourceType.Diagnostic,
65
+ ResourceType.ServicePolicy,
66
+ ResourceType.Product,
67
+ ResourceType.Api,
68
+ ];
69
+ export const TIER_3_RESOURCES = [
70
+ ResourceType.ProductPolicy,
71
+ ResourceType.ProductGroup,
72
+ ResourceType.ProductTag,
73
+ ResourceType.ProductApi,
74
+ ResourceType.ProductWiki,
75
+ ResourceType.ApiPolicy,
76
+ ResourceType.ApiTag,
77
+ ResourceType.ApiDiagnostic,
78
+ ResourceType.ApiOperation,
79
+ ResourceType.ApiSchema,
80
+ ResourceType.ApiRelease,
81
+ ResourceType.ApiTagDescription,
82
+ ResourceType.ApiWiki,
83
+ ResourceType.GraphQLResolver,
84
+ ResourceType.GatewayApi,
85
+ ResourceType.Subscription,
86
+ ];
87
+ export const TIER_4_RESOURCES = [
88
+ ResourceType.ApiOperationPolicy,
89
+ ResourceType.GraphQLResolverPolicy,
90
+ ];
91
+ /**
92
+ * Returns all resource types in topological order (dependencies first).
93
+ * This is the order in which resources should be extracted and published.
94
+ */
95
+ export function getTopologicalOrder() {
96
+ return [
97
+ ...TIER_1_RESOURCES,
98
+ ...TIER_2_RESOURCES,
99
+ ...TIER_3_RESOURCES,
100
+ ...TIER_4_RESOURCES,
101
+ ];
102
+ }
103
+ /**
104
+ * Returns the tier number (1-4) for a given resource type.
105
+ */
106
+ export function getResourceTier(type) {
107
+ if (TIER_1_RESOURCES.includes(type))
108
+ return 1;
109
+ if (TIER_2_RESOURCES.includes(type))
110
+ return 2;
111
+ if (TIER_3_RESOURCES.includes(type))
112
+ return 3;
113
+ if (TIER_4_RESOURCES.includes(type))
114
+ return 4;
115
+ throw new Error(`Unknown resource type: ${type}`);
116
+ }
117
+ /**
118
+ * Returns all dependencies for a given resource type.
119
+ */
120
+ export function getDependencies(type) {
121
+ return DEPENDENCY_EDGES.filter((edge) => edge.from === type);
122
+ }
123
+ /**
124
+ * Returns all resource types that depend on a given resource type.
125
+ */
126
+ export function getDependents(type) {
127
+ return DEPENDENCY_EDGES.filter((edge) => edge.to === type).map((edge) => edge.from);
128
+ }
129
+ /**
130
+ * Validates that the dependency graph is acyclic.
131
+ * Throws an error if a cycle is detected.
132
+ */
133
+ export function assertAcyclic() {
134
+ const visited = new Set();
135
+ const recursionStack = new Set();
136
+ function hasCycle(current) {
137
+ visited.add(current);
138
+ recursionStack.add(current);
139
+ const deps = getDependencies(current);
140
+ for (const edge of deps) {
141
+ if (!visited.has(edge.to)) {
142
+ if (hasCycle(edge.to)) {
143
+ return true;
144
+ }
145
+ }
146
+ else if (recursionStack.has(edge.to)) {
147
+ return true;
148
+ }
149
+ }
150
+ recursionStack.delete(current);
151
+ return false;
152
+ }
153
+ for (const type of getTopologicalOrder()) {
154
+ if (!visited.has(type)) {
155
+ if (hasCycle(type)) {
156
+ throw new Error('Dependency graph contains a cycle');
157
+ }
158
+ }
159
+ }
160
+ }
161
+ // Assert at module load time that the graph is acyclic
162
+ assertAcyclic();
163
+ //# sourceMappingURL=dependency-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-graph.js","sourceRoot":"","sources":["../../src/lib/dependency-graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * T041: Exit code constants and aggregation
3
+ * Provides standardised exit codes and a reusable aggregation function
4
+ * for combining per-resource results into a single process exit code.
5
+ */
6
+ /** All operations completed successfully. */
7
+ export declare const EXIT_SUCCESS = 0;
8
+ /** Some resources failed but others succeeded (partial failure). */
9
+ export declare const EXIT_PARTIAL = 1;
10
+ /** Cannot proceed — auth failure, invalid config, network unreachable, or total failure. */
11
+ export declare const EXIT_FATAL = 2;
12
+ /**
13
+ * Outcome of a single resource operation (extract or publish).
14
+ */
15
+ export interface ResourceResult {
16
+ status: 'success' | 'error';
17
+ error?: Error;
18
+ }
19
+ /**
20
+ * Aggregate an array of per-resource results into a single exit code.
21
+ *
22
+ * - Returns EXIT_SUCCESS (0) if all results succeeded.
23
+ * - Returns EXIT_PARTIAL (1) if some failed and some succeeded.
24
+ * - Returns EXIT_FATAL (2) if all failed or there are zero results.
25
+ */
26
+ export declare function aggregateExitCode(results: ResourceResult[]): number;
27
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../../src/lib/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6CAA6C;AAC7C,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,oEAAoE;AACpE,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,4FAA4F;AAC5F,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAiBnE"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * T041: Exit code constants and aggregation
3
+ * Provides standardised exit codes and a reusable aggregation function
4
+ * for combining per-resource results into a single process exit code.
5
+ */
6
+ /** All operations completed successfully. */
7
+ export const EXIT_SUCCESS = 0;
8
+ /** Some resources failed but others succeeded (partial failure). */
9
+ export const EXIT_PARTIAL = 1;
10
+ /** Cannot proceed — auth failure, invalid config, network unreachable, or total failure. */
11
+ export const EXIT_FATAL = 2;
12
+ /**
13
+ * Aggregate an array of per-resource results into a single exit code.
14
+ *
15
+ * - Returns EXIT_SUCCESS (0) if all results succeeded.
16
+ * - Returns EXIT_PARTIAL (1) if some failed and some succeeded.
17
+ * - Returns EXIT_FATAL (2) if all failed or there are zero results.
18
+ */
19
+ export function aggregateExitCode(results) {
20
+ if (results.length === 0) {
21
+ return EXIT_SUCCESS;
22
+ }
23
+ const successCount = results.filter((r) => r.status === 'success').length;
24
+ const errorCount = results.filter((r) => r.status === 'error').length;
25
+ if (errorCount === 0) {
26
+ return EXIT_SUCCESS;
27
+ }
28
+ if (successCount > 0) {
29
+ return EXIT_PARTIAL;
30
+ }
31
+ return EXIT_FATAL;
32
+ }
33
+ //# sourceMappingURL=exit-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/lib/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6CAA6C;AAC7C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAE9B,oEAAoE;AACpE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAE9B,4FAA4F;AAC5F,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAU5B;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAyB;IACzD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAC1E,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IAEtE,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * T014: Structured logger with stderr output
3
+ * Supports log levels, timestamps, and --log-level option.
4
+ * Sanitizes sensitive data from log output per Constitution §VIII.
5
+ */
6
+ export declare enum LogLevel {
7
+ DEBUG = "DEBUG",
8
+ INFO = "INFO",
9
+ WARN = "WARN",
10
+ ERROR = "ERROR"
11
+ }
12
+ export type LogFormat = 'structured' | 'pretty';
13
+ export interface LoggerOptions {
14
+ level?: LogLevel;
15
+ format?: LogFormat;
16
+ }
17
+ export declare class Logger {
18
+ private level;
19
+ private format;
20
+ configure(options: LoggerOptions): void;
21
+ /**
22
+ * Switch between structured (timestamped) and pretty (clean) output.
23
+ * Pretty mode omits timestamps and level prefixes — ideal for
24
+ * human-facing commands like `apiops init`.
25
+ */
26
+ setFormat(format: LogFormat): void;
27
+ debug(message: string, ...args: unknown[]): void;
28
+ info(message: string, ...args: unknown[]): void;
29
+ warn(message: string, ...args: unknown[]): void;
30
+ error(message: string, ...args: unknown[]): void;
31
+ private log;
32
+ }
33
+ /**
34
+ * Parse a log-level string into a LogLevel enum value.
35
+ * Falls back to INFO for unrecognised values (Commander choices() prevents this in practice).
36
+ */
37
+ export declare function parseLogLevel(value: string): LogLevel;
38
+ export declare const logger: Logger;
39
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,oBAAY,QAAQ;IAClB,KAAK,UAAU;IACf,IAAI,SAAS;IACb,IAAI,SAAS;IACb,KAAK,UAAU;CAChB;AAED,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AA0DD,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAA2B;IAEzC,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAOvC;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAIlC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAIhD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAIhD,OAAO,CAAC,GAAG;CAuBZ;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAMrD;AAGD,eAAO,MAAM,MAAM,QAAe,CAAC"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * T014: Structured logger with stderr output
3
+ * Supports log levels, timestamps, and --log-level option.
4
+ * Sanitizes sensitive data from log output per Constitution §VIII.
5
+ */
6
+ import anyAscii from 'any-ascii';
7
+ export var LogLevel;
8
+ (function (LogLevel) {
9
+ LogLevel["DEBUG"] = "DEBUG";
10
+ LogLevel["INFO"] = "INFO";
11
+ LogLevel["WARN"] = "WARN";
12
+ LogLevel["ERROR"] = "ERROR";
13
+ })(LogLevel || (LogLevel = {}));
14
+ const LOG_LEVEL_PRIORITY = {
15
+ [LogLevel.DEBUG]: 0,
16
+ [LogLevel.INFO]: 1,
17
+ [LogLevel.WARN]: 2,
18
+ [LogLevel.ERROR]: 3,
19
+ };
20
+ /** Keys whose values are redacted before logging (case-insensitive match). */
21
+ const SENSITIVE_KEY_PATTERNS = [
22
+ 'token',
23
+ 'secret',
24
+ 'password',
25
+ 'credential',
26
+ 'authorization',
27
+ 'apikey',
28
+ 'api_key',
29
+ 'client_secret',
30
+ 'access_token',
31
+ 'refresh_token',
32
+ ];
33
+ /**
34
+ * Determines whether a key name looks sensitive.
35
+ * Matches if ANY sensitive pattern appears as a substring of the lower-cased key.
36
+ * Standalone "key" is treated as sensitive (e.g. subscription keys in ARM responses)
37
+ * but compound words like "keyName", "keyVault" are NOT matched since they are
38
+ * non-secret APIM metadata fields.
39
+ */
40
+ function isSensitiveKey(key) {
41
+ const lower = key.toLowerCase();
42
+ if (lower === 'key')
43
+ return true;
44
+ return SENSITIVE_KEY_PATTERNS.some((pattern) => lower.includes(pattern));
45
+ }
46
+ /**
47
+ * Recursively sanitize a value, replacing sensitive fields with '***'.
48
+ * Handles objects, arrays, and inline bearer tokens in strings.
49
+ */
50
+ function sanitize(value) {
51
+ if (typeof value === 'string') {
52
+ // Redact inline bearer tokens (e.g. "Bearer eyJ...")
53
+ return value.replace(/Bearer\s+[A-Za-z0-9\-._~+/]+=*/gi, 'Bearer ***');
54
+ }
55
+ if (Array.isArray(value)) {
56
+ return value.map((item) => sanitize(item));
57
+ }
58
+ if (typeof value === 'object' && value !== null) {
59
+ const sanitized = {};
60
+ for (const [k, v] of Object.entries(value)) {
61
+ sanitized[k] = isSensitiveKey(k) ? '***' : sanitize(v);
62
+ }
63
+ return sanitized;
64
+ }
65
+ return value;
66
+ }
67
+ export class Logger {
68
+ level = LogLevel.INFO;
69
+ format = 'structured';
70
+ configure(options) {
71
+ this.level = options.level ?? LogLevel.INFO;
72
+ if (options.format !== undefined) {
73
+ this.format = options.format;
74
+ }
75
+ }
76
+ /**
77
+ * Switch between structured (timestamped) and pretty (clean) output.
78
+ * Pretty mode omits timestamps and level prefixes — ideal for
79
+ * human-facing commands like `apiops init`.
80
+ */
81
+ setFormat(format) {
82
+ this.format = format;
83
+ }
84
+ debug(message, ...args) {
85
+ this.log(LogLevel.DEBUG, message, ...args);
86
+ }
87
+ info(message, ...args) {
88
+ this.log(LogLevel.INFO, message, ...args);
89
+ }
90
+ warn(message, ...args) {
91
+ this.log(LogLevel.WARN, message, ...args);
92
+ }
93
+ error(message, ...args) {
94
+ this.log(LogLevel.ERROR, message, ...args);
95
+ }
96
+ log(level, message, ...args) {
97
+ // Filter messages based on configured log level
98
+ if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.level]) {
99
+ return;
100
+ }
101
+ const sanitizedArgs = args.map((arg) => sanitize(arg));
102
+ const formattedArgs = sanitizedArgs.length > 0 ? ' ' + JSON.stringify(sanitizedArgs) : '';
103
+ let logLine;
104
+ if (this.format === 'pretty') {
105
+ logLine = anyAscii(`${message}${formattedArgs}`);
106
+ }
107
+ else {
108
+ const timestamp = new Date().toISOString();
109
+ logLine = anyAscii(`${timestamp} [${level}] ${message}${formattedArgs}`);
110
+ }
111
+ // Always write to stderr, never stdout (stdout is for --format json)
112
+ process.stderr.write(logLine + '\n');
113
+ }
114
+ }
115
+ /**
116
+ * Parse a log-level string into a LogLevel enum value.
117
+ * Falls back to INFO for unrecognised values (Commander choices() prevents this in practice).
118
+ */
119
+ export function parseLogLevel(value) {
120
+ const upper = value.toUpperCase();
121
+ if (Object.values(LogLevel).includes(upper)) {
122
+ return upper;
123
+ }
124
+ return LogLevel.INFO;
125
+ }
126
+ // Export singleton instance and class (class export enables test mocking per §VI)
127
+ export const logger = new Logger();
128
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * T018: Parallel execution runner with concurrency control.
3
+ *
4
+ * Custom implementation (no external dependencies such as p-limit) to limit
5
+ * concurrent APIM REST API calls and avoid 429 rate limiting. Azure APIM has
6
+ * strict per-second request limits, so unbounded Promise.all() would fire all
7
+ * requests simultaneously, triggering throttling. Bounded concurrency is a
8
+ * requirement from research.md R8 and justified in tasks.md T018.
9
+ *
10
+ * Built-in implementation without external dependencies (no p-limit).
11
+ */
12
+ export interface ParallelRunnerOptions {
13
+ concurrency: number;
14
+ }
15
+ export interface TaskResult<T> {
16
+ status: 'fulfilled' | 'rejected';
17
+ value?: T;
18
+ reason?: Error;
19
+ }
20
+ /**
21
+ * Executes tasks in parallel with bounded concurrency.
22
+ * Uses Promise.allSettled for fault tolerance.
23
+ */
24
+ export declare class ParallelRunner {
25
+ private concurrency;
26
+ constructor(options: ParallelRunnerOptions);
27
+ /**
28
+ * Run tasks in parallel with bounded concurrency.
29
+ * Returns results for all tasks, including failures.
30
+ */
31
+ runAll<T>(tasks: (() => Promise<T>)[]): Promise<TaskResult<T>[]>;
32
+ private executeTask;
33
+ }
34
+ /**
35
+ * Helper function to run tasks with default concurrency.
36
+ */
37
+ export declare function runParallel<T>(tasks: (() => Promise<T>)[], concurrency?: number): Promise<TaskResult<T>[]>;
38
+ //# sourceMappingURL=parallel-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel-runner.d.ts","sourceRoot":"","sources":["../../src/lib/parallel-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,MAAM,EAAE,WAAW,GAAG,UAAU,CAAC;IACjC,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,qBAAqB;IAI1C;;;OAGG;IACG,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YA+BxD,WAAW;CAe1B;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,CAAC,EACjC,KAAK,EAAE,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAC3B,WAAW,SAAI,GACd,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAG1B"}