@fntio/infra-client 0.0.0-stage → 0.5.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 (940) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/LICENSE +93 -0
  3. package/README.md +875 -2
  4. package/assets/acl-reconciler/index.js +1604 -0
  5. package/assets/api/index.js +9857 -0
  6. package/assets/api/package.json +9 -0
  7. package/assets/api/vendor_modules/.package-lock.json +857 -0
  8. package/assets/api/vendor_modules/accepts/HISTORY.md +243 -0
  9. package/assets/api/vendor_modules/accepts/LICENSE +23 -0
  10. package/assets/api/vendor_modules/accepts/README.md +140 -0
  11. package/assets/api/vendor_modules/accepts/index.js +238 -0
  12. package/assets/api/vendor_modules/accepts/package.json +47 -0
  13. package/assets/api/vendor_modules/array-flatten/LICENSE +21 -0
  14. package/assets/api/vendor_modules/array-flatten/README.md +43 -0
  15. package/assets/api/vendor_modules/array-flatten/array-flatten.js +64 -0
  16. package/assets/api/vendor_modules/array-flatten/package.json +39 -0
  17. package/assets/api/vendor_modules/aws-jwt-verify/LICENSE +175 -0
  18. package/assets/api/vendor_modules/aws-jwt-verify/README.md +1033 -0
  19. package/assets/api/vendor_modules/aws-jwt-verify/asn1.d.ts +20 -0
  20. package/assets/api/vendor_modules/aws-jwt-verify/assert.d.ts +41 -0
  21. package/assets/api/vendor_modules/aws-jwt-verify/cognito-verifier.d.ts +183 -0
  22. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/asn1.js +301 -0
  23. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/assert.js +108 -0
  24. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/cognito-verifier.js +158 -0
  25. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/error.js +131 -0
  26. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/https-common.js +29 -0
  27. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/https-node.js +89 -0
  28. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/https.js +52 -0
  29. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/index.js +9 -0
  30. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/jwk.js +221 -0
  31. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/jwt-model.js +10 -0
  32. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/jwt-rsa.js +397 -0
  33. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/jwt.js +161 -0
  34. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/node-web-compat-node.js +48 -0
  35. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/node-web-compat-web.js +78 -0
  36. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/node-web-compat.js +11 -0
  37. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/package.json +1 -0
  38. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/safe-json-parse.js +34 -0
  39. package/assets/api/vendor_modules/aws-jwt-verify/dist/cjs/typing-util.js +6 -0
  40. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/asn1.js +296 -0
  41. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/assert.js +101 -0
  42. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/cognito-verifier.js +153 -0
  43. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/error.js +101 -0
  44. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/https-common.js +25 -0
  45. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/https-node.js +85 -0
  46. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/https.js +48 -0
  47. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/index.js +4 -0
  48. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/jwk.js +208 -0
  49. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/jwt-model.js +7 -0
  50. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/jwt-rsa.js +389 -0
  51. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/jwt.js +156 -0
  52. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/node-web-compat-node.js +45 -0
  53. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/node-web-compat-web.js +75 -0
  54. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/node-web-compat.js +10 -0
  55. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/package.json +1 -0
  56. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/safe-json-parse.js +29 -0
  57. package/assets/api/vendor_modules/aws-jwt-verify/dist/esm/typing-util.js +5 -0
  58. package/assets/api/vendor_modules/aws-jwt-verify/error.d.ts +108 -0
  59. package/assets/api/vendor_modules/aws-jwt-verify/https-common.d.ts +9 -0
  60. package/assets/api/vendor_modules/aws-jwt-verify/https-node.d.ts +20 -0
  61. package/assets/api/vendor_modules/aws-jwt-verify/https.d.ts +35 -0
  62. package/assets/api/vendor_modules/aws-jwt-verify/index.d.ts +2 -0
  63. package/assets/api/vendor_modules/aws-jwt-verify/jwk.d.ts +76 -0
  64. package/assets/api/vendor_modules/aws-jwt-verify/jwt-model.d.ts +78 -0
  65. package/assets/api/vendor_modules/aws-jwt-verify/jwt-rsa.d.ts +348 -0
  66. package/assets/api/vendor_modules/aws-jwt-verify/jwt.d.ts +51 -0
  67. package/assets/api/vendor_modules/aws-jwt-verify/package.json +136 -0
  68. package/assets/api/vendor_modules/aws-jwt-verify/safe-json-parse.d.ts +18 -0
  69. package/assets/api/vendor_modules/aws-jwt-verify/typing-util.d.ts +38 -0
  70. package/assets/api/vendor_modules/body-parser/HISTORY.md +703 -0
  71. package/assets/api/vendor_modules/body-parser/LICENSE +23 -0
  72. package/assets/api/vendor_modules/body-parser/README.md +476 -0
  73. package/assets/api/vendor_modules/body-parser/index.js +156 -0
  74. package/assets/api/vendor_modules/body-parser/lib/read.js +205 -0
  75. package/assets/api/vendor_modules/body-parser/lib/types/json.js +247 -0
  76. package/assets/api/vendor_modules/body-parser/lib/types/raw.js +105 -0
  77. package/assets/api/vendor_modules/body-parser/lib/types/text.js +125 -0
  78. package/assets/api/vendor_modules/body-parser/lib/types/urlencoded.js +303 -0
  79. package/assets/api/vendor_modules/body-parser/node_modules/qs/.editorconfig +46 -0
  80. package/assets/api/vendor_modules/body-parser/node_modules/qs/.github/FUNDING.yml +12 -0
  81. package/assets/api/vendor_modules/body-parser/node_modules/qs/.github/SECURITY.md +11 -0
  82. package/assets/api/vendor_modules/body-parser/node_modules/qs/.github/THREAT_MODEL.md +80 -0
  83. package/assets/api/vendor_modules/body-parser/node_modules/qs/.nycrc +13 -0
  84. package/assets/api/vendor_modules/body-parser/node_modules/qs/CHANGELOG.md +872 -0
  85. package/assets/api/vendor_modules/body-parser/node_modules/qs/LICENSE.md +29 -0
  86. package/assets/api/vendor_modules/body-parser/node_modules/qs/README.md +804 -0
  87. package/assets/api/vendor_modules/body-parser/node_modules/qs/dist/qs.js +141 -0
  88. package/assets/api/vendor_modules/body-parser/node_modules/qs/eslint.config.mjs +57 -0
  89. package/assets/api/vendor_modules/body-parser/node_modules/qs/lib/formats.js +23 -0
  90. package/assets/api/vendor_modules/body-parser/node_modules/qs/lib/index.js +11 -0
  91. package/assets/api/vendor_modules/body-parser/node_modules/qs/lib/parse.js +503 -0
  92. package/assets/api/vendor_modules/body-parser/node_modules/qs/lib/stringify.js +378 -0
  93. package/assets/api/vendor_modules/body-parser/node_modules/qs/lib/utils.js +512 -0
  94. package/assets/api/vendor_modules/body-parser/node_modules/qs/package.json +95 -0
  95. package/assets/api/vendor_modules/body-parser/node_modules/qs/test/empty-keys-cases.js +267 -0
  96. package/assets/api/vendor_modules/body-parser/node_modules/qs/test/parse.js +2296 -0
  97. package/assets/api/vendor_modules/body-parser/node_modules/qs/test/stringify.js +1995 -0
  98. package/assets/api/vendor_modules/body-parser/node_modules/qs/test/utils.js +822 -0
  99. package/assets/api/vendor_modules/body-parser/package.json +55 -0
  100. package/assets/api/vendor_modules/bytes/History.md +97 -0
  101. package/assets/api/vendor_modules/bytes/LICENSE +23 -0
  102. package/assets/api/vendor_modules/bytes/Readme.md +152 -0
  103. package/assets/api/vendor_modules/bytes/index.js +170 -0
  104. package/assets/api/vendor_modules/bytes/package.json +42 -0
  105. package/assets/api/vendor_modules/call-bind-apply-helpers/.eslintrc +17 -0
  106. package/assets/api/vendor_modules/call-bind-apply-helpers/.github/FUNDING.yml +12 -0
  107. package/assets/api/vendor_modules/call-bind-apply-helpers/.nycrc +9 -0
  108. package/assets/api/vendor_modules/call-bind-apply-helpers/CHANGELOG.md +30 -0
  109. package/assets/api/vendor_modules/call-bind-apply-helpers/LICENSE +21 -0
  110. package/assets/api/vendor_modules/call-bind-apply-helpers/README.md +62 -0
  111. package/assets/api/vendor_modules/call-bind-apply-helpers/actualApply.d.ts +1 -0
  112. package/assets/api/vendor_modules/call-bind-apply-helpers/actualApply.js +10 -0
  113. package/assets/api/vendor_modules/call-bind-apply-helpers/applyBind.d.ts +19 -0
  114. package/assets/api/vendor_modules/call-bind-apply-helpers/applyBind.js +10 -0
  115. package/assets/api/vendor_modules/call-bind-apply-helpers/functionApply.d.ts +1 -0
  116. package/assets/api/vendor_modules/call-bind-apply-helpers/functionApply.js +4 -0
  117. package/assets/api/vendor_modules/call-bind-apply-helpers/functionCall.d.ts +1 -0
  118. package/assets/api/vendor_modules/call-bind-apply-helpers/functionCall.js +4 -0
  119. package/assets/api/vendor_modules/call-bind-apply-helpers/index.d.ts +64 -0
  120. package/assets/api/vendor_modules/call-bind-apply-helpers/index.js +15 -0
  121. package/assets/api/vendor_modules/call-bind-apply-helpers/package.json +85 -0
  122. package/assets/api/vendor_modules/call-bind-apply-helpers/reflectApply.d.ts +3 -0
  123. package/assets/api/vendor_modules/call-bind-apply-helpers/reflectApply.js +4 -0
  124. package/assets/api/vendor_modules/call-bind-apply-helpers/test/index.js +63 -0
  125. package/assets/api/vendor_modules/call-bind-apply-helpers/tsconfig.json +9 -0
  126. package/assets/api/vendor_modules/call-bound/.eslintrc +13 -0
  127. package/assets/api/vendor_modules/call-bound/.github/FUNDING.yml +12 -0
  128. package/assets/api/vendor_modules/call-bound/.nycrc +9 -0
  129. package/assets/api/vendor_modules/call-bound/CHANGELOG.md +42 -0
  130. package/assets/api/vendor_modules/call-bound/LICENSE +21 -0
  131. package/assets/api/vendor_modules/call-bound/README.md +53 -0
  132. package/assets/api/vendor_modules/call-bound/index.d.ts +94 -0
  133. package/assets/api/vendor_modules/call-bound/index.js +19 -0
  134. package/assets/api/vendor_modules/call-bound/package.json +99 -0
  135. package/assets/api/vendor_modules/call-bound/test/index.js +61 -0
  136. package/assets/api/vendor_modules/call-bound/tsconfig.json +10 -0
  137. package/assets/api/vendor_modules/content-disposition/HISTORY.md +60 -0
  138. package/assets/api/vendor_modules/content-disposition/LICENSE +22 -0
  139. package/assets/api/vendor_modules/content-disposition/README.md +142 -0
  140. package/assets/api/vendor_modules/content-disposition/index.js +458 -0
  141. package/assets/api/vendor_modules/content-disposition/package.json +44 -0
  142. package/assets/api/vendor_modules/content-type/HISTORY.md +29 -0
  143. package/assets/api/vendor_modules/content-type/LICENSE +22 -0
  144. package/assets/api/vendor_modules/content-type/README.md +94 -0
  145. package/assets/api/vendor_modules/content-type/index.js +225 -0
  146. package/assets/api/vendor_modules/content-type/package.json +42 -0
  147. package/assets/api/vendor_modules/cookie/LICENSE +24 -0
  148. package/assets/api/vendor_modules/cookie/README.md +317 -0
  149. package/assets/api/vendor_modules/cookie/SECURITY.md +25 -0
  150. package/assets/api/vendor_modules/cookie/index.js +335 -0
  151. package/assets/api/vendor_modules/cookie/package.json +44 -0
  152. package/assets/api/vendor_modules/cookie-signature/History.md +42 -0
  153. package/assets/api/vendor_modules/cookie-signature/Readme.md +42 -0
  154. package/assets/api/vendor_modules/cookie-signature/index.js +51 -0
  155. package/assets/api/vendor_modules/cookie-signature/package.json +18 -0
  156. package/assets/api/vendor_modules/debug/.coveralls.yml +1 -0
  157. package/assets/api/vendor_modules/debug/.eslintrc +11 -0
  158. package/assets/api/vendor_modules/debug/.travis.yml +14 -0
  159. package/assets/api/vendor_modules/debug/CHANGELOG.md +362 -0
  160. package/assets/api/vendor_modules/debug/LICENSE +19 -0
  161. package/assets/api/vendor_modules/debug/Makefile +50 -0
  162. package/assets/api/vendor_modules/debug/README.md +312 -0
  163. package/assets/api/vendor_modules/debug/component.json +19 -0
  164. package/assets/api/vendor_modules/debug/karma.conf.js +70 -0
  165. package/assets/api/vendor_modules/debug/node.js +1 -0
  166. package/assets/api/vendor_modules/debug/package.json +49 -0
  167. package/assets/api/vendor_modules/debug/src/browser.js +185 -0
  168. package/assets/api/vendor_modules/debug/src/debug.js +202 -0
  169. package/assets/api/vendor_modules/debug/src/index.js +10 -0
  170. package/assets/api/vendor_modules/debug/src/inspector-log.js +15 -0
  171. package/assets/api/vendor_modules/debug/src/node.js +248 -0
  172. package/assets/api/vendor_modules/depd/History.md +103 -0
  173. package/assets/api/vendor_modules/depd/LICENSE +22 -0
  174. package/assets/api/vendor_modules/depd/Readme.md +280 -0
  175. package/assets/api/vendor_modules/depd/index.js +538 -0
  176. package/assets/api/vendor_modules/depd/lib/browser/index.js +77 -0
  177. package/assets/api/vendor_modules/depd/package.json +45 -0
  178. package/assets/api/vendor_modules/destroy/LICENSE +23 -0
  179. package/assets/api/vendor_modules/destroy/README.md +63 -0
  180. package/assets/api/vendor_modules/destroy/index.js +209 -0
  181. package/assets/api/vendor_modules/destroy/package.json +48 -0
  182. package/assets/api/vendor_modules/dunder-proto/.eslintrc +5 -0
  183. package/assets/api/vendor_modules/dunder-proto/.github/FUNDING.yml +12 -0
  184. package/assets/api/vendor_modules/dunder-proto/.nycrc +13 -0
  185. package/assets/api/vendor_modules/dunder-proto/CHANGELOG.md +24 -0
  186. package/assets/api/vendor_modules/dunder-proto/LICENSE +21 -0
  187. package/assets/api/vendor_modules/dunder-proto/README.md +54 -0
  188. package/assets/api/vendor_modules/dunder-proto/get.d.ts +5 -0
  189. package/assets/api/vendor_modules/dunder-proto/get.js +30 -0
  190. package/assets/api/vendor_modules/dunder-proto/package.json +76 -0
  191. package/assets/api/vendor_modules/dunder-proto/set.d.ts +5 -0
  192. package/assets/api/vendor_modules/dunder-proto/set.js +35 -0
  193. package/assets/api/vendor_modules/dunder-proto/test/get.js +34 -0
  194. package/assets/api/vendor_modules/dunder-proto/test/index.js +4 -0
  195. package/assets/api/vendor_modules/dunder-proto/test/set.js +50 -0
  196. package/assets/api/vendor_modules/dunder-proto/tsconfig.json +9 -0
  197. package/assets/api/vendor_modules/ee-first/LICENSE +22 -0
  198. package/assets/api/vendor_modules/ee-first/README.md +80 -0
  199. package/assets/api/vendor_modules/ee-first/index.js +95 -0
  200. package/assets/api/vendor_modules/ee-first/package.json +29 -0
  201. package/assets/api/vendor_modules/encodeurl/LICENSE +22 -0
  202. package/assets/api/vendor_modules/encodeurl/README.md +109 -0
  203. package/assets/api/vendor_modules/encodeurl/index.js +60 -0
  204. package/assets/api/vendor_modules/encodeurl/package.json +40 -0
  205. package/assets/api/vendor_modules/es-define-property/.eslintrc +13 -0
  206. package/assets/api/vendor_modules/es-define-property/.github/FUNDING.yml +12 -0
  207. package/assets/api/vendor_modules/es-define-property/.nycrc +9 -0
  208. package/assets/api/vendor_modules/es-define-property/CHANGELOG.md +29 -0
  209. package/assets/api/vendor_modules/es-define-property/LICENSE +21 -0
  210. package/assets/api/vendor_modules/es-define-property/README.md +49 -0
  211. package/assets/api/vendor_modules/es-define-property/index.d.ts +3 -0
  212. package/assets/api/vendor_modules/es-define-property/index.js +14 -0
  213. package/assets/api/vendor_modules/es-define-property/package.json +81 -0
  214. package/assets/api/vendor_modules/es-define-property/test/index.js +56 -0
  215. package/assets/api/vendor_modules/es-define-property/tsconfig.json +10 -0
  216. package/assets/api/vendor_modules/es-errors/.eslintrc +5 -0
  217. package/assets/api/vendor_modules/es-errors/.github/FUNDING.yml +12 -0
  218. package/assets/api/vendor_modules/es-errors/CHANGELOG.md +40 -0
  219. package/assets/api/vendor_modules/es-errors/LICENSE +21 -0
  220. package/assets/api/vendor_modules/es-errors/README.md +55 -0
  221. package/assets/api/vendor_modules/es-errors/eval.d.ts +3 -0
  222. package/assets/api/vendor_modules/es-errors/eval.js +4 -0
  223. package/assets/api/vendor_modules/es-errors/index.d.ts +3 -0
  224. package/assets/api/vendor_modules/es-errors/index.js +4 -0
  225. package/assets/api/vendor_modules/es-errors/package.json +80 -0
  226. package/assets/api/vendor_modules/es-errors/range.d.ts +3 -0
  227. package/assets/api/vendor_modules/es-errors/range.js +4 -0
  228. package/assets/api/vendor_modules/es-errors/ref.d.ts +3 -0
  229. package/assets/api/vendor_modules/es-errors/ref.js +4 -0
  230. package/assets/api/vendor_modules/es-errors/syntax.d.ts +3 -0
  231. package/assets/api/vendor_modules/es-errors/syntax.js +4 -0
  232. package/assets/api/vendor_modules/es-errors/test/index.js +19 -0
  233. package/assets/api/vendor_modules/es-errors/tsconfig.json +49 -0
  234. package/assets/api/vendor_modules/es-errors/type.d.ts +3 -0
  235. package/assets/api/vendor_modules/es-errors/type.js +4 -0
  236. package/assets/api/vendor_modules/es-errors/uri.d.ts +3 -0
  237. package/assets/api/vendor_modules/es-errors/uri.js +4 -0
  238. package/assets/api/vendor_modules/es-object-atoms/.eslintrc +16 -0
  239. package/assets/api/vendor_modules/es-object-atoms/.github/FUNDING.yml +12 -0
  240. package/assets/api/vendor_modules/es-object-atoms/CHANGELOG.md +44 -0
  241. package/assets/api/vendor_modules/es-object-atoms/LICENSE +21 -0
  242. package/assets/api/vendor_modules/es-object-atoms/README.md +63 -0
  243. package/assets/api/vendor_modules/es-object-atoms/RequireObjectCoercible.d.ts +3 -0
  244. package/assets/api/vendor_modules/es-object-atoms/RequireObjectCoercible.js +11 -0
  245. package/assets/api/vendor_modules/es-object-atoms/ToObject.d.ts +7 -0
  246. package/assets/api/vendor_modules/es-object-atoms/ToObject.js +10 -0
  247. package/assets/api/vendor_modules/es-object-atoms/index.d.ts +3 -0
  248. package/assets/api/vendor_modules/es-object-atoms/index.js +4 -0
  249. package/assets/api/vendor_modules/es-object-atoms/isObject.d.ts +3 -0
  250. package/assets/api/vendor_modules/es-object-atoms/isObject.js +6 -0
  251. package/assets/api/vendor_modules/es-object-atoms/package.json +79 -0
  252. package/assets/api/vendor_modules/es-object-atoms/test/index.js +38 -0
  253. package/assets/api/vendor_modules/es-object-atoms/tsconfig.json +7 -0
  254. package/assets/api/vendor_modules/escape-html/LICENSE +24 -0
  255. package/assets/api/vendor_modules/escape-html/Readme.md +43 -0
  256. package/assets/api/vendor_modules/escape-html/index.js +78 -0
  257. package/assets/api/vendor_modules/escape-html/package.json +24 -0
  258. package/assets/api/vendor_modules/etag/HISTORY.md +83 -0
  259. package/assets/api/vendor_modules/etag/LICENSE +22 -0
  260. package/assets/api/vendor_modules/etag/README.md +159 -0
  261. package/assets/api/vendor_modules/etag/index.js +131 -0
  262. package/assets/api/vendor_modules/etag/package.json +47 -0
  263. package/assets/api/vendor_modules/express/History.md +3676 -0
  264. package/assets/api/vendor_modules/express/LICENSE +24 -0
  265. package/assets/api/vendor_modules/express/Readme.md +260 -0
  266. package/assets/api/vendor_modules/express/index.js +11 -0
  267. package/assets/api/vendor_modules/express/lib/application.js +661 -0
  268. package/assets/api/vendor_modules/express/lib/express.js +116 -0
  269. package/assets/api/vendor_modules/express/lib/middleware/init.js +43 -0
  270. package/assets/api/vendor_modules/express/lib/middleware/query.js +47 -0
  271. package/assets/api/vendor_modules/express/lib/request.js +525 -0
  272. package/assets/api/vendor_modules/express/lib/response.js +1179 -0
  273. package/assets/api/vendor_modules/express/lib/router/index.js +673 -0
  274. package/assets/api/vendor_modules/express/lib/router/layer.js +181 -0
  275. package/assets/api/vendor_modules/express/lib/router/route.js +230 -0
  276. package/assets/api/vendor_modules/express/lib/utils.js +304 -0
  277. package/assets/api/vendor_modules/express/lib/view.js +182 -0
  278. package/assets/api/vendor_modules/express/package.json +102 -0
  279. package/assets/api/vendor_modules/finalhandler/HISTORY.md +216 -0
  280. package/assets/api/vendor_modules/finalhandler/LICENSE +22 -0
  281. package/assets/api/vendor_modules/finalhandler/README.md +147 -0
  282. package/assets/api/vendor_modules/finalhandler/SECURITY.md +25 -0
  283. package/assets/api/vendor_modules/finalhandler/index.js +341 -0
  284. package/assets/api/vendor_modules/finalhandler/package.json +47 -0
  285. package/assets/api/vendor_modules/forwarded/HISTORY.md +21 -0
  286. package/assets/api/vendor_modules/forwarded/LICENSE +22 -0
  287. package/assets/api/vendor_modules/forwarded/README.md +57 -0
  288. package/assets/api/vendor_modules/forwarded/index.js +90 -0
  289. package/assets/api/vendor_modules/forwarded/package.json +45 -0
  290. package/assets/api/vendor_modules/fresh/HISTORY.md +70 -0
  291. package/assets/api/vendor_modules/fresh/LICENSE +23 -0
  292. package/assets/api/vendor_modules/fresh/README.md +119 -0
  293. package/assets/api/vendor_modules/fresh/index.js +137 -0
  294. package/assets/api/vendor_modules/fresh/package.json +46 -0
  295. package/assets/api/vendor_modules/function-bind/.eslintrc +21 -0
  296. package/assets/api/vendor_modules/function-bind/.github/FUNDING.yml +12 -0
  297. package/assets/api/vendor_modules/function-bind/.github/SECURITY.md +3 -0
  298. package/assets/api/vendor_modules/function-bind/.nycrc +13 -0
  299. package/assets/api/vendor_modules/function-bind/CHANGELOG.md +136 -0
  300. package/assets/api/vendor_modules/function-bind/LICENSE +20 -0
  301. package/assets/api/vendor_modules/function-bind/README.md +46 -0
  302. package/assets/api/vendor_modules/function-bind/implementation.js +84 -0
  303. package/assets/api/vendor_modules/function-bind/index.js +5 -0
  304. package/assets/api/vendor_modules/function-bind/package.json +87 -0
  305. package/assets/api/vendor_modules/function-bind/test/.eslintrc +9 -0
  306. package/assets/api/vendor_modules/function-bind/test/index.js +252 -0
  307. package/assets/api/vendor_modules/get-intrinsic/.eslintrc +42 -0
  308. package/assets/api/vendor_modules/get-intrinsic/.github/FUNDING.yml +12 -0
  309. package/assets/api/vendor_modules/get-intrinsic/.nycrc +9 -0
  310. package/assets/api/vendor_modules/get-intrinsic/CHANGELOG.md +186 -0
  311. package/assets/api/vendor_modules/get-intrinsic/LICENSE +21 -0
  312. package/assets/api/vendor_modules/get-intrinsic/README.md +71 -0
  313. package/assets/api/vendor_modules/get-intrinsic/index.js +378 -0
  314. package/assets/api/vendor_modules/get-intrinsic/package.json +97 -0
  315. package/assets/api/vendor_modules/get-intrinsic/test/GetIntrinsic.js +274 -0
  316. package/assets/api/vendor_modules/get-proto/.eslintrc +10 -0
  317. package/assets/api/vendor_modules/get-proto/.github/FUNDING.yml +12 -0
  318. package/assets/api/vendor_modules/get-proto/.nycrc +9 -0
  319. package/assets/api/vendor_modules/get-proto/CHANGELOG.md +21 -0
  320. package/assets/api/vendor_modules/get-proto/LICENSE +21 -0
  321. package/assets/api/vendor_modules/get-proto/Object.getPrototypeOf.d.ts +5 -0
  322. package/assets/api/vendor_modules/get-proto/Object.getPrototypeOf.js +6 -0
  323. package/assets/api/vendor_modules/get-proto/README.md +50 -0
  324. package/assets/api/vendor_modules/get-proto/Reflect.getPrototypeOf.d.ts +3 -0
  325. package/assets/api/vendor_modules/get-proto/Reflect.getPrototypeOf.js +4 -0
  326. package/assets/api/vendor_modules/get-proto/index.d.ts +5 -0
  327. package/assets/api/vendor_modules/get-proto/index.js +27 -0
  328. package/assets/api/vendor_modules/get-proto/package.json +81 -0
  329. package/assets/api/vendor_modules/get-proto/test/index.js +68 -0
  330. package/assets/api/vendor_modules/get-proto/tsconfig.json +9 -0
  331. package/assets/api/vendor_modules/gopd/.eslintrc +16 -0
  332. package/assets/api/vendor_modules/gopd/.github/FUNDING.yml +12 -0
  333. package/assets/api/vendor_modules/gopd/CHANGELOG.md +45 -0
  334. package/assets/api/vendor_modules/gopd/LICENSE +21 -0
  335. package/assets/api/vendor_modules/gopd/README.md +40 -0
  336. package/assets/api/vendor_modules/gopd/gOPD.d.ts +1 -0
  337. package/assets/api/vendor_modules/gopd/gOPD.js +4 -0
  338. package/assets/api/vendor_modules/gopd/index.d.ts +5 -0
  339. package/assets/api/vendor_modules/gopd/index.js +15 -0
  340. package/assets/api/vendor_modules/gopd/package.json +77 -0
  341. package/assets/api/vendor_modules/gopd/test/index.js +36 -0
  342. package/assets/api/vendor_modules/gopd/tsconfig.json +9 -0
  343. package/assets/api/vendor_modules/has-symbols/.eslintrc +11 -0
  344. package/assets/api/vendor_modules/has-symbols/.github/FUNDING.yml +12 -0
  345. package/assets/api/vendor_modules/has-symbols/.nycrc +9 -0
  346. package/assets/api/vendor_modules/has-symbols/CHANGELOG.md +91 -0
  347. package/assets/api/vendor_modules/has-symbols/LICENSE +21 -0
  348. package/assets/api/vendor_modules/has-symbols/README.md +46 -0
  349. package/assets/api/vendor_modules/has-symbols/index.d.ts +3 -0
  350. package/assets/api/vendor_modules/has-symbols/index.js +14 -0
  351. package/assets/api/vendor_modules/has-symbols/package.json +111 -0
  352. package/assets/api/vendor_modules/has-symbols/shams.d.ts +3 -0
  353. package/assets/api/vendor_modules/has-symbols/shams.js +45 -0
  354. package/assets/api/vendor_modules/has-symbols/test/index.js +22 -0
  355. package/assets/api/vendor_modules/has-symbols/test/shams/core-js.js +29 -0
  356. package/assets/api/vendor_modules/has-symbols/test/shams/get-own-property-symbols.js +29 -0
  357. package/assets/api/vendor_modules/has-symbols/test/tests.js +58 -0
  358. package/assets/api/vendor_modules/has-symbols/tsconfig.json +10 -0
  359. package/assets/api/vendor_modules/hasown/.github/FUNDING.yml +12 -0
  360. package/assets/api/vendor_modules/hasown/.nycrc +13 -0
  361. package/assets/api/vendor_modules/hasown/CHANGELOG.md +58 -0
  362. package/assets/api/vendor_modules/hasown/LICENSE +21 -0
  363. package/assets/api/vendor_modules/hasown/README.md +40 -0
  364. package/assets/api/vendor_modules/hasown/eslint.config.mjs +6 -0
  365. package/assets/api/vendor_modules/hasown/index.d.ts +3 -0
  366. package/assets/api/vendor_modules/hasown/index.js +8 -0
  367. package/assets/api/vendor_modules/hasown/package.json +91 -0
  368. package/assets/api/vendor_modules/hasown/tsconfig.json +6 -0
  369. package/assets/api/vendor_modules/http-errors/HISTORY.md +186 -0
  370. package/assets/api/vendor_modules/http-errors/LICENSE +23 -0
  371. package/assets/api/vendor_modules/http-errors/README.md +169 -0
  372. package/assets/api/vendor_modules/http-errors/index.js +290 -0
  373. package/assets/api/vendor_modules/http-errors/package.json +54 -0
  374. package/assets/api/vendor_modules/iconv-lite/Changelog.md +162 -0
  375. package/assets/api/vendor_modules/iconv-lite/LICENSE +21 -0
  376. package/assets/api/vendor_modules/iconv-lite/README.md +156 -0
  377. package/assets/api/vendor_modules/iconv-lite/encodings/dbcs-codec.js +555 -0
  378. package/assets/api/vendor_modules/iconv-lite/encodings/dbcs-data.js +176 -0
  379. package/assets/api/vendor_modules/iconv-lite/encodings/index.js +22 -0
  380. package/assets/api/vendor_modules/iconv-lite/encodings/internal.js +188 -0
  381. package/assets/api/vendor_modules/iconv-lite/encodings/sbcs-codec.js +72 -0
  382. package/assets/api/vendor_modules/iconv-lite/encodings/sbcs-data-generated.js +451 -0
  383. package/assets/api/vendor_modules/iconv-lite/encodings/sbcs-data.js +174 -0
  384. package/assets/api/vendor_modules/iconv-lite/encodings/tables/big5-added.json +122 -0
  385. package/assets/api/vendor_modules/iconv-lite/encodings/tables/cp936.json +264 -0
  386. package/assets/api/vendor_modules/iconv-lite/encodings/tables/cp949.json +273 -0
  387. package/assets/api/vendor_modules/iconv-lite/encodings/tables/cp950.json +177 -0
  388. package/assets/api/vendor_modules/iconv-lite/encodings/tables/eucjp.json +182 -0
  389. package/assets/api/vendor_modules/iconv-lite/encodings/tables/gb18030-ranges.json +1 -0
  390. package/assets/api/vendor_modules/iconv-lite/encodings/tables/gbk-added.json +55 -0
  391. package/assets/api/vendor_modules/iconv-lite/encodings/tables/shiftjis.json +125 -0
  392. package/assets/api/vendor_modules/iconv-lite/encodings/utf16.js +177 -0
  393. package/assets/api/vendor_modules/iconv-lite/encodings/utf7.js +290 -0
  394. package/assets/api/vendor_modules/iconv-lite/lib/bom-handling.js +52 -0
  395. package/assets/api/vendor_modules/iconv-lite/lib/extend-node.js +217 -0
  396. package/assets/api/vendor_modules/iconv-lite/lib/index.d.ts +24 -0
  397. package/assets/api/vendor_modules/iconv-lite/lib/index.js +153 -0
  398. package/assets/api/vendor_modules/iconv-lite/lib/streams.js +121 -0
  399. package/assets/api/vendor_modules/iconv-lite/package.json +46 -0
  400. package/assets/api/vendor_modules/inherits/LICENSE +16 -0
  401. package/assets/api/vendor_modules/inherits/README.md +42 -0
  402. package/assets/api/vendor_modules/inherits/inherits.js +9 -0
  403. package/assets/api/vendor_modules/inherits/inherits_browser.js +27 -0
  404. package/assets/api/vendor_modules/inherits/package.json +29 -0
  405. package/assets/api/vendor_modules/ipaddr.js/LICENSE +19 -0
  406. package/assets/api/vendor_modules/ipaddr.js/README.md +233 -0
  407. package/assets/api/vendor_modules/ipaddr.js/ipaddr.min.js +1 -0
  408. package/assets/api/vendor_modules/ipaddr.js/lib/ipaddr.js +673 -0
  409. package/assets/api/vendor_modules/ipaddr.js/lib/ipaddr.js.d.ts +68 -0
  410. package/assets/api/vendor_modules/ipaddr.js/package.json +35 -0
  411. package/assets/api/vendor_modules/math-intrinsics/.eslintrc +16 -0
  412. package/assets/api/vendor_modules/math-intrinsics/.github/FUNDING.yml +12 -0
  413. package/assets/api/vendor_modules/math-intrinsics/CHANGELOG.md +24 -0
  414. package/assets/api/vendor_modules/math-intrinsics/LICENSE +21 -0
  415. package/assets/api/vendor_modules/math-intrinsics/README.md +50 -0
  416. package/assets/api/vendor_modules/math-intrinsics/abs.d.ts +1 -0
  417. package/assets/api/vendor_modules/math-intrinsics/abs.js +4 -0
  418. package/assets/api/vendor_modules/math-intrinsics/constants/maxArrayLength.d.ts +3 -0
  419. package/assets/api/vendor_modules/math-intrinsics/constants/maxArrayLength.js +4 -0
  420. package/assets/api/vendor_modules/math-intrinsics/constants/maxSafeInteger.d.ts +3 -0
  421. package/assets/api/vendor_modules/math-intrinsics/constants/maxSafeInteger.js +5 -0
  422. package/assets/api/vendor_modules/math-intrinsics/constants/maxValue.d.ts +3 -0
  423. package/assets/api/vendor_modules/math-intrinsics/constants/maxValue.js +5 -0
  424. package/assets/api/vendor_modules/math-intrinsics/floor.d.ts +1 -0
  425. package/assets/api/vendor_modules/math-intrinsics/floor.js +4 -0
  426. package/assets/api/vendor_modules/math-intrinsics/isFinite.d.ts +3 -0
  427. package/assets/api/vendor_modules/math-intrinsics/isFinite.js +12 -0
  428. package/assets/api/vendor_modules/math-intrinsics/isInteger.d.ts +3 -0
  429. package/assets/api/vendor_modules/math-intrinsics/isInteger.js +16 -0
  430. package/assets/api/vendor_modules/math-intrinsics/isNaN.d.ts +1 -0
  431. package/assets/api/vendor_modules/math-intrinsics/isNaN.js +6 -0
  432. package/assets/api/vendor_modules/math-intrinsics/isNegativeZero.d.ts +3 -0
  433. package/assets/api/vendor_modules/math-intrinsics/isNegativeZero.js +6 -0
  434. package/assets/api/vendor_modules/math-intrinsics/max.d.ts +1 -0
  435. package/assets/api/vendor_modules/math-intrinsics/max.js +4 -0
  436. package/assets/api/vendor_modules/math-intrinsics/min.d.ts +1 -0
  437. package/assets/api/vendor_modules/math-intrinsics/min.js +4 -0
  438. package/assets/api/vendor_modules/math-intrinsics/mod.d.ts +3 -0
  439. package/assets/api/vendor_modules/math-intrinsics/mod.js +9 -0
  440. package/assets/api/vendor_modules/math-intrinsics/package.json +86 -0
  441. package/assets/api/vendor_modules/math-intrinsics/pow.d.ts +1 -0
  442. package/assets/api/vendor_modules/math-intrinsics/pow.js +4 -0
  443. package/assets/api/vendor_modules/math-intrinsics/round.d.ts +1 -0
  444. package/assets/api/vendor_modules/math-intrinsics/round.js +4 -0
  445. package/assets/api/vendor_modules/math-intrinsics/sign.d.ts +3 -0
  446. package/assets/api/vendor_modules/math-intrinsics/sign.js +11 -0
  447. package/assets/api/vendor_modules/math-intrinsics/test/index.js +192 -0
  448. package/assets/api/vendor_modules/math-intrinsics/tsconfig.json +3 -0
  449. package/assets/api/vendor_modules/media-typer/HISTORY.md +22 -0
  450. package/assets/api/vendor_modules/media-typer/LICENSE +22 -0
  451. package/assets/api/vendor_modules/media-typer/README.md +81 -0
  452. package/assets/api/vendor_modules/media-typer/index.js +270 -0
  453. package/assets/api/vendor_modules/media-typer/package.json +26 -0
  454. package/assets/api/vendor_modules/merge-descriptors/HISTORY.md +21 -0
  455. package/assets/api/vendor_modules/merge-descriptors/LICENSE +23 -0
  456. package/assets/api/vendor_modules/merge-descriptors/README.md +49 -0
  457. package/assets/api/vendor_modules/merge-descriptors/index.js +60 -0
  458. package/assets/api/vendor_modules/merge-descriptors/package.json +39 -0
  459. package/assets/api/vendor_modules/methods/HISTORY.md +29 -0
  460. package/assets/api/vendor_modules/methods/LICENSE +24 -0
  461. package/assets/api/vendor_modules/methods/README.md +51 -0
  462. package/assets/api/vendor_modules/methods/index.js +69 -0
  463. package/assets/api/vendor_modules/methods/package.json +36 -0
  464. package/assets/api/vendor_modules/mime/CHANGELOG.md +164 -0
  465. package/assets/api/vendor_modules/mime/LICENSE +21 -0
  466. package/assets/api/vendor_modules/mime/README.md +90 -0
  467. package/assets/api/vendor_modules/mime/cli.js +8 -0
  468. package/assets/api/vendor_modules/mime/mime.js +108 -0
  469. package/assets/api/vendor_modules/mime/package.json +44 -0
  470. package/assets/api/vendor_modules/mime/src/build.js +53 -0
  471. package/assets/api/vendor_modules/mime/src/test.js +60 -0
  472. package/assets/api/vendor_modules/mime/types.json +1 -0
  473. package/assets/api/vendor_modules/mime-db/HISTORY.md +507 -0
  474. package/assets/api/vendor_modules/mime-db/LICENSE +23 -0
  475. package/assets/api/vendor_modules/mime-db/README.md +100 -0
  476. package/assets/api/vendor_modules/mime-db/db.json +8519 -0
  477. package/assets/api/vendor_modules/mime-db/index.js +12 -0
  478. package/assets/api/vendor_modules/mime-db/package.json +60 -0
  479. package/assets/api/vendor_modules/mime-types/HISTORY.md +397 -0
  480. package/assets/api/vendor_modules/mime-types/LICENSE +23 -0
  481. package/assets/api/vendor_modules/mime-types/README.md +113 -0
  482. package/assets/api/vendor_modules/mime-types/index.js +188 -0
  483. package/assets/api/vendor_modules/mime-types/package.json +44 -0
  484. package/assets/api/vendor_modules/ms/index.js +152 -0
  485. package/assets/api/vendor_modules/ms/license.md +21 -0
  486. package/assets/api/vendor_modules/ms/package.json +37 -0
  487. package/assets/api/vendor_modules/ms/readme.md +51 -0
  488. package/assets/api/vendor_modules/negotiator/HISTORY.md +108 -0
  489. package/assets/api/vendor_modules/negotiator/LICENSE +24 -0
  490. package/assets/api/vendor_modules/negotiator/README.md +203 -0
  491. package/assets/api/vendor_modules/negotiator/index.js +82 -0
  492. package/assets/api/vendor_modules/negotiator/lib/charset.js +169 -0
  493. package/assets/api/vendor_modules/negotiator/lib/encoding.js +184 -0
  494. package/assets/api/vendor_modules/negotiator/lib/language.js +179 -0
  495. package/assets/api/vendor_modules/negotiator/lib/mediaType.js +294 -0
  496. package/assets/api/vendor_modules/negotiator/package.json +42 -0
  497. package/assets/api/vendor_modules/object-inspect/.eslintrc +53 -0
  498. package/assets/api/vendor_modules/object-inspect/.github/FUNDING.yml +12 -0
  499. package/assets/api/vendor_modules/object-inspect/.nycrc +13 -0
  500. package/assets/api/vendor_modules/object-inspect/CHANGELOG.md +424 -0
  501. package/assets/api/vendor_modules/object-inspect/LICENSE +21 -0
  502. package/assets/api/vendor_modules/object-inspect/example/all.js +23 -0
  503. package/assets/api/vendor_modules/object-inspect/example/circular.js +6 -0
  504. package/assets/api/vendor_modules/object-inspect/example/fn.js +5 -0
  505. package/assets/api/vendor_modules/object-inspect/example/inspect.js +10 -0
  506. package/assets/api/vendor_modules/object-inspect/index.js +544 -0
  507. package/assets/api/vendor_modules/object-inspect/package-support.json +20 -0
  508. package/assets/api/vendor_modules/object-inspect/package.json +105 -0
  509. package/assets/api/vendor_modules/object-inspect/readme.markdown +84 -0
  510. package/assets/api/vendor_modules/object-inspect/test/bigint.js +58 -0
  511. package/assets/api/vendor_modules/object-inspect/test/browser/dom.js +15 -0
  512. package/assets/api/vendor_modules/object-inspect/test/circular.js +16 -0
  513. package/assets/api/vendor_modules/object-inspect/test/deep.js +12 -0
  514. package/assets/api/vendor_modules/object-inspect/test/element.js +53 -0
  515. package/assets/api/vendor_modules/object-inspect/test/err.js +48 -0
  516. package/assets/api/vendor_modules/object-inspect/test/fakes.js +29 -0
  517. package/assets/api/vendor_modules/object-inspect/test/fn.js +76 -0
  518. package/assets/api/vendor_modules/object-inspect/test/global.js +17 -0
  519. package/assets/api/vendor_modules/object-inspect/test/has.js +15 -0
  520. package/assets/api/vendor_modules/object-inspect/test/holes.js +15 -0
  521. package/assets/api/vendor_modules/object-inspect/test/indent-option.js +271 -0
  522. package/assets/api/vendor_modules/object-inspect/test/inspect.js +139 -0
  523. package/assets/api/vendor_modules/object-inspect/test/lowbyte.js +12 -0
  524. package/assets/api/vendor_modules/object-inspect/test/number.js +58 -0
  525. package/assets/api/vendor_modules/object-inspect/test/quoteStyle.js +26 -0
  526. package/assets/api/vendor_modules/object-inspect/test/toStringTag.js +40 -0
  527. package/assets/api/vendor_modules/object-inspect/test/undef.js +12 -0
  528. package/assets/api/vendor_modules/object-inspect/test/values.js +261 -0
  529. package/assets/api/vendor_modules/object-inspect/test-core-js.js +26 -0
  530. package/assets/api/vendor_modules/object-inspect/util.inspect.js +1 -0
  531. package/assets/api/vendor_modules/on-finished/HISTORY.md +98 -0
  532. package/assets/api/vendor_modules/on-finished/LICENSE +23 -0
  533. package/assets/api/vendor_modules/on-finished/README.md +162 -0
  534. package/assets/api/vendor_modules/on-finished/index.js +234 -0
  535. package/assets/api/vendor_modules/on-finished/package.json +39 -0
  536. package/assets/api/vendor_modules/parseurl/HISTORY.md +58 -0
  537. package/assets/api/vendor_modules/parseurl/LICENSE +24 -0
  538. package/assets/api/vendor_modules/parseurl/README.md +133 -0
  539. package/assets/api/vendor_modules/parseurl/index.js +158 -0
  540. package/assets/api/vendor_modules/parseurl/package.json +40 -0
  541. package/assets/api/vendor_modules/path-to-regexp/LICENSE +21 -0
  542. package/assets/api/vendor_modules/path-to-regexp/Readme.md +35 -0
  543. package/assets/api/vendor_modules/path-to-regexp/index.js +158 -0
  544. package/assets/api/vendor_modules/path-to-regexp/package.json +30 -0
  545. package/assets/api/vendor_modules/proxy-addr/HISTORY.md +167 -0
  546. package/assets/api/vendor_modules/proxy-addr/LICENSE +22 -0
  547. package/assets/api/vendor_modules/proxy-addr/README.md +139 -0
  548. package/assets/api/vendor_modules/proxy-addr/index.js +359 -0
  549. package/assets/api/vendor_modules/proxy-addr/package.json +51 -0
  550. package/assets/api/vendor_modules/qs/.editorconfig +46 -0
  551. package/assets/api/vendor_modules/qs/.github/FUNDING.yml +12 -0
  552. package/assets/api/vendor_modules/qs/.github/SECURITY.md +11 -0
  553. package/assets/api/vendor_modules/qs/.github/THREAT_MODEL.md +78 -0
  554. package/assets/api/vendor_modules/qs/.nycrc +13 -0
  555. package/assets/api/vendor_modules/qs/CHANGELOG.md +833 -0
  556. package/assets/api/vendor_modules/qs/LICENSE.md +29 -0
  557. package/assets/api/vendor_modules/qs/README.md +758 -0
  558. package/assets/api/vendor_modules/qs/dist/qs.js +141 -0
  559. package/assets/api/vendor_modules/qs/eslint.config.mjs +57 -0
  560. package/assets/api/vendor_modules/qs/lib/formats.js +23 -0
  561. package/assets/api/vendor_modules/qs/lib/index.js +11 -0
  562. package/assets/api/vendor_modules/qs/lib/parse.js +414 -0
  563. package/assets/api/vendor_modules/qs/lib/stringify.js +363 -0
  564. package/assets/api/vendor_modules/qs/lib/utils.js +381 -0
  565. package/assets/api/vendor_modules/qs/package.json +95 -0
  566. package/assets/api/vendor_modules/qs/test/empty-keys-cases.js +267 -0
  567. package/assets/api/vendor_modules/qs/test/parse.js +1933 -0
  568. package/assets/api/vendor_modules/qs/test/stringify.js +1448 -0
  569. package/assets/api/vendor_modules/qs/test/utils.js +626 -0
  570. package/assets/api/vendor_modules/range-parser/HISTORY.md +56 -0
  571. package/assets/api/vendor_modules/range-parser/LICENSE +23 -0
  572. package/assets/api/vendor_modules/range-parser/README.md +84 -0
  573. package/assets/api/vendor_modules/range-parser/index.js +162 -0
  574. package/assets/api/vendor_modules/range-parser/package.json +44 -0
  575. package/assets/api/vendor_modules/raw-body/LICENSE +22 -0
  576. package/assets/api/vendor_modules/raw-body/README.md +223 -0
  577. package/assets/api/vendor_modules/raw-body/index.d.ts +87 -0
  578. package/assets/api/vendor_modules/raw-body/index.js +336 -0
  579. package/assets/api/vendor_modules/raw-body/package.json +47 -0
  580. package/assets/api/vendor_modules/safe-buffer/LICENSE +21 -0
  581. package/assets/api/vendor_modules/safe-buffer/README.md +584 -0
  582. package/assets/api/vendor_modules/safe-buffer/index.d.ts +187 -0
  583. package/assets/api/vendor_modules/safe-buffer/index.js +65 -0
  584. package/assets/api/vendor_modules/safe-buffer/package.json +51 -0
  585. package/assets/api/vendor_modules/safer-buffer/LICENSE +21 -0
  586. package/assets/api/vendor_modules/safer-buffer/Porting-Buffer.md +268 -0
  587. package/assets/api/vendor_modules/safer-buffer/Readme.md +156 -0
  588. package/assets/api/vendor_modules/safer-buffer/dangerous.js +58 -0
  589. package/assets/api/vendor_modules/safer-buffer/package.json +34 -0
  590. package/assets/api/vendor_modules/safer-buffer/safer.js +77 -0
  591. package/assets/api/vendor_modules/safer-buffer/tests.js +406 -0
  592. package/assets/api/vendor_modules/send/HISTORY.md +538 -0
  593. package/assets/api/vendor_modules/send/LICENSE +23 -0
  594. package/assets/api/vendor_modules/send/README.md +327 -0
  595. package/assets/api/vendor_modules/send/SECURITY.md +24 -0
  596. package/assets/api/vendor_modules/send/index.js +1142 -0
  597. package/assets/api/vendor_modules/send/node_modules/ms/index.js +162 -0
  598. package/assets/api/vendor_modules/send/node_modules/ms/license.md +21 -0
  599. package/assets/api/vendor_modules/send/node_modules/ms/package.json +38 -0
  600. package/assets/api/vendor_modules/send/node_modules/ms/readme.md +59 -0
  601. package/assets/api/vendor_modules/send/package.json +62 -0
  602. package/assets/api/vendor_modules/serve-static/HISTORY.md +493 -0
  603. package/assets/api/vendor_modules/serve-static/LICENSE +25 -0
  604. package/assets/api/vendor_modules/serve-static/README.md +257 -0
  605. package/assets/api/vendor_modules/serve-static/index.js +209 -0
  606. package/assets/api/vendor_modules/serve-static/package.json +42 -0
  607. package/assets/api/vendor_modules/serverless-http/LICENSE.txt +33 -0
  608. package/assets/api/vendor_modules/serverless-http/README.md +117 -0
  609. package/assets/api/vendor_modules/serverless-http/lib/finish.js +42 -0
  610. package/assets/api/vendor_modules/serverless-http/lib/framework/get-framework.js +79 -0
  611. package/assets/api/vendor_modules/serverless-http/lib/provider/aws/clean-up-event.js +98 -0
  612. package/assets/api/vendor_modules/serverless-http/lib/provider/aws/create-request.js +110 -0
  613. package/assets/api/vendor_modules/serverless-http/lib/provider/aws/format-response.js +45 -0
  614. package/assets/api/vendor_modules/serverless-http/lib/provider/aws/index.js +15 -0
  615. package/assets/api/vendor_modules/serverless-http/lib/provider/aws/is-binary.js +42 -0
  616. package/assets/api/vendor_modules/serverless-http/lib/provider/aws/sanitize-headers.js +21 -0
  617. package/assets/api/vendor_modules/serverless-http/lib/provider/azure/clean-up-request.js +41 -0
  618. package/assets/api/vendor_modules/serverless-http/lib/provider/azure/create-request.js +45 -0
  619. package/assets/api/vendor_modules/serverless-http/lib/provider/azure/format-response.js +18 -0
  620. package/assets/api/vendor_modules/serverless-http/lib/provider/azure/index.js +13 -0
  621. package/assets/api/vendor_modules/serverless-http/lib/provider/azure/is-binary.js +42 -0
  622. package/assets/api/vendor_modules/serverless-http/lib/provider/azure/sanitize-headers.js +23 -0
  623. package/assets/api/vendor_modules/serverless-http/lib/provider/azure/set-cookie.json +1 -0
  624. package/assets/api/vendor_modules/serverless-http/lib/provider/get-provider.js +17 -0
  625. package/assets/api/vendor_modules/serverless-http/lib/request.js +38 -0
  626. package/assets/api/vendor_modules/serverless-http/lib/response.js +135 -0
  627. package/assets/api/vendor_modules/serverless-http/package.json +93 -0
  628. package/assets/api/vendor_modules/serverless-http/serverless-http.d.ts +41 -0
  629. package/assets/api/vendor_modules/serverless-http/serverless-http.js +23 -0
  630. package/assets/api/vendor_modules/setprototypeof/LICENSE +13 -0
  631. package/assets/api/vendor_modules/setprototypeof/README.md +31 -0
  632. package/assets/api/vendor_modules/setprototypeof/index.d.ts +2 -0
  633. package/assets/api/vendor_modules/setprototypeof/index.js +17 -0
  634. package/assets/api/vendor_modules/setprototypeof/package.json +38 -0
  635. package/assets/api/vendor_modules/setprototypeof/test/index.js +24 -0
  636. package/assets/api/vendor_modules/side-channel/.editorconfig +9 -0
  637. package/assets/api/vendor_modules/side-channel/.eslintrc +12 -0
  638. package/assets/api/vendor_modules/side-channel/.github/FUNDING.yml +12 -0
  639. package/assets/api/vendor_modules/side-channel/.nycrc +13 -0
  640. package/assets/api/vendor_modules/side-channel/CHANGELOG.md +120 -0
  641. package/assets/api/vendor_modules/side-channel/LICENSE +21 -0
  642. package/assets/api/vendor_modules/side-channel/README.md +61 -0
  643. package/assets/api/vendor_modules/side-channel/index.d.ts +14 -0
  644. package/assets/api/vendor_modules/side-channel/index.js +46 -0
  645. package/assets/api/vendor_modules/side-channel/package.json +85 -0
  646. package/assets/api/vendor_modules/side-channel/test/index.js +120 -0
  647. package/assets/api/vendor_modules/side-channel/tsconfig.json +9 -0
  648. package/assets/api/vendor_modules/side-channel-list/.editorconfig +9 -0
  649. package/assets/api/vendor_modules/side-channel-list/.eslintrc +11 -0
  650. package/assets/api/vendor_modules/side-channel-list/.github/FUNDING.yml +12 -0
  651. package/assets/api/vendor_modules/side-channel-list/.nycrc +13 -0
  652. package/assets/api/vendor_modules/side-channel-list/CHANGELOG.md +36 -0
  653. package/assets/api/vendor_modules/side-channel-list/LICENSE +21 -0
  654. package/assets/api/vendor_modules/side-channel-list/README.md +62 -0
  655. package/assets/api/vendor_modules/side-channel-list/index.d.ts +13 -0
  656. package/assets/api/vendor_modules/side-channel-list/index.js +111 -0
  657. package/assets/api/vendor_modules/side-channel-list/list.d.ts +14 -0
  658. package/assets/api/vendor_modules/side-channel-list/package.json +77 -0
  659. package/assets/api/vendor_modules/side-channel-list/test/index.js +154 -0
  660. package/assets/api/vendor_modules/side-channel-list/tsconfig.json +9 -0
  661. package/assets/api/vendor_modules/side-channel-map/.editorconfig +9 -0
  662. package/assets/api/vendor_modules/side-channel-map/.eslintrc +11 -0
  663. package/assets/api/vendor_modules/side-channel-map/.github/FUNDING.yml +12 -0
  664. package/assets/api/vendor_modules/side-channel-map/.nycrc +13 -0
  665. package/assets/api/vendor_modules/side-channel-map/CHANGELOG.md +22 -0
  666. package/assets/api/vendor_modules/side-channel-map/LICENSE +21 -0
  667. package/assets/api/vendor_modules/side-channel-map/README.md +62 -0
  668. package/assets/api/vendor_modules/side-channel-map/index.d.ts +15 -0
  669. package/assets/api/vendor_modules/side-channel-map/index.js +68 -0
  670. package/assets/api/vendor_modules/side-channel-map/package.json +80 -0
  671. package/assets/api/vendor_modules/side-channel-map/test/index.js +114 -0
  672. package/assets/api/vendor_modules/side-channel-map/tsconfig.json +9 -0
  673. package/assets/api/vendor_modules/side-channel-weakmap/.editorconfig +9 -0
  674. package/assets/api/vendor_modules/side-channel-weakmap/.eslintrc +12 -0
  675. package/assets/api/vendor_modules/side-channel-weakmap/.github/FUNDING.yml +12 -0
  676. package/assets/api/vendor_modules/side-channel-weakmap/.nycrc +13 -0
  677. package/assets/api/vendor_modules/side-channel-weakmap/CHANGELOG.md +28 -0
  678. package/assets/api/vendor_modules/side-channel-weakmap/LICENSE +21 -0
  679. package/assets/api/vendor_modules/side-channel-weakmap/README.md +62 -0
  680. package/assets/api/vendor_modules/side-channel-weakmap/index.d.ts +15 -0
  681. package/assets/api/vendor_modules/side-channel-weakmap/index.js +84 -0
  682. package/assets/api/vendor_modules/side-channel-weakmap/package.json +87 -0
  683. package/assets/api/vendor_modules/side-channel-weakmap/test/index.js +114 -0
  684. package/assets/api/vendor_modules/side-channel-weakmap/tsconfig.json +9 -0
  685. package/assets/api/vendor_modules/statuses/HISTORY.md +87 -0
  686. package/assets/api/vendor_modules/statuses/LICENSE +23 -0
  687. package/assets/api/vendor_modules/statuses/README.md +139 -0
  688. package/assets/api/vendor_modules/statuses/codes.json +65 -0
  689. package/assets/api/vendor_modules/statuses/index.js +146 -0
  690. package/assets/api/vendor_modules/statuses/package.json +49 -0
  691. package/assets/api/vendor_modules/toidentifier/HISTORY.md +9 -0
  692. package/assets/api/vendor_modules/toidentifier/LICENSE +21 -0
  693. package/assets/api/vendor_modules/toidentifier/README.md +61 -0
  694. package/assets/api/vendor_modules/toidentifier/index.js +32 -0
  695. package/assets/api/vendor_modules/toidentifier/package.json +38 -0
  696. package/assets/api/vendor_modules/type-is/HISTORY.md +259 -0
  697. package/assets/api/vendor_modules/type-is/LICENSE +23 -0
  698. package/assets/api/vendor_modules/type-is/README.md +170 -0
  699. package/assets/api/vendor_modules/type-is/index.js +266 -0
  700. package/assets/api/vendor_modules/type-is/package.json +45 -0
  701. package/assets/api/vendor_modules/unpipe/HISTORY.md +4 -0
  702. package/assets/api/vendor_modules/unpipe/LICENSE +22 -0
  703. package/assets/api/vendor_modules/unpipe/README.md +43 -0
  704. package/assets/api/vendor_modules/unpipe/index.js +69 -0
  705. package/assets/api/vendor_modules/unpipe/package.json +27 -0
  706. package/assets/api/vendor_modules/utils-merge/LICENSE +20 -0
  707. package/assets/api/vendor_modules/utils-merge/README.md +34 -0
  708. package/assets/api/vendor_modules/utils-merge/index.js +23 -0
  709. package/assets/api/vendor_modules/utils-merge/package.json +40 -0
  710. package/assets/api/vendor_modules/vary/HISTORY.md +39 -0
  711. package/assets/api/vendor_modules/vary/LICENSE +22 -0
  712. package/assets/api/vendor_modules/vary/README.md +101 -0
  713. package/assets/api/vendor_modules/vary/index.js +149 -0
  714. package/assets/api/vendor_modules/vary/package.json +43 -0
  715. package/assets/federation-presignup/index.js +108 -0
  716. package/assets/firstadmin/index.js +361 -0
  717. package/assets/headscale-apikey/index.js +140 -0
  718. package/assets/invoke-relay/index.js +96 -0
  719. package/assets/issuer-canary/index.js +71 -0
  720. package/assets/issuer-publish/index.js +87 -0
  721. package/assets/keyminter/index.js +209 -0
  722. package/assets/plugin-authorizer/index.js +1740 -0
  723. package/assets/plugin-catalog/index.js +881 -0
  724. package/assets/reapproval/index.js +3761 -0
  725. package/assets/sg-manager/index.js +176 -0
  726. package/assets/tailnet-resolver/index.js +55 -0
  727. package/assets/web/chunk-2MOGDYK4.js +1 -0
  728. package/assets/web/chunk-2SO4BVIT.js +1 -0
  729. package/assets/web/chunk-2V6RSAAC.js +1 -0
  730. package/assets/web/chunk-32GNBTAL.js +1 -0
  731. package/assets/web/chunk-33SYY2JB.js +1 -0
  732. package/assets/web/chunk-3VWYT7AX.js +1 -0
  733. package/assets/web/chunk-4FG4DAWU.js +4 -0
  734. package/assets/web/chunk-4N2IUS6T.js +1 -0
  735. package/assets/web/chunk-4SK6XQ6C.js +1 -0
  736. package/assets/web/chunk-65WE5MXA.js +8 -0
  737. package/assets/web/chunk-6D7SSSJF.js +1 -0
  738. package/assets/web/chunk-6KFR7DYY.js +1 -0
  739. package/assets/web/chunk-A4WHI3ZG.js +8 -0
  740. package/assets/web/chunk-BNFKRZTP.js +1 -0
  741. package/assets/web/chunk-CG56PH3M.js +1 -0
  742. package/assets/web/chunk-CGO25AIM.js +1 -0
  743. package/assets/web/chunk-CP4XZPOA.js +1 -0
  744. package/assets/web/chunk-CV7EODPO.js +1 -0
  745. package/assets/web/chunk-D7TR2ORJ.js +1 -0
  746. package/assets/web/chunk-DCOFBAKJ.js +1 -0
  747. package/assets/web/chunk-DOLRLYW7.js +1 -0
  748. package/assets/web/chunk-EEJ3X466.js +1 -0
  749. package/assets/web/chunk-EQ4PF25J.js +1 -0
  750. package/assets/web/chunk-EVP5UVDQ.js +1 -0
  751. package/assets/web/chunk-EW2VMNHE.js +1 -0
  752. package/assets/web/chunk-FIUVIKAN.js +1 -0
  753. package/assets/web/chunk-GHEU25TG.js +1 -0
  754. package/assets/web/chunk-GK2T2SMO.js +1 -0
  755. package/assets/web/chunk-GKI3R2JB.js +1 -0
  756. package/assets/web/chunk-GPKKIOHD.js +2 -0
  757. package/assets/web/chunk-H4AVFUDM.js +1 -0
  758. package/assets/web/chunk-H5H727H6.js +1 -0
  759. package/assets/web/chunk-HGVFH6YM.js +1 -0
  760. package/assets/web/chunk-HHPIANBK.js +1 -0
  761. package/assets/web/chunk-HK56COCB.js +1 -0
  762. package/assets/web/chunk-HZUB7LFV.js +1 -0
  763. package/assets/web/chunk-I7NTNTBA.js +1 -0
  764. package/assets/web/chunk-IKK5DQ3Z.js +1 -0
  765. package/assets/web/chunk-IMH56UBX.js +1 -0
  766. package/assets/web/chunk-J3SSPCFV.js +1 -0
  767. package/assets/web/chunk-J4C7C5KO.js +1 -0
  768. package/assets/web/chunk-J57JB4MU.js +1 -0
  769. package/assets/web/chunk-JMBXRK3I.js +4 -0
  770. package/assets/web/chunk-KCCEQIXX.js +1 -0
  771. package/assets/web/chunk-KEBESIXR.js +1 -0
  772. package/assets/web/chunk-KPNHT4MK.js +1 -0
  773. package/assets/web/chunk-LMLXTVZG.js +1 -0
  774. package/assets/web/chunk-M6OAYNRE.js +1 -0
  775. package/assets/web/chunk-M7MGX5I4.js +1 -0
  776. package/assets/web/chunk-MU2VNTNY.js +1 -0
  777. package/assets/web/chunk-NABAVDRL.js +1 -0
  778. package/assets/web/chunk-NO5D6WDF.js +1 -0
  779. package/assets/web/chunk-O4QSFUXB.js +1 -0
  780. package/assets/web/chunk-OATVFQXO.js +1 -0
  781. package/assets/web/chunk-P5WRM37W.js +5 -0
  782. package/assets/web/chunk-PCP6D2SM.js +1 -0
  783. package/assets/web/chunk-PMMBJK7Q.js +1 -0
  784. package/assets/web/chunk-PSMER3HX.js +1 -0
  785. package/assets/web/chunk-QPBWZLCT.js +1 -0
  786. package/assets/web/chunk-QVABVDO5.js +1 -0
  787. package/assets/web/chunk-RI77LE5V.js +1 -0
  788. package/assets/web/chunk-RKGUEXZ2.js +1 -0
  789. package/assets/web/chunk-RMFH2YTZ.js +1 -0
  790. package/assets/web/chunk-RROPCBUH.js +1 -0
  791. package/assets/web/chunk-SJMLX5AT.js +1 -0
  792. package/assets/web/chunk-TKVALOE4.js +2 -0
  793. package/assets/web/chunk-TM43WUKM.js +1 -0
  794. package/assets/web/chunk-VKWV3ANT.js +1 -0
  795. package/assets/web/chunk-VTMYG6YW.js +1 -0
  796. package/assets/web/chunk-VWW4SA5R.js +1 -0
  797. package/assets/web/chunk-WEDAFMID.js +1 -0
  798. package/assets/web/chunk-WFIHWVQO.js +1 -0
  799. package/assets/web/chunk-XJM3HDJQ.js +1 -0
  800. package/assets/web/chunk-YVJV2RUY.js +1 -0
  801. package/assets/web/chunk-Z3KONI7L.js +1 -0
  802. package/assets/web/chunk-ZDCURXPS.js +1 -0
  803. package/assets/web/favicon.ico +0 -0
  804. package/assets/web/index.html +63 -0
  805. package/assets/web/main-S6E3BC5O.js +2 -0
  806. package/assets/web/polyfills-7RSNIJ6J.js +2 -0
  807. package/assets/web/styles-R6ZUWC6K.css +1 -0
  808. package/dist/index.d.ts +27 -0
  809. package/dist/index.js +66 -0
  810. package/dist/lambdacode/api/services/brandingShapes.d.ts +5 -0
  811. package/dist/lambdacode/api/services/brandingShapes.js +15 -0
  812. package/dist/lambdacode/issuer/objects.d.ts +8 -0
  813. package/dist/lambdacode/issuer/objects.js +11 -0
  814. package/dist/lambdacode/network/naming.d.ts +52 -0
  815. package/dist/lambdacode/network/naming.js +67 -0
  816. package/dist/lib/access-portal-hub.d.ts +53 -0
  817. package/dist/lib/access-portal-hub.js +87 -0
  818. package/dist/lib/access-portal.d.ts +32 -0
  819. package/dist/lib/access-portal.js +174 -0
  820. package/dist/lib/audit-log.d.ts +18 -0
  821. package/dist/lib/audit-log.js +25 -0
  822. package/dist/lib/connector-stack.d.ts +28 -0
  823. package/dist/lib/connector-stack.js +81 -0
  824. package/dist/lib/constructs/app-function.d.ts +14 -0
  825. package/dist/lib/constructs/app-function.js +84 -0
  826. package/dist/lib/constructs/app-table.d.ts +12 -0
  827. package/dist/lib/constructs/app-table.js +58 -0
  828. package/dist/lib/constructs/mirrored-image.d.ts +12 -0
  829. package/dist/lib/constructs/mirrored-image.js +80 -0
  830. package/dist/lib/constructs/monitoring.d.ts +21 -0
  831. package/dist/lib/constructs/monitoring.js +133 -0
  832. package/dist/lib/constructs/oidc-issuer.d.ts +44 -0
  833. package/dist/lib/constructs/oidc-issuer.js +234 -0
  834. package/dist/lib/constructs/scratch-tmpfs.d.ts +5 -0
  835. package/dist/lib/constructs/scratch-tmpfs.js +48 -0
  836. package/dist/lib/constructs/sg-manager.d.ts +27 -0
  837. package/dist/lib/constructs/sg-manager.js +88 -0
  838. package/dist/lib/constructs/tailnet-connector.d.ts +29 -0
  839. package/dist/lib/constructs/tailnet-connector.js +177 -0
  840. package/dist/lib/constructs/tailnet-resolver.d.ts +30 -0
  841. package/dist/lib/constructs/tailnet-resolver.js +71 -0
  842. package/dist/lib/constructs/target-account-trust.d.ts +32 -0
  843. package/dist/lib/constructs/target-account-trust.js +81 -0
  844. package/dist/lib/constructs/vending-api.d.ts +103 -0
  845. package/dist/lib/constructs/vending-api.js +203 -0
  846. package/dist/lib/constructs/web-acl.d.ts +61 -0
  847. package/dist/lib/constructs/web-acl.js +213 -0
  848. package/dist/lib/constructs/web-identity.d.ts +49 -0
  849. package/dist/lib/constructs/web-identity.js +116 -0
  850. package/dist/lib/creds-stack.d.ts +151 -0
  851. package/dist/lib/creds-stack.js +592 -0
  852. package/dist/lib/data-stack.d.ts +53 -0
  853. package/dist/lib/data-stack.js +282 -0
  854. package/dist/lib/dimensions-validation.d.ts +20 -0
  855. package/dist/lib/dimensions-validation.js +51 -0
  856. package/dist/lib/federation.d.ts +113 -0
  857. package/dist/lib/federation.js +254 -0
  858. package/dist/lib/managed-login-branding.json +450 -0
  859. package/dist/lib/network-stack.d.ts +58 -0
  860. package/dist/lib/network-stack.js +776 -0
  861. package/dist/lib/network-validation.d.ts +54 -0
  862. package/dist/lib/network-validation.js +220 -0
  863. package/dist/lib/pkg-paths.d.ts +3 -0
  864. package/dist/lib/pkg-paths.js +51 -0
  865. package/dist/lib/plugins/plugin-api.d.ts +40 -0
  866. package/dist/lib/plugins/plugin-api.js +125 -0
  867. package/dist/lib/plugins/plugin-catalog-activation.d.ts +31 -0
  868. package/dist/lib/plugins/plugin-catalog-activation.js +109 -0
  869. package/dist/lib/plugins/registration.d.ts +41 -0
  870. package/dist/lib/plugins/registration.js +121 -0
  871. package/dist/lib/plugins/runtime.d.ts +10 -0
  872. package/dist/lib/plugins/runtime.js +17 -0
  873. package/dist/lib/project-config.d.ts +164 -0
  874. package/dist/lib/project-config.js +2 -0
  875. package/dist/lib/target-account-stack.d.ts +15 -0
  876. package/dist/lib/target-account-stack.js +59 -0
  877. package/dist/lib/target-account-template.d.ts +13 -0
  878. package/dist/lib/target-account-template.js +64 -0
  879. package/dist/lib/web-cert-stack.d.ts +30 -0
  880. package/dist/lib/web-cert-stack.js +90 -0
  881. package/dist/lib/web-stack.d.ts +103 -0
  882. package/dist/lib/web-stack.js +540 -0
  883. package/node_modules/@fntio/infra-client-plugin-sdk/README.md +303 -0
  884. package/node_modules/@fntio/infra-client-plugin-sdk/dist/backend/context.d.ts +31 -0
  885. package/node_modules/@fntio/infra-client-plugin-sdk/dist/backend/context.js +58 -0
  886. package/node_modules/@fntio/infra-client-plugin-sdk/dist/backend/index.d.ts +9 -0
  887. package/node_modules/@fntio/infra-client-plugin-sdk/dist/backend/index.js +26 -0
  888. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/client.d.ts +59 -0
  889. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/client.js +290 -0
  890. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/errors.d.ts +14 -0
  891. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/errors.js +32 -0
  892. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/http.d.ts +72 -0
  893. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/http.js +170 -0
  894. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/index.d.ts +11 -0
  895. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/index.js +28 -0
  896. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/theme-apply.d.ts +22 -0
  897. package/node_modules/@fntio/infra-client-plugin-sdk/dist/browser/theme-apply.js +22 -0
  898. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/access.d.ts +14 -0
  899. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/access.js +41 -0
  900. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/authorizer.d.ts +17 -0
  901. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/authorizer.js +44 -0
  902. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/canonical.d.ts +2 -0
  903. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/canonical.js +21 -0
  904. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/catalog.d.ts +39 -0
  905. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/catalog.js +18 -0
  906. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/discovery.d.ts +78 -0
  907. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/discovery.js +48 -0
  908. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/fields.d.ts +7 -0
  909. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/fields.js +2 -0
  910. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/manifest.d.ts +59 -0
  911. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/manifest.js +19 -0
  912. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/messages.d.ts +111 -0
  913. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/messages.js +109 -0
  914. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/paths.d.ts +20 -0
  915. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/paths.js +49 -0
  916. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/theme.d.ts +21 -0
  917. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/theme.js +60 -0
  918. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/transport.d.ts +14 -0
  919. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/transport.js +10 -0
  920. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/validate.d.ts +27 -0
  921. package/node_modules/@fntio/infra-client-plugin-sdk/dist/contracts/validate.js +321 -0
  922. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/devHost.d.ts +61 -0
  923. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/devHost.js +99 -0
  924. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/fakeDocument.d.ts +12 -0
  925. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/fakeDocument.js +22 -0
  926. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/fakeWindows.d.ts +22 -0
  927. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/fakeWindows.js +46 -0
  928. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/index.d.ts +4 -0
  929. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/index.js +20 -0
  930. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/samples.d.ts +37 -0
  931. package/node_modules/@fntio/infra-client-plugin-sdk/dist/fixtures/samples.js +228 -0
  932. package/node_modules/@fntio/infra-client-plugin-sdk/dist/host/host.d.ts +47 -0
  933. package/node_modules/@fntio/infra-client-plugin-sdk/dist/host/host.js +121 -0
  934. package/node_modules/@fntio/infra-client-plugin-sdk/dist/host/index.d.ts +5 -0
  935. package/node_modules/@fntio/infra-client-plugin-sdk/dist/host/index.js +22 -0
  936. package/node_modules/@fntio/infra-client-plugin-sdk/dist/index.d.ts +10 -0
  937. package/node_modules/@fntio/infra-client-plugin-sdk/dist/index.js +28 -0
  938. package/node_modules/@fntio/infra-client-plugin-sdk/package.json +99 -0
  939. package/openapi.yaml +4284 -0
  940. package/package.json +124 -4
package/openapi.yaml ADDED
@@ -0,0 +1,4284 @@
1
+ # The HTTP contract of the portal API — every route the Express app mounts.
2
+ # lambdacode/api/__tests__/openapi.test.ts fails when a mounted route is
3
+ # missing here (or a documented one is gone), so this file cannot go stale.
4
+ # The private dev repo generates its Postman collection FROM this file.
5
+ openapi: 3.1.0
6
+ info:
7
+ title: Infra Client API
8
+ version: 0.5.0
9
+ summary: Self-hosted AWS access portal — credential vending, access requests, admin catalog, private-network resources.
10
+ description: |
11
+ One Express app behind CloudFront (`/api/*`) and API Gateway (no prefix).
12
+
13
+ ## Authentication
14
+
15
+ Every route except `GET /health` and `GET /.well-known/infra-client` takes
16
+ `Authorization: Bearer <token>`, where the token is one of:
17
+
18
+ - **Human** — a Cognito **ID token** from the portal's user pool (in-app sign-in).
19
+ Admin routes additionally require membership of the `admins` group
20
+ (`cognito:groups` claim).
21
+ - **Service user** — a Cognito **access token** minted with the
22
+ `client_credentials` grant by an app client an admin created under
23
+ *Admin → Service users*. It carries the `api/invoke` scope; its `sub` is
24
+ the client id. **Every service user is an app admin**, so it may call
25
+ every route below — including `POST /credentials` to vend AWS credentials
26
+ for the roles granted to it.
27
+
28
+ Token exchange for service users (see the Access Model wiki page, "Service users"):
29
+
30
+ POST https://<cognito domain>/oauth2/token
31
+ Authorization: Basic base64(clientId:clientSecret)
32
+ Content-Type: application/x-www-form-urlencoded
33
+
34
+ grant_type=client_credentials&scope=api/invoke
35
+
36
+ ## Conventions
37
+
38
+ - Errors are always JSON `{ "message": "…" }`. `401` = no/invalid token,
39
+ `403` = not an admin (or no grant on a vend), `404` = addressed thing
40
+ missing, `409` = already exists / still in use / already decided,
41
+ `400` = malformed input, `501` = feature not deployed (private network,
42
+ branding storage), `502` = a downstream AWS call failed.
43
+ - Timestamps are ISO-8601 strings in UTC.
44
+ - `accountNumber` is always the 12-digit AWS account id.
45
+ - `userId` is the Cognito `sub` for humans and the app client id for
46
+ service users — both are valid grant principals everywhere a `userId`
47
+ path parameter appears.
48
+ - Lists are returned whole; there is no server-side paging.
49
+ - Temporary access uses the duration presets `1, 12, 24, 72, 168, 720`
50
+ hours (1 h … 30 d). Omitting the duration means long-term (standing) access.
51
+ license:
52
+ name: Elastic License 2.0
53
+ identifier: Elastic-2.0
54
+ servers:
55
+ - url: https://{host}/api
56
+ description: Through the portal's CloudFront distribution (the web domain in your project config).
57
+ variables:
58
+ host:
59
+ default: portal.example.com
60
+ description: Your deployment's web domain.
61
+ security:
62
+ - bearerAuth: []
63
+ tags:
64
+ - name: Health
65
+ description: Liveness and the public discovery document.
66
+ - name: Access
67
+ description: What the caller may assume, and vending credentials or a console sign-in for it.
68
+ - name: Requests
69
+ description: The caller's own access requests (raising, listing, acknowledging decisions).
70
+ - name: Preferences
71
+ description: The caller's per-role and network preferences.
72
+ - name: Network
73
+ description: Private-network (VPN) sites and device enrollment.
74
+ - name: Resources
75
+ description: Private-network resources the caller can reach.
76
+ - name: Notifications
77
+ description: The caller's revoked-access notices (the bell).
78
+ - name: "Admin: setup"
79
+ description: First-run checklist state and branding.
80
+ - name: "Admin: accounts & roles"
81
+ description: The catalog of AWS accounts and the roles registered in them.
82
+ - name: "Admin: grants"
83
+ description: Who holds which role, directly or via groups.
84
+ - name: "Admin: users"
85
+ description: The Cognito directory and per-user cascades.
86
+ - name: "Admin: service users"
87
+ description: Machine-to-machine app clients (client_credentials).
88
+ - name: "Admin: groups"
89
+ description: Role/resource bundles whose members inherit the bundle.
90
+ - name: "Admin: requests"
91
+ description: The approval queue and history.
92
+ - name: "Admin: resources"
93
+ description: Private-network resource catalog and resource grants.
94
+ - name: "Admin: network"
95
+ description: Site topology and the grants→ACL reconciler.
96
+ - name: "Admin: audit"
97
+ description: The vend / console / device-key event log.
98
+ - name: Plugins
99
+ description: What the signed-in caller may open, for the portal's own navigation.
100
+ - name: "Admin: plugins"
101
+ description: Every installed plugin definition, and who may use each binding.
102
+
103
+ paths:
104
+ /health:
105
+ get:
106
+ tags: [Health]
107
+ summary: Liveness
108
+ operationId: health
109
+ security: []
110
+ responses:
111
+ "200":
112
+ description: The API is up.
113
+ content:
114
+ application/json:
115
+ schema:
116
+ type: object
117
+ properties:
118
+ ok: { type: boolean, const: true }
119
+ required: [ok]
120
+
121
+ /.well-known/infra-client:
122
+ get:
123
+ tags: [Health]
124
+ summary: Discovery document (public)
125
+ operationId: discovery
126
+ description: |
127
+ What the desktop app reads to self-configure from a deployment URL:
128
+ the project name, the Cognito pool/client ids the SPA already ships
129
+ with, the OIDC issuer, and the VPN control planes. Never secrets.
130
+ security: []
131
+ responses:
132
+ "200":
133
+ description: Discovery document.
134
+ content:
135
+ application/json:
136
+ schema: { $ref: "#/components/schemas/Discovery" }
137
+
138
+ /accounts:
139
+ get:
140
+ tags: [Access]
141
+ summary: List my access
142
+ operationId: listAccess
143
+ description: |
144
+ Accounts and roles the caller may assume right now (direct and group-provided grants, expired ones excluded), each with its resolved `~/.aws` profile name.
145
+ With `limit`, one page of the list contract: sorts `position` (the admin order, default), `name`, `number`; facets `environment`, `main` (`true`/`false` — whether the account sits in the dashboard's Main section), `favorite` (`true`/`false` — the caller's own favorites), plus `tenant`, `project`, `stage` on a deployment with account dimensions (`unclassified` for an account without one).
146
+ Each account carries `main: false` only when an admin took it off the Main section.
147
+ parameters:
148
+ - $ref: "#/components/parameters/listQ"
149
+ - $ref: "#/components/parameters/listFilter"
150
+ - $ref: "#/components/parameters/listSort"
151
+ - $ref: "#/components/parameters/listLimit"
152
+ - $ref: "#/components/parameters/listCursor"
153
+ responses:
154
+ "200":
155
+ description: The caller's accounts — the whole list, or one page when `limit` was passed.
156
+ content:
157
+ application/json:
158
+ schema:
159
+ oneOf:
160
+ - type: object
161
+ properties:
162
+ accounts:
163
+ type: array
164
+ items: { $ref: "#/components/schemas/AccountAccess" }
165
+ required: [accounts]
166
+ - $ref: "#/components/schemas/AccountAccessPage"
167
+ "400": { $ref: "#/components/responses/BadRequest" }
168
+ "401": { $ref: "#/components/responses/Unauthorized" }
169
+ "502": { $ref: "#/components/responses/Upstream" }
170
+
171
+ /accounts/home:
172
+ get:
173
+ tags: [Access]
174
+ summary: My dashboard
175
+ operationId: homeAccess
176
+ description: |
177
+ The caller's access cut into the dashboard's shortcuts. `sectioned` is true once the caller holds an account
178
+ that is not main (or whenever `layout` is `sections`); until then `main` is the whole list and the dashboard
179
+ shows no sections. A caller who holds nothing is never sectioned, whatever the layout. Accounts the caller
180
+ holds nothing in are not listed: asking for one is `GET /requests/catalog`'s job.
181
+ responses:
182
+ "200":
183
+ description: The dashboard.
184
+ content:
185
+ application/json:
186
+ schema:
187
+ type: object
188
+ properties:
189
+ sectioned: { type: boolean }
190
+ heldTotal: { type: integer, minimum: 0 }
191
+ main: { type: array, items: { $ref: "#/components/schemas/AccountAccess" } }
192
+ favorites: { type: array, items: { $ref: "#/components/schemas/AccountAccess" } }
193
+ recent: { type: array, items: { $ref: "#/components/schemas/AccountAccess" }, description: Newest first. }
194
+ favoriteNumbers: { type: array, items: { $ref: "#/components/schemas/AccountNumber" } }
195
+ layout: { type: string, enum: [auto, sections, plain], description: The deployment-wide setting behind `sectioned` (`PUT /admin/dashboard-layout`). }
196
+ required: [sectioned, heldTotal, main, favorites, recent, favoriteNumbers, layout]
197
+ "401": { $ref: "#/components/responses/Unauthorized" }
198
+ "502": { $ref: "#/components/responses/Upstream" }
199
+
200
+ /accounts/names:
201
+ get:
202
+ tags: [Access]
203
+ summary: Friendly names of every registered account
204
+ operationId: listAccountNames
205
+ description: |
206
+ Account number → admin-set name, for every registered account that has one — the label lookup the web app
207
+ binds on chips and rows. Catalog facts only, never roles or holders; a few dozen KB where the full catalog is
208
+ megabytes. Every signed-in user may read it (the request catalog already shows every account).
209
+ responses:
210
+ "200":
211
+ description: The name map.
212
+ content:
213
+ application/json:
214
+ schema:
215
+ type: object
216
+ properties:
217
+ names:
218
+ type: object
219
+ additionalProperties: { type: string }
220
+ required: [names]
221
+ "401": { $ref: "#/components/responses/Unauthorized" }
222
+ "502": { $ref: "#/components/responses/Upstream" }
223
+ /accounts/expiry:
224
+ get:
225
+ tags: [Access]
226
+ summary: My expiry notices
227
+ operationId: listExpiryNotices
228
+ description: The caller's temporary role grants nearing (`expiring`) or past (`expired`) their end — the bell feed.
229
+ responses:
230
+ "200":
231
+ description: Expiry notices by phase.
232
+ content:
233
+ application/json:
234
+ schema: { $ref: "#/components/schemas/ExpiryNotices" }
235
+ "401": { $ref: "#/components/responses/Unauthorized" }
236
+ "502": { $ref: "#/components/responses/Upstream" }
237
+
238
+ /accounts/expiry/seen:
239
+ post:
240
+ tags: [Access]
241
+ summary: Acknowledge expiry notices
242
+ operationId: markExpiryNoticesSeen
243
+ responses:
244
+ "200":
245
+ description: How many notices were newly marked seen.
246
+ content:
247
+ application/json:
248
+ schema: { $ref: "#/components/schemas/Cleared" }
249
+ "401": { $ref: "#/components/responses/Unauthorized" }
250
+ "502": { $ref: "#/components/responses/Upstream" }
251
+
252
+ /accounts/{accountNumber}/roles/{roleName}/console:
253
+ post:
254
+ tags: [Access]
255
+ summary: Console sign-in URL
256
+ operationId: consoleSignIn
257
+ description: |
258
+ "Go to Console": same grant check as `POST /credentials`, returns a
259
+ short-lived AWS console federation URL. Every call — vended, denied or
260
+ failed — writes an audit event.
261
+ parameters:
262
+ - $ref: "#/components/parameters/accountNumber"
263
+ - $ref: "#/components/parameters/roleName"
264
+ requestBody:
265
+ content:
266
+ application/json:
267
+ schema:
268
+ type: object
269
+ properties:
270
+ destination:
271
+ type: string
272
+ format: uri
273
+ description: Optional post-login destination; must be an `https://…console.aws.amazon.com/` URL.
274
+ example: { destination: "https://eu-central-1.console.aws.amazon.com/s3/home" }
275
+ responses:
276
+ "200":
277
+ description: The sign-in URL.
278
+ content:
279
+ application/json:
280
+ schema: { $ref: "#/components/schemas/ConsoleSignIn" }
281
+ "400": { $ref: "#/components/responses/BadRequest" }
282
+ "401": { $ref: "#/components/responses/Unauthorized" }
283
+ "403":
284
+ description: No active grant for this role (`NO_GRANT` or `EXPIRED`), or the role is no longer in the catalog (`NO_ROLE`).
285
+ content:
286
+ application/json:
287
+ schema: { $ref: "#/components/schemas/Error" }
288
+ "502": { $ref: "#/components/responses/Upstream" }
289
+
290
+ /credentials:
291
+ post:
292
+ tags: [Access]
293
+ summary: Vend credentials
294
+ operationId: vendCredentials
295
+ description: |
296
+ Temporary AWS credentials for a role the caller holds. The session
297
+ length is the role's `sessionDurationSeconds` (default 3600), capped
298
+ by the IAM role's MaxSessionDuration — a cap violation is a `502`
299
+ whose message says so. Every call writes an audit event.
300
+ requestBody:
301
+ required: true
302
+ content:
303
+ application/json:
304
+ schema:
305
+ type: object
306
+ properties:
307
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
308
+ role:
309
+ type: string
310
+ maxLength: 128
311
+ description: The role name (not the ARN). May not contain `#` or `/`.
312
+ background:
313
+ type: boolean
314
+ description: "true = an automatic renewal (desktop keep-fresh), which does not count as the person reaching for the account: it leaves the dashboard's Recent section alone."
315
+ required: [accountNumber, role]
316
+ example: { accountNumber: "123456789012", role: "ReadOnly" }
317
+ responses:
318
+ "200":
319
+ description: Credentials.
320
+ content:
321
+ application/json:
322
+ schema: { $ref: "#/components/schemas/VendedCredentials" }
323
+ "400": { $ref: "#/components/responses/BadRequest" }
324
+ "401": { $ref: "#/components/responses/Unauthorized" }
325
+ "403":
326
+ description: No active grant for this role (`NO_GRANT` or `EXPIRED`), or the role is no longer in the catalog (`NO_ROLE`).
327
+ content:
328
+ application/json:
329
+ schema: { $ref: "#/components/schemas/Error" }
330
+ "502": { $ref: "#/components/responses/Upstream" }
331
+
332
+ /requests/catalog:
333
+ get:
334
+ tags: [Requests]
335
+ summary: Requestable roles
336
+ operationId: listRequestableRoles
337
+ description: |
338
+ The role catalog minus what the caller already holds long-term or has pending. Account numbers and role names only — never ARNs or holders.
339
+ With `limit`, one page of the list contract: sorts `name` (default), `number`; facets `tenant`, `project`, `stage` on a deployment with account dimensions (`unclassified` for an account without one), none otherwise.
340
+ parameters:
341
+ - $ref: "#/components/parameters/listQ"
342
+ - $ref: "#/components/parameters/listFilter"
343
+ - $ref: "#/components/parameters/listSort"
344
+ - $ref: "#/components/parameters/listLimit"
345
+ - $ref: "#/components/parameters/listCursor"
346
+ responses:
347
+ "200":
348
+ description: Accounts with requestable roles — the whole list, or one page when `limit` was passed.
349
+ content:
350
+ application/json:
351
+ schema:
352
+ oneOf:
353
+ - type: object
354
+ properties:
355
+ accounts:
356
+ type: array
357
+ items: { $ref: "#/components/schemas/RequestableAccount" }
358
+ required: [accounts]
359
+ - $ref: "#/components/schemas/RequestableAccountPage"
360
+ "400": { $ref: "#/components/responses/BadRequest" }
361
+ "401": { $ref: "#/components/responses/Unauthorized" }
362
+ "502": { $ref: "#/components/responses/Upstream" }
363
+
364
+ /requests/resource-catalog:
365
+ get:
366
+ tags: [Requests]
367
+ summary: Requestable resources
368
+ operationId: listRequestableResources
369
+ description: Private-network resources the caller may ask for — name, type, description and account only; connection details appear only after a grant (`GET /resources`).
370
+ responses:
371
+ "200":
372
+ description: Requestable resources.
373
+ content:
374
+ application/json:
375
+ schema:
376
+ type: object
377
+ properties:
378
+ resources:
379
+ type: array
380
+ items: { $ref: "#/components/schemas/RequestableResource" }
381
+ required: [resources]
382
+ "401": { $ref: "#/components/responses/Unauthorized" }
383
+ "502": { $ref: "#/components/responses/Upstream" }
384
+
385
+ /requests:
386
+ get:
387
+ tags: [Requests]
388
+ summary: My requests
389
+ operationId: listMyRequests
390
+ description: The caller's own requests, newest first. Resource rows carry a resolved `resourceName`.
391
+ responses:
392
+ "200":
393
+ description: The caller's requests.
394
+ content:
395
+ application/json:
396
+ schema:
397
+ type: object
398
+ properties:
399
+ requests:
400
+ type: array
401
+ items: { $ref: "#/components/schemas/AccessRequest" }
402
+ required: [requests]
403
+ "401": { $ref: "#/components/responses/Unauthorized" }
404
+ "502": { $ref: "#/components/responses/Upstream" }
405
+ post:
406
+ tags: [Requests]
407
+ summary: Request a role
408
+ operationId: createRequest
409
+ description: Ask for a role. The requester is always the caller. `409` if the caller already holds it long-term or has one pending; `404` if the role is not catalogued.
410
+ requestBody:
411
+ required: true
412
+ content:
413
+ application/json:
414
+ schema:
415
+ type: object
416
+ properties:
417
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
418
+ roleName: { type: string }
419
+ reason: { type: string, maxLength: 500 }
420
+ durationHours: { $ref: "#/components/schemas/DurationHours" }
421
+ required: [accountNumber, roleName]
422
+ example: { accountNumber: "123456789012", roleName: "ReadOnly", reason: "Investigating an incident", durationHours: 24 }
423
+ responses:
424
+ "201":
425
+ description: The pending request.
426
+ content:
427
+ application/json:
428
+ schema: { $ref: "#/components/schemas/RequestEnvelope" }
429
+ "400": { $ref: "#/components/responses/BadRequest" }
430
+ "401": { $ref: "#/components/responses/Unauthorized" }
431
+ "404": { $ref: "#/components/responses/NotFound" }
432
+ "409": { $ref: "#/components/responses/Conflict" }
433
+ "502": { $ref: "#/components/responses/Upstream" }
434
+
435
+ /requests/resource:
436
+ post:
437
+ tags: [Requests]
438
+ summary: Request a resource
439
+ operationId: createResourceRequest
440
+ description: Ask for private-network access to one resource. Same rules as requesting a role.
441
+ requestBody:
442
+ required: true
443
+ content:
444
+ application/json:
445
+ schema:
446
+ type: object
447
+ properties:
448
+ resourceId: { type: string }
449
+ reason: { type: string, maxLength: 500 }
450
+ durationHours: { $ref: "#/components/schemas/DurationHours" }
451
+ required: [resourceId]
452
+ example: { resourceId: "7f1c2b3a-0000-4000-8000-000000000000", reason: "Need the staging database", durationHours: 72 }
453
+ responses:
454
+ "201":
455
+ description: The pending request.
456
+ content:
457
+ application/json:
458
+ schema: { $ref: "#/components/schemas/RequestEnvelope" }
459
+ "400": { $ref: "#/components/responses/BadRequest" }
460
+ "401": { $ref: "#/components/responses/Unauthorized" }
461
+ "404": { $ref: "#/components/responses/NotFound" }
462
+ "409": { $ref: "#/components/responses/Conflict" }
463
+ "502": { $ref: "#/components/responses/Upstream" }
464
+
465
+ /requests/seen:
466
+ post:
467
+ tags: [Requests]
468
+ summary: Acknowledge decisions
469
+ operationId: markRequestsSeen
470
+ description: Marks the caller's decided requests as seen (clears the bell badge).
471
+ responses:
472
+ "200":
473
+ description: How many requests were newly marked seen.
474
+ content:
475
+ application/json:
476
+ schema: { $ref: "#/components/schemas/Cleared" }
477
+ "401": { $ref: "#/components/responses/Unauthorized" }
478
+ "502": { $ref: "#/components/responses/Upstream" }
479
+
480
+ /preferences:
481
+ get:
482
+ tags: [Preferences]
483
+ summary: List my role preferences
484
+ operationId: listPreferences
485
+ description: Every (account, role) the caller has customised — profile-name override, role label, auto-vend star.
486
+ responses:
487
+ "200":
488
+ description: Preference rows.
489
+ content:
490
+ application/json:
491
+ schema:
492
+ type: object
493
+ properties:
494
+ preferences:
495
+ type: array
496
+ items: { $ref: "#/components/schemas/RolePreference" }
497
+ required: [preferences]
498
+ "401": { $ref: "#/components/responses/Unauthorized" }
499
+ "502": { $ref: "#/components/responses/Upstream" }
500
+
501
+ /preferences/auto-vend/{accountNumber}/{role}:
502
+ put:
503
+ tags: [Preferences]
504
+ summary: Set the auto-vend star
505
+ operationId: setAutoVend
506
+ description: Starred roles are vended silently on app load (desktop keeps them fresh in `~/.aws/credentials`).
507
+ parameters:
508
+ - $ref: "#/components/parameters/accountNumber"
509
+ - $ref: "#/components/parameters/role"
510
+ requestBody:
511
+ required: true
512
+ content:
513
+ application/json:
514
+ schema:
515
+ type: object
516
+ properties:
517
+ autoVend: { type: boolean }
518
+ required: [autoVend]
519
+ example: { autoVend: true }
520
+ responses:
521
+ "200":
522
+ description: The saved value.
523
+ content:
524
+ application/json:
525
+ schema:
526
+ type: object
527
+ properties:
528
+ autoVend: { type: boolean }
529
+ required: [autoVend]
530
+ "400": { $ref: "#/components/responses/BadRequest" }
531
+ "401": { $ref: "#/components/responses/Unauthorized" }
532
+ "502": { $ref: "#/components/responses/Upstream" }
533
+
534
+ /preferences/favorites/{accountNumber}:
535
+ put:
536
+ tags: [Preferences]
537
+ summary: Star or unstar an account
538
+ operationId: setFavorite
539
+ description: A starred account shows in the dashboard's Favorites section on every device. At most 50; starring a starred account changes nothing.
540
+ parameters:
541
+ - $ref: "#/components/parameters/accountNumber"
542
+ requestBody:
543
+ required: true
544
+ content:
545
+ application/json:
546
+ schema:
547
+ type: object
548
+ properties:
549
+ favorite: { type: boolean }
550
+ required: [favorite]
551
+ responses:
552
+ "200":
553
+ description: The saved state.
554
+ content:
555
+ application/json:
556
+ schema:
557
+ type: object
558
+ properties:
559
+ favorite: { type: boolean }
560
+ required: [favorite]
561
+ "400": { $ref: "#/components/responses/BadRequest" }
562
+ "401": { $ref: "#/components/responses/Unauthorized" }
563
+ "502": { $ref: "#/components/responses/Upstream" }
564
+
565
+ /preferences/network:
566
+ get:
567
+ tags: [Preferences]
568
+ summary: Get my network preferences
569
+ operationId: getNetworkPrefs
570
+ description: Device-independent VPN preferences — the auto-reconnect toggle and the site a reconnect rejoins.
571
+ responses:
572
+ "200":
573
+ description: Network preferences.
574
+ content:
575
+ application/json:
576
+ schema: { $ref: "#/components/schemas/NetworkPrefs" }
577
+ "401": { $ref: "#/components/responses/Unauthorized" }
578
+ "502": { $ref: "#/components/responses/Upstream" }
579
+ put:
580
+ tags: [Preferences]
581
+ summary: Update my network preferences
582
+ operationId: setNetworkPrefs
583
+ requestBody:
584
+ required: true
585
+ content:
586
+ application/json:
587
+ schema:
588
+ type: object
589
+ description: At least one field.
590
+ properties:
591
+ autoReconnect: { type: boolean }
592
+ lastSiteId: { type: string, minLength: 1, maxLength: 64 }
593
+ example: { autoReconnect: true, lastSiteId: "dev" }
594
+ responses:
595
+ "200":
596
+ description: The preferences after the update.
597
+ content:
598
+ application/json:
599
+ schema: { $ref: "#/components/schemas/NetworkPrefs" }
600
+ "400": { $ref: "#/components/responses/BadRequest" }
601
+ "401": { $ref: "#/components/responses/Unauthorized" }
602
+ "502": { $ref: "#/components/responses/Upstream" }
603
+
604
+ /preferences/notifications:
605
+ get:
606
+ tags: [Preferences]
607
+ summary: Get my notification preferences
608
+ operationId: getNotificationPrefs
609
+ description: Which bell items may pop up as native notifications (desktop toasts, browser notifications). Everything is on until turned off; the row follows the user across devices.
610
+ responses:
611
+ "200":
612
+ description: Notification preferences.
613
+ content:
614
+ application/json:
615
+ schema: { $ref: "#/components/schemas/NotificationPrefs" }
616
+ "401": { $ref: "#/components/responses/Unauthorized" }
617
+ "502": { $ref: "#/components/responses/Upstream" }
618
+ put:
619
+ tags: [Preferences]
620
+ summary: Update my notification preferences
621
+ operationId: setNotificationPrefs
622
+ requestBody:
623
+ required: true
624
+ content:
625
+ application/json:
626
+ schema:
627
+ type: object
628
+ description: At least one field; `kinds` may be partial.
629
+ properties:
630
+ enabled: { type: boolean }
631
+ kinds:
632
+ type: object
633
+ additionalProperties: { type: boolean }
634
+ example: { enabled: true, kinds: { requests: false } }
635
+ responses:
636
+ "200":
637
+ description: The preferences after the update.
638
+ content:
639
+ application/json:
640
+ schema: { $ref: "#/components/schemas/NotificationPrefs" }
641
+ "400": { $ref: "#/components/responses/BadRequest" }
642
+ "401": { $ref: "#/components/responses/Unauthorized" }
643
+ "502": { $ref: "#/components/responses/Upstream" }
644
+
645
+ /preferences/profile-name/{accountNumber}/{role}:
646
+ get:
647
+ tags: [Preferences]
648
+ summary: Get my profile-name override
649
+ operationId: getProfileName
650
+ parameters:
651
+ - $ref: "#/components/parameters/accountNumber"
652
+ - $ref: "#/components/parameters/role"
653
+ responses:
654
+ "200":
655
+ description: The override, or `null` when the admin default applies.
656
+ content:
657
+ application/json:
658
+ schema: { $ref: "#/components/schemas/ProfileNameValue" }
659
+ "400": { $ref: "#/components/responses/BadRequest" }
660
+ "401": { $ref: "#/components/responses/Unauthorized" }
661
+ "502": { $ref: "#/components/responses/Upstream" }
662
+ put:
663
+ tags: [Preferences]
664
+ summary: Set my profile-name override
665
+ operationId: setProfileName
666
+ description: A blank or absent `profileName` clears the override (same as DELETE).
667
+ parameters:
668
+ - $ref: "#/components/parameters/accountNumber"
669
+ - $ref: "#/components/parameters/role"
670
+ requestBody:
671
+ content:
672
+ application/json:
673
+ schema:
674
+ type: object
675
+ properties:
676
+ profileName: { type: string, maxLength: 128 }
677
+ example: { profileName: "acme-prod-readonly" }
678
+ responses:
679
+ "200":
680
+ description: The saved value (`null` when cleared).
681
+ content:
682
+ application/json:
683
+ schema: { $ref: "#/components/schemas/ProfileNameValue" }
684
+ "400": { $ref: "#/components/responses/BadRequest" }
685
+ "401": { $ref: "#/components/responses/Unauthorized" }
686
+ "502": { $ref: "#/components/responses/Upstream" }
687
+ delete:
688
+ tags: [Preferences]
689
+ summary: Clear my profile-name override
690
+ operationId: clearProfileName
691
+ parameters:
692
+ - $ref: "#/components/parameters/accountNumber"
693
+ - $ref: "#/components/parameters/role"
694
+ responses:
695
+ "204": { description: Cleared. }
696
+ "400": { $ref: "#/components/responses/BadRequest" }
697
+ "401": { $ref: "#/components/responses/Unauthorized" }
698
+ "502": { $ref: "#/components/responses/Upstream" }
699
+
700
+ /preferences/role-label/{accountNumber}/{role}:
701
+ put:
702
+ tags: [Preferences]
703
+ summary: Set my role label
704
+ operationId: setRoleLabel
705
+ description: A personal display name for the role card. Blank or absent clears it (the admin display name shows again).
706
+ parameters:
707
+ - $ref: "#/components/parameters/accountNumber"
708
+ - $ref: "#/components/parameters/role"
709
+ requestBody:
710
+ content:
711
+ application/json:
712
+ schema:
713
+ type: object
714
+ properties:
715
+ roleLabel: { type: string, maxLength: 64 }
716
+ example: { roleLabel: "Prod read-only" }
717
+ responses:
718
+ "200":
719
+ description: The saved value (`null` when cleared).
720
+ content:
721
+ application/json:
722
+ schema:
723
+ type: object
724
+ properties:
725
+ roleLabel: { type: [string, "null"] }
726
+ required: [roleLabel]
727
+ "400": { $ref: "#/components/responses/BadRequest" }
728
+ "401": { $ref: "#/components/responses/Unauthorized" }
729
+ "502": { $ref: "#/components/responses/Upstream" }
730
+ delete:
731
+ tags: [Preferences]
732
+ summary: Clear my role label
733
+ operationId: clearRoleLabel
734
+ parameters:
735
+ - $ref: "#/components/parameters/accountNumber"
736
+ - $ref: "#/components/parameters/role"
737
+ responses:
738
+ "204": { description: Cleared. }
739
+ "400": { $ref: "#/components/responses/BadRequest" }
740
+ "401": { $ref: "#/components/responses/Unauthorized" }
741
+ "502": { $ref: "#/components/responses/Upstream" }
742
+
743
+ /network:
744
+ get:
745
+ tags: [Network]
746
+ summary: Network sites
747
+ operationId: listNetworkSites
748
+ description: Whether private-network access is deployed, and the sites a device may enrol in. Split-DNS and VPC detail are admin-only (`GET /admin/network`).
749
+ responses:
750
+ "200":
751
+ description: Site list.
752
+ content:
753
+ application/json:
754
+ schema:
755
+ type: object
756
+ properties:
757
+ enabled: { type: boolean }
758
+ controlUrl:
759
+ type: [string, "null"]
760
+ description: Legacy single-site field — always the first site's control URL.
761
+ sites:
762
+ type: array
763
+ items: { $ref: "#/components/schemas/PublicSite" }
764
+ required: [enabled, controlUrl, sites]
765
+ "401": { $ref: "#/components/responses/Unauthorized" }
766
+
767
+ /network/device-key:
768
+ post:
769
+ tags: [Network]
770
+ summary: Mint a device enrollment key
771
+ operationId: mintDeviceKey
772
+ description: |
773
+ A single-use, 30-minute enrollment key for ONE site, bound to the
774
+ caller's identity (their `sub` becomes the device's network user).
775
+ Reachability is enforced by the grants→ACL reconciler, not here.
776
+ Every mint writes an audit event (`NETWORK_KEY`).
777
+ requestBody:
778
+ content:
779
+ application/json:
780
+ schema:
781
+ type: object
782
+ properties:
783
+ siteId:
784
+ type: string
785
+ description: Defaults to the first site.
786
+ example: { siteId: "dev" }
787
+ responses:
788
+ "200":
789
+ description: The key and where to use it.
790
+ content:
791
+ application/json:
792
+ schema: { $ref: "#/components/schemas/DeviceKey" }
793
+ "400": { $ref: "#/components/responses/BadRequest" }
794
+ "401": { $ref: "#/components/responses/Unauthorized" }
795
+ "501": { $ref: "#/components/responses/NotDeployed" }
796
+ "502": { $ref: "#/components/responses/Upstream" }
797
+
798
+ /network/shares:
799
+ get:
800
+ tags: [Network]
801
+ summary: My dev shares and what teammates share with me
802
+ operationId: listDevShares
803
+ description: |
804
+ Dev shares: a user exposes ONE local port on their laptop to named users/groups on the same
805
+ site for a bounded time. `mine` = shares the caller owns (with grantees); `sharedWithMe` = live
806
+ shares the caller holds directly or through a group. Expired shares are never returned.
807
+ Reachability is enforced by the ACL reconciler from the OWNER'S enrolled device IPs. Answers
808
+ while the network exists even if `devShares` was later disabled (leftover shares stay visible).
809
+ responses:
810
+ "200":
811
+ description: Both lists, soonest expiry first.
812
+ content:
813
+ application/json:
814
+ schema:
815
+ type: object
816
+ properties:
817
+ mine: { type: array, items: { $ref: "#/components/schemas/DevShare" } }
818
+ sharedWithMe: { type: array, items: { $ref: "#/components/schemas/DevShareWithMe" } }
819
+ required: [mine, sharedWithMe]
820
+ "401": { $ref: "#/components/responses/Unauthorized" }
821
+ "501": { $ref: "#/components/responses/NotDeployed" }
822
+ "502": { $ref: "#/components/responses/Upstream" }
823
+ post:
824
+ tags: [Network]
825
+ summary: Start a dev share
826
+ operationId: createDevShare
827
+ description: |
828
+ Writes a `share#<id>` grant per grantee (users and, when `allowGroupTargets`, groups) plus the
829
+ share's definition, then kicks the ACL reconciler so the rule lands within seconds. `hostname`/`ip`
830
+ are the desktop app's own tailnet address — display-only, so grantees get a URL; the rule itself
831
+ targets the owner's enrolled device IPs. `hostname` must be the owner's node name on the share's
832
+ site (`<name>.<siteId>.tail.internal`). Duration is capped by `network.devShares.maxDurationHours`.
833
+ At most 10 live shares per owner, one per port. 501 while `devShares` is disabled.
834
+ requestBody:
835
+ required: true
836
+ content:
837
+ application/json:
838
+ schema:
839
+ type: object
840
+ properties:
841
+ port: { type: integer, minimum: 1, maximum: 65535 }
842
+ label: { type: string, maxLength: 60, description: "Defaults to \"Port <port>\"." }
843
+ siteId: { type: string, description: Defaults to the first site. }
844
+ durationHours: { type: integer, minimum: 1 }
845
+ hostname: { type: string, description: The owner's MagicDNS name. }
846
+ ip: { type: string, description: The owner's tailnet IPv4 (100.64.0.0/10). }
847
+ grantees:
848
+ type: array
849
+ minItems: 1
850
+ maxItems: 50
851
+ items:
852
+ type: object
853
+ properties:
854
+ kind: { type: string, enum: [user, group] }
855
+ id: { type: string }
856
+ required: [kind, id]
857
+ required: [port, durationHours, grantees]
858
+ example:
859
+ port: 4200
860
+ label: Checkout redesign
861
+ siteId: dev
862
+ durationHours: 8
863
+ hostname: devs-macbook.dev.tail.internal
864
+ grantees: [{ kind: user, id: 8d2c…-sub }, { kind: group, id: 1f4a…-group }]
865
+ responses:
866
+ "201":
867
+ description: The new share as its owner sees it.
868
+ content:
869
+ application/json:
870
+ schema:
871
+ type: object
872
+ properties:
873
+ share: { $ref: "#/components/schemas/DevShare" }
874
+ required: [share]
875
+ "400": { $ref: "#/components/responses/BadRequest" }
876
+ "401": { $ref: "#/components/responses/Unauthorized" }
877
+ "501": { $ref: "#/components/responses/NotDeployed" }
878
+ "502": { $ref: "#/components/responses/Upstream" }
879
+
880
+ /network/shares/directory:
881
+ get:
882
+ tags: [Network]
883
+ summary: Who a dev share can target
884
+ operationId: listDevShareDirectory
885
+ description: |
886
+ The one directory read open to non-admins, and deliberately thin: every user's sub + email
887
+ (invited-but-unconfirmed users omitted) and every group's id, name and member count. 501 while
888
+ `devShares` is disabled.
889
+ responses:
890
+ "200":
891
+ description: Users and groups, sorted by email / name.
892
+ content:
893
+ application/json:
894
+ schema: { $ref: "#/components/schemas/DevShareDirectory" }
895
+ "401": { $ref: "#/components/responses/Unauthorized" }
896
+ "501": { $ref: "#/components/responses/NotDeployed" }
897
+ "502": { $ref: "#/components/responses/Upstream" }
898
+
899
+ /network/shares/{shareId}:
900
+ delete:
901
+ tags: [Network]
902
+ summary: Stop a dev share
903
+ operationId: deleteDevShare
904
+ description: |
905
+ Owner or admin. Every grant row and the definition go; grantees who lose access get a revocation
906
+ notice of kind `SHARE` (via `OWNER`, or `ADMIN` when an admin stopped it). Kicks the reconciler.
907
+ Works while the network exists even if `devShares` was later disabled.
908
+ parameters:
909
+ - name: shareId
910
+ in: path
911
+ required: true
912
+ schema: { type: string, pattern: "^[a-f0-9]{12}$" }
913
+ responses:
914
+ "204": { description: Stopped. }
915
+ "401": { $ref: "#/components/responses/Unauthorized" }
916
+ "403": { $ref: "#/components/responses/Forbidden" }
917
+ "404": { $ref: "#/components/responses/NotFound" }
918
+ "501": { $ref: "#/components/responses/NotDeployed" }
919
+ "502": { $ref: "#/components/responses/Upstream" }
920
+
921
+ /resources:
922
+ get:
923
+ tags: [Resources]
924
+ summary: My reachable resources
925
+ operationId: listReachableResources
926
+ description: Private-network resources the caller holds an active grant on — the only place connection details (`cidr`, `ports`, `dnsName`) are exposed to non-admins.
927
+ responses:
928
+ "200":
929
+ description: Reachable resources, sorted by name.
930
+ content:
931
+ application/json:
932
+ schema:
933
+ type: object
934
+ properties:
935
+ resources:
936
+ type: array
937
+ items: { $ref: "#/components/schemas/ReachableResource" }
938
+ required: [resources]
939
+ "401": { $ref: "#/components/responses/Unauthorized" }
940
+ "502": { $ref: "#/components/responses/Upstream" }
941
+
942
+ /resources/expiry:
943
+ get:
944
+ tags: [Resources]
945
+ summary: My resource expiry notices
946
+ operationId: listResourceExpiryNotices
947
+ responses:
948
+ "200":
949
+ description: Temporary resource grants nearing / past their end.
950
+ content:
951
+ application/json:
952
+ schema:
953
+ type: object
954
+ properties:
955
+ expiring:
956
+ type: array
957
+ items: { $ref: "#/components/schemas/ResourceExpiryNotice" }
958
+ expired:
959
+ type: array
960
+ items: { $ref: "#/components/schemas/ResourceExpiryNotice" }
961
+ required: [expiring, expired]
962
+ "401": { $ref: "#/components/responses/Unauthorized" }
963
+ "502": { $ref: "#/components/responses/Upstream" }
964
+
965
+ /resources/expiry/seen:
966
+ post:
967
+ tags: [Resources]
968
+ summary: Acknowledge resource expiry notices
969
+ operationId: markResourceExpiryNoticesSeen
970
+ responses:
971
+ "200":
972
+ description: How many notices were newly marked seen.
973
+ content:
974
+ application/json:
975
+ schema: { $ref: "#/components/schemas/Cleared" }
976
+ "401": { $ref: "#/components/responses/Unauthorized" }
977
+ "502": { $ref: "#/components/responses/Upstream" }
978
+
979
+ /notifications/revocations:
980
+ get:
981
+ tags: [Notifications]
982
+ summary: My revocation notices
983
+ operationId: listRevocationNotices
984
+ description: Access the caller lost (admin revoke, group change, reapproval, cascade), newest first. Kept 30 days.
985
+ responses:
986
+ "200":
987
+ description: Revocation notices.
988
+ content:
989
+ application/json:
990
+ schema:
991
+ type: object
992
+ properties:
993
+ notices:
994
+ type: array
995
+ items: { $ref: "#/components/schemas/RevocationNotice" }
996
+ required: [notices]
997
+ "401": { $ref: "#/components/responses/Unauthorized" }
998
+ "502": { $ref: "#/components/responses/Upstream" }
999
+
1000
+ /notifications/revocations/seen:
1001
+ post:
1002
+ tags: [Notifications]
1003
+ summary: Acknowledge revocation notices
1004
+ operationId: markRevocationNoticesSeen
1005
+ responses:
1006
+ "200":
1007
+ description: How many notices were newly marked seen.
1008
+ content:
1009
+ application/json:
1010
+ schema: { $ref: "#/components/schemas/Cleared" }
1011
+ "401": { $ref: "#/components/responses/Unauthorized" }
1012
+ "502": { $ref: "#/components/responses/Upstream" }
1013
+
1014
+ # ---------------------------------------------------------------- admin ---
1015
+
1016
+ /admin/setup:
1017
+ get:
1018
+ tags: ["Admin: setup"]
1019
+ summary: Setup checklist state
1020
+ operationId: getSetupStatus
1021
+ description: First-run checklist inputs, aggregated live — items check themselves off as the deployment fills in.
1022
+ responses:
1023
+ "200":
1024
+ description: Setup status.
1025
+ content:
1026
+ application/json:
1027
+ schema: { $ref: "#/components/schemas/SetupStatus" }
1028
+ "401": { $ref: "#/components/responses/Unauthorized" }
1029
+ "403": { $ref: "#/components/responses/Forbidden" }
1030
+ "502": { $ref: "#/components/responses/Upstream" }
1031
+
1032
+ /admin/branding:
1033
+ put:
1034
+ tags: ["Admin: setup"]
1035
+ summary: Save the branding overlay
1036
+ operationId: saveBranding
1037
+ description: Writes `/branding.json` in the web bucket (the SPA fetches it from the web origin at boot — there is no GET here). `dismissed` hides the first-admin theme wizard.
1038
+ requestBody:
1039
+ required: true
1040
+ content:
1041
+ application/json:
1042
+ schema:
1043
+ type: object
1044
+ description: At least one of `branding`, `dismissed`.
1045
+ properties:
1046
+ branding: { $ref: "#/components/schemas/BrandingOverlay" }
1047
+ dismissed: { type: boolean }
1048
+ example: { branding: { projectName: "Acme Access", primaryColor: "#3e63dd" }, dismissed: true }
1049
+ responses:
1050
+ "204": { description: Saved. }
1051
+ "400": { $ref: "#/components/responses/BadRequest" }
1052
+ "401": { $ref: "#/components/responses/Unauthorized" }
1053
+ "403": { $ref: "#/components/responses/Forbidden" }
1054
+ "501": { $ref: "#/components/responses/NotDeployed" }
1055
+ "502": { $ref: "#/components/responses/Upstream" }
1056
+
1057
+ /admin/accounts:
1058
+ get:
1059
+ tags: ["Admin: accounts & roles"]
1060
+ summary: List the catalog
1061
+ operationId: adminListAccounts
1062
+ description: |
1063
+ Every registered account with its roles; each role carries its unexpired-grantee count.
1064
+ With `limit`, one page of the list contract: sorts `position` (the admin order, default), `name`, `number`; facets `environment`, `status`, `main` (`true`/`false`), plus `tenant`, `project`, `stage` on a deployment with account dimensions (`unclassified` for an account without one).
1065
+ parameters:
1066
+ - $ref: "#/components/parameters/listQ"
1067
+ - $ref: "#/components/parameters/listFilter"
1068
+ - $ref: "#/components/parameters/listSort"
1069
+ - $ref: "#/components/parameters/listLimit"
1070
+ - $ref: "#/components/parameters/listCursor"
1071
+ responses:
1072
+ "200":
1073
+ description: The catalog — the whole list, or one page when `limit` was passed.
1074
+ content:
1075
+ application/json:
1076
+ schema:
1077
+ oneOf:
1078
+ - type: object
1079
+ properties:
1080
+ accounts:
1081
+ type: array
1082
+ items: { $ref: "#/components/schemas/AdminAccount" }
1083
+ required: [accounts]
1084
+ - $ref: "#/components/schemas/AdminAccountPage"
1085
+ "400": { $ref: "#/components/responses/BadRequest" }
1086
+ "401": { $ref: "#/components/responses/Unauthorized" }
1087
+ "403": { $ref: "#/components/responses/Forbidden" }
1088
+ "502": { $ref: "#/components/responses/Upstream" }
1089
+ post:
1090
+ tags: ["Admin: accounts & roles"]
1091
+ summary: Register an account
1092
+ operationId: adminCreateAccount
1093
+ requestBody:
1094
+ required: true
1095
+ content:
1096
+ application/json:
1097
+ schema: { $ref: "#/components/schemas/AccountCreate" }
1098
+ example: { accountNumber: "123456789012", name: "Production", environment: "prod", profileName: "acme-prod" }
1099
+ responses:
1100
+ "201":
1101
+ description: The account.
1102
+ content:
1103
+ application/json:
1104
+ schema: { $ref: "#/components/schemas/AccountEnvelope" }
1105
+ "200":
1106
+ description: Already registered with the same values (a retry); the stored account, nothing changed. Different values are a `409`.
1107
+ content:
1108
+ application/json:
1109
+ schema: { $ref: "#/components/schemas/AccountEnvelope" }
1110
+ "400": { $ref: "#/components/responses/BadRequest" }
1111
+ "401": { $ref: "#/components/responses/Unauthorized" }
1112
+ "403": { $ref: "#/components/responses/Forbidden" }
1113
+ "409": { $ref: "#/components/responses/Conflict" }
1114
+ "502": { $ref: "#/components/responses/Upstream" }
1115
+
1116
+ /admin/dashboard-layout:
1117
+ get:
1118
+ tags: ["Admin: accounts & roles"]
1119
+ summary: The deployment-wide dashboard layout
1120
+ operationId: adminGetDashboardLayout
1121
+ description: |
1122
+ How every user's dashboard is laid out. `auto` (the default): a user gets Main / Favorites / Recent and the
1123
+ search once they hold an account an admin took off the Main section, and the plain list until then — so a
1124
+ deployment that never touches the Main flag looks as it always did. `sections`: everyone gets the sections.
1125
+ `plain`: nobody does. The per-account "Show in the Main section" flag still decides what sits in Main.
1126
+ responses:
1127
+ "200":
1128
+ description: The current mode.
1129
+ content:
1130
+ application/json:
1131
+ schema: { $ref: "#/components/schemas/DashboardLayout" }
1132
+ "401": { $ref: "#/components/responses/Unauthorized" }
1133
+ "403": { $ref: "#/components/responses/Forbidden" }
1134
+ "502": { $ref: "#/components/responses/Upstream" }
1135
+ put:
1136
+ tags: ["Admin: accounts & roles"]
1137
+ summary: Set the deployment-wide dashboard layout
1138
+ operationId: adminSetDashboardLayout
1139
+ description: Takes effect on each user's next dashboard load; a change is recorded in the activity log.
1140
+ requestBody:
1141
+ required: true
1142
+ content:
1143
+ application/json:
1144
+ schema: { $ref: "#/components/schemas/DashboardLayout" }
1145
+ responses:
1146
+ "200":
1147
+ description: The stored mode.
1148
+ content:
1149
+ application/json:
1150
+ schema: { $ref: "#/components/schemas/DashboardLayout" }
1151
+ "400": { $ref: "#/components/responses/BadRequest" }
1152
+ "401": { $ref: "#/components/responses/Unauthorized" }
1153
+ "403": { $ref: "#/components/responses/Forbidden" }
1154
+ "502": { $ref: "#/components/responses/Upstream" }
1155
+ /admin/accounts/order:
1156
+ put:
1157
+ tags: ["Admin: accounts & roles"]
1158
+ summary: Set the display order of the accounts
1159
+ operationId: adminReorderAccounts
1160
+ description: The whole list, first to last; each account's position becomes its index, and each listed role's its position inside its account. This is the order every page shows to every user (Your access and the admin tabs). Accounts left out, and roles left out of an account's list, lose any position they had and list after the ordered ones, by name.
1161
+ requestBody:
1162
+ required: true
1163
+ content:
1164
+ application/json:
1165
+ schema: { $ref: "#/components/schemas/AccountOrder" }
1166
+ example: { accounts: [{ accountNumber: "111111111111", roles: ["DevRole", "AdminRole"] }, { accountNumber: "222222222222" }] }
1167
+ responses:
1168
+ "200":
1169
+ description: The ordered accounts as stored, in the new order — only the ones the request listed, never the whole catalog.
1170
+ content:
1171
+ application/json:
1172
+ schema:
1173
+ type: object
1174
+ properties:
1175
+ accounts:
1176
+ type: array
1177
+ items: { $ref: "#/components/schemas/AdminAccount" }
1178
+ required: [accounts]
1179
+ "400": { $ref: "#/components/responses/BadRequest" }
1180
+ "401": { $ref: "#/components/responses/Unauthorized" }
1181
+ "403": { $ref: "#/components/responses/Forbidden" }
1182
+ "404": { $ref: "#/components/responses/NotFound" }
1183
+ /admin/accounts/{accountNumber}:
1184
+ get:
1185
+ tags: ["Admin: accounts & roles"]
1186
+ summary: Get one account
1187
+ operationId: adminGetAccount
1188
+ parameters:
1189
+ - $ref: "#/components/parameters/accountNumber"
1190
+ responses:
1191
+ "200":
1192
+ description: The account with its roles.
1193
+ content:
1194
+ application/json:
1195
+ schema: { $ref: "#/components/schemas/AccountEnvelope" }
1196
+ "401": { $ref: "#/components/responses/Unauthorized" }
1197
+ "403": { $ref: "#/components/responses/Forbidden" }
1198
+ "404": { $ref: "#/components/responses/NotFound" }
1199
+ "502": { $ref: "#/components/responses/Upstream" }
1200
+ patch:
1201
+ tags: ["Admin: accounts & roles"]
1202
+ summary: Update an account
1203
+ operationId: adminUpdateAccount
1204
+ description: At least one field. `profileName` is the `~/.aws` profile users get when they hold exactly one role here; `""` clears it; it must be unique across accounts and roles (`409`).
1205
+ parameters:
1206
+ - $ref: "#/components/parameters/accountNumber"
1207
+ requestBody:
1208
+ required: true
1209
+ content:
1210
+ application/json:
1211
+ schema: { $ref: "#/components/schemas/AccountPatch" }
1212
+ example: { name: "Production (EU)", status: "active" }
1213
+ responses:
1214
+ "200":
1215
+ description: The updated account.
1216
+ content:
1217
+ application/json:
1218
+ schema: { $ref: "#/components/schemas/AccountEnvelope" }
1219
+ "400": { $ref: "#/components/responses/BadRequest" }
1220
+ "401": { $ref: "#/components/responses/Unauthorized" }
1221
+ "403": { $ref: "#/components/responses/Forbidden" }
1222
+ "404": { $ref: "#/components/responses/NotFound" }
1223
+ "409": { $ref: "#/components/responses/Conflict" }
1224
+ "502": { $ref: "#/components/responses/Upstream" }
1225
+ delete:
1226
+ tags: ["Admin: accounts & roles"]
1227
+ summary: Remove an account
1228
+ operationId: adminDeleteAccount
1229
+ description: "**Cascades**: for each of the account's roles, every grant is revoked (losses are noticed), group bundles drop it and its open requests are denied with the reason; then the roles and the account go. Refused with 409 while the account still has network resources — remove those first. Grants go before the catalog rows, so a call that failed halfway can be repeated."
1230
+ parameters:
1231
+ - $ref: "#/components/parameters/accountNumber"
1232
+ responses:
1233
+ "204": { description: Removed. }
1234
+ "401": { $ref: "#/components/responses/Unauthorized" }
1235
+ "403": { $ref: "#/components/responses/Forbidden" }
1236
+ "404": { $ref: "#/components/responses/NotFound" }
1237
+ "409": { $ref: "#/components/responses/Conflict" }
1238
+ "502": { $ref: "#/components/responses/Upstream" }
1239
+
1240
+ /admin/accounts/{accountNumber}/roles:
1241
+ post:
1242
+ tags: ["Admin: accounts & roles"]
1243
+ summary: Add a role
1244
+ operationId: adminCreateRole
1245
+ description: Registers a role users can be granted. Auto-registers the account if it is not catalogued yet. The ARN's account must equal the path's `accountNumber`.
1246
+ parameters:
1247
+ - $ref: "#/components/parameters/accountNumber"
1248
+ requestBody:
1249
+ required: true
1250
+ content:
1251
+ application/json:
1252
+ schema: { $ref: "#/components/schemas/RoleCreate" }
1253
+ example: { roleName: "ReadOnly", displayName: "Read only", roleArn: "arn:aws:iam::123456789012:role/ReadOnly", policyTier: "READ_ONLY", sessionDurationSeconds: 3600, icon: "view" }
1254
+ responses:
1255
+ "201":
1256
+ description: The role.
1257
+ content:
1258
+ application/json:
1259
+ schema: { $ref: "#/components/schemas/RoleEnvelope" }
1260
+ "200":
1261
+ description: Already registered with the same values (a retry); the stored role, nothing changed. Different values, or a name that differs only in case, are a `409`.
1262
+ content:
1263
+ application/json:
1264
+ schema: { $ref: "#/components/schemas/RoleEnvelope" }
1265
+ "400": { $ref: "#/components/responses/BadRequest" }
1266
+ "401": { $ref: "#/components/responses/Unauthorized" }
1267
+ "403": { $ref: "#/components/responses/Forbidden" }
1268
+ "409": { $ref: "#/components/responses/Conflict" }
1269
+ "502": { $ref: "#/components/responses/Upstream" }
1270
+
1271
+ /admin/accounts/{accountNumber}/roles/{roleName}:
1272
+ patch:
1273
+ tags: ["Admin: accounts & roles"]
1274
+ summary: Update a role
1275
+ operationId: adminUpdateRole
1276
+ description: At least one field. `sessionDurationSeconds` (900–43200) is what vends ask STS for; `profileName` must be unique across accounts and roles (`409`).
1277
+ parameters:
1278
+ - $ref: "#/components/parameters/accountNumber"
1279
+ - $ref: "#/components/parameters/roleName"
1280
+ requestBody:
1281
+ required: true
1282
+ content:
1283
+ application/json:
1284
+ schema: { $ref: "#/components/schemas/RolePatch" }
1285
+ example: { displayName: "Read only (EU)", sessionDurationSeconds: 7200, color: "#3e63dd" }
1286
+ responses:
1287
+ "200":
1288
+ description: The updated role.
1289
+ content:
1290
+ application/json:
1291
+ schema: { $ref: "#/components/schemas/RoleEnvelope" }
1292
+ "400": { $ref: "#/components/responses/BadRequest" }
1293
+ "401": { $ref: "#/components/responses/Unauthorized" }
1294
+ "403": { $ref: "#/components/responses/Forbidden" }
1295
+ "404": { $ref: "#/components/responses/NotFound" }
1296
+ "409": { $ref: "#/components/responses/Conflict" }
1297
+ "502": { $ref: "#/components/responses/Upstream" }
1298
+ delete:
1299
+ tags: ["Admin: accounts & roles"]
1300
+ summary: Remove a role
1301
+ operationId: adminDeleteRole
1302
+ description: "**Cascades**: every grant on the role is revoked (losses are noticed), groups bundling it drop it (a group left empty is removed), and its open requests and reviews are denied with the reason. Grants go before the catalog row, so a call that failed halfway can be repeated: an already-removed role still sweeps its leftovers before the 404."
1303
+ parameters:
1304
+ - $ref: "#/components/parameters/accountNumber"
1305
+ - $ref: "#/components/parameters/roleName"
1306
+ responses:
1307
+ "204": { description: Removed. }
1308
+ "401": { $ref: "#/components/responses/Unauthorized" }
1309
+ "403": { $ref: "#/components/responses/Forbidden" }
1310
+ "404": { $ref: "#/components/responses/NotFound" }
1311
+ "502": { $ref: "#/components/responses/Upstream" }
1312
+
1313
+ /admin/accounts/{accountNumber}/roles/{roleName}/test-session:
1314
+ post:
1315
+ tags: ["Admin: accounts & roles"]
1316
+ summary: Test a session length
1317
+ operationId: adminTestSession
1318
+ description: "Tries `AssumeRoleWithWebIdentity` as the calling admin for `durationSeconds`, discarding the credentials. `ok: false` carries STS's message (usually the IAM role's MaxSessionDuration is lower)."
1319
+ parameters:
1320
+ - $ref: "#/components/parameters/accountNumber"
1321
+ - $ref: "#/components/parameters/roleName"
1322
+ requestBody:
1323
+ required: true
1324
+ content:
1325
+ application/json:
1326
+ schema:
1327
+ type: object
1328
+ properties:
1329
+ durationSeconds: { type: integer, minimum: 900, maximum: 43200 }
1330
+ required: [durationSeconds]
1331
+ example: { durationSeconds: 14400 }
1332
+ responses:
1333
+ "200":
1334
+ description: The outcome.
1335
+ content:
1336
+ application/json:
1337
+ schema: { $ref: "#/components/schemas/TestSessionResult" }
1338
+ "400": { $ref: "#/components/responses/BadRequest" }
1339
+ "401": { $ref: "#/components/responses/Unauthorized" }
1340
+ "403": { $ref: "#/components/responses/Forbidden" }
1341
+ "502": { $ref: "#/components/responses/Upstream" }
1342
+
1343
+ /admin/accounts/{accountNumber}/roles/{roleName}/grants:
1344
+ get:
1345
+ tags: ["Admin: grants"]
1346
+ summary: Who holds this role
1347
+ operationId: adminListGrantees
1348
+ parameters:
1349
+ - $ref: "#/components/parameters/accountNumber"
1350
+ - $ref: "#/components/parameters/roleName"
1351
+ responses:
1352
+ "200":
1353
+ description: Holders, direct and via groups.
1354
+ content:
1355
+ application/json:
1356
+ schema:
1357
+ type: object
1358
+ properties:
1359
+ grantees:
1360
+ type: array
1361
+ items: { $ref: "#/components/schemas/Grantee" }
1362
+ required: [grantees]
1363
+ "401": { $ref: "#/components/responses/Unauthorized" }
1364
+ "403": { $ref: "#/components/responses/Forbidden" }
1365
+ "502": { $ref: "#/components/responses/Upstream" }
1366
+
1367
+ /admin/accounts/{accountNumber}/roles/{roleName}/grants/{userId}:
1368
+ put:
1369
+ tags: ["Admin: grants"]
1370
+ summary: Grant a role
1371
+ operationId: adminAssignRole
1372
+ description: Idempotent. `durationHours` makes the grant temporary; re-granting overwrites the expiry (the "extend" path). A long-term grant is never downgraded to temporary. `userId` may be a service user's client id.
1373
+ parameters:
1374
+ - $ref: "#/components/parameters/accountNumber"
1375
+ - $ref: "#/components/parameters/roleName"
1376
+ - $ref: "#/components/parameters/userId"
1377
+ requestBody:
1378
+ content:
1379
+ application/json:
1380
+ schema:
1381
+ type: object
1382
+ properties:
1383
+ durationHours: { $ref: "#/components/schemas/DurationHours" }
1384
+ example: { durationHours: 24 }
1385
+ responses:
1386
+ "200":
1387
+ description: The grant as stored.
1388
+ content:
1389
+ application/json:
1390
+ schema:
1391
+ type: object
1392
+ properties:
1393
+ grant: { $ref: "#/components/schemas/Grant" }
1394
+ required: [grant]
1395
+ "400": { $ref: "#/components/responses/BadRequest" }
1396
+ "401": { $ref: "#/components/responses/Unauthorized" }
1397
+ "403": { $ref: "#/components/responses/Forbidden" }
1398
+ "404": { $ref: "#/components/responses/NotFound" }
1399
+ "502": { $ref: "#/components/responses/Upstream" }
1400
+ delete:
1401
+ tags: ["Admin: grants"]
1402
+ summary: Revoke a role
1403
+ operationId: adminRevokeRole
1404
+ description: Removes the direct grant only — group-provided access stays (change the group instead). The loss is noticed if it ends the user's access.
1405
+ parameters:
1406
+ - $ref: "#/components/parameters/accountNumber"
1407
+ - $ref: "#/components/parameters/roleName"
1408
+ - $ref: "#/components/parameters/userId"
1409
+ responses:
1410
+ "204": { description: Revoked. }
1411
+ "401": { $ref: "#/components/responses/Unauthorized" }
1412
+ "403": { $ref: "#/components/responses/Forbidden" }
1413
+ "404": { $ref: "#/components/responses/NotFound" }
1414
+ "502": { $ref: "#/components/responses/Upstream" }
1415
+
1416
+ /admin/grants/bulk:
1417
+ post:
1418
+ tags: ["Admin: grants"]
1419
+ summary: Grant roles in bulk
1420
+ operationId: adminBulkAssign
1421
+ description: Up to 20 roles × 50 users in one call. Always `200` with a per-pair result — one bad pair never fails the rest.
1422
+ requestBody:
1423
+ required: true
1424
+ content:
1425
+ application/json:
1426
+ schema:
1427
+ type: object
1428
+ properties:
1429
+ userIds: { type: array, items: { type: string }, minItems: 1, maxItems: 50 }
1430
+ roles: { type: array, items: { $ref: "#/components/schemas/RoleRef" }, minItems: 1, maxItems: 20 }
1431
+ durationHours: { $ref: "#/components/schemas/DurationHours" }
1432
+ required: [userIds, roles]
1433
+ example: { userIds: ["1a2b3c4d-0000-4000-8000-000000000000"], roles: [{ accountNumber: "123456789012", roleName: "ReadOnly" }], durationHours: 168 }
1434
+ responses:
1435
+ "200":
1436
+ description: Per-pair results.
1437
+ content:
1438
+ application/json:
1439
+ schema:
1440
+ type: object
1441
+ properties:
1442
+ results:
1443
+ type: array
1444
+ items: { $ref: "#/components/schemas/BulkAssignResult" }
1445
+ required: [results]
1446
+ "400": { $ref: "#/components/responses/BadRequest" }
1447
+ "401": { $ref: "#/components/responses/Unauthorized" }
1448
+ "403": { $ref: "#/components/responses/Forbidden" }
1449
+ "502": { $ref: "#/components/responses/Upstream" }
1450
+
1451
+ /admin/grants/bulk-revoke:
1452
+ post:
1453
+ tags: ["Admin: grants"]
1454
+ summary: Revoke roles in bulk
1455
+ operationId: adminBulkRevoke
1456
+ description: Always `200` with per-pair results — pairs with no direct grant are `SKIPPED`; group-provided pairs `FAILED` (membership, not a direct revoke, removes those).
1457
+ requestBody:
1458
+ required: true
1459
+ content:
1460
+ application/json:
1461
+ schema:
1462
+ type: object
1463
+ properties:
1464
+ userIds: { type: array, items: { type: string }, minItems: 1, maxItems: 50 }
1465
+ roles: { type: array, items: { $ref: "#/components/schemas/RoleRef" }, minItems: 1, maxItems: 20 }
1466
+ required: [userIds, roles]
1467
+ example: { userIds: ["1a2b3c4d-0000-4000-8000-000000000000"], roles: [{ accountNumber: "123456789012", roleName: "ReadOnly" }] }
1468
+ responses:
1469
+ "200":
1470
+ description: Per-pair results.
1471
+ content:
1472
+ application/json:
1473
+ schema:
1474
+ type: object
1475
+ properties:
1476
+ results:
1477
+ type: array
1478
+ items: { $ref: "#/components/schemas/BulkRevokeResult" }
1479
+ required: [results]
1480
+ "400": { $ref: "#/components/responses/BadRequest" }
1481
+ "401": { $ref: "#/components/responses/Unauthorized" }
1482
+ "403": { $ref: "#/components/responses/Forbidden" }
1483
+ "502": { $ref: "#/components/responses/Upstream" }
1484
+
1485
+ /admin/users:
1486
+ get:
1487
+ tags: ["Admin: users"]
1488
+ summary: List users
1489
+ operationId: adminListUsers
1490
+ description: |
1491
+ The Cognito directory (source of truth — a user with no grants still appears) with each user's effective roles and resources.
1492
+ With `limit`, one page of the list contract: sorts `email` (default), `lastSeen`; facets `admin` (`admin`/`member`), `status` (`invited`/`active`).
1493
+ parameters:
1494
+ - $ref: "#/components/parameters/listQ"
1495
+ - $ref: "#/components/parameters/listFilter"
1496
+ - $ref: "#/components/parameters/listSort"
1497
+ - $ref: "#/components/parameters/listLimit"
1498
+ - $ref: "#/components/parameters/listCursor"
1499
+ responses:
1500
+ "200":
1501
+ description: Users — the whole list, or one page when `limit` was passed.
1502
+ content:
1503
+ application/json:
1504
+ schema:
1505
+ oneOf:
1506
+ - type: object
1507
+ properties:
1508
+ users:
1509
+ type: array
1510
+ items: { $ref: "#/components/schemas/User" }
1511
+ required: [users]
1512
+ - $ref: "#/components/schemas/UserPage"
1513
+ "400": { $ref: "#/components/responses/BadRequest" }
1514
+ "401": { $ref: "#/components/responses/Unauthorized" }
1515
+ "403": { $ref: "#/components/responses/Forbidden" }
1516
+ "502": { $ref: "#/components/responses/Upstream" }
1517
+ post:
1518
+ tags: ["Admin: users"]
1519
+ summary: Invite a user
1520
+ operationId: adminCreateUser
1521
+ description: Creates the Cognito user and, unless `sendEmail` is `false`, **sends the invitation email**. The response carries the sign-up link either way — the same `/login#inv=…` link the email holds, valid 7 days; anyone holding it can set the password. `409` if the email is taken.
1522
+ requestBody:
1523
+ required: true
1524
+ content:
1525
+ application/json:
1526
+ schema:
1527
+ type: object
1528
+ properties:
1529
+ email: { type: string, format: email }
1530
+ admin: { type: boolean, default: false, description: Also add to the `admins` group. }
1531
+ sendEmail: { type: boolean, default: true, description: "`false`: Cognito emails nothing and the response carries `signupLink` for you to pass on." }
1532
+ required: [email]
1533
+ example: { email: "new.user@example.com", admin: false, sendEmail: true }
1534
+ responses:
1535
+ "201":
1536
+ description: "The new user (`pendingInvite: true`), plus `signupLink` only when `sendEmail` was `false`."
1537
+ content:
1538
+ application/json:
1539
+ schema:
1540
+ type: object
1541
+ properties:
1542
+ user: { $ref: "#/components/schemas/User" }
1543
+ signupLink: { type: string, description: "Only when `sendEmail` was `false` — it carries the temporary password. Absolute when the deploy has a web domain, else path-only (`/login#inv=…`)." }
1544
+ required: [user]
1545
+ "400": { $ref: "#/components/responses/BadRequest" }
1546
+ "401": { $ref: "#/components/responses/Unauthorized" }
1547
+ "403": { $ref: "#/components/responses/Forbidden" }
1548
+ "409": { $ref: "#/components/responses/Conflict" }
1549
+ "502": { $ref: "#/components/responses/Upstream" }
1550
+
1551
+ /admin/users/bulk:
1552
+ post:
1553
+ tags: ["Admin: users"]
1554
+ summary: Invite users in bulk
1555
+ operationId: adminBulkCreateUsers
1556
+ description: Up to 50 emails. Always `200` with a per-row `CREATED`/`FAILED` result — one taken email never fails the rest. Each `CREATED` row sent a real invitation email, or — with `sendEmail` `false` — carries its `signupLink` instead.
1557
+ requestBody:
1558
+ required: true
1559
+ content:
1560
+ application/json:
1561
+ schema:
1562
+ type: object
1563
+ properties:
1564
+ emails: { type: array, items: { type: string, format: email }, minItems: 1, maxItems: 50 }
1565
+ admin: { type: boolean, default: false }
1566
+ sendEmail: { type: boolean, default: true }
1567
+ required: [emails]
1568
+ example: { emails: ["a@example.com", "b@example.com"], admin: false }
1569
+ responses:
1570
+ "200":
1571
+ description: Per-row results.
1572
+ content:
1573
+ application/json:
1574
+ schema:
1575
+ type: object
1576
+ properties:
1577
+ results:
1578
+ type: array
1579
+ items: { $ref: "#/components/schemas/BulkCreateResult" }
1580
+ required: [results]
1581
+ "400": { $ref: "#/components/responses/BadRequest" }
1582
+ "401": { $ref: "#/components/responses/Unauthorized" }
1583
+ "403": { $ref: "#/components/responses/Forbidden" }
1584
+ "502": { $ref: "#/components/responses/Upstream" }
1585
+
1586
+ /admin/users/bulk-delete:
1587
+ post:
1588
+ tags: ["Admin: users"]
1589
+ summary: Delete users in bulk
1590
+ operationId: adminBulkDeleteUsers
1591
+ description: Up to 50 users, each with the full delete cascade. Always `200` with per-row results; the caller's own account is refused so a sweep can never lock everyone out.
1592
+ requestBody:
1593
+ required: true
1594
+ content:
1595
+ application/json:
1596
+ schema:
1597
+ type: object
1598
+ properties:
1599
+ userIds: { type: array, items: { type: string }, minItems: 1, maxItems: 50 }
1600
+ required: [userIds]
1601
+ example: { userIds: ["1a2b3c4d-0000-4000-8000-000000000000"] }
1602
+ responses:
1603
+ "200":
1604
+ description: Per-row results.
1605
+ content:
1606
+ application/json:
1607
+ schema:
1608
+ type: object
1609
+ properties:
1610
+ results:
1611
+ type: array
1612
+ items: { $ref: "#/components/schemas/BulkDeleteResult" }
1613
+ required: [results]
1614
+ "400": { $ref: "#/components/responses/BadRequest" }
1615
+ "401": { $ref: "#/components/responses/Unauthorized" }
1616
+ "403": { $ref: "#/components/responses/Forbidden" }
1617
+ "502": { $ref: "#/components/responses/Upstream" }
1618
+
1619
+ /admin/users/{userId}:
1620
+ get:
1621
+ tags: ["Admin: users"]
1622
+ summary: One user with all their access
1623
+ operationId: adminGetUser
1624
+ description: The listing caps each user's `roles` and `resources` at 50 entries (`roleCount` / `resourceCount` carry the totals); this returns every entry for one user.
1625
+ parameters:
1626
+ - $ref: "#/components/parameters/userId"
1627
+ responses:
1628
+ "200":
1629
+ description: The user.
1630
+ content:
1631
+ application/json:
1632
+ schema:
1633
+ type: object
1634
+ properties:
1635
+ user: { $ref: "#/components/schemas/User" }
1636
+ required: [user]
1637
+ "401": { $ref: "#/components/responses/Unauthorized" }
1638
+ "403": { $ref: "#/components/responses/Forbidden" }
1639
+ "404": { $ref: "#/components/responses/NotFound" }
1640
+ "502": { $ref: "#/components/responses/Upstream" }
1641
+ patch:
1642
+ tags: ["Admin: users"]
1643
+ summary: Update a user
1644
+ operationId: adminUpdateUser
1645
+ description: Change the email and/or `admins`-group membership. Removing the last admin is refused (`409`).
1646
+ parameters:
1647
+ - $ref: "#/components/parameters/userId"
1648
+ requestBody:
1649
+ required: true
1650
+ content:
1651
+ application/json:
1652
+ schema:
1653
+ type: object
1654
+ description: At least one field.
1655
+ properties:
1656
+ email: { type: string, format: email }
1657
+ admin: { type: boolean }
1658
+ example: { admin: true }
1659
+ responses:
1660
+ "204": { description: Updated. }
1661
+ "400": { $ref: "#/components/responses/BadRequest" }
1662
+ "401": { $ref: "#/components/responses/Unauthorized" }
1663
+ "403": { $ref: "#/components/responses/Forbidden" }
1664
+ "404": { $ref: "#/components/responses/NotFound" }
1665
+ "409": { $ref: "#/components/responses/Conflict" }
1666
+ "502": { $ref: "#/components/responses/Upstream" }
1667
+ delete:
1668
+ tags: ["Admin: users"]
1669
+ summary: Delete a user
1670
+ operationId: adminDeleteUser
1671
+ description: "**Cascades**: grants, group memberships, preferences and access requests go too."
1672
+ parameters:
1673
+ - $ref: "#/components/parameters/userId"
1674
+ responses:
1675
+ "204": { description: Deleted. }
1676
+ "401": { $ref: "#/components/responses/Unauthorized" }
1677
+ "403": { $ref: "#/components/responses/Forbidden" }
1678
+ "404": { $ref: "#/components/responses/NotFound" }
1679
+ "409": { $ref: "#/components/responses/Conflict" }
1680
+ "502": { $ref: "#/components/responses/Upstream" }
1681
+
1682
+ /admin/users/{userId}/grants:
1683
+ get:
1684
+ tags: ["Admin: users"]
1685
+ summary: A user's role grants
1686
+ operationId: adminListUserGrants
1687
+ description: Everything the user holds, direct and via groups (audit view). Works for service users too.
1688
+ parameters:
1689
+ - $ref: "#/components/parameters/userId"
1690
+ responses:
1691
+ "200":
1692
+ description: Grants.
1693
+ content:
1694
+ application/json:
1695
+ schema:
1696
+ type: object
1697
+ properties:
1698
+ grants:
1699
+ type: array
1700
+ items: { $ref: "#/components/schemas/UserGrant" }
1701
+ required: [grants]
1702
+ "401": { $ref: "#/components/responses/Unauthorized" }
1703
+ "403": { $ref: "#/components/responses/Forbidden" }
1704
+ "502": { $ref: "#/components/responses/Upstream" }
1705
+
1706
+ /admin/users/{userId}/resource-grants:
1707
+ get:
1708
+ tags: ["Admin: users"]
1709
+ summary: A user's resource grants
1710
+ operationId: adminListUserResourceGrants
1711
+ parameters:
1712
+ - $ref: "#/components/parameters/userId"
1713
+ responses:
1714
+ "200":
1715
+ description: Resource grants with resolved names.
1716
+ content:
1717
+ application/json:
1718
+ schema:
1719
+ type: object
1720
+ properties:
1721
+ grants:
1722
+ type: array
1723
+ items: { $ref: "#/components/schemas/UserResourceGrantNamed" }
1724
+ required: [grants]
1725
+ "401": { $ref: "#/components/responses/Unauthorized" }
1726
+ "403": { $ref: "#/components/responses/Forbidden" }
1727
+ "502": { $ref: "#/components/responses/Upstream" }
1728
+
1729
+ /admin/users/{userId}/revoke-all:
1730
+ post:
1731
+ tags: ["Admin: users"]
1732
+ summary: Revoke everything
1733
+ operationId: adminRevokeAll
1734
+ description: Every direct role and resource grant AND every group membership of the user goes (preferences stay). Each real loss is noticed.
1735
+ parameters:
1736
+ - $ref: "#/components/parameters/userId"
1737
+ responses:
1738
+ "200":
1739
+ description: How many rows were removed.
1740
+ content:
1741
+ application/json:
1742
+ schema:
1743
+ type: object
1744
+ properties:
1745
+ removed: { type: integer }
1746
+ required: [removed]
1747
+ "401": { $ref: "#/components/responses/Unauthorized" }
1748
+ "403": { $ref: "#/components/responses/Forbidden" }
1749
+ "502": { $ref: "#/components/responses/Upstream" }
1750
+
1751
+ /admin/users/{userId}/resend-invite:
1752
+ post:
1753
+ tags: ["Admin: users"]
1754
+ summary: Resend the invitation
1755
+ operationId: adminResendInvite
1756
+ description: Re-sends the invitation email with a fresh temporary password. `409` if the user already completed setup.
1757
+ parameters:
1758
+ - $ref: "#/components/parameters/userId"
1759
+ responses:
1760
+ "204": { description: Sent. }
1761
+ "401": { $ref: "#/components/responses/Unauthorized" }
1762
+ "403": { $ref: "#/components/responses/Forbidden" }
1763
+ "404": { $ref: "#/components/responses/NotFound" }
1764
+ "409": { $ref: "#/components/responses/Conflict" }
1765
+ "502": { $ref: "#/components/responses/Upstream" }
1766
+
1767
+ /admin/users/{userId}/signup-link:
1768
+ post:
1769
+ tags: ["Admin: users"]
1770
+ summary: Mint a fresh sign-up link
1771
+ operationId: adminMintSignupLink
1772
+ description: A new temporary password for a user who has not set their own yet, returned as the `/login#inv=…` link (valid 7 days). It retires the previous temporary password — the emailed link and any copied one stop working. `409` once the user completed setup.
1773
+ parameters:
1774
+ - $ref: "#/components/parameters/userId"
1775
+ responses:
1776
+ "200":
1777
+ description: The link.
1778
+ content:
1779
+ application/json:
1780
+ schema:
1781
+ type: object
1782
+ properties:
1783
+ signupLink: { type: string }
1784
+ required: [signupLink]
1785
+ "401": { $ref: "#/components/responses/Unauthorized" }
1786
+ "403": { $ref: "#/components/responses/Forbidden" }
1787
+ "404": { $ref: "#/components/responses/NotFound" }
1788
+ "409": { $ref: "#/components/responses/Conflict" }
1789
+ "502": { $ref: "#/components/responses/Upstream" }
1790
+
1791
+ /admin/users/{userId}/reset-mfa:
1792
+ post:
1793
+ tags: ["Admin: users"]
1794
+ summary: Reset MFA
1795
+ operationId: adminResetMfa
1796
+ description: Lost-authenticator recovery — TOTP off, the user signs in with password alone again and can re-enrol. No-op if never enrolled.
1797
+ parameters:
1798
+ - $ref: "#/components/parameters/userId"
1799
+ responses:
1800
+ "204": { description: Reset. }
1801
+ "401": { $ref: "#/components/responses/Unauthorized" }
1802
+ "403": { $ref: "#/components/responses/Forbidden" }
1803
+ "404": { $ref: "#/components/responses/NotFound" }
1804
+ "502": { $ref: "#/components/responses/Upstream" }
1805
+
1806
+ /admin/service-users:
1807
+ get:
1808
+ tags: ["Admin: service users"]
1809
+ summary: List service users
1810
+ operationId: adminListServiceUsers
1811
+ responses:
1812
+ "200":
1813
+ description: Service users with their role grants.
1814
+ content:
1815
+ application/json:
1816
+ schema:
1817
+ type: object
1818
+ properties:
1819
+ serviceUsers:
1820
+ type: array
1821
+ items: { $ref: "#/components/schemas/ServiceUser" }
1822
+ required: [serviceUsers]
1823
+ "401": { $ref: "#/components/responses/Unauthorized" }
1824
+ "403": { $ref: "#/components/responses/Forbidden" }
1825
+ "502": { $ref: "#/components/responses/Upstream" }
1826
+ post:
1827
+ tags: ["Admin: service users"]
1828
+ summary: Create a service user
1829
+ operationId: adminCreateServiceUser
1830
+ description: Creates a `client_credentials` app client. The `201` body carries the `clientSecret` — **the only time it is ever returned**. Grant roles to it with the ordinary grant routes, using its `clientId` as the `userId`.
1831
+ requestBody:
1832
+ required: true
1833
+ content:
1834
+ application/json:
1835
+ schema:
1836
+ type: object
1837
+ properties:
1838
+ name: { type: string, minLength: 1, maxLength: 64, description: Unique among live service users. }
1839
+ required: [name]
1840
+ example: { name: "provisioning-app" }
1841
+ responses:
1842
+ "201":
1843
+ description: The service user and its secret.
1844
+ content:
1845
+ application/json:
1846
+ schema: { $ref: "#/components/schemas/ServiceUserWithSecret" }
1847
+ "400": { $ref: "#/components/responses/BadRequest" }
1848
+ "401": { $ref: "#/components/responses/Unauthorized" }
1849
+ "403": { $ref: "#/components/responses/Forbidden" }
1850
+ "409": { $ref: "#/components/responses/Conflict" }
1851
+ "502": { $ref: "#/components/responses/Upstream" }
1852
+
1853
+ /admin/service-users/{clientId}:
1854
+ delete:
1855
+ tags: ["Admin: service users"]
1856
+ summary: Delete a service user
1857
+ operationId: adminDeleteServiceUser
1858
+ description: "**Cascades**: the app client(s), every grant, and the registry row. Issued tokens stay signature-valid up to an hour but are refused on the next request."
1859
+ parameters:
1860
+ - $ref: "#/components/parameters/clientId"
1861
+ responses:
1862
+ "204": { description: Deleted. }
1863
+ "400": { $ref: "#/components/responses/BadRequest" }
1864
+ "401": { $ref: "#/components/responses/Unauthorized" }
1865
+ "403": { $ref: "#/components/responses/Forbidden" }
1866
+ "404": { $ref: "#/components/responses/NotFound" }
1867
+ "502": { $ref: "#/components/responses/Upstream" }
1868
+
1869
+ /admin/service-users/{clientId}/rotate:
1870
+ post:
1871
+ tags: ["Admin: service users"]
1872
+ summary: Rotate the secret
1873
+ operationId: adminRotateServiceUser
1874
+ description: Creates a replacement client + secret carrying the same grants; the previous secret keeps working until `DELETE …/previous`. `409` while a previous secret is still active. The returned `serviceUser.clientId` is the NEW id.
1875
+ parameters:
1876
+ - $ref: "#/components/parameters/clientId"
1877
+ responses:
1878
+ "200":
1879
+ description: The replacement and its secret (returned once).
1880
+ content:
1881
+ application/json:
1882
+ schema: { $ref: "#/components/schemas/ServiceUserWithSecret" }
1883
+ "400": { $ref: "#/components/responses/BadRequest" }
1884
+ "401": { $ref: "#/components/responses/Unauthorized" }
1885
+ "403": { $ref: "#/components/responses/Forbidden" }
1886
+ "404": { $ref: "#/components/responses/NotFound" }
1887
+ "409": { $ref: "#/components/responses/Conflict" }
1888
+ "502": { $ref: "#/components/responses/Upstream" }
1889
+
1890
+ /admin/service-users/{clientId}/previous:
1891
+ delete:
1892
+ tags: ["Admin: service users"]
1893
+ summary: Finish a rotation
1894
+ operationId: adminRemovePreviousSecret
1895
+ description: Retires the previous client (its grants and registry row go). `clientId` is the CURRENT client's id.
1896
+ parameters:
1897
+ - $ref: "#/components/parameters/clientId"
1898
+ responses:
1899
+ "204": { description: Retired. }
1900
+ "400": { $ref: "#/components/responses/BadRequest" }
1901
+ "401": { $ref: "#/components/responses/Unauthorized" }
1902
+ "403": { $ref: "#/components/responses/Forbidden" }
1903
+ "404": { $ref: "#/components/responses/NotFound" }
1904
+ "502": { $ref: "#/components/responses/Upstream" }
1905
+
1906
+ /admin/groups:
1907
+ get:
1908
+ tags: ["Admin: groups"]
1909
+ summary: List groups
1910
+ operationId: adminListGroups
1911
+ description: Every bundle with its roles, resources (names resolved) and members (emails resolved).
1912
+ responses:
1913
+ "200":
1914
+ description: Groups.
1915
+ content:
1916
+ application/json:
1917
+ schema:
1918
+ type: object
1919
+ properties:
1920
+ groups:
1921
+ type: array
1922
+ items: { $ref: "#/components/schemas/GroupView" }
1923
+ required: [groups]
1924
+ "401": { $ref: "#/components/responses/Unauthorized" }
1925
+ "403": { $ref: "#/components/responses/Forbidden" }
1926
+ "502": { $ref: "#/components/responses/Upstream" }
1927
+ post:
1928
+ tags: ["Admin: groups"]
1929
+ summary: Create a group
1930
+ operationId: adminCreateGroup
1931
+ description: A bundle needs at least one role or resource. Names are unique (case-insensitive, `409`).
1932
+ requestBody:
1933
+ required: true
1934
+ content:
1935
+ application/json:
1936
+ schema: { $ref: "#/components/schemas/GroupInput" }
1937
+ example: { name: "Platform team", description: "Read access everywhere", roles: [{ accountNumber: "123456789012", roleName: "ReadOnly" }], resources: [] }
1938
+ responses:
1939
+ "201":
1940
+ description: The group (members and resources as raw ids).
1941
+ content:
1942
+ application/json:
1943
+ schema: { $ref: "#/components/schemas/GroupEnvelope" }
1944
+ "400": { $ref: "#/components/responses/BadRequest" }
1945
+ "401": { $ref: "#/components/responses/Unauthorized" }
1946
+ "403": { $ref: "#/components/responses/Forbidden" }
1947
+ "404": { $ref: "#/components/responses/NotFound" }
1948
+ "409": { $ref: "#/components/responses/Conflict" }
1949
+ "502": { $ref: "#/components/responses/Upstream" }
1950
+
1951
+ /admin/groups/{groupId}:
1952
+ get:
1953
+ tags: ["Admin: groups"]
1954
+ summary: One group with its whole bundle
1955
+ operationId: adminGetGroup
1956
+ description: The list caps each group's `roles` at 50 (`roleCount` carries the total); this returns every role, member and resource of one group.
1957
+ parameters:
1958
+ - $ref: "#/components/parameters/groupId"
1959
+ responses:
1960
+ "200":
1961
+ description: The group.
1962
+ content:
1963
+ application/json:
1964
+ schema: { $ref: "#/components/schemas/GroupEnvelope" }
1965
+ "401": { $ref: "#/components/responses/Unauthorized" }
1966
+ "403": { $ref: "#/components/responses/Forbidden" }
1967
+ "404": { $ref: "#/components/responses/NotFound" }
1968
+ "502": { $ref: "#/components/responses/Upstream" }
1969
+ patch:
1970
+ tags: ["Admin: groups"]
1971
+ summary: Update a group
1972
+ operationId: adminUpdateGroup
1973
+ description: At least one field. A `roles`/`resources` change reconciles every member — added targets are granted to all, removed ones revoked unless held directly or via another group (losses are noticed).
1974
+ parameters:
1975
+ - $ref: "#/components/parameters/groupId"
1976
+ requestBody:
1977
+ required: true
1978
+ content:
1979
+ application/json:
1980
+ schema: { $ref: "#/components/schemas/GroupInput" }
1981
+ example: { roles: [{ accountNumber: "123456789012", roleName: "ReadOnly" }, { accountNumber: "123456789012", roleName: "PowerUser" }] }
1982
+ responses:
1983
+ "200":
1984
+ description: The updated group.
1985
+ content:
1986
+ application/json:
1987
+ schema: { $ref: "#/components/schemas/GroupEnvelope" }
1988
+ "400": { $ref: "#/components/responses/BadRequest" }
1989
+ "401": { $ref: "#/components/responses/Unauthorized" }
1990
+ "403": { $ref: "#/components/responses/Forbidden" }
1991
+ "404": { $ref: "#/components/responses/NotFound" }
1992
+ "409": { $ref: "#/components/responses/Conflict" }
1993
+ "502": { $ref: "#/components/responses/Upstream" }
1994
+ delete:
1995
+ tags: ["Admin: groups"]
1996
+ summary: Delete a group
1997
+ operationId: adminDeleteGroup
1998
+ description: Pulls the bundle from every member (direct and other-group access survives; losses are noticed).
1999
+ parameters:
2000
+ - $ref: "#/components/parameters/groupId"
2001
+ responses:
2002
+ "204": { description: Deleted. }
2003
+ "401": { $ref: "#/components/responses/Unauthorized" }
2004
+ "403": { $ref: "#/components/responses/Forbidden" }
2005
+ "404": { $ref: "#/components/responses/NotFound" }
2006
+ "502": { $ref: "#/components/responses/Upstream" }
2007
+
2008
+ /admin/groups/{groupId}/roles:
2009
+ get:
2010
+ tags: ["Admin: groups"]
2011
+ summary: The bundle's roles, paged
2012
+ operationId: adminListGroupRoles
2013
+ description: The list contract over one group's roles (`q` matches role name, display name, account name or number; sorts `account` (default), `role`). Without `limit`, the first 50.
2014
+ parameters:
2015
+ - $ref: "#/components/parameters/groupId"
2016
+ - $ref: "#/components/parameters/listQ"
2017
+ - $ref: "#/components/parameters/listSort"
2018
+ - $ref: "#/components/parameters/listLimit"
2019
+ - $ref: "#/components/parameters/listCursor"
2020
+ responses:
2021
+ "200":
2022
+ description: One page of the bundle.
2023
+ content:
2024
+ application/json:
2025
+ schema:
2026
+ allOf:
2027
+ - $ref: "#/components/schemas/ListPage"
2028
+ - type: object
2029
+ properties:
2030
+ items:
2031
+ type: array
2032
+ items:
2033
+ type: object
2034
+ properties:
2035
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
2036
+ accountName: { type: string }
2037
+ roleName: { type: string }
2038
+ displayName: { type: string }
2039
+ required: [accountNumber, roleName]
2040
+ required: [items]
2041
+ "400": { $ref: "#/components/responses/BadRequest" }
2042
+ "401": { $ref: "#/components/responses/Unauthorized" }
2043
+ "403": { $ref: "#/components/responses/Forbidden" }
2044
+ "404": { $ref: "#/components/responses/NotFound" }
2045
+ "502": { $ref: "#/components/responses/Upstream" }
2046
+ post:
2047
+ tags: ["Admin: groups"]
2048
+ summary: Add one role to a group
2049
+ operationId: adminAddGroupRole
2050
+ description: |
2051
+ Adds a single catalogued role to the bundle — the call an account-registration pipeline makes per new account.
2052
+ Idempotent and race-free: the row is written only if absent, so a retry or two concurrent adds leave one row,
2053
+ and a role already in the bundle answers `200` with nothing changed, noticed or logged. Members who gain the
2054
+ role are noticed, as with a `PATCH`. Prefer this over `PATCH` with the full role list for large groups.
2055
+ Answers with the change, not the bundle (a 4,000-role group answers in well under a second); read the bundle
2056
+ with `GET /admin/groups/{groupId}` or page it with `GET …/roles`.
2057
+ parameters:
2058
+ - $ref: "#/components/parameters/groupId"
2059
+ requestBody:
2060
+ required: true
2061
+ content:
2062
+ application/json:
2063
+ schema: { $ref: "#/components/schemas/GroupRoleRef" }
2064
+ example: { accountNumber: "123456789012", roleName: "ReadOnly" }
2065
+ responses:
2066
+ "201":
2067
+ description: The role was added.
2068
+ content:
2069
+ application/json:
2070
+ schema: { $ref: "#/components/schemas/GroupRoleChange" }
2071
+ "200":
2072
+ description: The role was already in the bundle; nothing changed.
2073
+ content:
2074
+ application/json:
2075
+ schema: { $ref: "#/components/schemas/GroupRoleChange" }
2076
+ "400": { $ref: "#/components/responses/BadRequest" }
2077
+ "401": { $ref: "#/components/responses/Unauthorized" }
2078
+ "403": { $ref: "#/components/responses/Forbidden" }
2079
+ "404": { $ref: "#/components/responses/NotFound" }
2080
+ "502": { $ref: "#/components/responses/Upstream" }
2081
+
2082
+ /admin/groups/{groupId}/roles/bulk:
2083
+ post:
2084
+ tags: ["Admin: groups"]
2085
+ summary: Add every matching account's role to a group
2086
+ operationId: adminAddGroupRolesBulk
2087
+ description: |
2088
+ The group editor's "add by dimension": every registered account matching `filter` (dimension values, `unclassified` for
2089
+ accounts without one; keys AND together, values OR) and `q` (account name or number) that has a role named `roleName`
2090
+ goes into the bundle. Rows are written only if absent, roles already bundled are skipped, members who gain
2091
+ access are noticed as with a single add. One call writes at most 500 new rows and reports `remaining`; call again
2092
+ until it is 0. `dryRun: true` only counts. Matching is over the catalog; access is unchanged by it until the rows
2093
+ are written.
2094
+ parameters:
2095
+ - $ref: "#/components/parameters/groupId"
2096
+ requestBody:
2097
+ required: true
2098
+ content:
2099
+ application/json:
2100
+ schema:
2101
+ type: object
2102
+ properties:
2103
+ roleName: { type: string, minLength: 1 }
2104
+ filter:
2105
+ type: object
2106
+ properties:
2107
+ tenant: { type: array, items: { type: string } }
2108
+ project: { type: array, items: { type: string } }
2109
+ stage: { type: array, items: { type: string } }
2110
+ q: { type: string, description: Narrows by account name or number (every whitespace-separated token must occur). }
2111
+ dryRun: { type: boolean, default: false }
2112
+ required: [roleName]
2113
+ example: { roleName: "ReadOnly", filter: { tenant: ["acme"], stage: ["prod"] } }
2114
+ responses:
2115
+ "201":
2116
+ description: At least one role was added.
2117
+ content:
2118
+ application/json:
2119
+ schema: { $ref: "#/components/schemas/GroupRolesBulkResult" }
2120
+ "200":
2121
+ description: Nothing new (every match was already bundled), or the dry run's count.
2122
+ content:
2123
+ application/json:
2124
+ schema: { $ref: "#/components/schemas/GroupRolesBulkResult" }
2125
+ "400": { $ref: "#/components/responses/BadRequest" }
2126
+ "401": { $ref: "#/components/responses/Unauthorized" }
2127
+ "403": { $ref: "#/components/responses/Forbidden" }
2128
+ "404": { $ref: "#/components/responses/NotFound" }
2129
+ "502": { $ref: "#/components/responses/Upstream" }
2130
+
2131
+ /admin/groups/suggest:
2132
+ get:
2133
+ tags: ["Admin: groups"]
2134
+ summary: Groups to add a freshly registered role to
2135
+ operationId: adminSuggestGroups
2136
+ description: |
2137
+ Groups that already bundle a role of this name in the account's sibling accounts — same tenant and stage by the
2138
+ catalog's dimensions (deployments with `accountDimensions`). The role form offers them right after a role is
2139
+ registered; adding is the single-role `POST /admin/groups/{groupId}/roles`. Empty without dimensions or siblings;
2140
+ at most 10, most siblings first.
2141
+ parameters:
2142
+ - name: accountNumber
2143
+ in: query
2144
+ required: true
2145
+ schema: { $ref: "#/components/schemas/AccountNumber" }
2146
+ - name: roleName
2147
+ in: query
2148
+ required: true
2149
+ schema: { type: string, minLength: 1 }
2150
+ responses:
2151
+ "200":
2152
+ description: Suggested groups.
2153
+ content:
2154
+ application/json:
2155
+ schema:
2156
+ type: object
2157
+ properties:
2158
+ suggestions:
2159
+ type: array
2160
+ items:
2161
+ type: object
2162
+ properties:
2163
+ groupId: { type: string }
2164
+ name: { type: string }
2165
+ siblingAccounts: { type: integer, minimum: 1, description: Sibling accounts whose role of this name the group bundles. }
2166
+ required: [groupId, name, siblingAccounts]
2167
+ required: [suggestions]
2168
+ "400": { $ref: "#/components/responses/BadRequest" }
2169
+ "401": { $ref: "#/components/responses/Unauthorized" }
2170
+ "403": { $ref: "#/components/responses/Forbidden" }
2171
+ "502": { $ref: "#/components/responses/Upstream" }
2172
+
2173
+ /admin/groups/{groupId}/roles/{accountNumber}/{roleName}:
2174
+ delete:
2175
+ tags: ["Admin: groups"]
2176
+ summary: Remove one role from a group
2177
+ operationId: adminRemoveGroupRole
2178
+ description: Removes a single role from the bundle (members lose it unless held another way, and are noticed). A role not in the bundle is still `204`. The bundle's last target cannot be removed this way (`400`) — delete the group instead.
2179
+ parameters:
2180
+ - $ref: "#/components/parameters/groupId"
2181
+ - $ref: "#/components/parameters/accountNumber"
2182
+ - $ref: "#/components/parameters/roleName"
2183
+ responses:
2184
+ "204": { description: Removed, or was not there. }
2185
+ "400": { $ref: "#/components/responses/BadRequest" }
2186
+ "401": { $ref: "#/components/responses/Unauthorized" }
2187
+ "403": { $ref: "#/components/responses/Forbidden" }
2188
+ "404": { $ref: "#/components/responses/NotFound" }
2189
+ "502": { $ref: "#/components/responses/Upstream" }
2190
+
2191
+ /admin/groups/{groupId}/members:
2192
+ post:
2193
+ tags: ["Admin: groups"]
2194
+ summary: Add members
2195
+ operationId: adminAddMembers
2196
+ description: Every new member inherits the whole bundle. Already-members are ignored.
2197
+ parameters:
2198
+ - $ref: "#/components/parameters/groupId"
2199
+ requestBody:
2200
+ required: true
2201
+ content:
2202
+ application/json:
2203
+ schema: { $ref: "#/components/schemas/UserIdList" }
2204
+ example: { userIds: ["1a2b3c4d-0000-4000-8000-000000000000"] }
2205
+ responses:
2206
+ "200":
2207
+ description: How many members were added.
2208
+ content:
2209
+ application/json:
2210
+ schema:
2211
+ type: object
2212
+ properties:
2213
+ added: { type: integer }
2214
+ required: [added]
2215
+ "400": { $ref: "#/components/responses/BadRequest" }
2216
+ "401": { $ref: "#/components/responses/Unauthorized" }
2217
+ "403": { $ref: "#/components/responses/Forbidden" }
2218
+ "404": { $ref: "#/components/responses/NotFound" }
2219
+ "502": { $ref: "#/components/responses/Upstream" }
2220
+
2221
+ /admin/groups/{groupId}/members/remove:
2222
+ post:
2223
+ tags: ["Admin: groups"]
2224
+ summary: Remove members
2225
+ operationId: adminRemoveMembers
2226
+ description: A POST because it carries a body. Only this group's access is pulled (losses are noticed).
2227
+ parameters:
2228
+ - $ref: "#/components/parameters/groupId"
2229
+ requestBody:
2230
+ required: true
2231
+ content:
2232
+ application/json:
2233
+ schema: { $ref: "#/components/schemas/UserIdList" }
2234
+ example: { userIds: ["1a2b3c4d-0000-4000-8000-000000000000"] }
2235
+ responses:
2236
+ "200":
2237
+ description: How many members were removed.
2238
+ content:
2239
+ application/json:
2240
+ schema:
2241
+ type: object
2242
+ properties:
2243
+ removed: { type: integer }
2244
+ required: [removed]
2245
+ "400": { $ref: "#/components/responses/BadRequest" }
2246
+ "401": { $ref: "#/components/responses/Unauthorized" }
2247
+ "403": { $ref: "#/components/responses/Forbidden" }
2248
+ "404": { $ref: "#/components/responses/NotFound" }
2249
+ "502": { $ref: "#/components/responses/Upstream" }
2250
+
2251
+ /admin/requests:
2252
+ get:
2253
+ tags: ["Admin: requests"]
2254
+ summary: Queue or history
2255
+ operationId: adminListRequests
2256
+ description: With `status`, that queue (oldest first); without it, the full history (newest first). Rows carry the requester's email, service-user name, group name and resource name where applicable.
2257
+ parameters:
2258
+ - name: status
2259
+ in: query
2260
+ schema: { type: string, enum: [PENDING, APPROVED, DENIED] }
2261
+ example: PENDING
2262
+ - name: usage
2263
+ in: query
2264
+ description: "`1` adds `usage` (the holder's role use in the review window) to pending reapprovals. Costly — only the Requests page sets it, never the bell poll."
2265
+ schema: { type: string, enum: ["1"] }
2266
+ responses:
2267
+ "200":
2268
+ description: Requests.
2269
+ content:
2270
+ application/json:
2271
+ schema:
2272
+ type: object
2273
+ properties:
2274
+ requests:
2275
+ type: array
2276
+ items: { $ref: "#/components/schemas/AccessRequestAdminView" }
2277
+ required: [requests]
2278
+ "400": { $ref: "#/components/responses/BadRequest" }
2279
+ "401": { $ref: "#/components/responses/Unauthorized" }
2280
+ "403": { $ref: "#/components/responses/Forbidden" }
2281
+ "502": { $ref: "#/components/responses/Upstream" }
2282
+
2283
+ /admin/requests/{requestId}/approve:
2284
+ post:
2285
+ tags: ["Admin: requests"]
2286
+ summary: Approve
2287
+ operationId: adminApproveRequest
2288
+ description: Approves **and grants** (a role, a resource, or — for reviews — confirms the admin/service user/group). The approver's `durationHours` is final, overriding what was requested. `409` if another admin already decided.
2289
+ parameters:
2290
+ - $ref: "#/components/parameters/requestId"
2291
+ requestBody:
2292
+ content:
2293
+ application/json:
2294
+ schema:
2295
+ type: object
2296
+ properties:
2297
+ note: { type: string, maxLength: 500, description: Shown to the requester with the decision. }
2298
+ durationHours: { $ref: "#/components/schemas/DurationHours" }
2299
+ example: { note: "Approved for the incident.", durationHours: 24 }
2300
+ responses:
2301
+ "200":
2302
+ description: The decided request.
2303
+ content:
2304
+ application/json:
2305
+ schema: { $ref: "#/components/schemas/RequestEnvelope" }
2306
+ "400": { $ref: "#/components/responses/BadRequest" }
2307
+ "401": { $ref: "#/components/responses/Unauthorized" }
2308
+ "403": { $ref: "#/components/responses/Forbidden" }
2309
+ "404": { $ref: "#/components/responses/NotFound" }
2310
+ "409": { $ref: "#/components/responses/Conflict" }
2311
+ "502": { $ref: "#/components/responses/Upstream" }
2312
+
2313
+ /admin/requests/{requestId}/deny:
2314
+ post:
2315
+ tags: ["Admin: requests"]
2316
+ summary: Deny
2317
+ operationId: adminDenyRequest
2318
+ description: Grants nothing. For a reapproval/review, denying **ends** the standing access under review (losses are noticed). `409` if already decided.
2319
+ parameters:
2320
+ - $ref: "#/components/parameters/requestId"
2321
+ requestBody:
2322
+ content:
2323
+ application/json:
2324
+ schema:
2325
+ type: object
2326
+ properties:
2327
+ note: { type: string, maxLength: 500 }
2328
+ example: { note: "Not needed for this role." }
2329
+ responses:
2330
+ "200":
2331
+ description: The decided request.
2332
+ content:
2333
+ application/json:
2334
+ schema: { $ref: "#/components/schemas/RequestEnvelope" }
2335
+ "400": { $ref: "#/components/responses/BadRequest" }
2336
+ "401": { $ref: "#/components/responses/Unauthorized" }
2337
+ "403": { $ref: "#/components/responses/Forbidden" }
2338
+ "404": { $ref: "#/components/responses/NotFound" }
2339
+ "409": { $ref: "#/components/responses/Conflict" }
2340
+ "502": { $ref: "#/components/responses/Upstream" }
2341
+
2342
+ /admin/resources:
2343
+ get:
2344
+ tags: ["Admin: resources"]
2345
+ summary: List resources
2346
+ operationId: adminListResources
2347
+ description: The private-network resource catalog with connection details.
2348
+ responses:
2349
+ "200":
2350
+ description: Resources, sorted by name.
2351
+ content:
2352
+ application/json:
2353
+ schema:
2354
+ type: object
2355
+ properties:
2356
+ resources:
2357
+ type: array
2358
+ items: { $ref: "#/components/schemas/Resource" }
2359
+ required: [resources]
2360
+ "401": { $ref: "#/components/responses/Unauthorized" }
2361
+ "403": { $ref: "#/components/responses/Forbidden" }
2362
+ "502": { $ref: "#/components/responses/Upstream" }
2363
+ post:
2364
+ tags: ["Admin: resources"]
2365
+ summary: Register a resource
2366
+ operationId: adminCreateResource
2367
+ description: A resource is reachable only through a site, so this is `501` on deployments without a private network. `cidr` accepts a bare IP or a /16–/32 CIDR. The account must be catalogued (`404`).
2368
+ requestBody:
2369
+ required: true
2370
+ content:
2371
+ application/json:
2372
+ schema: { $ref: "#/components/schemas/ResourceCreate" }
2373
+ example: { accountNumber: "123456789012", name: "Staging database", type: DATABASE, cidr: "10.0.1.25/32", ports: [5432], dnsName: "staging-db.internal", securityGroupId: "sg-0123456789abcdef0", description: "Postgres 16" }
2374
+ responses:
2375
+ "201":
2376
+ description: The resource.
2377
+ content:
2378
+ application/json:
2379
+ schema: { $ref: "#/components/schemas/ResourceEnvelope" }
2380
+ "400": { $ref: "#/components/responses/BadRequest" }
2381
+ "401": { $ref: "#/components/responses/Unauthorized" }
2382
+ "403": { $ref: "#/components/responses/Forbidden" }
2383
+ "404": { $ref: "#/components/responses/NotFound" }
2384
+ "501": { $ref: "#/components/responses/NotDeployed" }
2385
+ "502": { $ref: "#/components/responses/Upstream" }
2386
+
2387
+ /admin/resources/status:
2388
+ get:
2389
+ tags: ["Admin: network"]
2390
+ summary: Reconciler status
2391
+ operationId: adminReconcilerStatus
2392
+ description: The grants→ACL reconciler's last-pass summary — per-resource reachability verdicts, connector freshness, rule counts.
2393
+ responses:
2394
+ "200":
2395
+ description: Status.
2396
+ content:
2397
+ application/json:
2398
+ schema: { $ref: "#/components/schemas/ReconcilerStatus" }
2399
+ "401": { $ref: "#/components/responses/Unauthorized" }
2400
+ "403": { $ref: "#/components/responses/Forbidden" }
2401
+ "502": { $ref: "#/components/responses/Upstream" }
2402
+
2403
+ /admin/resources/{resourceId}:
2404
+ patch:
2405
+ tags: ["Admin: resources"]
2406
+ summary: Update a resource
2407
+ operationId: adminUpdateResource
2408
+ description: At least one field. `accountNumber` is immutable (it IS the connector binding) — moving a resource means recreating it.
2409
+ parameters:
2410
+ - $ref: "#/components/parameters/resourceId"
2411
+ requestBody:
2412
+ required: true
2413
+ content:
2414
+ application/json:
2415
+ schema: { $ref: "#/components/schemas/ResourcePatch" }
2416
+ example: { ports: [5432, 5433], description: "Postgres 16 + pgbouncer" }
2417
+ responses:
2418
+ "200":
2419
+ description: The updated resource.
2420
+ content:
2421
+ application/json:
2422
+ schema: { $ref: "#/components/schemas/ResourceEnvelope" }
2423
+ "400": { $ref: "#/components/responses/BadRequest" }
2424
+ "401": { $ref: "#/components/responses/Unauthorized" }
2425
+ "403": { $ref: "#/components/responses/Forbidden" }
2426
+ "404": { $ref: "#/components/responses/NotFound" }
2427
+ "502": { $ref: "#/components/responses/Upstream" }
2428
+ delete:
2429
+ tags: ["Admin: resources"]
2430
+ summary: Remove a resource
2431
+ operationId: adminDeleteResource
2432
+ description: "**Cascades**: every grant on the resource is revoked (losses are noticed), groups bundling it drop it (a group left empty is removed), and its open requests and reviews are denied with the reason. Grants go before the catalog row, so a call that failed halfway can be repeated."
2433
+ parameters:
2434
+ - $ref: "#/components/parameters/resourceId"
2435
+ responses:
2436
+ "204": { description: Removed. }
2437
+ "401": { $ref: "#/components/responses/Unauthorized" }
2438
+ "403": { $ref: "#/components/responses/Forbidden" }
2439
+ "404": { $ref: "#/components/responses/NotFound" }
2440
+ "502": { $ref: "#/components/responses/Upstream" }
2441
+
2442
+ /admin/resources/{resourceId}/grants:
2443
+ get:
2444
+ tags: ["Admin: resources"]
2445
+ summary: Who can reach this resource
2446
+ operationId: adminListResourceGrantees
2447
+ parameters:
2448
+ - $ref: "#/components/parameters/resourceId"
2449
+ responses:
2450
+ "200":
2451
+ description: Holders with emails resolved.
2452
+ content:
2453
+ application/json:
2454
+ schema:
2455
+ type: object
2456
+ properties:
2457
+ grantees:
2458
+ type: array
2459
+ items: { $ref: "#/components/schemas/ResourceGrantee" }
2460
+ required: [grantees]
2461
+ "401": { $ref: "#/components/responses/Unauthorized" }
2462
+ "403": { $ref: "#/components/responses/Forbidden" }
2463
+ "502": { $ref: "#/components/responses/Upstream" }
2464
+
2465
+ /admin/resources/{resourceId}/grants/{userId}:
2466
+ put:
2467
+ tags: ["Admin: resources"]
2468
+ summary: Grant a resource
2469
+ operationId: adminAssignResource
2470
+ description: Idempotent; re-granting overwrites the expiry. A long-term grant is never downgraded. Reachability follows on the reconciler's next pass (≤ 5 min).
2471
+ parameters:
2472
+ - $ref: "#/components/parameters/resourceId"
2473
+ - $ref: "#/components/parameters/userId"
2474
+ requestBody:
2475
+ content:
2476
+ application/json:
2477
+ schema:
2478
+ type: object
2479
+ properties:
2480
+ durationHours: { $ref: "#/components/schemas/DurationHours" }
2481
+ example: { durationHours: 72 }
2482
+ responses:
2483
+ "200":
2484
+ description: The grant.
2485
+ content:
2486
+ application/json:
2487
+ schema:
2488
+ type: object
2489
+ properties:
2490
+ grant: { $ref: "#/components/schemas/UserResourceGrant" }
2491
+ required: [grant]
2492
+ "400": { $ref: "#/components/responses/BadRequest" }
2493
+ "401": { $ref: "#/components/responses/Unauthorized" }
2494
+ "403": { $ref: "#/components/responses/Forbidden" }
2495
+ "404": { $ref: "#/components/responses/NotFound" }
2496
+ "502": { $ref: "#/components/responses/Upstream" }
2497
+ delete:
2498
+ tags: ["Admin: resources"]
2499
+ summary: Revoke a resource
2500
+ operationId: adminRevokeResource
2501
+ parameters:
2502
+ - $ref: "#/components/parameters/resourceId"
2503
+ - $ref: "#/components/parameters/userId"
2504
+ responses:
2505
+ "204": { description: Revoked. }
2506
+ "401": { $ref: "#/components/responses/Unauthorized" }
2507
+ "403": { $ref: "#/components/responses/Forbidden" }
2508
+ "404": { $ref: "#/components/responses/NotFound" }
2509
+ "502": { $ref: "#/components/responses/Upstream" }
2510
+
2511
+ /admin/network:
2512
+ get:
2513
+ tags: ["Admin: network"]
2514
+ summary: Network topology
2515
+ operationId: adminNetworkTopology
2516
+ description: Everything the admin Network map needs — the full site config (split DNS and declared VPCs included) plus the reconciler's last-pass status.
2517
+ responses:
2518
+ "200":
2519
+ description: Sites and status.
2520
+ content:
2521
+ application/json:
2522
+ schema:
2523
+ type: object
2524
+ properties:
2525
+ sites:
2526
+ type: array
2527
+ items: { $ref: "#/components/schemas/NetworkSite" }
2528
+ status: { $ref: "#/components/schemas/ReconcilerStatus" }
2529
+ required: [sites, status]
2530
+ "401": { $ref: "#/components/responses/Unauthorized" }
2531
+ "403": { $ref: "#/components/responses/Forbidden" }
2532
+ "502": { $ref: "#/components/responses/Upstream" }
2533
+
2534
+ /admin/network/shares:
2535
+ get:
2536
+ tags: ["Admin: network"]
2537
+ summary: Every live dev share
2538
+ operationId: adminListDevShares
2539
+ description: Owner, port, site, expiry and grantees of every unexpired share; stop one with `DELETE /network/shares/{shareId}` (admins may).
2540
+ responses:
2541
+ "200":
2542
+ description: Soonest expiry first.
2543
+ content:
2544
+ application/json:
2545
+ schema:
2546
+ type: object
2547
+ properties:
2548
+ shares: { type: array, items: { $ref: "#/components/schemas/DevShare" } }
2549
+ required: [shares]
2550
+ "401": { $ref: "#/components/responses/Unauthorized" }
2551
+ "403": { $ref: "#/components/responses/Forbidden" }
2552
+ "501": { $ref: "#/components/responses/NotDeployed" }
2553
+ "502": { $ref: "#/components/responses/Upstream" }
2554
+
2555
+ /admin/network/sync:
2556
+ post:
2557
+ tags: ["Admin: network"]
2558
+ summary: Sync now
2559
+ operationId: adminNetworkSync
2560
+ description: Kicks the grants→ACL reconciler ahead of its 5-minute schedule. Fire-and-forget — re-read `GET /admin/resources/status` for the outcome.
2561
+ responses:
2562
+ "202":
2563
+ description: Sync requested.
2564
+ content:
2565
+ application/json:
2566
+ schema: { $ref: "#/components/schemas/Message" }
2567
+ "401": { $ref: "#/components/responses/Unauthorized" }
2568
+ "403": { $ref: "#/components/responses/Forbidden" }
2569
+ "501": { $ref: "#/components/responses/NotDeployed" }
2570
+ "502": { $ref: "#/components/responses/Upstream" }
2571
+
2572
+ /admin/audit:
2573
+ get:
2574
+ tags: ["Admin: audit"]
2575
+ summary: The activity log
2576
+ operationId: adminListAudit
2577
+ description: |
2578
+ Every recorded action, newest first: who did it, what, to whom or what, the outcome and why. The window is
2579
+ `from`/`to` (a span of at most 90 days, anywhere inside the retention), or `days` back from now (default 7).
2580
+ A full page (`limit`, default 200, max 1000) reports `nextBefore`; pass it back as `before` for older rows.
2581
+ `user` (the person, group or service user an action was about) returns that subject's own trail. Per-user
2582
+ derived rows (`derived: true`, written by the access diff for group, cascade and bulk changes) are hidden
2583
+ unless `derived=true`. Names are joined from the directory,
2584
+ the group list and the resource catalog; a caller deleted since carries `deleted: true` and their snapshot name.
2585
+ Rows written before the general log (vend-only) are returned in the same shape.
2586
+ parameters:
2587
+ - name: from
2588
+ in: query
2589
+ schema: { type: string, format: date-time }
2590
+ - name: to
2591
+ in: query
2592
+ schema: { type: string, format: date-time }
2593
+ - name: before
2594
+ in: query
2595
+ description: Upper bound for the next page, inclusive (the previous page's `nextBefore`); send `skip` with it.
2596
+ schema: { type: string, format: date-time }
2597
+ - name: skip
2598
+ in: query
2599
+ description: Comma-separated event ids already held whose `at` equals `before` — rows written in one batch can share an instant, so the cursor is inclusive and these are left out.
2600
+ schema: { type: string }
2601
+ - name: days
2602
+ in: query
2603
+ description: Shorthand for `from` = now minus this many days.
2604
+ schema: { type: integer, minimum: 1, maximum: 90 }
2605
+ example: 7
2606
+ - name: limit
2607
+ in: query
2608
+ schema: { type: integer, minimum: 1, maximum: 1000, default: 200 }
2609
+ - name: user
2610
+ in: query
2611
+ description: Subject ids, comma-separated (Cognito subs, group ids or service-user client ids; at most 10 — one indexed query each, merged). `userId` is accepted as an alias.
2612
+ schema: { type: string }
2613
+ - name: userId
2614
+ in: query
2615
+ deprecated: true
2616
+ schema: { type: string }
2617
+ - name: actor
2618
+ in: query
2619
+ description: Who did it, comma-separated (subs, client ids, or `system:<job>`; at most 10). Rows from before the general log are found by their caller; VPN session rows (`vpn.connect`/`vpn.disconnect`) by the person who connected, never by `system:reconciler`.
2620
+ schema: { type: string }
2621
+ - name: category
2622
+ in: query
2623
+ description: Comma-separated.
2624
+ schema: { type: string, example: "access,request" }
2625
+ - name: outcome
2626
+ in: query
2627
+ description: Comma-separated.
2628
+ schema: { type: string, example: "DENIED,FAILED" }
2629
+ - name: account
2630
+ in: query
2631
+ description: Comma-separated account numbers.
2632
+ schema: { type: string }
2633
+ - name: group
2634
+ in: query
2635
+ description: "Comma-separated group ids — everything about each group: its own rows, rows through it, rows where it is the subject."
2636
+ schema: { type: string }
2637
+ - name: target
2638
+ in: query
2639
+ description: Exact targets (`role#<account>#<name>`, `resource#<id>`, …). Repeat the parameter for several; a value is never split (a role name may contain a comma).
2640
+ schema:
2641
+ type: array
2642
+ items: { type: string }
2643
+ style: form
2644
+ explode: true
2645
+ - name: derived
2646
+ in: query
2647
+ schema: { type: boolean, default: false }
2648
+ responses:
2649
+ "200":
2650
+ description: One page of the log.
2651
+ content:
2652
+ application/json:
2653
+ schema: { $ref: "#/components/schemas/ActivityPage" }
2654
+ "400": { $ref: "#/components/responses/BadRequest" }
2655
+ "401": { $ref: "#/components/responses/Unauthorized" }
2656
+ "403": { $ref: "#/components/responses/Forbidden" }
2657
+ "502": { $ref: "#/components/responses/Upstream" }
2658
+
2659
+ /admin/access-report/jobs:
2660
+ post:
2661
+ tags: ["Admin: audit"]
2662
+ summary: Build the access report in the background
2663
+ operationId: adminStartAccessReport
2664
+ description: Starts the report as a job (a large catalog produces more rows than one API call may carry) and answers at once with its id. Poll `GET /admin/access-report/jobs/{jobId}` until `status` is `done`, then download from `url` (valid 15 minutes). Only the admin who started a job can read it.
2665
+ responses:
2666
+ "202":
2667
+ description: The job, running.
2668
+ content:
2669
+ application/json:
2670
+ schema:
2671
+ type: object
2672
+ properties:
2673
+ job: { $ref: "#/components/schemas/ReportJob" }
2674
+ required: [job]
2675
+ "401": { $ref: "#/components/responses/Unauthorized" }
2676
+ "403": { $ref: "#/components/responses/Forbidden" }
2677
+ "502": { $ref: "#/components/responses/Upstream" }
2678
+
2679
+ /admin/access-report/jobs/{jobId}:
2680
+ get:
2681
+ tags: ["Admin: audit"]
2682
+ summary: An access report job
2683
+ operationId: adminGetAccessReportJob
2684
+ parameters:
2685
+ - name: jobId
2686
+ in: path
2687
+ required: true
2688
+ schema: { type: string, format: uuid }
2689
+ responses:
2690
+ "200":
2691
+ description: The job; with `url` once done.
2692
+ content:
2693
+ application/json:
2694
+ schema:
2695
+ type: object
2696
+ properties:
2697
+ job: { $ref: "#/components/schemas/ReportJob" }
2698
+ required: [job]
2699
+ "400": { $ref: "#/components/responses/BadRequest" }
2700
+ "401": { $ref: "#/components/responses/Unauthorized" }
2701
+ "403": { $ref: "#/components/responses/Forbidden" }
2702
+ "404": { $ref: "#/components/responses/NotFound" }
2703
+ "502": { $ref: "#/components/responses/Upstream" }
2704
+
2705
+ /admin/access-report:
2706
+ get:
2707
+ tags: ["Admin: audit"]
2708
+ summary: Who can reach what right now (CSV)
2709
+ operationId: adminAccessReport
2710
+ description: One row per person (or service user) and target they hold this instant — how (direct, or through which groups), who granted it, when, until when, and when they were last seen. The log explains how each row came to be; this is the state. Built inline, so it fits only while the result stays under API Gateway's 6 MB; the app uses the job endpoints above.
2711
+ responses:
2712
+ "200":
2713
+ description: "A CSV download (`Content-Disposition: attachment`), UTF-8 with BOM."
2714
+ content:
2715
+ text/csv:
2716
+ schema: { type: string }
2717
+ "401": { $ref: "#/components/responses/Unauthorized" }
2718
+ "403": { $ref: "#/components/responses/Forbidden" }
2719
+ "502": { $ref: "#/components/responses/Upstream" }
2720
+
2721
+ /plugins:
2722
+ get:
2723
+ tags: [Plugins]
2724
+ summary: Plugins this caller may open
2725
+ operationId: listPlugins
2726
+ description: >-
2727
+ Metadata only, never plugin code. A plugin appears only where the caller has an available capability,
2728
+ and a UI entry only where its own permission is available in at least one listed account. Account names
2729
+ come from the Accounts catalog, so a caller holding nothing but a plugin grant still sees the account.
2730
+ The feature being off, or no plugin being registered, is an empty list — never an error, and never
2731
+ cached across callers.
2732
+ responses:
2733
+ "200":
2734
+ description: The caller's plugins.
2735
+ content:
2736
+ application/json:
2737
+ schema: { $ref: "#/components/schemas/PluginDiscovery" }
2738
+ "401": { $ref: "#/components/responses/Unauthorized" }
2739
+ "502": { $ref: "#/components/responses/Upstream" }
2740
+
2741
+ /plugins/expiry:
2742
+ get:
2743
+ tags: [Plugins]
2744
+ summary: My plugin expiry notices
2745
+ operationId: listPluginExpiryNotices
2746
+ description: Temporary plugin permissions nearing / past their end, named for the bell (a removed plugin keeps its label; an account without a name shows its number).
2747
+ responses:
2748
+ "200":
2749
+ description: Soonest expiry first; most recently expired first.
2750
+ content:
2751
+ application/json:
2752
+ schema:
2753
+ type: object
2754
+ properties:
2755
+ expiring:
2756
+ type: array
2757
+ items: { $ref: "#/components/schemas/PluginExpiryNotice" }
2758
+ expired:
2759
+ type: array
2760
+ items: { $ref: "#/components/schemas/PluginExpiryNotice" }
2761
+ required: [expiring, expired]
2762
+ "401": { $ref: "#/components/responses/Unauthorized" }
2763
+ "502": { $ref: "#/components/responses/Upstream" }
2764
+
2765
+ /plugins/expiry/seen:
2766
+ post:
2767
+ tags: [Plugins]
2768
+ summary: Acknowledge plugin expiry notices
2769
+ operationId: markPluginExpiryNoticesSeen
2770
+ responses:
2771
+ "200":
2772
+ description: How many notices were newly marked seen.
2773
+ content:
2774
+ application/json:
2775
+ schema: { $ref: "#/components/schemas/Cleared" }
2776
+ "401": { $ref: "#/components/responses/Unauthorized" }
2777
+ "502": { $ref: "#/components/responses/Upstream" }
2778
+
2779
+ /admin/plugins:
2780
+ get:
2781
+ tags: ["Admin: plugins"]
2782
+ summary: Every plugin definition
2783
+ operationId: adminListPlugins
2784
+ description: >-
2785
+ The grant editor's view: installed, disabled and unavailable definitions, plus tombstones still worth
2786
+ labelling for grants that outlived them. Independent of the admin's own plugin grants, so a binding
2787
+ nobody holds yet is still assignable. Handler internals and credentials are never included.
2788
+ responses:
2789
+ "200":
2790
+ description: The catalog.
2791
+ content:
2792
+ application/json:
2793
+ schema: { $ref: "#/components/schemas/PluginAdminCatalog" }
2794
+ "401": { $ref: "#/components/responses/Unauthorized" }
2795
+ "403": { $ref: "#/components/responses/Forbidden" }
2796
+ "502": { $ref: "#/components/responses/Upstream" }
2797
+
2798
+ /admin/users/{userId}/plugin-grants:
2799
+ get:
2800
+ tags: ["Admin: plugins"]
2801
+ summary: A user's plugin access
2802
+ operationId: adminListUserPluginGrants
2803
+ description: >-
2804
+ Their stored plugin rows (expired and dormant included, so the editor can show why one does nothing)
2805
+ and the capabilities those add up to, direct and through groups. A sibling of the resource-grants
2806
+ view: one call covers every plugin, so the user page never sweeps per-plugin endpoints.
2807
+ parameters:
2808
+ - $ref: "#/components/parameters/userId"
2809
+ responses:
2810
+ "200":
2811
+ description: Stored assignments and effective capabilities.
2812
+ content:
2813
+ application/json:
2814
+ schema: { $ref: "#/components/schemas/UserPluginAccess" }
2815
+ "401": { $ref: "#/components/responses/Unauthorized" }
2816
+ "403": { $ref: "#/components/responses/Forbidden" }
2817
+ "502": { $ref: "#/components/responses/Upstream" }
2818
+
2819
+ /admin/groups/{groupId}/plugin-grants:
2820
+ get:
2821
+ tags: ["Admin: plugins"]
2822
+ summary: A group's plugin assignments
2823
+ operationId: adminListGroupPluginGrants
2824
+ description: >-
2825
+ The bindings this group hands its members, each marked with whether it can authorize anything right
2826
+ now. The groups list carries the same bindings as bare references; this adds the availability the
2827
+ editor needs to show a dormant assignment as dormant and still offer to revoke it.
2828
+ parameters:
2829
+ - $ref: "#/components/parameters/groupId"
2830
+ responses:
2831
+ "200":
2832
+ description: The group's assignments.
2833
+ content:
2834
+ application/json:
2835
+ schema:
2836
+ type: object
2837
+ properties:
2838
+ assignments:
2839
+ type: array
2840
+ items: { $ref: "#/components/schemas/PluginAssignment" }
2841
+ required: [assignments]
2842
+ "401": { $ref: "#/components/responses/Unauthorized" }
2843
+ "403": { $ref: "#/components/responses/Forbidden" }
2844
+ "404": { $ref: "#/components/responses/NotFound" }
2845
+ "502": { $ref: "#/components/responses/Upstream" }
2846
+
2847
+ /admin/plugins/{pluginId}/accounts/{accountNumber}/grants:
2848
+ get:
2849
+ tags: ["Admin: plugins"]
2850
+ summary: Who holds this plugin binding
2851
+ operationId: adminListPluginGrants
2852
+ description: Stored assignments (users and groups, expired rows included) and the effective holders with provenance.
2853
+ parameters:
2854
+ - $ref: "#/components/parameters/pluginId"
2855
+ - $ref: "#/components/parameters/accountNumber"
2856
+ responses:
2857
+ "200":
2858
+ description: Assignments and holders.
2859
+ content:
2860
+ application/json:
2861
+ schema:
2862
+ type: object
2863
+ properties:
2864
+ assignments:
2865
+ type: array
2866
+ items: { $ref: "#/components/schemas/PluginAssignment" }
2867
+ holders:
2868
+ type: array
2869
+ items: { $ref: "#/components/schemas/PluginHolder" }
2870
+ required: [assignments, holders]
2871
+ "400": { $ref: "#/components/responses/BadRequest" }
2872
+ "401": { $ref: "#/components/responses/Unauthorized" }
2873
+ "403": { $ref: "#/components/responses/Forbidden" }
2874
+ "404": { $ref: "#/components/responses/NotFound" }
2875
+ "502": { $ref: "#/components/responses/Upstream" }
2876
+ put:
2877
+ tags: ["Admin: plugins"]
2878
+ summary: Assign plugin access
2879
+ operationId: adminAssignPlugin
2880
+ description: >-
2881
+ Idempotent; re-assigning rewrites the row (the extend path) and never downgrades a long-term grant to
2882
+ a temporary one. Groups are standing, so an expiry on a group is refused. 404 for an unknown plugin,
2883
+ group, or user (a person in the pool or a registered service user). 409 when the plugin is installed
2884
+ but the binding is unavailable (disabled, removed, unsupported, or an unregistered account).
2885
+ parameters:
2886
+ - $ref: "#/components/parameters/pluginId"
2887
+ - $ref: "#/components/parameters/accountNumber"
2888
+ requestBody:
2889
+ required: true
2890
+ content:
2891
+ application/json:
2892
+ schema:
2893
+ type: object
2894
+ properties:
2895
+ principal: { $ref: "#/components/schemas/PluginPrincipal" }
2896
+ permission: { $ref: "#/components/schemas/PluginPermission" }
2897
+ durationHours: { $ref: "#/components/schemas/DurationHours" }
2898
+ required: [principal, permission]
2899
+ example: { principal: { kind: user, userId: 6f1e2d3c-0000-4000-8000-000000000001 }, permission: user }
2900
+ responses:
2901
+ "200":
2902
+ description: The stored assignment.
2903
+ content:
2904
+ application/json:
2905
+ schema:
2906
+ type: object
2907
+ properties:
2908
+ assignment: { $ref: "#/components/schemas/PluginAssignment" }
2909
+ required: [assignment]
2910
+ "400": { $ref: "#/components/responses/BadRequest" }
2911
+ "401": { $ref: "#/components/responses/Unauthorized" }
2912
+ "403": { $ref: "#/components/responses/Forbidden" }
2913
+ "404": { $ref: "#/components/responses/NotFound" }
2914
+ "409": { $ref: "#/components/responses/Conflict" }
2915
+ "502": { $ref: "#/components/responses/Upstream" }
2916
+ delete:
2917
+ tags: ["Admin: plugins"]
2918
+ summary: Revoke plugin access
2919
+ operationId: adminRevokePlugin
2920
+ description: >-
2921
+ Idempotent, and deliberately unconditional: a stale row on a disabled or removed plugin stays
2922
+ revocable, so availability is not checked first. Holders who lose a capability are noticed.
2923
+ parameters:
2924
+ - $ref: "#/components/parameters/pluginId"
2925
+ - $ref: "#/components/parameters/accountNumber"
2926
+ requestBody:
2927
+ required: true
2928
+ content:
2929
+ application/json:
2930
+ schema:
2931
+ type: object
2932
+ properties:
2933
+ principal: { $ref: "#/components/schemas/PluginPrincipal" }
2934
+ permission: { $ref: "#/components/schemas/PluginPermission" }
2935
+ required: [principal, permission]
2936
+ example: { principal: { kind: group, groupId: platform-team }, permission: admin }
2937
+ responses:
2938
+ "204": { description: Revoked (or there was nothing to revoke — this is idempotent). }
2939
+ "400": { $ref: "#/components/responses/BadRequest" }
2940
+ "401": { $ref: "#/components/responses/Unauthorized" }
2941
+ "403": { $ref: "#/components/responses/Forbidden" }
2942
+ "404": { description: The named group does not exist. }
2943
+ "409": { $ref: "#/components/responses/Conflict" }
2944
+ "502": { $ref: "#/components/responses/Upstream" }
2945
+
2946
+ components:
2947
+ securitySchemes:
2948
+ bearerAuth:
2949
+ type: http
2950
+ scheme: bearer
2951
+ bearerFormat: JWT
2952
+ description: A Cognito ID token (humans) or a `client_credentials` access token with the `api/invoke` scope (service users).
2953
+
2954
+ parameters:
2955
+ accountNumber:
2956
+ name: accountNumber
2957
+ in: path
2958
+ required: true
2959
+ schema: { $ref: "#/components/schemas/AccountNumber" }
2960
+ roleName:
2961
+ name: roleName
2962
+ in: path
2963
+ required: true
2964
+ description: The IAM role name as catalogued (not the ARN).
2965
+ schema: { type: string }
2966
+ role:
2967
+ name: role
2968
+ in: path
2969
+ required: true
2970
+ description: The IAM role name as catalogued (not the ARN).
2971
+ schema: { type: string }
2972
+ userId:
2973
+ name: userId
2974
+ in: path
2975
+ required: true
2976
+ description: A Cognito `sub`, or a service user's client id.
2977
+ schema: { type: string }
2978
+ requestId:
2979
+ name: requestId
2980
+ in: path
2981
+ required: true
2982
+ schema: { type: string }
2983
+ groupId:
2984
+ name: groupId
2985
+ in: path
2986
+ required: true
2987
+ schema: { type: string }
2988
+ resourceId:
2989
+ name: resourceId
2990
+ in: path
2991
+ required: true
2992
+ schema: { type: string }
2993
+ pluginId:
2994
+ name: pluginId
2995
+ in: path
2996
+ required: true
2997
+ description: The plugin's registered id.
2998
+ schema: { type: string, pattern: "^[a-z][a-z0-9-]{0,63}$" }
2999
+ example: parameters
3000
+ clientId:
3001
+ name: clientId
3002
+ in: path
3003
+ required: true
3004
+ description: A Cognito app client id (lowercase alphanumerics).
3005
+ schema: { type: string, pattern: "^[a-z0-9]{1,128}$" }
3006
+ # The list contract (catalog-sized lists): pass `limit` to receive one page — `{ items, nextCursor, total,
3007
+ # facets }` — instead of the whole list. Pages are cut in the API from an in-memory catalog index after
3008
+ # access is decided, so search is substring-by-token, sorts are any listed key, totals are exact.
3009
+ listQ:
3010
+ name: q
3011
+ in: query
3012
+ description: Whitespace-separated tokens; every token must occur (case-insensitive substring) in the row's searchable text (name, number, role names).
3013
+ schema: { type: string }
3014
+ listFilter:
3015
+ name: filter
3016
+ in: query
3017
+ description: Facet filters, `filter[key]=a,b` (any of the listed values; keys AND together). Each route names its facet keys.
3018
+ style: deepObject
3019
+ explode: true
3020
+ schema:
3021
+ type: object
3022
+ additionalProperties: { type: string }
3023
+ listSort:
3024
+ name: sort
3025
+ in: query
3026
+ description: A sort key the route lists; prefix `-` for descending. Ties break on the row id.
3027
+ schema: { type: string }
3028
+ listLimit:
3029
+ name: limit
3030
+ in: query
3031
+ description: Page size, 1–200. Present = paged response; absent = the whole list (older clients).
3032
+ schema: { type: integer, minimum: 1, maximum: 200 }
3033
+ listCursor:
3034
+ name: cursor
3035
+ in: query
3036
+ description: The previous page's `nextCursor`. Opaque; tied to the same `q`/`filter`/`sort` (400 otherwise). Rows inserted or removed between pages are neither skipped nor repeated.
3037
+ schema: { type: string }
3038
+
3039
+ responses:
3040
+ BadRequest:
3041
+ description: Malformed input — the message says which field.
3042
+ content:
3043
+ application/json:
3044
+ schema: { $ref: "#/components/schemas/Error" }
3045
+ Unauthorized:
3046
+ description: Missing, invalid or expired bearer token.
3047
+ content:
3048
+ application/json:
3049
+ schema: { $ref: "#/components/schemas/Error" }
3050
+ Forbidden:
3051
+ description: Admin access required.
3052
+ content:
3053
+ application/json:
3054
+ schema: { $ref: "#/components/schemas/Error" }
3055
+ NotFound:
3056
+ description: The addressed thing does not exist.
3057
+ content:
3058
+ application/json:
3059
+ schema: { $ref: "#/components/schemas/Error" }
3060
+ Conflict:
3061
+ description: Already exists, still in use, or already decided.
3062
+ content:
3063
+ application/json:
3064
+ schema: { $ref: "#/components/schemas/Error" }
3065
+ NotDeployed:
3066
+ description: The feature is not deployed on this installation.
3067
+ content:
3068
+ application/json:
3069
+ schema: { $ref: "#/components/schemas/Error" }
3070
+ Upstream:
3071
+ description: A downstream AWS call failed (details stay in the Lambda log).
3072
+ content:
3073
+ application/json:
3074
+ schema: { $ref: "#/components/schemas/Error" }
3075
+
3076
+ schemas:
3077
+ ReportJob:
3078
+ type: object
3079
+ properties:
3080
+ jobId: { type: string, format: uuid }
3081
+ kind: { type: string, enum: [accessReport] }
3082
+ status: { type: string, enum: [running, done, failed] }
3083
+ requestedBy: { type: string }
3084
+ startedAt: { type: string, format: date-time }
3085
+ finishedAt: { type: string, format: date-time }
3086
+ rows: { type: integer, minimum: 0 }
3087
+ error: { type: string }
3088
+ url: { type: string, format: uri, description: Presigned download, present once `done`; valid 15 minutes. }
3089
+ required: [jobId, kind, status, requestedBy, startedAt]
3090
+ ListPage:
3091
+ type: object
3092
+ description: One page of the list contract. `items` is typed per route.
3093
+ properties:
3094
+ nextCursor: { type: string, description: Pass as `cursor` for the next page; absent on the last page. }
3095
+ total: { type: integer, minimum: 0, description: Rows matching `q` and the filters, across all pages. }
3096
+ facets:
3097
+ type: object
3098
+ description: "Per facet key: value → row count over the rows matching `q` and the OTHER facets' filters (so a filtered facet still shows its alternatives)."
3099
+ additionalProperties:
3100
+ type: object
3101
+ additionalProperties: { type: integer }
3102
+ required: [total, facets]
3103
+ AccountAccessPage:
3104
+ allOf:
3105
+ - $ref: "#/components/schemas/ListPage"
3106
+ - type: object
3107
+ properties:
3108
+ items: { type: array, items: { $ref: "#/components/schemas/AccountAccess" } }
3109
+ required: [items]
3110
+ RequestableAccountPage:
3111
+ allOf:
3112
+ - $ref: "#/components/schemas/ListPage"
3113
+ - type: object
3114
+ properties:
3115
+ items: { type: array, items: { $ref: "#/components/schemas/RequestableAccount" } }
3116
+ required: [items]
3117
+ AdminAccountPage:
3118
+ allOf:
3119
+ - $ref: "#/components/schemas/ListPage"
3120
+ - type: object
3121
+ properties:
3122
+ items: { type: array, items: { $ref: "#/components/schemas/AdminAccount" } }
3123
+ required: [items]
3124
+ UserPage:
3125
+ allOf:
3126
+ - $ref: "#/components/schemas/ListPage"
3127
+ - type: object
3128
+ properties:
3129
+ items: { type: array, items: { $ref: "#/components/schemas/User" } }
3130
+ required: [items]
3131
+ PluginPermission:
3132
+ type: string
3133
+ enum: [user, admin]
3134
+ description: A plugin's two permission levels. `admin` includes `user` only where the plugin declares `user`.
3135
+ PluginPrincipal:
3136
+ type: object
3137
+ description: Who a plugin assignment is for. Groups are standing — they carry no expiry.
3138
+ oneOf:
3139
+ - type: object
3140
+ properties:
3141
+ kind: { type: string, enum: [user] }
3142
+ userId: { type: string, description: Cognito sub. }
3143
+ required: [kind, userId]
3144
+ - type: object
3145
+ properties:
3146
+ kind: { type: string, enum: [group] }
3147
+ groupId: { type: string }
3148
+ required: [kind, groupId]
3149
+ PluginUnavailableReason:
3150
+ type: string
3151
+ enum: [plugin-unknown, plugin-disabled, plugin-removed, plugin-unsupported, permission-undeclared, account-unbound, account-unregistered]
3152
+ description: Why a stored row cannot authorize anything right now.
3153
+ PluginAssignment:
3154
+ type: object
3155
+ description: One stored grant row, as the editor sees it. A row that is expired or unavailable is kept, shown, and revocable.
3156
+ properties:
3157
+ pluginId: { type: string }
3158
+ accountNumber: { type: string }
3159
+ permission: { $ref: "#/components/schemas/PluginPermission" }
3160
+ principal: { $ref: "#/components/schemas/PluginPrincipal" }
3161
+ grantedBy: { type: string }
3162
+ grantedAt: { type: string, format: date-time }
3163
+ expiresAt: { type: string, format: date-time }
3164
+ expired: { type: boolean }
3165
+ available: { type: boolean, description: Whether this row can authorize anything right now. }
3166
+ reason: { $ref: "#/components/schemas/PluginUnavailableReason" }
3167
+ required: [pluginId, accountNumber, permission, principal, expired, available]
3168
+ PluginCapability:
3169
+ type: object
3170
+ description: An effective capability, with the stored grants behind it. Implication is applied here, never stored.
3171
+ properties:
3172
+ pluginId: { type: string }
3173
+ accountNumber: { type: string }
3174
+ permission: { $ref: "#/components/schemas/PluginPermission" }
3175
+ available: { type: boolean }
3176
+ reason: { $ref: "#/components/schemas/PluginUnavailableReason" }
3177
+ sources:
3178
+ type: array
3179
+ description: The grants this capability cites — a user capability may cite an admin grant, never the reverse.
3180
+ items:
3181
+ type: object
3182
+ properties:
3183
+ permission: { $ref: "#/components/schemas/PluginPermission" }
3184
+ groups: { type: array, items: { type: string } }
3185
+ required: [permission, groups]
3186
+ required: [pluginId, accountNumber, permission, available, sources]
3187
+ PluginHolder:
3188
+ type: object
3189
+ description: Someone who can use the binding right now, directly or through a group.
3190
+ properties:
3191
+ userId: { type: string }
3192
+ email: { type: string }
3193
+ capabilities:
3194
+ type: array
3195
+ items: { $ref: "#/components/schemas/PluginCapability" }
3196
+ required: [userId, capabilities]
3197
+ UserPluginAccess:
3198
+ type: object
3199
+ description: A user's stored plugin rows and the capabilities they add up to (direct plus via groups).
3200
+ properties:
3201
+ assignments:
3202
+ type: array
3203
+ items: { $ref: "#/components/schemas/PluginAssignment" }
3204
+ capabilities:
3205
+ type: array
3206
+ items: { $ref: "#/components/schemas/PluginCapability" }
3207
+ required: [assignments, capabilities]
3208
+ PluginDiscoveryUiEntry:
3209
+ type: object
3210
+ properties:
3211
+ label: { type: string }
3212
+ icon: { type: string }
3213
+ order: { type: integer }
3214
+ url: { type: string, description: Absolute path on the portal origin, under the plugin's immutable asset prefix. }
3215
+ required: [label, url]
3216
+ PluginDiscovery:
3217
+ type: object
3218
+ description: Caller discovery. An empty list means the feature is off or nothing is registered.
3219
+ properties:
3220
+ schemaVersion: { type: integer, enum: [1] }
3221
+ refreshAfterSeconds: { type: integer, description: How long the portal may keep this before refreshing (15–300). }
3222
+ plugins:
3223
+ type: array
3224
+ items:
3225
+ type: object
3226
+ properties:
3227
+ id: { type: string }
3228
+ displayName: { type: string }
3229
+ description: { type: string }
3230
+ version: { type: string }
3231
+ revision: { type: string }
3232
+ apiBaseUrl: { type: string }
3233
+ ui:
3234
+ type: object
3235
+ properties:
3236
+ user: { $ref: "#/components/schemas/PluginDiscoveryUiEntry" }
3237
+ admin: { $ref: "#/components/schemas/PluginDiscoveryUiEntry" }
3238
+ accounts:
3239
+ type: array
3240
+ items:
3241
+ type: object
3242
+ properties:
3243
+ accountNumber: { type: string }
3244
+ displayName: { type: string, description: From the Accounts catalog, not from any IAM role grant. }
3245
+ regions: { type: array, items: { type: string } }
3246
+ permissions:
3247
+ type: array
3248
+ description: Effective capabilities on this account, not stored assignments.
3249
+ items: { $ref: "#/components/schemas/PluginPermission" }
3250
+ required: [accountNumber, displayName, permissions]
3251
+ required: [id, displayName, version, revision, apiBaseUrl, ui, accounts]
3252
+ required: [schemaVersion, refreshAfterSeconds, plugins]
3253
+ PluginAdminCatalog:
3254
+ type: object
3255
+ description: Every definition, for the grant editor.
3256
+ properties:
3257
+ schemaVersion: { type: integer, enum: [1] }
3258
+ plugins:
3259
+ type: array
3260
+ items:
3261
+ type: object
3262
+ properties:
3263
+ id: { type: string }
3264
+ displayName: { type: string }
3265
+ description: { type: string }
3266
+ version: { type: string }
3267
+ revision: { type: string }
3268
+ schemaVersion: { type: integer }
3269
+ hostApiVersion: { type: integer }
3270
+ status: { type: string, enum: [active, disabled, removed, unsupported] }
3271
+ enabled: { type: boolean }
3272
+ installed: { type: boolean, description: false = tombstone, kept so historical grants keep their labels. }
3273
+ permissions:
3274
+ type: array
3275
+ items:
3276
+ type: object
3277
+ properties:
3278
+ id: { $ref: "#/components/schemas/PluginPermission" }
3279
+ label: { type: string }
3280
+ description: { type: string }
3281
+ implies:
3282
+ type: array
3283
+ items: { $ref: "#/components/schemas/PluginPermission" }
3284
+ required: [id, label, implies]
3285
+ accounts:
3286
+ type: array
3287
+ items:
3288
+ type: object
3289
+ properties:
3290
+ accountNumber: { type: string }
3291
+ displayName: { type: string }
3292
+ regions: { type: array, items: { type: string } }
3293
+ available: { type: boolean }
3294
+ reason: { type: string, enum: [unregistered] }
3295
+ required: [accountNumber, available]
3296
+ ui:
3297
+ type: object
3298
+ properties:
3299
+ user: { type: object, properties: { label: { type: string }, icon: { type: string }, order: { type: integer } }, required: [label] }
3300
+ admin: { type: object, properties: { label: { type: string }, icon: { type: string }, order: { type: integer } }, required: [label] }
3301
+ routes:
3302
+ type: array
3303
+ items:
3304
+ type: object
3305
+ properties:
3306
+ id: { type: string }
3307
+ method: { type: string }
3308
+ path: { type: string }
3309
+ permission: { $ref: "#/components/schemas/PluginPermission" }
3310
+ required: [id, method, path, permission]
3311
+ updatedAt: { type: string, format: date-time }
3312
+ required: [id, displayName, version, revision, schemaVersion, hostApiVersion, status, enabled, installed, permissions, accounts, ui, routes, updatedAt]
3313
+ required: [schemaVersion, plugins]
3314
+ Error:
3315
+ type: object
3316
+ properties:
3317
+ message: { type: string }
3318
+ required: [message]
3319
+ Message:
3320
+ type: object
3321
+ properties:
3322
+ message: { type: string }
3323
+ required: [message]
3324
+ Cleared:
3325
+ type: object
3326
+ properties:
3327
+ cleared: { type: integer, description: How many rows were newly marked seen. }
3328
+ required: [cleared]
3329
+ AccountNumber:
3330
+ type: string
3331
+ pattern: "^\\d{12}$"
3332
+ description: 12-digit AWS account id.
3333
+ example: "123456789012"
3334
+ DurationHours:
3335
+ type: integer
3336
+ enum: [1, 12, 24, 72, 168, 720]
3337
+ description: Temporary-access preset in hours (1 h, 12 h, 1 d, 3 d, 7 d, 30 d). Omit for long-term access.
3338
+ RoleRef:
3339
+ type: object
3340
+ properties:
3341
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3342
+ roleName: { type: string }
3343
+ required: [accountNumber, roleName]
3344
+ UserIdList:
3345
+ type: object
3346
+ properties:
3347
+ userIds: { type: array, items: { type: string }, minItems: 1 }
3348
+ required: [userIds]
3349
+ ProfileNameValue:
3350
+ type: object
3351
+ properties:
3352
+ profileName: { type: [string, "null"] }
3353
+ required: [profileName]
3354
+
3355
+ Discovery:
3356
+ type: object
3357
+ properties:
3358
+ projectName: { type: string, description: "Empty when unset — clients fall back to the hostname." }
3359
+ cognito:
3360
+ type: object
3361
+ properties:
3362
+ userPoolId: { type: string }
3363
+ clientId: { type: string }
3364
+ region: { type: string }
3365
+ required: [userPoolId, clientId, region]
3366
+ issuer: { type: string, format: uri, description: The OIDC issuer URL baked into cross-account trust. }
3367
+ network:
3368
+ type: [object, "null"]
3369
+ description: "`null` when no private network is deployed."
3370
+ properties:
3371
+ controlUrl: { type: string, format: uri, description: Legacy single-site field (first site). }
3372
+ sites:
3373
+ type: array
3374
+ items:
3375
+ type: object
3376
+ properties:
3377
+ id: { type: string }
3378
+ displayName: { type: string }
3379
+ controlUrl: { type: string, format: uri }
3380
+ required: [id, displayName, controlUrl]
3381
+ required: [controlUrl, sites]
3382
+ required: [projectName, cognito, issuer, network]
3383
+
3384
+ AccountAccess:
3385
+ type: object
3386
+ properties:
3387
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3388
+ name: { type: string, description: Admin-set friendly name. }
3389
+ environment: { type: string }
3390
+ dims: { $ref: "#/components/schemas/AccountDims" }
3391
+ sortOrder: { type: integer, minimum: 0, description: Admin-set display position; the list is already in this order. }
3392
+ position: { type: integer, minimum: 0, description: Index in the admin order (the `position` sort key). }
3393
+ main: { type: boolean, enum: [false], description: Present (false) only for an account an admin took off the dashboard's Main section. }
3394
+ roles:
3395
+ type: array
3396
+ items: { $ref: "#/components/schemas/RoleAccess" }
3397
+ required: [accountNumber, position, roles]
3398
+ RoleAccess:
3399
+ type: object
3400
+ properties:
3401
+ role: { type: string }
3402
+ roleArn: { type: string }
3403
+ displayName: { type: string }
3404
+ description: { type: string }
3405
+ icon: { type: string }
3406
+ expiresAt: { type: string, format: date-time, description: End of a temporary grant; absent = long-term. }
3407
+ profileName: { type: string, description: THE `~/.aws` profile name for this role — what the desktop writes. }
3408
+ profileSource: { type: string, enum: [override, account, role, default] }
3409
+ suggestedProfileName: { type: string, description: What the name would be without the caller's override. }
3410
+ required: [role, roleArn, profileName, profileSource, suggestedProfileName]
3411
+ VendedCredentials:
3412
+ type: object
3413
+ properties:
3414
+ accessKeyId: { type: string }
3415
+ secretKey: { type: string }
3416
+ sessionToken: { type: string }
3417
+ expiration: { type: string, format: date-time }
3418
+ required: [accessKeyId, secretKey, sessionToken]
3419
+ ConsoleSignIn:
3420
+ type: object
3421
+ properties:
3422
+ url: { type: string, format: uri, description: Short-lived federation sign-in URL. }
3423
+ expiration: { type: string, format: date-time }
3424
+ required: [url]
3425
+ ExpiryNotice:
3426
+ type: object
3427
+ properties:
3428
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3429
+ roleName: { type: string }
3430
+ expiresAt: { type: string, format: date-time }
3431
+ seen: { type: boolean, description: Acknowledged for THIS phase (expiring vs expired). }
3432
+ required: [accountNumber, roleName, expiresAt, seen]
3433
+ ExpiryNotices:
3434
+ type: object
3435
+ properties:
3436
+ expiring: { type: array, items: { $ref: "#/components/schemas/ExpiryNotice" } }
3437
+ expired: { type: array, items: { $ref: "#/components/schemas/ExpiryNotice" } }
3438
+ required: [expiring, expired]
3439
+
3440
+ RequestableAccount:
3441
+ type: object
3442
+ properties:
3443
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3444
+ name: { type: string }
3445
+ dims: { $ref: "#/components/schemas/AccountDims" }
3446
+ roles:
3447
+ type: array
3448
+ items:
3449
+ type: object
3450
+ properties:
3451
+ roleName: { type: string }
3452
+ displayName: { type: string }
3453
+ description: { type: string }
3454
+ required: [roleName]
3455
+ required: [accountNumber, roles]
3456
+ RequestableResource:
3457
+ type: object
3458
+ properties:
3459
+ resourceId: { type: string }
3460
+ name: { type: string }
3461
+ type: { $ref: "#/components/schemas/ResourceType" }
3462
+ description: { type: string }
3463
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3464
+ accountName: { type: string }
3465
+ required: [resourceId, name, type, accountNumber]
3466
+ AccessRequest:
3467
+ type: object
3468
+ description: One access request or review. `kind` says what is under decision; `type` whether it was raised by a user (`ACCESS`) or by the periodic review sweep (`REAPPROVAL`).
3469
+ properties:
3470
+ requestId: { type: string }
3471
+ userId: { type: string, description: "The requester's sub (reapproval: the holder; group reapproval: the groupId; service-user review: the client id)." }
3472
+ kind: { type: string, enum: [ROLE, RESOURCE, ADMIN, SERVICE_USER, PLUGIN, GROUP], description: "PLUGIN = a plugin permission (pluginId + accountNumber + permission); GROUP = the yearly review of a whole group's bundle (userId and groupId are the group; approve restarts its clock, deny deletes the group). Both reapproval-only." }
3473
+ type: { type: string, enum: [ACCESS, REAPPROVAL] }
3474
+ groupId: { type: string, description: Set on group reapprovals. }
3475
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3476
+ roleName: { type: string }
3477
+ resourceId: { type: string }
3478
+ pluginId: { type: string, description: Set on PLUGIN rows. }
3479
+ permission: { type: string, enum: [user, admin], description: Set on PLUGIN rows. }
3480
+ resourceName: { type: string, description: Resolved by the route on RESOURCE rows. }
3481
+ reason: { type: string }
3482
+ requestedDurationHours: { $ref: "#/components/schemas/DurationHours" }
3483
+ grantedDurationHours: { $ref: "#/components/schemas/DurationHours" }
3484
+ status: { type: string, enum: [PENDING, APPROVED, DENIED] }
3485
+ createdAt: { type: string, format: date-time }
3486
+ decidedAt: { type: string, format: date-time }
3487
+ decidedBy: { type: string }
3488
+ decisionNote: { type: string }
3489
+ seen: { type: boolean, description: Requester acknowledged the decision. }
3490
+ required: [requestId, userId, status, createdAt]
3491
+ AccessRequestAdminView:
3492
+ allOf:
3493
+ - $ref: "#/components/schemas/AccessRequest"
3494
+ - type: object
3495
+ properties:
3496
+ email: { type: string, description: Requester's email; empty if the user is gone. }
3497
+ serviceUser: { type: string, description: Registry name when the requester is a service user. }
3498
+ group: { type: string, description: Group name on group reapprovals. }
3499
+ usage:
3500
+ type: object
3501
+ description: Only with `?usage=1` on pending role reapprovals.
3502
+ properties:
3503
+ count: { type: integer }
3504
+ lastAt: { type: string, format: date-time }
3505
+ required: [count]
3506
+ required: [email]
3507
+ RequestEnvelope:
3508
+ type: object
3509
+ properties:
3510
+ request: { $ref: "#/components/schemas/AccessRequest" }
3511
+ required: [request]
3512
+
3513
+ RolePreference:
3514
+ type: object
3515
+ properties:
3516
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3517
+ role: { type: string }
3518
+ profileName: { type: [string, "null"] }
3519
+ roleLabel: { type: [string, "null"] }
3520
+ autoVend: { type: boolean }
3521
+ required: [accountNumber, role, profileName, roleLabel, autoVend]
3522
+ NetworkPrefs:
3523
+ type: object
3524
+ properties:
3525
+ autoReconnect: { type: boolean }
3526
+ lastSiteId: { type: [string, "null"] }
3527
+ required: [autoReconnect, lastSiteId]
3528
+
3529
+ NotificationPrefs:
3530
+ type: object
3531
+ properties:
3532
+ enabled: { type: boolean, description: Master switch. }
3533
+ kinds:
3534
+ type: object
3535
+ description: Per item kind — granted (a direct grant), revoked, decided (a request decision), expiring (temporary access near or past its end), session (the sign-in is about to reach its cap), requests (admins — a new request waiting), reviews (admins — yearly reviews raised).
3536
+ additionalProperties: { type: boolean }
3537
+ required: [enabled, kinds]
3538
+
3539
+ PublicSite:
3540
+ type: object
3541
+ properties:
3542
+ id: { type: string }
3543
+ displayName: { type: string }
3544
+ controlUrl: { type: string, format: uri }
3545
+ accounts: { type: array, items: { $ref: "#/components/schemas/AccountNumber" }, description: Accounts in this routing domain. }
3546
+ required: [id, controlUrl, accounts]
3547
+ NetworkSite:
3548
+ allOf:
3549
+ - $ref: "#/components/schemas/PublicSite"
3550
+ - type: object
3551
+ properties:
3552
+ splitDns:
3553
+ type: object
3554
+ additionalProperties: { type: array, items: { type: string } }
3555
+ description: Private zone → resolver IPs.
3556
+ connectorVpcs:
3557
+ type: object
3558
+ additionalProperties:
3559
+ type: array
3560
+ items:
3561
+ type: object
3562
+ properties:
3563
+ vpcId: { type: string }
3564
+ routes: { type: array, items: { type: string } }
3565
+ region: { type: string, description: Set when the VPC is outside the hub's region. }
3566
+ name: { type: string, description: Set for every connector VPC of an account but its one unnamed VPC; suffixes the connector hostname. }
3567
+ required: [vpcId, routes]
3568
+ description: Keyed by account number, one entry per connector VPC.
3569
+ DevShareGrantee:
3570
+ type: object
3571
+ properties:
3572
+ kind: { type: string, enum: [user, group] }
3573
+ id: { type: string }
3574
+ name: { type: string, description: Email (user) or group name; the id when the directory no longer knows it. }
3575
+ required: [kind, id, name]
3576
+ DevShare:
3577
+ type: object
3578
+ description: A dev share as its owner (or an admin) sees it.
3579
+ properties:
3580
+ shareId: { type: string, pattern: "^[a-f0-9]{12}$" }
3581
+ ownerSub: { type: string }
3582
+ ownerName: { type: string, description: The owner's email at creation. }
3583
+ port: { type: integer }
3584
+ label: { type: string }
3585
+ siteId: { type: string }
3586
+ hostname: { type: string }
3587
+ ip: { type: string }
3588
+ url:
3589
+ type: [string, "null"]
3590
+ description: "`http://<hostname|ip>:<port>`; null until the desktop app reported an address."
3591
+ createdAt: { type: string, format: date-time }
3592
+ expiresAt: { type: string, format: date-time }
3593
+ grantees: { type: array, items: { $ref: "#/components/schemas/DevShareGrantee" } }
3594
+ required: [shareId, ownerSub, ownerName, port, label, siteId, url, createdAt, expiresAt, grantees]
3595
+ DevShareWithMe:
3596
+ type: object
3597
+ description: A dev share as a grantee sees it (no grantee list).
3598
+ properties:
3599
+ shareId: { type: string }
3600
+ ownerSub: { type: string }
3601
+ ownerName: { type: string }
3602
+ port: { type: integer }
3603
+ label: { type: string }
3604
+ siteId: { type: string }
3605
+ url: { type: [string, "null"] }
3606
+ expiresAt: { type: string, format: date-time }
3607
+ viaGroups:
3608
+ type: array
3609
+ items: { type: string }
3610
+ description: Names of the caller's groups the share came through; empty = granted directly.
3611
+ required: [shareId, ownerSub, ownerName, port, label, siteId, url, expiresAt, viaGroups]
3612
+ DevShareDirectory:
3613
+ type: object
3614
+ properties:
3615
+ users:
3616
+ type: array
3617
+ items:
3618
+ type: object
3619
+ properties:
3620
+ userId: { type: string }
3621
+ email: { type: string }
3622
+ required: [userId, email]
3623
+ groups:
3624
+ type: array
3625
+ items:
3626
+ type: object
3627
+ properties:
3628
+ groupId: { type: string }
3629
+ name: { type: string }
3630
+ members: { type: integer }
3631
+ required: [groupId, name, members]
3632
+ required: [users, groups]
3633
+
3634
+ DeviceKey:
3635
+ type: object
3636
+ properties:
3637
+ key: { type: string, description: Single-use enrollment key. }
3638
+ expiresAt: { type: string, format: date-time }
3639
+ controlUrl: { type: string, format: uri }
3640
+ siteId: { type: string }
3641
+ required: [key, expiresAt, controlUrl, siteId]
3642
+
3643
+ ResourceType:
3644
+ type: string
3645
+ enum: [DATABASE, WEB, HOST]
3646
+ ReachableResource:
3647
+ type: object
3648
+ properties:
3649
+ resourceId: { type: string }
3650
+ name: { type: string }
3651
+ type: { $ref: "#/components/schemas/ResourceType" }
3652
+ cidr: { type: string }
3653
+ ports: { type: array, items: { type: integer } }
3654
+ dnsName: { type: string }
3655
+ sshUser: { type: string }
3656
+ description: { type: string }
3657
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3658
+ accountName: { type: string }
3659
+ expiresAt: { type: string, format: date-time, description: Absent = long-term. }
3660
+ required: [resourceId, name, type, cidr, ports, accountNumber]
3661
+ PluginExpiryNotice:
3662
+ type: object
3663
+ properties:
3664
+ pluginId: { type: string }
3665
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3666
+ permission: { $ref: "#/components/schemas/PluginPermission" }
3667
+ expiresAt: { type: string, format: date-time }
3668
+ seen: { type: boolean }
3669
+ pluginName: { type: string }
3670
+ accountName: { type: string }
3671
+ required: [pluginId, accountNumber, permission, expiresAt, seen, pluginName, accountName]
3672
+ ResourceExpiryNotice:
3673
+ type: object
3674
+ properties:
3675
+ resourceId: { type: string }
3676
+ name: { type: string }
3677
+ expiresAt: { type: string, format: date-time }
3678
+ seen: { type: boolean }
3679
+ required: [resourceId, name, expiresAt, seen]
3680
+ RevocationNotice:
3681
+ type: object
3682
+ description: One access change for the bell — a loss, or (since the activity log) a gain the person did not ask for. `revokedAt` is the notice's timestamp either way.
3683
+ properties:
3684
+ noticeId: { type: string }
3685
+ change: { type: string, enum: [GRANTED, REVOKED], description: Rows written before grants were noticed are REVOKED. }
3686
+ kind: { type: string, enum: [ROLE, RESOURCE, SHARE, PLUGIN, BUNDLE], description: SHARE = a dev share stopped early (resourceId = share id, resourceName = its label). PLUGIN = a plugin permission lost (pluginId + accountNumber + permission, pluginName = the plugin's display name). BUNDLE = one row for `count` targets that changed together (more than five gained or lost by one person through a group membership or bundle edit, or a cascade); groupId/groupName when a group carried it. Direct admin grants and revokes stay one row per target. }
3687
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3688
+ roleName: { type: string }
3689
+ resourceId: { type: string }
3690
+ resourceName: { type: string }
3691
+ pluginId: { type: string }
3692
+ permission: { type: string, enum: [user, admin] }
3693
+ pluginName: { type: string }
3694
+ count: { type: integer, description: BUNDLE only — how many targets the row stands for. }
3695
+ groupId: { type: string, description: BUNDLE only — the group whose membership or bundle edit carried the change. }
3696
+ groupName: { type: string, description: BUNDLE only — that group's name at the time. }
3697
+ revokedAt: { type: string, format: date-time }
3698
+ via: { type: string, enum: [ADMIN, GROUP, REAPPROVAL, CASCADE, OWNER] }
3699
+ seen: { type: boolean }
3700
+ required: [noticeId, change, kind, revokedAt, via, seen]
3701
+
3702
+ SetupStatus:
3703
+ type: object
3704
+ properties:
3705
+ issuerUrl: { type: string, format: uri }
3706
+ region: { type: string }
3707
+ emailConfigured: { type: boolean }
3708
+ emailFrom: { type: string }
3709
+ accounts: { type: integer }
3710
+ roles: { type: integer }
3711
+ usersTotal: { type: integer }
3712
+ invitedActive: { type: boolean, description: Someone other than the caller has finished sign-in. }
3713
+ vended: { type: boolean, description: At least one successful vend or console-open is on record. }
3714
+ configAccounts:
3715
+ type: array
3716
+ items:
3717
+ type: object
3718
+ properties:
3719
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3720
+ roles: { type: array, items: { type: string } }
3721
+ registered: { type: boolean }
3722
+ required: [accountNumber, roles, registered]
3723
+ required: [issuerUrl, region, emailConfigured, accounts, roles, usersTotal, invitedActive, vended, configAccounts]
3724
+ BrandingOverlay:
3725
+ type: object
3726
+ properties:
3727
+ projectName: { type: string }
3728
+ logoUrl: { type: string, description: "`https://` URL or `data:image/*` URI (≤ 64 KB)." }
3729
+ primaryColor: { type: string, pattern: "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" }
3730
+ primaryHoverColor: { type: string }
3731
+ accentColor: { type: string }
3732
+ grayTone: { type: string }
3733
+ radius: { type: string }
3734
+ iconSet: { type: string, enum: [outline, bold, solid] }
3735
+ panelStrength: { type: integer, minimum: 0, maximum: 100 }
3736
+ accentDepth: { type: integer, minimum: 0, maximum: 100 }
3737
+ borderStrength: { type: integer, minimum: 0, maximum: 100 }
3738
+ gradientStrength: { type: integer, minimum: 0, maximum: 100 }
3739
+
3740
+ AdminAccount:
3741
+ type: object
3742
+ properties:
3743
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3744
+ name: { type: string }
3745
+ environment: { type: string }
3746
+ status: { type: string }
3747
+ profileName: { type: string }
3748
+ sortOrder: { type: integer, minimum: 0, description: "Display position (PUT /admin/accounts/order); absent = after the ordered ones. The list is already in this order." }
3749
+ main: { type: boolean, description: "Shown in everyone's dashboard Main section (the default). Sections appear on a user's dashboard only once they hold an account that is not main." }
3750
+ dims: { $ref: "#/components/schemas/AccountDims" }
3751
+ position: { type: integer, minimum: 0, description: Index in the admin order (the `position` sort key). }
3752
+ roles: { type: array, items: { $ref: "#/components/schemas/AdminRole" } }
3753
+ required: [accountNumber, roles]
3754
+ DashboardLayout:
3755
+ type: object
3756
+ properties:
3757
+ mode: { type: string, enum: [auto, sections, plain] }
3758
+ required: [mode]
3759
+ AccountDims:
3760
+ type: object
3761
+ description: |
3762
+ Account dimensions (deployments with `accountDimensions` on): read off the name at registration — first hyphen-separated
3763
+ segment = tenant, last = stage, the rest = project (`acme-data-platform-prod`; `acme-prod` has no project) — editable by an
3764
+ admin afterwards and never re-derived when the account is renamed. They filter lists; they never decide access.
3765
+ properties:
3766
+ tenant: { type: string, minLength: 1 }
3767
+ project: { type: string, minLength: 1 }
3768
+ stage: { type: string, minLength: 1 }
3769
+ required: [tenant, stage]
3770
+ AdminRole:
3771
+ type: object
3772
+ properties:
3773
+ roleName: { type: string }
3774
+ displayName: { type: string }
3775
+ roleArn: { type: string }
3776
+ policyTier: { type: string }
3777
+ description: { type: string }
3778
+ color: { type: string, description: "Chip tint `#rrggbb`." }
3779
+ icon: { type: string, enum: [view, admin, operate, deploy, data, billing, analytics, access] }
3780
+ profileName: { type: string }
3781
+ sessionDurationSeconds: { type: integer, minimum: 900, maximum: 43200 }
3782
+ sortOrder: { type: integer, minimum: 0, description: "Display position inside the account (PUT /admin/accounts/order); absent = after the ordered ones. Lists are already in this order." }
3783
+ grantees: { type: integer, description: Unexpired holders (list route only). }
3784
+ required: [roleName, roleArn]
3785
+ AccountEnvelope:
3786
+ type: object
3787
+ properties:
3788
+ account: { $ref: "#/components/schemas/AdminAccount" }
3789
+ required: [account]
3790
+ RoleEnvelope:
3791
+ type: object
3792
+ properties:
3793
+ role: { $ref: "#/components/schemas/AdminRole" }
3794
+ required: [role]
3795
+ ProfileName:
3796
+ type: string
3797
+ pattern: "^([A-Za-z0-9][A-Za-z0-9_.-]{0,63})?$"
3798
+ description: A `~/.aws/credentials` section name (letters, digits, `.`, `_`, `-`); empty string clears.
3799
+ AccountCreate:
3800
+ type: object
3801
+ properties:
3802
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3803
+ name: { type: string }
3804
+ environment: { type: string }
3805
+ status: { type: string }
3806
+ profileName: { $ref: "#/components/schemas/ProfileName" }
3807
+ main: { type: boolean, default: true, description: "On everyone's dashboard Main section. A pipeline registering rarely used accounts passes false." }
3808
+ dims: { $ref: "#/components/schemas/AccountDims", description: "Explicit dimensions (a pipeline that knows them). Omitted, they are read off `name` when the deployment has account dimensions on." }
3809
+ required: [accountNumber]
3810
+ AccountOrder:
3811
+ type: object
3812
+ properties:
3813
+ accounts:
3814
+ type: array
3815
+ minItems: 1
3816
+ maxItems: 5000
3817
+ items:
3818
+ type: object
3819
+ properties:
3820
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3821
+ roles:
3822
+ type: array
3823
+ maxItems: 200
3824
+ uniqueItems: true
3825
+ items: { type: string, minLength: 1, maxLength: 64 }
3826
+ description: The account's roles, first to last; omit to leave their positions alone.
3827
+ required: [accountNumber]
3828
+ required: [accounts]
3829
+ AccountPatch:
3830
+ type: object
3831
+ description: At least one field.
3832
+ properties:
3833
+ name: { type: string }
3834
+ environment: { type: string }
3835
+ status: { type: string }
3836
+ profileName: { $ref: "#/components/schemas/ProfileName" }
3837
+ main: { type: boolean, description: "On everyone's dashboard Main section (true is the default state of an account)." }
3838
+ dims:
3839
+ oneOf:
3840
+ - $ref: "#/components/schemas/AccountDims"
3841
+ - type: "null"
3842
+ description: The admin's correction of tenant / project / stage; `null` clears them. A rename never changes them.
3843
+ RoleCreate:
3844
+ type: object
3845
+ properties:
3846
+ roleName: { type: string, description: "May not contain `#` or `/`." }
3847
+ displayName: { type: string, maxLength: 128 }
3848
+ roleArn: { type: string, pattern: "^arn:aws:iam::\\d{12}:role/.+" }
3849
+ policyTier: { type: string }
3850
+ description: { type: string }
3851
+ color: { type: string, pattern: "^(#[0-9a-fA-F]{6})?$" }
3852
+ icon: { type: string, enum: ["", view, admin, operate, deploy, data, billing, analytics, access] }
3853
+ profileName: { $ref: "#/components/schemas/ProfileName" }
3854
+ sessionDurationSeconds: { type: integer, minimum: 900, maximum: 43200 }
3855
+ required: [roleName, roleArn]
3856
+ RolePatch:
3857
+ type: object
3858
+ description: At least one field.
3859
+ properties:
3860
+ displayName: { type: string, maxLength: 128 }
3861
+ roleArn: { type: string, pattern: "^arn:aws:iam::\\d{12}:role/.+" }
3862
+ policyTier: { type: string }
3863
+ description: { type: string }
3864
+ color: { type: string, pattern: "^(#[0-9a-fA-F]{6})?$" }
3865
+ icon: { type: string, enum: ["", view, admin, operate, deploy, data, billing, analytics, access] }
3866
+ profileName: { $ref: "#/components/schemas/ProfileName" }
3867
+ sessionDurationSeconds: { type: integer, minimum: 900, maximum: 43200 }
3868
+ TestSessionResult:
3869
+ type: object
3870
+ properties:
3871
+ ok: { type: boolean }
3872
+ message: { type: string, description: STS's message when `ok` is false. }
3873
+ expiration: { type: string, format: date-time }
3874
+ required: [ok]
3875
+
3876
+ Grant:
3877
+ type: object
3878
+ properties:
3879
+ userId: { type: string }
3880
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3881
+ roleName: { type: string }
3882
+ expiresAt: { type: string, format: date-time, description: Absent = long-term. }
3883
+ required: [userId, accountNumber, roleName]
3884
+ Grantee:
3885
+ type: object
3886
+ properties:
3887
+ userId: { type: string }
3888
+ grantedBy: { type: string }
3889
+ grantedAt: { type: string, format: date-time }
3890
+ expiresAt: { type: string, format: date-time }
3891
+ direct: { type: boolean, description: Holds a direct grant row. }
3892
+ viaGroup: { type: string, description: First group providing it when there is no direct grant. }
3893
+ viaGroups: { type: array, items: { type: string }, description: Every group of theirs whose bundle holds it. }
3894
+ required: [userId, direct, viaGroups]
3895
+ UserGrant:
3896
+ type: object
3897
+ properties:
3898
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3899
+ roleName: { type: string }
3900
+ grantedBy: { type: string }
3901
+ grantedAt: { type: string, format: date-time }
3902
+ expiresAt: { type: string, format: date-time, description: Effective expiry; absent when long-term or group-provided. }
3903
+ viaGroup: { type: string }
3904
+ viaGroups: { type: array, items: { type: string } }
3905
+ required: [accountNumber, roleName]
3906
+ BulkAssignResult:
3907
+ type: object
3908
+ properties:
3909
+ userId: { type: string }
3910
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3911
+ roleName: { type: string }
3912
+ status: { type: string, enum: [GRANTED, ALREADY_HAD, FAILED] }
3913
+ message: { type: string }
3914
+ required: [userId, accountNumber, roleName, status]
3915
+ BulkRevokeResult:
3916
+ type: object
3917
+ properties:
3918
+ userId: { type: string }
3919
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3920
+ roleName: { type: string }
3921
+ status: { type: string, enum: [REVOKED, SKIPPED, FAILED] }
3922
+ message: { type: string }
3923
+ required: [userId, accountNumber, roleName, status]
3924
+
3925
+ User:
3926
+ type: object
3927
+ properties:
3928
+ userId: { type: string, description: "Cognito `sub` — the stable id grants are keyed by." }
3929
+ email: { type: string }
3930
+ admin: { type: boolean }
3931
+ pendingInvite: { type: boolean, description: Invited and never signed in — still on the temporary password, and not seen through a federated sign-in either. }
3932
+ lastSeenAt: { type: string, format: date-time }
3933
+ claims:
3934
+ type: object
3935
+ additionalProperties: { type: string }
3936
+ description: "Federated claims on the user, keyed by the config `claims` key (e.g. `gid`). Only when at least one is set."
3937
+ roleCount: { type: integer, minimum: 0, description: "Every role the user holds; `roles` carries at most 50 of them in the listing." }
3938
+ resourceCount: { type: integer, minimum: 0, description: "Every resource the user holds; `resources` carries at most 50 of them in the listing." }
3939
+ roleNames: { type: array, items: { type: string }, description: "Distinct role names over every role held (listing only) — complete where `roles` is cut." }
3940
+ groupNames: { type: array, items: { type: string }, description: Distinct team names over every role and resource held (listing only). }
3941
+ roles:
3942
+ type: array
3943
+ items:
3944
+ type: object
3945
+ properties:
3946
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3947
+ roleName: { type: string }
3948
+ direct: { type: boolean }
3949
+ groups: { type: array, items: { type: string }, description: Names of the user's groups whose bundle also grants it. }
3950
+ required: [accountNumber, roleName, direct, groups]
3951
+ resources:
3952
+ type: array
3953
+ items:
3954
+ type: object
3955
+ properties:
3956
+ resourceId: { type: string }
3957
+ name: { type: string }
3958
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
3959
+ direct: { type: boolean }
3960
+ groups: { type: array, items: { type: string } }
3961
+ required: [resourceId, name, direct, groups]
3962
+ required: [userId, email, admin, pendingInvite, roles, resources]
3963
+ BulkCreateResult:
3964
+ type: object
3965
+ properties:
3966
+ email: { type: string }
3967
+ status: { type: string, enum: [CREATED, FAILED] }
3968
+ userId: { type: string }
3969
+ signupLink: { type: string, description: "On CREATED rows when `sendEmail` was `false`." }
3970
+ message: { type: string }
3971
+ required: [email, status]
3972
+ BulkDeleteResult:
3973
+ type: object
3974
+ properties:
3975
+ userId: { type: string }
3976
+ status: { type: string, enum: [DELETED, FAILED] }
3977
+ message: { type: string }
3978
+ required: [userId, status]
3979
+
3980
+ ServiceUser:
3981
+ type: object
3982
+ properties:
3983
+ clientId: { type: string }
3984
+ name: { type: string }
3985
+ createdAt: { type: string, format: date-time }
3986
+ createdBy: { type: string }
3987
+ lastUsedAt: { type: string, format: date-time }
3988
+ secretCreatedAt: { type: string, format: date-time }
3989
+ reviewedAt: { type: string, format: date-time }
3990
+ roles: { type: array, items: { $ref: "#/components/schemas/UserGrant" } }
3991
+ previous:
3992
+ type: object
3993
+ description: Mid-rotation — the replaced client that still works.
3994
+ properties:
3995
+ clientId: { type: string }
3996
+ rotatedAt: { type: string, format: date-time }
3997
+ lastUsedAt: { type: string, format: date-time }
3998
+ required: [clientId]
3999
+ required: [clientId, name, createdAt, createdBy, roles]
4000
+ ServiceUserWithSecret:
4001
+ type: object
4002
+ properties:
4003
+ serviceUser: { $ref: "#/components/schemas/ServiceUser" }
4004
+ clientSecret: { type: string, description: Returned exactly once. }
4005
+ required: [serviceUser, clientSecret]
4006
+
4007
+ GroupInput:
4008
+ type: object
4009
+ properties:
4010
+ name: { type: string, minLength: 1, maxLength: 64 }
4011
+ description: { type: string, maxLength: 500 }
4012
+ roles: { type: array, items: { $ref: "#/components/schemas/RoleRef" } }
4013
+ resources: { type: array, items: { type: string }, description: Resource ids. }
4014
+ Group:
4015
+ type: object
4016
+ properties:
4017
+ groupId: { type: string }
4018
+ name: { type: string }
4019
+ description: { type: string }
4020
+ roles: { type: array, items: { $ref: "#/components/schemas/RoleRef" }, description: "In the list, at most 50 of them; `roleCount` is the total and GET /admin/groups/{groupId} carries all." }
4021
+ roleCount: { type: integer, minimum: 0 }
4022
+ resources: { type: array, items: { type: string }, description: Resource ids. }
4023
+ plugins:
4024
+ type: array
4025
+ description: Plugin permissions in the bundle.
4026
+ items:
4027
+ type: object
4028
+ properties:
4029
+ pluginId: { type: string }
4030
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
4031
+ permission: { type: string, enum: [user, admin] }
4032
+ required: [pluginId, accountNumber, permission]
4033
+ members: { type: array, items: { type: string }, description: Cognito subs, sorted. }
4034
+ createdAt: { type: string, format: date-time }
4035
+ createdBy: { type: string }
4036
+ required: [groupId, name, roles, resources, plugins, members, createdAt, createdBy]
4037
+ GroupView:
4038
+ type: object
4039
+ properties:
4040
+ groupId: { type: string }
4041
+ name: { type: string }
4042
+ description: { type: string }
4043
+ roles: { type: array, items: { $ref: "#/components/schemas/RoleRef" } }
4044
+ resources:
4045
+ type: array
4046
+ items:
4047
+ type: object
4048
+ properties:
4049
+ resourceId: { type: string }
4050
+ name: { type: string }
4051
+ required: [resourceId, name]
4052
+ members:
4053
+ type: array
4054
+ items:
4055
+ type: object
4056
+ properties:
4057
+ userId: { type: string }
4058
+ email: { type: string }
4059
+ required: [userId, email]
4060
+ createdAt: { type: string, format: date-time }
4061
+ createdBy: { type: string }
4062
+ required: [groupId, name, roles, resources, members, createdAt, createdBy]
4063
+ GroupEnvelope:
4064
+ type: object
4065
+ properties:
4066
+ group: { $ref: "#/components/schemas/Group" }
4067
+ required: [group]
4068
+ GroupRoleChange:
4069
+ type: object
4070
+ description: One role in or out of a bundle — what changed, never the bundle itself.
4071
+ properties:
4072
+ groupId: { type: string }
4073
+ name: { type: string }
4074
+ role: { $ref: "#/components/schemas/GroupRoleRef" }
4075
+ added: { type: boolean, description: "False when the role was already in the bundle." }
4076
+ required: [groupId, name, role, added]
4077
+ GroupRolesBulkResult:
4078
+ type: object
4079
+ properties:
4080
+ matched: { type: integer, description: Accounts matching the filter that have the role. }
4081
+ added: { type: integer, description: Rows written (absent on a dry run). }
4082
+ skipped: { type: integer, description: Matches already in the bundle (absent on a dry run). }
4083
+ remaining: { type: integer, description: "Matches not yet written: one call writes at most 500, call again until this is 0 (absent on a dry run)." }
4084
+ group: { $ref: "#/components/schemas/Group" }
4085
+ required: [matched]
4086
+
4087
+ Resource:
4088
+ type: object
4089
+ properties:
4090
+ resourceId: { type: string }
4091
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
4092
+ name: { type: string }
4093
+ type: { $ref: "#/components/schemas/ResourceType" }
4094
+ cidr: { type: string, description: "Always `a.b.c.d/nn` with 24 ≤ nn ≤ 32." }
4095
+ ports: { type: array, items: { type: integer } }
4096
+ dnsName: { type: string, description: Connect name shown to users; the reconciler re-resolves it each pass. }
4097
+ sshUser: { type: string }
4098
+ securityGroupId: { type: string, description: When set, the reconciler keeps a connector ingress rule in it. }
4099
+ description: { type: string }
4100
+ createdAt: { type: string, format: date-time }
4101
+ createdBy: { type: string }
4102
+ required: [resourceId, accountNumber, name, type, cidr, ports, createdAt, createdBy]
4103
+ ResourceCreate:
4104
+ type: object
4105
+ properties:
4106
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
4107
+ name: { type: string }
4108
+ type: { $ref: "#/components/schemas/ResourceType" }
4109
+ cidr: { type: string, description: Bare IPv4 or /16–/32 CIDR. }
4110
+ ports: { type: array, items: { type: integer, minimum: 1, maximum: 65535 }, minItems: 1 }
4111
+ dnsName: { type: string }
4112
+ sshUser: { type: string }
4113
+ securityGroupId: { type: string }
4114
+ description: { type: string }
4115
+ required: [accountNumber, name, type, cidr, ports]
4116
+ ResourcePatch:
4117
+ type: object
4118
+ description: At least one field.
4119
+ properties:
4120
+ name: { type: string }
4121
+ type: { $ref: "#/components/schemas/ResourceType" }
4122
+ cidr: { type: string }
4123
+ ports: { type: array, items: { type: integer, minimum: 1, maximum: 65535 }, minItems: 1 }
4124
+ dnsName: { type: string }
4125
+ sshUser: { type: string }
4126
+ securityGroupId: { type: string }
4127
+ description: { type: string }
4128
+ ResourceEnvelope:
4129
+ type: object
4130
+ properties:
4131
+ resource: { $ref: "#/components/schemas/Resource" }
4132
+ required: [resource]
4133
+ ResourceGrantee:
4134
+ type: object
4135
+ properties:
4136
+ userId: { type: string }
4137
+ email: { type: string }
4138
+ grantedBy: { type: string }
4139
+ grantedAt: { type: string, format: date-time }
4140
+ expiresAt: { type: string, format: date-time }
4141
+ direct: { type: boolean }
4142
+ viaGroup: { type: string }
4143
+ viaGroups: { type: array, items: { type: string } }
4144
+ required: [userId, email, direct, viaGroups]
4145
+ UserResourceGrant:
4146
+ type: object
4147
+ properties:
4148
+ resourceId: { type: string }
4149
+ grantedBy: { type: string }
4150
+ grantedAt: { type: string, format: date-time }
4151
+ expiresAt: { type: string, format: date-time }
4152
+ viaGroup: { type: string }
4153
+ viaGroups: { type: array, items: { type: string } }
4154
+ required: [resourceId]
4155
+ UserResourceGrantNamed:
4156
+ allOf:
4157
+ - $ref: "#/components/schemas/UserResourceGrant"
4158
+ - type: object
4159
+ properties:
4160
+ resourceName: { type: string }
4161
+ required: [resourceName]
4162
+
4163
+ ReconcilerStatus:
4164
+ type: object
4165
+ properties:
4166
+ at: { type: [string, "null"], format: date-time, description: Oldest site pass; `null` = never ran. }
4167
+ resources:
4168
+ type: object
4169
+ description: Keyed by resourceId.
4170
+ additionalProperties:
4171
+ type: object
4172
+ properties:
4173
+ status: { type: string }
4174
+ users: { type: integer }
4175
+ sg: { type: string, description: "SG-manager verdict for the resource's security group: ok, not-found, invalid, error, other-vpc (the group is in none of the account's connector VPCs), sg-sync-failed." }
4176
+ sgId: { type: string }
4177
+ addr: { type: string, enum: [dns, dns-stale] }
4178
+ addrIp: { type: string }
4179
+ addrName: { type: string }
4180
+ required: [status]
4181
+ staleConnectors: { type: array, items: { type: string } }
4182
+ resourcesLive: { type: integer }
4183
+ rules: { type: integer }
4184
+ shares:
4185
+ type: object
4186
+ description: Dev shares keyed by shareId — `live` (users = enrolled grantees named) or why not (`owner-not-enrolled`, `no-grantees`, `no-enrolled-grantees`, `invalid-port`).
4187
+ additionalProperties:
4188
+ type: object
4189
+ properties:
4190
+ status: { type: string }
4191
+ users: { type: integer }
4192
+ required: [status]
4193
+ sharesLive: { type: integer }
4194
+ sites:
4195
+ type: object
4196
+ additionalProperties:
4197
+ type: object
4198
+ properties:
4199
+ at: { type: [string, "null"], format: date-time }
4200
+ staleConnectors: { type: array, items: { type: string } }
4201
+ resourcesLive: { type: integer }
4202
+ rules: { type: integer }
4203
+ sharesLive: { type: integer }
4204
+ required: [at, staleConnectors, resourcesLive, rules]
4205
+ connectors:
4206
+ type: array
4207
+ items:
4208
+ type: object
4209
+ properties:
4210
+ siteId: { type: string }
4211
+ account: { type: string }
4212
+ name: { type: string }
4213
+ vpcName: { type: string, description: Which of the account's connector VPCs (its config name); absent = the unnamed one. }
4214
+ nodeId: { type: string }
4215
+ trusted: { type: boolean }
4216
+ online: { type: boolean }
4217
+ lastSeen: { type: string, format: date-time }
4218
+ advertisedRoutes: { type: array, items: { type: string } }
4219
+ approvedRoutes: { type: array, items: { type: string } }
4220
+ required: [siteId, account, name, trusted, online, advertisedRoutes, approvedRoutes]
4221
+ devices:
4222
+ type: object
4223
+ description: Keyed by user sub.
4224
+ additionalProperties:
4225
+ type: object
4226
+ properties:
4227
+ count: { type: integer }
4228
+ online: { type: boolean }
4229
+ lastSeen: { type: string, format: date-time }
4230
+ sites: { type: array, items: { type: string } }
4231
+ required: [count, online, sites]
4232
+ required: [at, resources, staleConnectors, resourcesLive, rules, connectors, devices]
4233
+
4234
+ ActivityActor:
4235
+ type: object
4236
+ properties:
4237
+ kind: { type: string, enum: [user, service, system] }
4238
+ id: { type: string, description: Cognito sub, app client id, or `system:<job>`. }
4239
+ name: { type: string, description: The live directory name when the caller still exists, else the write-time snapshot. }
4240
+ claims:
4241
+ type: object
4242
+ additionalProperties: { type: string }
4243
+ deleted: { type: boolean, description: Present when the caller is no longer in the directory. }
4244
+ required: [kind, id]
4245
+ ActivitySubject:
4246
+ type: object
4247
+ properties:
4248
+ kind: { type: string, enum: [user, group, serviceUser] }
4249
+ id: { type: string }
4250
+ name: { type: string }
4251
+ deleted: { type: boolean }
4252
+ required: [kind, id]
4253
+ ActivityEventView:
4254
+ type: object
4255
+ description: One recorded action. `action` is `object.verb` (role.grant, request.approve, credentials.vend, vpn.connect, admin.access, …); `outcome` says whether it happened.
4256
+ properties:
4257
+ eventId: { type: string }
4258
+ category: { type: string, enum: [access, request, vend, network, catalog, users, auth] }
4259
+ action: { type: string }
4260
+ outcome: { type: string, enum: [OK, DENIED, FAILED] }
4261
+ reason: { type: string, description: Caller-safe cause on DENIED and FAILED rows. }
4262
+ actor: { $ref: "#/components/schemas/ActivityActor" }
4263
+ subject: { $ref: "#/components/schemas/ActivitySubject" }
4264
+ target: { type: string, description: "`role#<account>#<name>`, `resource#<id>`, `plugin#<id>#<account>#<permission>`, `share#<id>`, `group#<id>`, `user#<sub>`, `serviceuser#<id>`, `account#<n>`, `site#<id>`, `sg#<id>`, `route#<METHOD /path>`." }
4265
+ targetName: { type: string }
4266
+ accountNumber: { $ref: "#/components/schemas/AccountNumber" }
4267
+ details:
4268
+ type: object
4269
+ description: expiresAt, durationHours, note, via (ADMIN | GROUP | REAPPROVAL | CASCADE | OWNER | EXPIRY), groupId, requestId, batchId, changed (key → {from, to}), affected (up to 50 {userId, name, change}) + affectedCount, deniedReason, and action-specific keys.
4270
+ additionalProperties: true
4271
+ derived: { type: boolean, description: A per-user effective-access change the access diff wrote (access.gain / access.lose), linked to its batch's primary row. }
4272
+ at: { type: string, format: date-time }
4273
+ day: { type: string, description: UTC calendar day `YYYY-MM-DD`. }
4274
+ required: [eventId, category, action, outcome, actor, at, day]
4275
+ ActivityPage:
4276
+ type: object
4277
+ properties:
4278
+ events:
4279
+ type: array
4280
+ items: { $ref: "#/components/schemas/ActivityEventView" }
4281
+ from: { type: string, format: date-time }
4282
+ to: { type: string, format: date-time }
4283
+ nextBefore: { type: string, format: date-time, description: Present when the page filled up — pass as `before` (with `skip`) to continue. }
4284
+ required: [events, from, to]