@lukoweb/apitogo 0.2.22 → 0.2.24

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 (599) hide show
  1. package/README.md +94 -94
  2. package/cli.js +13 -13
  3. package/client.d.ts +8 -8
  4. package/dist/cli/cli.js +561 -232
  5. package/dist/declarations/cli/platform/client/platform-api.d.ts +18 -0
  6. package/dist/declarations/config/validators/InputNavigationSchema.d.ts +7 -7
  7. package/dist/declarations/config/validators/ZudokuConfig.d.ts +1 -1
  8. package/docs/cli/commands.md +75 -75
  9. package/docs/cli/go-live.md +123 -123
  10. package/docs/cli/overview.md +91 -91
  11. package/docs/cli/setup.md +141 -141
  12. package/docs/cli/shape.md +127 -127
  13. package/docs/components/alert.mdx +130 -130
  14. package/docs/components/badge.mdx +70 -70
  15. package/docs/components/button.mdx +132 -132
  16. package/docs/components/callout.mdx +112 -112
  17. package/docs/components/card.mdx +104 -104
  18. package/docs/components/checkbox.mdx +72 -72
  19. package/docs/components/client-only.mdx +79 -79
  20. package/docs/components/code-tabs.mdx +179 -179
  21. package/docs/components/dialog.mdx +167 -167
  22. package/docs/components/head.mdx +200 -200
  23. package/docs/components/icons.mdx +27 -27
  24. package/docs/components/input.mdx +96 -96
  25. package/docs/components/label.mdx +86 -86
  26. package/docs/components/link.mdx +242 -242
  27. package/docs/components/markdown.mdx +151 -151
  28. package/docs/components/mermaid.mdx +81 -81
  29. package/docs/components/playground.mdx +85 -85
  30. package/docs/components/secret.mdx +79 -79
  31. package/docs/components/select.mdx +176 -176
  32. package/docs/components/shadcn.mdx +73 -73
  33. package/docs/components/slider.mdx +108 -108
  34. package/docs/components/slot.mdx +119 -119
  35. package/docs/components/stepper.mdx +138 -138
  36. package/docs/components/switch.mdx +96 -96
  37. package/docs/components/syntax-highlight.mdx +602 -602
  38. package/docs/components/textarea.mdx +78 -78
  39. package/docs/components/tooltip.mdx +195 -195
  40. package/docs/components/typography.mdx +61 -61
  41. package/docs/components.mdx +60 -60
  42. package/docs/concepts/auth-provider-api-identities.md +105 -105
  43. package/docs/configuration/ai-assistants.md +65 -65
  44. package/docs/configuration/api-catalog.md +109 -109
  45. package/docs/configuration/api-reference.md +397 -397
  46. package/docs/configuration/authentication-auth0.md +181 -181
  47. package/docs/configuration/authentication-azure-ad.md +245 -245
  48. package/docs/configuration/authentication-clerk.md +117 -117
  49. package/docs/configuration/authentication-firebase.md +69 -69
  50. package/docs/configuration/authentication-pingfederate.md +143 -143
  51. package/docs/configuration/authentication-supabase.md +233 -233
  52. package/docs/configuration/authentication.md +159 -159
  53. package/docs/configuration/build-configuration.mdx +147 -147
  54. package/docs/configuration/docs.md +282 -282
  55. package/docs/configuration/footer.mdx +118 -118
  56. package/docs/configuration/gateway.md +221 -221
  57. package/docs/configuration/llms.md +90 -90
  58. package/docs/configuration/make-config.mdx +124 -124
  59. package/docs/configuration/manifest.md +128 -128
  60. package/docs/configuration/navigation.mdx +421 -421
  61. package/docs/configuration/overview.md +166 -166
  62. package/docs/configuration/plans.md +153 -153
  63. package/docs/configuration/protected-routes.md +150 -150
  64. package/docs/configuration/search.md +164 -164
  65. package/docs/configuration/sentry.mdx +44 -44
  66. package/docs/configuration/site.md +124 -124
  67. package/docs/configuration/slots.mdx +125 -125
  68. package/docs/configuration/vite-config.md +18 -18
  69. package/docs/custom-plugins.md +285 -285
  70. package/docs/customization/colors-theme.mdx +278 -278
  71. package/docs/customization/fonts.md +110 -110
  72. package/docs/customization/landing-page.md +188 -188
  73. package/docs/deploy/apache-nginx.md +41 -41
  74. package/docs/deploy/apitogo.md +17 -17
  75. package/docs/deploy/cloudflare-pages.md +74 -74
  76. package/docs/deploy/direct-upload.md +17 -17
  77. package/docs/deploy/github-pages.md +49 -49
  78. package/docs/deploy/vercel.md +101 -101
  79. package/docs/deployment.md +9 -9
  80. package/docs/extending/events.md +124 -124
  81. package/docs/guides/custom-pages.md +110 -110
  82. package/docs/guides/environment-variables.md +94 -94
  83. package/docs/guides/managing-api-keys-and-identities.md +89 -89
  84. package/docs/guides/mermaid.mdx +70 -70
  85. package/docs/guides/navigation-rules.mdx +203 -203
  86. package/docs/guides/processors.mdx +234 -234
  87. package/docs/guides/static-files.md +55 -55
  88. package/docs/guides/transforming-examples.md +156 -156
  89. package/docs/guides/using-multiple-apis.md +87 -87
  90. package/docs/markdown/admonitions.md +128 -128
  91. package/docs/markdown/code-blocks.md +196 -196
  92. package/docs/markdown/frontmatter.md +173 -173
  93. package/docs/markdown/mdx.md +68 -68
  94. package/docs/markdown/overview.md +275 -275
  95. package/docs/mcp/go-live.md +100 -100
  96. package/docs/mcp/overview.md +76 -76
  97. package/docs/mcp/setup.md +173 -173
  98. package/docs/mcp/shape.md +77 -77
  99. package/docs/mcp/tools.md +102 -102
  100. package/docs/plugins.md +24 -24
  101. package/docs/quickstart.md +72 -72
  102. package/docs/writing.mdx +72 -72
  103. package/package.json +1 -1
  104. package/src/app/ZuploBuildConfig.ts +36 -36
  105. package/src/app/apitogoBrandTheme.ts +47 -47
  106. package/src/app/defaultTheme.css +77 -77
  107. package/src/app/demo-cdn.html +37 -37
  108. package/src/app/demo.html +21 -21
  109. package/src/app/demo.tsx +77 -77
  110. package/src/app/entry.client.tsx +107 -107
  111. package/src/app/entry.server.tsx +160 -160
  112. package/src/app/env.ts +40 -40
  113. package/src/app/main.css +400 -400
  114. package/src/app/main.tsx +167 -167
  115. package/src/app/polyfills.ts +47 -47
  116. package/src/app/processRoutes.tsx +51 -51
  117. package/src/app/sentry.ts +24 -24
  118. package/src/app/standalone.html +23 -23
  119. package/src/app/standalone.tsx +60 -60
  120. package/src/app/utils/createRedirectRoutes.ts +11 -11
  121. package/src/config/apitogo-config-core.ts +7 -3
  122. package/src/config/apitogo-config-loader.browser.ts +17 -17
  123. package/src/config/apitogo-config-loader.node.ts +88 -88
  124. package/src/config/apitogo-config-loader.ts +6 -6
  125. package/src/config/build-apitogo-config.ts +61 -61
  126. package/src/config/config.ts +74 -74
  127. package/src/config/create-plugin.ts +71 -71
  128. package/src/config/default-landing-content.ts +149 -149
  129. package/src/config/file-exists.ts +6 -6
  130. package/src/config/gateway-limits.ts +128 -128
  131. package/src/config/landing-manifest.ts +11 -11
  132. package/src/config/landing-openapi-showcase.ts +124 -124
  133. package/src/config/loader.ts +375 -375
  134. package/src/config/local-manifest.ts +545 -545
  135. package/src/config/resolve-modules.ts +354 -354
  136. package/src/config/v2/__fixtures__/scenario-a-docs-only.json +6 -6
  137. package/src/config/v2/__fixtures__/scenario-b-managed-origin.json +14 -14
  138. package/src/config/v2/__fixtures__/scenario-c-proxy-oidc.json +15 -15
  139. package/src/config/v2/__fixtures__/scenario-h-full-stack.json +28 -28
  140. package/src/config/v2/docs-navigation.ts +72 -72
  141. package/src/config/v2/errors.ts +42 -42
  142. package/src/config/v2/gateway-reference.ts +220 -220
  143. package/src/config/v2/gateway-request.ts +123 -123
  144. package/src/config/v2/home-redirect.ts +98 -98
  145. package/src/config/v2/index.ts +126 -126
  146. package/src/config/v2/init.ts +273 -273
  147. package/src/config/v2/layout.ts +237 -237
  148. package/src/config/v2/ledger.ts +235 -235
  149. package/src/config/v2/link-directory.ts +34 -0
  150. package/src/config/v2/load.ts +70 -70
  151. package/src/config/v2/manifest.ts +452 -452
  152. package/src/config/v2/parse.ts +214 -214
  153. package/src/config/v2/paths.ts +54 -54
  154. package/src/config/v2/portal-profile.ts +88 -88
  155. package/src/config/v2/resolve.ts +188 -188
  156. package/src/config/v2/rules.ts +714 -714
  157. package/src/config/v2/schema.ts +245 -245
  158. package/src/config/v2/services.ts +663 -663
  159. package/src/config/v2/workspace.ts +3 -2
  160. package/src/config/v2/wrapper.ts +24 -2
  161. package/src/config/validators/BuildSchema.ts +95 -95
  162. package/src/config/validators/HeaderNavigationSchema.ts +44 -44
  163. package/src/config/validators/InputNavigationSchema.test-d.ts +178 -178
  164. package/src/config/validators/InputNavigationSchema.ts +206 -206
  165. package/src/config/validators/ModulesSchema.ts +502 -502
  166. package/src/config/validators/NavigationSchema.ts +352 -352
  167. package/src/config/validators/ProtectedRoutesSchema.ts +35 -35
  168. package/src/config/validators/ZudokuConfig.ts +792 -792
  169. package/src/config/validators/auth.ts +3 -3
  170. package/src/config/validators/reason-codes.ts +7 -7
  171. package/src/env.d.ts +11 -11
  172. package/src/index.ts +83 -83
  173. package/src/lib/MissingIcon.tsx +22 -22
  174. package/src/lib/assets/language-icons/bun.tsx +50 -50
  175. package/src/lib/assets/language-icons/c.tsx +31 -31
  176. package/src/lib/assets/language-icons/commonlisp.tsx +22 -22
  177. package/src/lib/assets/language-icons/cpp.tsx +35 -35
  178. package/src/lib/assets/language-icons/csharp.tsx +35 -35
  179. package/src/lib/assets/language-icons/css.tsx +36 -36
  180. package/src/lib/assets/language-icons/dart.tsx +39 -39
  181. package/src/lib/assets/language-icons/elixir.tsx +19 -19
  182. package/src/lib/assets/language-icons/go.tsx +19 -19
  183. package/src/lib/assets/language-icons/graphql.tsx +19 -19
  184. package/src/lib/assets/language-icons/html.tsx +24 -24
  185. package/src/lib/assets/language-icons/java.tsx +35 -35
  186. package/src/lib/assets/language-icons/javascript.tsx +11 -11
  187. package/src/lib/assets/language-icons/json.tsx +19 -19
  188. package/src/lib/assets/language-icons/kotlin.tsx +30 -30
  189. package/src/lib/assets/language-icons/markdown.tsx +19 -19
  190. package/src/lib/assets/language-icons/mdx.tsx +23 -23
  191. package/src/lib/assets/language-icons/npm.tsx +15 -15
  192. package/src/lib/assets/language-icons/objectivec.tsx +23 -23
  193. package/src/lib/assets/language-icons/ocaml.tsx +34 -34
  194. package/src/lib/assets/language-icons/php.tsx +19 -19
  195. package/src/lib/assets/language-icons/pnpm.tsx +32 -32
  196. package/src/lib/assets/language-icons/powershell.tsx +27 -27
  197. package/src/lib/assets/language-icons/python.tsx +23 -23
  198. package/src/lib/assets/language-icons/react.tsx +21 -21
  199. package/src/lib/assets/language-icons/ruby.tsx +19 -19
  200. package/src/lib/assets/language-icons/rust.tsx +19 -19
  201. package/src/lib/assets/language-icons/scala.tsx +19 -19
  202. package/src/lib/assets/language-icons/shell.tsx +19 -19
  203. package/src/lib/assets/language-icons/swift.tsx +19 -19
  204. package/src/lib/assets/language-icons/toml.tsx +23 -23
  205. package/src/lib/assets/language-icons/typescript.tsx +23 -23
  206. package/src/lib/assets/language-icons/xml.tsx +19 -19
  207. package/src/lib/assets/language-icons/yaml.tsx +23 -23
  208. package/src/lib/assets/language-icons/yarn.tsx +17 -17
  209. package/src/lib/assets/language-icons/zig.tsx +32 -32
  210. package/src/lib/auth/issuer.ts +34 -34
  211. package/src/lib/authentication/AuthenticationPlugin.tsx +33 -33
  212. package/src/lib/authentication/auth-header-nav.ts +46 -46
  213. package/src/lib/authentication/authentication.ts +51 -51
  214. package/src/lib/authentication/components/CallbackHandler.tsx +45 -45
  215. package/src/lib/authentication/components/OAuthErrorPage.tsx +197 -197
  216. package/src/lib/authentication/components/ProductionUnlockPage.tsx +26 -26
  217. package/src/lib/authentication/components/SignIn.tsx +46 -46
  218. package/src/lib/authentication/components/SignOut.tsx +15 -15
  219. package/src/lib/authentication/components/SignUp.tsx +48 -48
  220. package/src/lib/authentication/constants.ts +1 -1
  221. package/src/lib/authentication/errors.ts +34 -34
  222. package/src/lib/authentication/header-nav-filter.ts +35 -35
  223. package/src/lib/authentication/hook.ts +141 -141
  224. package/src/lib/authentication/providers/auth0.tsx +91 -91
  225. package/src/lib/authentication/providers/azureb2c.tsx +223 -223
  226. package/src/lib/authentication/providers/clerk.tsx +224 -224
  227. package/src/lib/authentication/providers/dev-portal-auth-pages.tsx +602 -602
  228. package/src/lib/authentication/providers/dev-portal-constants.ts +38 -38
  229. package/src/lib/authentication/providers/dev-portal-demo.ts +151 -151
  230. package/src/lib/authentication/providers/dev-portal-utils.ts +279 -279
  231. package/src/lib/authentication/providers/dev-portal.tsx +448 -448
  232. package/src/lib/authentication/providers/firebase.tsx +486 -486
  233. package/src/lib/authentication/providers/openid.tsx +516 -516
  234. package/src/lib/authentication/providers/supabase.tsx +412 -412
  235. package/src/lib/authentication/providers/util.ts +26 -26
  236. package/src/lib/authentication/state.ts +180 -180
  237. package/src/lib/authentication/ui/AuthCard.tsx +7 -7
  238. package/src/lib/authentication/ui/EmailLinkCallbackUi.tsx +129 -129
  239. package/src/lib/authentication/ui/EmailLinkSentUi.tsx +105 -105
  240. package/src/lib/authentication/ui/EmailLinkSignInUi.tsx +100 -100
  241. package/src/lib/authentication/ui/EmailVerificationUi.tsx +128 -128
  242. package/src/lib/authentication/ui/ZudokuAuthUi.tsx +620 -620
  243. package/src/lib/authentication/ui/icons/Apple.tsx +10 -10
  244. package/src/lib/authentication/ui/icons/Facebook.tsx +15 -15
  245. package/src/lib/authentication/ui/icons/Github.tsx +16 -16
  246. package/src/lib/authentication/ui/icons/Google.tsx +16 -16
  247. package/src/lib/authentication/ui/icons/Microsoft.tsx +12 -12
  248. package/src/lib/authentication/ui/icons/X.tsx +10 -10
  249. package/src/lib/authentication/utils/relativeRedirectUrl.ts +16 -16
  250. package/src/lib/components/AiAssistantMenuItems.tsx +102 -102
  251. package/src/lib/components/AnchorLink.tsx +24 -24
  252. package/src/lib/components/Autocomplete.tsx +123 -123
  253. package/src/lib/components/Banner.tsx +52 -52
  254. package/src/lib/components/Bootstrap.tsx +77 -77
  255. package/src/lib/components/BuildCheck.tsx +87 -87
  256. package/src/lib/components/CategoryHeading.tsx +19 -19
  257. package/src/lib/components/ClientOnly.tsx +19 -19
  258. package/src/lib/components/DeveloperHint.tsx +39 -39
  259. package/src/lib/components/ErrorPage.tsx +26 -26
  260. package/src/lib/components/Footer.tsx +146 -146
  261. package/src/lib/components/Framed.tsx +51 -51
  262. package/src/lib/components/Header.tsx +261 -261
  263. package/src/lib/components/HeaderAuthActions.tsx +32 -32
  264. package/src/lib/components/HeaderNavigation.tsx +176 -176
  265. package/src/lib/components/Heading.tsx +84 -84
  266. package/src/lib/components/InlineCode.tsx +15 -15
  267. package/src/lib/components/LandingLayout.tsx +27 -27
  268. package/src/lib/components/LanguageIcon.tsx +199 -199
  269. package/src/lib/components/Layout.tsx +59 -59
  270. package/src/lib/components/Main.tsx +52 -52
  271. package/src/lib/components/Markdown.tsx +55 -55
  272. package/src/lib/components/Mermaid.tsx +74 -74
  273. package/src/lib/components/Meta.tsx +46 -46
  274. package/src/lib/components/MobileTopNavigation.tsx +283 -283
  275. package/src/lib/components/MultiSelect.tsx +86 -86
  276. package/src/lib/components/NotFoundPage.tsx +37 -37
  277. package/src/lib/components/PageProgress.tsx +28 -28
  278. package/src/lib/components/PagefindSearchMeta.tsx +14 -14
  279. package/src/lib/components/Pagination.tsx +44 -44
  280. package/src/lib/components/PathRenderer.tsx +61 -61
  281. package/src/lib/components/PluginHeads.tsx +17 -17
  282. package/src/lib/components/Search.tsx +70 -70
  283. package/src/lib/components/SiteTitle.tsx +58 -58
  284. package/src/lib/components/Slot.tsx +65 -65
  285. package/src/lib/components/Spinner.tsx +5 -5
  286. package/src/lib/components/StatusPage.tsx +96 -96
  287. package/src/lib/components/ThemeSwitch.tsx +99 -99
  288. package/src/lib/components/TopNavigation.tsx +90 -90
  289. package/src/lib/components/Typography.tsx +12 -12
  290. package/src/lib/components/Zudoku.tsx +105 -105
  291. package/src/lib/components/cache.ts +27 -27
  292. package/src/lib/components/context/RenderContext.ts +11 -11
  293. package/src/lib/components/context/RouterEventsEmitter.tsx +19 -19
  294. package/src/lib/components/context/SlotProvider.tsx +149 -149
  295. package/src/lib/components/context/ViewportAnchorContext.tsx +137 -137
  296. package/src/lib/components/context/ZudokuContext.ts +140 -140
  297. package/src/lib/components/context/ZudokuProvider.tsx +20 -20
  298. package/src/lib/components/context/ZudokuReactContext.tsx +17 -17
  299. package/src/lib/components/index.ts +36 -36
  300. package/src/lib/components/navigation/Navigation.tsx +51 -51
  301. package/src/lib/components/navigation/NavigationBadge.tsx +48 -48
  302. package/src/lib/components/navigation/NavigationCategory.tsx +157 -157
  303. package/src/lib/components/navigation/NavigationFilterContext.tsx +28 -28
  304. package/src/lib/components/navigation/NavigationFilterInput.tsx +35 -35
  305. package/src/lib/components/navigation/NavigationItem.tsx +181 -181
  306. package/src/lib/components/navigation/NavigationWrapper.tsx +49 -49
  307. package/src/lib/components/navigation/PoweredByZudoku.tsx +39 -39
  308. package/src/lib/components/navigation/Toc.tsx +137 -137
  309. package/src/lib/components/navigation/ZudokuLogo.tsx +25 -25
  310. package/src/lib/components/navigation/ZuploLogo.tsx +14 -14
  311. package/src/lib/components/navigation/utils.ts +234 -234
  312. package/src/lib/core/RouteGuard.tsx +260 -260
  313. package/src/lib/core/ZudokuContext.ts +272 -272
  314. package/src/lib/core/plugins.ts +139 -139
  315. package/src/lib/core/react-query.ts +1 -1
  316. package/src/lib/core/router.ts +1 -1
  317. package/src/lib/core/transform-config.ts +67 -67
  318. package/src/lib/demo/DemoAnnouncement.tsx +17 -17
  319. package/src/lib/errors/ErrorAlert.tsx +28 -28
  320. package/src/lib/errors/ErrorMessage.tsx +50 -50
  321. package/src/lib/errors/RouterError.tsx +18 -18
  322. package/src/lib/errors/ServerError.tsx +5 -5
  323. package/src/lib/errors/TopLevelError.tsx +6 -6
  324. package/src/lib/hooks/index.ts +13 -13
  325. package/src/lib/hooks/useEvent.ts +41 -41
  326. package/src/lib/hooks/useHighlighter.ts +15 -15
  327. package/src/lib/hooks/useHotkey.ts +70 -70
  328. package/src/lib/icons.ts +2 -2
  329. package/src/lib/navigation/applyRules.ts +127 -127
  330. package/src/lib/navigation/pathMatcher.ts +81 -81
  331. package/src/lib/oas/graphql/circular.ts +69 -69
  332. package/src/lib/oas/graphql/constants.ts +2 -2
  333. package/src/lib/oas/graphql/index.ts +791 -791
  334. package/src/lib/oas/parser/dereference/index.ts +84 -84
  335. package/src/lib/oas/parser/dereference/resolveRef.ts +32 -32
  336. package/src/lib/oas/parser/index.ts +129 -129
  337. package/src/lib/oas/parser/schemas/v3.0.json +1489 -1489
  338. package/src/lib/oas/parser/schemas/v3.1.json +1298 -1298
  339. package/src/lib/oas/parser/upgrade/index.ts +174 -174
  340. package/src/lib/plugins/api-catalog/Catalog.tsx +80 -80
  341. package/src/lib/plugins/api-catalog/index.tsx +119 -119
  342. package/src/lib/plugins/api-keys/CreateApiKey.tsx +128 -128
  343. package/src/lib/plugins/api-keys/CreateApiKeyDialog.tsx +49 -49
  344. package/src/lib/plugins/api-keys/ProtectedRoute.tsx +33 -33
  345. package/src/lib/plugins/api-keys/SettingsApiKeys.tsx +72 -72
  346. package/src/lib/plugins/api-keys/index.tsx +274 -274
  347. package/src/lib/plugins/api-keys/settings/ApiKeyItem.tsx +342 -342
  348. package/src/lib/plugins/api-keys/settings/ApiKeyList.tsx +67 -67
  349. package/src/lib/plugins/api-keys/settings/RevealApiKey.tsx +127 -127
  350. package/src/lib/plugins/custom-pages/index.tsx +32 -32
  351. package/src/lib/plugins/markdown/MdxPage.tsx +260 -260
  352. package/src/lib/plugins/markdown/assets/ChatGPTLogo.tsx +11 -11
  353. package/src/lib/plugins/markdown/assets/ClaudeLogo.tsx +19 -19
  354. package/src/lib/plugins/markdown/index.tsx +82 -82
  355. package/src/lib/plugins/openapi/ApiHeader.tsx +96 -96
  356. package/src/lib/plugins/openapi/CollapsibleCode.tsx +88 -88
  357. package/src/lib/plugins/openapi/ColorizedParam.tsx +115 -115
  358. package/src/lib/plugins/openapi/DownloadSchemaButton.tsx +94 -94
  359. package/src/lib/plugins/openapi/Endpoint.tsx +85 -85
  360. package/src/lib/plugins/openapi/GeneratedExampleSidecarBox.tsx +52 -52
  361. package/src/lib/plugins/openapi/MCPEndpoint.tsx +273 -273
  362. package/src/lib/plugins/openapi/OasProvider.tsx +74 -74
  363. package/src/lib/plugins/openapi/OperationList.tsx +275 -275
  364. package/src/lib/plugins/openapi/OperationListItem.tsx +183 -183
  365. package/src/lib/plugins/openapi/ParamInfos.tsx +96 -96
  366. package/src/lib/plugins/openapi/ParameterList.tsx +53 -53
  367. package/src/lib/plugins/openapi/ParameterListItem.tsx +161 -161
  368. package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +67 -67
  369. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +63 -63
  370. package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +120 -120
  371. package/src/lib/plugins/openapi/SchemaInfo.tsx +344 -344
  372. package/src/lib/plugins/openapi/SchemaList.tsx +113 -113
  373. package/src/lib/plugins/openapi/Sidecar.tsx +314 -314
  374. package/src/lib/plugins/openapi/SidecarBox.tsx +57 -57
  375. package/src/lib/plugins/openapi/SidecarExamples.tsx +177 -177
  376. package/src/lib/plugins/openapi/SimpleSelect.tsx +46 -46
  377. package/src/lib/plugins/openapi/client/GraphQLClient.tsx +73 -73
  378. package/src/lib/plugins/openapi/client/GraphQLContext.tsx +16 -16
  379. package/src/lib/plugins/openapi/client/createServer.ts +35 -35
  380. package/src/lib/plugins/openapi/client/useCreateQuery.ts +44 -44
  381. package/src/lib/plugins/openapi/components/ConstValue.tsx +24 -24
  382. package/src/lib/plugins/openapi/components/EnumValues.tsx +58 -58
  383. package/src/lib/plugins/openapi/components/NonHighlightedCode.tsx +22 -22
  384. package/src/lib/plugins/openapi/components/ResponseContent.tsx +117 -117
  385. package/src/lib/plugins/openapi/components/SelectOnClick.tsx +29 -29
  386. package/src/lib/plugins/openapi/context.tsx +16 -16
  387. package/src/lib/plugins/openapi/graphql/fragment-masking.ts +104 -104
  388. package/src/lib/plugins/openapi/graphql/gql.ts +95 -95
  389. package/src/lib/plugins/openapi/graphql/graphql.ts +835 -835
  390. package/src/lib/plugins/openapi/graphql/index.ts +2 -2
  391. package/src/lib/plugins/openapi/index.tsx +221 -221
  392. package/src/lib/plugins/openapi/interfaces.ts +100 -100
  393. package/src/lib/plugins/openapi/playground/BodyPanel.tsx +274 -274
  394. package/src/lib/plugins/openapi/playground/CollapsibleHeader.tsx +51 -51
  395. package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +60 -60
  396. package/src/lib/plugins/openapi/playground/Headers.tsx +194 -194
  397. package/src/lib/plugins/openapi/playground/IdentityDialog.tsx +75 -75
  398. package/src/lib/plugins/openapi/playground/IdentitySelector.tsx +38 -38
  399. package/src/lib/plugins/openapi/playground/ParamsGrid.tsx +45 -45
  400. package/src/lib/plugins/openapi/playground/PathParams.tsx +53 -53
  401. package/src/lib/plugins/openapi/playground/Playground.tsx +602 -602
  402. package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +62 -62
  403. package/src/lib/plugins/openapi/playground/QueryParams.tsx +151 -151
  404. package/src/lib/plugins/openapi/playground/RequestLoginDialog.tsx +70 -70
  405. package/src/lib/plugins/openapi/playground/Spinner.tsx +87 -87
  406. package/src/lib/plugins/openapi/playground/createUrl.ts +25 -25
  407. package/src/lib/plugins/openapi/playground/fileUtils.ts +36 -36
  408. package/src/lib/plugins/openapi/playground/rememberedIdentity.ts +26 -26
  409. package/src/lib/plugins/openapi/playground/request-panel/MultipartField.tsx +91 -91
  410. package/src/lib/plugins/openapi/playground/request-panel/UrlPath.tsx +31 -31
  411. package/src/lib/plugins/openapi/playground/request-panel/UrlQueryParams.tsx +29 -29
  412. package/src/lib/plugins/openapi/playground/request-panel/useKeyValueFieldManager.ts +340 -340
  413. package/src/lib/plugins/openapi/playground/result-panel/AudioPlayer.tsx +50 -50
  414. package/src/lib/plugins/openapi/playground/result-panel/ResponseStatusBar.tsx +117 -117
  415. package/src/lib/plugins/openapi/playground/result-panel/ResponseTab.tsx +355 -355
  416. package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +106 -106
  417. package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.ts +36 -36
  418. package/src/lib/plugins/openapi/playground/serializeQueryParams.ts +125 -125
  419. package/src/lib/plugins/openapi/playground/useRememberSkipLoginDialog.tsx +23 -23
  420. package/src/lib/plugins/openapi/processors/injectApitogoGatewayServer.ts +36 -36
  421. package/src/lib/plugins/openapi/processors/removeExtensions.ts +29 -29
  422. package/src/lib/plugins/openapi/processors/removeParameters.ts +103 -103
  423. package/src/lib/plugins/openapi/processors/removePaths.ts +57 -57
  424. package/src/lib/plugins/openapi/processors/traverse.ts +1 -1
  425. package/src/lib/plugins/openapi/schema/SchemaExampleAndDefault.tsx +39 -39
  426. package/src/lib/plugins/openapi/schema/SchemaPropertyItem.tsx +189 -189
  427. package/src/lib/plugins/openapi/schema/SchemaView.tsx +299 -299
  428. package/src/lib/plugins/openapi/schema/UnionView.tsx +132 -132
  429. package/src/lib/plugins/openapi/schema/union-helpers.ts +123 -123
  430. package/src/lib/plugins/openapi/schema/utils.ts +49 -49
  431. package/src/lib/plugins/openapi/state.ts +36 -36
  432. package/src/lib/plugins/openapi/util/buildTagCategories.ts +54 -54
  433. package/src/lib/plugins/openapi/util/createHttpSnippet.ts +135 -135
  434. package/src/lib/plugins/openapi/util/createNavigationCategory.tsx +39 -39
  435. package/src/lib/plugins/openapi/util/generateSchemaExample.ts +191 -191
  436. package/src/lib/plugins/openapi/util/getRoutes.tsx +265 -265
  437. package/src/lib/plugins/openapi/util/methodColorMap.tsx +11 -11
  438. package/src/lib/plugins/openapi/util/methodToColor.ts +27 -27
  439. package/src/lib/plugins/openapi/util/sanitizeMarkdownForMetatag.tsx +32 -32
  440. package/src/lib/plugins/openapi/util/useWarmupSchema.ts +23 -23
  441. package/src/lib/plugins/search-inkeep/index.tsx +108 -108
  442. package/src/lib/plugins/search-inkeep/inkeep.ts +24 -24
  443. package/src/lib/plugins/search-pagefind/IndexingDialog.tsx +162 -162
  444. package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +202 -202
  445. package/src/lib/plugins/search-pagefind/ResultList.tsx +122 -122
  446. package/src/lib/plugins/search-pagefind/get-results.tsx +74 -74
  447. package/src/lib/plugins/search-pagefind/index.tsx +21 -21
  448. package/src/lib/plugins/search-pagefind/types.ts +118 -118
  449. package/src/lib/shiki-constants.ts +24 -24
  450. package/src/lib/shiki.ts +179 -179
  451. package/src/lib/testing/index.tsx +147 -147
  452. package/src/lib/ui/Accordion.tsx +55 -55
  453. package/src/lib/ui/ActionButton.tsx +21 -21
  454. package/src/lib/ui/Alert.tsx +84 -84
  455. package/src/lib/ui/AlertDialog.tsx +195 -195
  456. package/src/lib/ui/AspectRatio.tsx +5 -5
  457. package/src/lib/ui/Badge.tsx +48 -48
  458. package/src/lib/ui/Breadcrumb.tsx +115 -115
  459. package/src/lib/ui/Button.tsx +65 -65
  460. package/src/lib/ui/ButtonGroup.tsx +80 -80
  461. package/src/lib/ui/Callout.tsx +113 -113
  462. package/src/lib/ui/Card.tsx +95 -95
  463. package/src/lib/ui/Carousel.tsx +259 -259
  464. package/src/lib/ui/Checkbox.tsx +28 -28
  465. package/src/lib/ui/CodeBlock.tsx +92 -92
  466. package/src/lib/ui/CodeTabPanel.tsx +13 -13
  467. package/src/lib/ui/CodeTabs.tsx +161 -161
  468. package/src/lib/ui/Collapsible.tsx +31 -31
  469. package/src/lib/ui/Command.tsx +191 -191
  470. package/src/lib/ui/Dialog.tsx +138 -138
  471. package/src/lib/ui/DismissibleAlert.tsx +74 -74
  472. package/src/lib/ui/Drawer.tsx +121 -121
  473. package/src/lib/ui/DropdownMenu.tsx +254 -254
  474. package/src/lib/ui/EmbeddedCodeBlock.tsx +99 -99
  475. package/src/lib/ui/Form.tsx +176 -176
  476. package/src/lib/ui/Frame.tsx +81 -81
  477. package/src/lib/ui/HoverCard.tsx +26 -26
  478. package/src/lib/ui/Input.tsx +23 -23
  479. package/src/lib/ui/InputGroup.tsx +168 -168
  480. package/src/lib/ui/Item.tsx +213 -213
  481. package/src/lib/ui/Kbd.tsx +28 -28
  482. package/src/lib/ui/Label.tsx +23 -23
  483. package/src/lib/ui/NativeSelect.tsx +48 -48
  484. package/src/lib/ui/NavigationMenu.tsx +169 -169
  485. package/src/lib/ui/Pagination.tsx +115 -115
  486. package/src/lib/ui/Popover.tsx +28 -28
  487. package/src/lib/ui/Progress.tsx +25 -25
  488. package/src/lib/ui/RadioGroup.tsx +41 -41
  489. package/src/lib/ui/ReactComponentDoc.tsx +68 -68
  490. package/src/lib/ui/ScrollArea.tsx +45 -45
  491. package/src/lib/ui/Secret.tsx +133 -133
  492. package/src/lib/ui/Select.tsx +184 -184
  493. package/src/lib/ui/Separator.tsx +25 -25
  494. package/src/lib/ui/Skeleton.tsx +15 -15
  495. package/src/lib/ui/Slider.tsx +25 -25
  496. package/src/lib/ui/Stepper.tsx +8 -8
  497. package/src/lib/ui/Switch.tsx +26 -26
  498. package/src/lib/ui/SyntaxHighlight.tsx +54 -54
  499. package/src/lib/ui/Tabs.tsx +52 -52
  500. package/src/lib/ui/Textarea.tsx +22 -22
  501. package/src/lib/ui/Toggle.tsx +42 -42
  502. package/src/lib/ui/ToggleGroup.tsx +58 -58
  503. package/src/lib/ui/Tooltip.tsx +65 -65
  504. package/src/lib/ui/Value.tsx +42 -42
  505. package/src/lib/ui/util.tsx +8 -8
  506. package/src/lib/util/MdxComponents.tsx +150 -150
  507. package/src/lib/util/cn.ts +6 -6
  508. package/src/lib/util/createVariantComponent.tsx +61 -61
  509. package/src/lib/util/ensureArray.ts +3 -3
  510. package/src/lib/util/flattenAllOf.ts +72 -72
  511. package/src/lib/util/flattenAllOfProcessor.ts +74 -74
  512. package/src/lib/util/hastToJsx.tsx +67 -67
  513. package/src/lib/util/humanFileSize.ts +15 -15
  514. package/src/lib/util/invariant.ts +52 -52
  515. package/src/lib/util/joinUrl.ts +60 -60
  516. package/src/lib/util/logInit.ts +9 -9
  517. package/src/lib/util/objectEntries.ts +5 -5
  518. package/src/lib/util/os.ts +18 -18
  519. package/src/lib/util/pastellize.ts +25 -25
  520. package/src/lib/util/problemJson.ts +63 -63
  521. package/src/lib/util/readFrontmatter.ts +14 -14
  522. package/src/lib/util/renderIf.ts +4 -4
  523. package/src/lib/util/scrollIntoViewIfNeeded.ts +18 -18
  524. package/src/lib/util/slugify.ts +21 -21
  525. package/src/lib/util/syncZustandState.ts +22 -22
  526. package/src/lib/util/traverse.ts +70 -70
  527. package/src/lib/util/types.ts +7 -7
  528. package/src/lib/util/url.ts +18 -18
  529. package/src/lib/util/useCopyToClipboard.ts +17 -17
  530. package/src/lib/util/useExposedProps.tsx +27 -27
  531. package/src/lib/util/useIsomorphicLayoutEffect.ts +6 -6
  532. package/src/lib/util/useLatest.ts +18 -18
  533. package/src/lib/util/useOnScreen.ts +34 -34
  534. package/src/lib/util/useScrollToAnchor.ts +75 -75
  535. package/src/lib/util/useScrollToTop.ts +18 -18
  536. package/src/types.d.ts +66 -66
  537. package/src/vite/api/SchemaManager.ts +371 -371
  538. package/src/vite/api/schema-codegen.ts +163 -163
  539. package/src/vite/build.ts +237 -237
  540. package/src/vite/config.ts +273 -273
  541. package/src/vite/css/collect.ts +42 -42
  542. package/src/vite/css/plugin.ts +105 -105
  543. package/src/vite/debug.ts +18 -18
  544. package/src/vite/dev-portal-env.ts +29 -29
  545. package/src/vite/dev-server.ts +294 -294
  546. package/src/vite/html.ts +52 -52
  547. package/src/vite/index.ts +2 -2
  548. package/src/vite/llms.ts +99 -99
  549. package/src/vite/mdx/rehype-extract-toc-with-jsx-export.ts +19 -19
  550. package/src/vite/mdx/rehype-extract-toc-with-jsx.ts +70 -70
  551. package/src/vite/mdx/remark-code-tabs.ts +47 -47
  552. package/src/vite/mdx/remark-inject-filepath.ts +13 -13
  553. package/src/vite/mdx/remark-last-modified.ts +103 -103
  554. package/src/vite/mdx/remark-link-rewrite.ts +23 -23
  555. package/src/vite/mdx/remark-normalize-image-url.ts +15 -15
  556. package/src/vite/mdx/remark-static-generation.ts +149 -149
  557. package/src/vite/mdx/utils.ts +32 -32
  558. package/src/vite/output.ts +261 -261
  559. package/src/vite/package-root.ts +12 -12
  560. package/src/vite/pagefind-dev-index.ts +100 -100
  561. package/src/vite/pagefind-dev-stub.ts +17 -17
  562. package/src/vite/plugin-api-keys.ts +55 -55
  563. package/src/vite/plugin-api.ts +328 -328
  564. package/src/vite/plugin-auth.ts +41 -41
  565. package/src/vite/plugin-component.ts +45 -45
  566. package/src/vite/plugin-config-reload.ts +47 -47
  567. package/src/vite/plugin-config.ts +131 -131
  568. package/src/vite/plugin-custom-pages.ts +36 -36
  569. package/src/vite/plugin-doc-metadata.ts +45 -45
  570. package/src/vite/plugin-docs.ts +205 -205
  571. package/src/vite/plugin-local-manifest.ts +100 -100
  572. package/src/vite/plugin-markdown-export.ts +214 -214
  573. package/src/vite/plugin-mdx.ts +149 -149
  574. package/src/vite/plugin-metadata.ts +30 -30
  575. package/src/vite/plugin-modules.ts +188 -188
  576. package/src/vite/plugin-navigation.ts +106 -106
  577. package/src/vite/plugin-offroot-resolve.ts +67 -67
  578. package/src/vite/plugin-search.ts +59 -59
  579. package/src/vite/plugin-shiki-register.ts +97 -97
  580. package/src/vite/plugin-theme.ts +458 -458
  581. package/src/vite/plugin.ts +48 -48
  582. package/src/vite/prerender/prerender.ts +242 -242
  583. package/src/vite/prerender/utils.ts +76 -76
  584. package/src/vite/prerender/worker.ts +118 -118
  585. package/src/vite/reporter.ts +34 -34
  586. package/src/vite/shadcn-registry.ts +48 -48
  587. package/src/vite/sitemap.ts +78 -78
  588. package/src/vite/ssr-templates/cloudflare.ts +19 -19
  589. package/src/vite/ssr-templates/node.ts +25 -25
  590. package/src/vite/ssr-templates/vercel.ts +22 -22
  591. package/src/vite/watch-ignore.ts +70 -70
  592. package/src/vite/zuplo.ts +30 -30
  593. package/src/vite-env.d.ts +6 -6
  594. package/src/zuplo/enrich-with-zuplo-mcp.ts +168 -168
  595. package/src/zuplo/enrich-with-zuplo.ts +256 -256
  596. package/src/zuplo/policy-types.ts +46 -46
  597. package/src/zuplo/with-zuplo-processors.ts +36 -36
  598. package/src/zuplo/with-zuplo.ts +14 -14
  599. package/dist/declarations/cli/platform/client/deploy-server.d.ts +0 -16
package/dist/cli/cli.js CHANGED
@@ -459,8 +459,9 @@ function syncAuthentication(normalized) {
459
459
  }
460
460
  const auth = authentication ?? {};
461
461
  auth.enabled = userPanelEnabled;
462
- auth.type = "dev-portal";
463
- if (userPanelEnabled) {
462
+ const keepsOpenId = auth.type === "openid";
463
+ if (!keepsOpenId) auth.type = "dev-portal";
464
+ if (userPanelEnabled && !keepsOpenId) {
464
465
  const native = asRecord(auth.native) ?? {};
465
466
  if (native.enabled === void 0) {
466
467
  native.enabled = true;
@@ -483,7 +484,7 @@ function syncAuthentication(normalized) {
483
484
  }
484
485
  }
485
486
  }
486
- if (normalized.demoMode !== void 0) {
487
+ if (normalized.demoMode !== void 0 && !keepsOpenId) {
487
488
  auth.demoMode = normalized.demoMode !== false;
488
489
  }
489
490
  normalized.authentication = auth;
@@ -836,7 +837,7 @@ import { stat as stat4 } from "node:fs/promises";
836
837
  var fileExists;
837
838
  var init_file_exists = __esm({
838
839
  "src/config/file-exists.ts"() {
839
- fileExists = (path103) => stat4(path103).then(() => true).catch(() => false);
840
+ fileExists = (path104) => stat4(path104).then(() => true).catch(() => false);
840
841
  }
841
842
  });
842
843
 
@@ -6189,8 +6190,8 @@ var ConfigV2Schema = z.strictObject({
6189
6190
  var REMOVED_KEYS = {
6190
6191
  "plans.provider": "plans.provider was removed. Only plans.billing.provider (stripe or none) is selectable."
6191
6192
  };
6192
- function pathToString(path103) {
6193
- return path103.reduce(
6193
+ function pathToString(path104) {
6194
+ return path104.reduce(
6194
6195
  (acc, segment) => typeof segment === "number" ? `${acc}[${segment}]` : acc === "" ? String(segment) : `${acc}.${String(segment)}`,
6195
6196
  ""
6196
6197
  );
@@ -6210,9 +6211,9 @@ function step(schema2, segment) {
6210
6211
  }
6211
6212
  return void 0;
6212
6213
  }
6213
- function knownKeysAt(path103) {
6214
+ function knownKeysAt(path104) {
6214
6215
  let current = ConfigV2Schema;
6215
- for (const segment of path103) {
6216
+ for (const segment of path104) {
6216
6217
  if (!current) return [];
6217
6218
  current = step(current, segment);
6218
6219
  }
@@ -6248,7 +6249,7 @@ function unknownKeyHint(fullPath, key, known) {
6248
6249
  return known.length > 0 ? `Allowed keys: ${known.join(", ")}.` : void 0;
6249
6250
  }
6250
6251
  function mapIssue(issue4) {
6251
- const path103 = pathToString(issue4.path);
6252
+ const path104 = pathToString(issue4.path);
6252
6253
  switch (issue4.code) {
6253
6254
  case "unrecognized_keys":
6254
6255
  return issue4.keys.map((key) => {
@@ -6264,20 +6265,20 @@ function mapIssue(issue4) {
6264
6265
  return [
6265
6266
  {
6266
6267
  code: "CONFIG_INVALID_VALUE",
6267
- path: path103,
6268
+ path: path104,
6268
6269
  message: `must be one of: ${issue4.values.map((v) => JSON.stringify(v)).join(", ")}.`
6269
6270
  }
6270
6271
  ];
6271
6272
  case "custom": {
6272
6273
  const code = typeof issue4.params?.code === "string" ? issue4.params.code : "CONFIG_INVALID_VALUE";
6273
- return [{ code, path: path103, message: issue4.message ?? "is invalid." }];
6274
+ return [{ code, path: path104, message: issue4.message ?? "is invalid." }];
6274
6275
  }
6275
6276
  case "invalid_type":
6276
6277
  return [
6277
- /received undefined/.test(issue4.message) ? { code: "CONFIG_MISSING_FIELD", path: path103, message: "is required." } : { code: "CONFIG_INVALID_VALUE", path: path103, message: issue4.message }
6278
+ /received undefined/.test(issue4.message) ? { code: "CONFIG_MISSING_FIELD", path: path104, message: "is required." } : { code: "CONFIG_INVALID_VALUE", path: path104, message: issue4.message }
6278
6279
  ];
6279
6280
  default:
6280
- return [{ code: "CONFIG_INVALID_VALUE", path: path103, message: issue4.message }];
6281
+ return [{ code: "CONFIG_INVALID_VALUE", path: path104, message: issue4.message }];
6281
6282
  }
6282
6283
  }
6283
6284
  function isRecord(value) {
@@ -7301,7 +7302,7 @@ var ServiceManifestSchema = z3.looseObject({
7301
7302
  }).optional()
7302
7303
  }).default({})
7303
7304
  });
7304
- var issue = (code, path103, message, hint) => ({ code, path: path103, message, hint });
7305
+ var issue = (code, path104, message, hint) => ({ code, path: path104, message, hint });
7305
7306
  function parseManifest(raw, file = "services.json") {
7306
7307
  const version = typeof raw === "object" && raw !== null && "schemaVersion" in raw ? raw.schemaVersion : void 0;
7307
7308
  if (typeof version === "number" && version > SUPPORTED_MANIFEST_SCHEMA) {
@@ -7555,8 +7556,8 @@ var METHODS = [
7555
7556
  "trace"
7556
7557
  ];
7557
7558
  var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
7558
- function actionKey(method, path103) {
7559
- const trimmed = path103.trim();
7559
+ function actionKey(method, path104) {
7560
+ const trimmed = path104.trim();
7560
7561
  const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
7561
7562
  const normalized = withSlash.length > 1 ? withSlash.replace(/\/+$/, "") || "/" : withSlash;
7562
7563
  return `${method.trim().toLowerCase()}:${normalized}`;
@@ -7566,8 +7567,8 @@ function configActionKey(entry) {
7566
7567
  return match?.[1] && match[2] ? actionKey(match[1], match[2]) : void 0;
7567
7568
  }
7568
7569
  function referenceOptions(gateway, gatewayBaseUrl, keyHeaderName) {
7569
- const access16 = gateway.policies.access;
7570
- const jwt = access16?.jwt ?? gateway.auth !== void 0;
7570
+ const access17 = gateway.policies.access;
7571
+ const jwt = access17?.jwt ?? gateway.auth !== void 0;
7571
7572
  const keys = (list2) => new Set(
7572
7573
  (list2 ?? []).flatMap((entry) => {
7573
7574
  const key = configActionKey(entry);
@@ -7579,8 +7580,8 @@ function referenceOptions(gateway, gatewayBaseUrl, keyHeaderName) {
7579
7580
  originUrl: gateway.origin.url,
7580
7581
  jwtRequired: jwt && gateway.auth !== void 0,
7581
7582
  oidcMetadataUrl: jwt ? gateway.auth?.metadataUrl : void 0,
7582
- apiKeyRequired: access16?.apiKey ?? true,
7583
- apiKeyHeader: keyHeaderName ?? access16?.apiKeyHeader ?? DEFAULT_KEY_HEADER,
7583
+ apiKeyRequired: access17?.apiKey ?? true,
7584
+ apiKeyHeader: keyHeaderName ?? access17?.apiKeyHeader ?? DEFAULT_KEY_HEADER,
7584
7585
  publicOperations: keys(gateway.policies.operations?.public),
7585
7586
  deniedOperations: keys(gateway.policies.operations?.deny)
7586
7587
  };
@@ -7593,8 +7594,8 @@ var ReferenceSpecError = class extends Error {
7593
7594
  };
7594
7595
  function operationsOf(paths) {
7595
7596
  return Object.entries(paths).flatMap(
7596
- ([path103, item]) => isObject(item) ? METHODS.filter((method) => isObject(item[method])).map(
7597
- (method) => [path103, item, method]
7597
+ ([path104, item]) => isObject(item) ? METHODS.filter((method) => isObject(item[method])).map(
7598
+ (method) => [path104, item, method]
7598
7599
  ) : []
7599
7600
  );
7600
7601
  }
@@ -7609,14 +7610,14 @@ function buildReferenceSpec(specText, options) {
7609
7610
  throw new ReferenceSpecError("The OpenAPI file could not be read.");
7610
7611
  const doc = structuredClone(root);
7611
7612
  const paths = isObject(doc.paths) ? doc.paths : {};
7612
- for (const [path103, item, method] of operationsOf(paths))
7613
- if (options.deniedOperations.has(actionKey(method, path103)))
7613
+ for (const [path104, item, method] of operationsOf(paths))
7614
+ if (options.deniedOperations.has(actionKey(method, path104)))
7614
7615
  delete item[method];
7615
- for (const [path103, item] of Object.entries(paths))
7616
+ for (const [path104, item] of Object.entries(paths))
7616
7617
  if (!isObject(item) || !METHODS.some((method) => method in item))
7617
- delete paths[path103];
7618
- for (const [path103, item, method] of operationsOf(paths))
7619
- if (options.publicOperations.has(actionKey(method, path103)))
7618
+ delete paths[path104];
7619
+ for (const [path104, item, method] of operationsOf(paths))
7620
+ if (options.publicOperations.has(actionKey(method, path104)))
7620
7621
  item[method].security = [];
7621
7622
  doc.servers = [{ url: options.gatewayBaseUrl.replace(/\/+$/, "") }];
7622
7623
  for (const item of Object.values(paths)) {
@@ -8021,7 +8022,11 @@ function buildSiteConfig(resolved, plan2, theme, extras = {}) {
8021
8022
  },
8022
8023
  modules: {
8023
8024
  docs: { enabled: plan2.docs },
8024
- userPanel: { enabled: plan2.userPanel }
8025
+ // The plans pages (pricing, choosing a plan) exist only when billing is on, and the plans service is what makes it so.
8026
+ userPanel: {
8027
+ enabled: plan2.userPanel,
8028
+ ...plan2.plansPlugin ? { plans: { enabled: true } } : {}
8029
+ }
8025
8030
  },
8026
8031
  ...plan2.docs ? {
8027
8032
  docs: {
@@ -8042,10 +8047,21 @@ function buildSiteConfig(resolved, plan2, theme, extras = {}) {
8042
8047
  ...navigation.length > 0 ? { navigation } : {},
8043
8048
  ...redirects.length > 0 ? { redirects } : {},
8044
8049
  ...theme !== void 0 ? { theme } : {},
8045
- ...plan2.auth ? { authentication: { type: "openid", ...plan2.auth } } : {},
8050
+ ...plan2.auth ? { authentication: authenticationFor(plan2) } : {},
8046
8051
  ...plan2.preview ? { preview: true } : {}
8047
8052
  };
8048
8053
  }
8054
+ function authenticationFor(plan2) {
8055
+ if (plan2.plansPlugin)
8056
+ return {
8057
+ type: "dev-portal",
8058
+ apiBaseUrl: plan2.plansPlugin.apiBaseUrl,
8059
+ demoMode: false,
8060
+ // Accounts are made at the identity (its own sign-up page), never at the plans backend.
8061
+ native: { enabled: false }
8062
+ };
8063
+ return { type: "openid", ...plan2.auth };
8064
+ }
8049
8065
  var PREVIEW_BANNER_MESSAGE = "Preview mode: sign-in and plans use a stand-in manifest. Run `apitogo deploy` for the real services.";
8050
8066
  function renderWrapper(plan2) {
8051
8067
  const imports = [
@@ -8194,9 +8210,27 @@ async function preparePortal(resolved, manifest, mode, options = {}) {
8194
8210
 
8195
8211
  // src/config/v2/workspace.ts
8196
8212
  import { createHash as createHash2 } from "node:crypto";
8197
- import { access as access2, lstat, readFile as readFile7, rm as rm3, symlink } from "node:fs/promises";
8213
+ import { access as access2, lstat, readFile as readFile7, rm as rm3 } from "node:fs/promises";
8198
8214
  import path13 from "node:path";
8199
8215
  import { glob as glob3 } from "glob";
8216
+
8217
+ // src/config/v2/link-directory.ts
8218
+ import { symlink } from "node:fs/promises";
8219
+ async function linkDirectory(target, link, options = {}) {
8220
+ const create = options.symlinkFn ?? symlink;
8221
+ const platform = options.platform ?? process.platform;
8222
+ try {
8223
+ await create(target, link, "dir");
8224
+ return "symlink";
8225
+ } catch (error) {
8226
+ if (platform !== "win32" || error.code !== "EPERM")
8227
+ throw error;
8228
+ await create(target, link, "junction");
8229
+ return "junction";
8230
+ }
8231
+ }
8232
+
8233
+ // src/config/v2/workspace.ts
8200
8234
  var exists2 = (file) => access2(file).then(
8201
8235
  () => true,
8202
8236
  () => false
@@ -8207,7 +8241,7 @@ async function relink(target, link) {
8207
8241
  () => false
8208
8242
  ))
8209
8243
  await rm3(link, { recursive: true, force: true });
8210
- await symlink(target, link, "dir");
8244
+ await linkDirectory(target, link);
8211
8245
  }
8212
8246
  async function materializeWorkspace(resolved, prepared) {
8213
8247
  const root = path13.dirname(prepared.wrapperPath);
@@ -9003,8 +9037,8 @@ var PlatformApiClient = class {
9003
9037
  constructor(config2) {
9004
9038
  this.config = config2;
9005
9039
  }
9006
- url(path103) {
9007
- return `${this.config.apiUrl}${path103.startsWith("/") ? path103 : `/${path103}`}`;
9040
+ url(path104) {
9041
+ return `${this.config.apiUrl}${path104.startsWith("/") ? path104 : `/${path104}`}`;
9008
9042
  }
9009
9043
  headers(extra) {
9010
9044
  return {
@@ -9014,9 +9048,9 @@ var PlatformApiClient = class {
9014
9048
  ...extra
9015
9049
  };
9016
9050
  }
9017
- async request(method, path103, init4) {
9051
+ async request(method, path104, init4) {
9018
9052
  const response = await fetchWithRetry(
9019
- this.url(path103),
9053
+ this.url(path104),
9020
9054
  {
9021
9055
  method,
9022
9056
  ...init4,
@@ -9332,6 +9366,34 @@ var PlatformApiClient = class {
9332
9366
  }
9333
9367
  );
9334
9368
  }
9369
+ /**
9370
+ * Adds or updates an upstream login connection of the project's Active identity. The same request twice changes
9371
+ * nothing. The answer carries the redirect address to register with the provider.
9372
+ */
9373
+ putProjectIdentityConnection(projectId, connectionId2, body) {
9374
+ return this.request(
9375
+ "PUT",
9376
+ `/api/v1/projects/${projectId}/identity/connections/${encodeURIComponent(connectionId2)}`,
9377
+ {
9378
+ headers: { "Content-Type": "application/json" },
9379
+ body: JSON.stringify(body)
9380
+ }
9381
+ );
9382
+ }
9383
+ /** The upstream login connections of the project's identity (never their secrets). */
9384
+ listProjectIdentityConnections(projectId) {
9385
+ return this.request(
9386
+ "GET",
9387
+ `/api/v1/projects/${projectId}/identity/connections`
9388
+ );
9389
+ }
9390
+ /** Removes a connection. One that is not there is a success. Users who signed in through it keep their accounts. */
9391
+ async deleteProjectIdentityConnection(projectId, connectionId2) {
9392
+ await this.request(
9393
+ "DELETE",
9394
+ `/api/v1/projects/${projectId}/identity/connections/${encodeURIComponent(connectionId2)}`
9395
+ );
9396
+ }
9335
9397
  /** The state of the project's identity, or null when it has none. */
9336
9398
  async getProjectIdentity(projectId) {
9337
9399
  try {
@@ -9425,15 +9487,15 @@ var PlatformApiClient = class {
9425
9487
  }
9426
9488
  );
9427
9489
  }
9428
- deleteDevPortalPage(projectId, path103) {
9429
- const query = new URLSearchParams({ path: path103 });
9490
+ deleteDevPortalPage(projectId, path104) {
9491
+ const query = new URLSearchParams({ path: path104 });
9430
9492
  return this.request(
9431
9493
  "DELETE",
9432
9494
  `/api/v1/projects/${projectId}/dev-portal/pages/files?${query.toString()}`
9433
9495
  );
9434
9496
  }
9435
- renameDevPortalPage(projectId, path103, newName) {
9436
- const query = new URLSearchParams({ path: path103 });
9497
+ renameDevPortalPage(projectId, path104, newName) {
9498
+ const query = new URLSearchParams({ path: path104 });
9437
9499
  return this.request(
9438
9500
  "POST",
9439
9501
  `/api/v1/projects/${projectId}/dev-portal/pages/files/rename?${query.toString()}`,
@@ -9549,8 +9611,8 @@ var PlatformApiClient = class {
9549
9611
  * the project-less endpoint is used; `planTier` overrides the tier used for paid-plan checks.
9550
9612
  */
9551
9613
  validateGatewayPlans(plans, options = {}) {
9552
- const path103 = options.projectId ? `/api/v1/projects/${options.projectId}/gateway/plans/validate` : "/api/v1/gateway/plans/validate";
9553
- return this.request("POST", path103, {
9614
+ const path104 = options.projectId ? `/api/v1/projects/${options.projectId}/gateway/plans/validate` : "/api/v1/gateway/plans/validate";
9615
+ return this.request("POST", path104, {
9554
9616
  headers: { "Content-Type": "application/json" },
9555
9617
  body: JSON.stringify({ plans, planTier: options.planTier })
9556
9618
  });
@@ -9754,7 +9816,6 @@ import {
9754
9816
  rm as rm8,
9755
9817
  writeFile as writeFile14
9756
9818
  } from "node:fs/promises";
9757
- import { createRequire as createRequire2 } from "node:module";
9758
9819
  import path48 from "node:path";
9759
9820
 
9760
9821
  // src/vite/build.ts
@@ -9906,7 +9967,7 @@ import {
9906
9967
  // package.json
9907
9968
  var package_default = {
9908
9969
  name: "@lukoweb/apitogo",
9909
- version: "0.2.22",
9970
+ version: "0.2.24",
9910
9971
  type: "module",
9911
9972
  sideEffects: [
9912
9973
  "**/*.css",
@@ -10688,14 +10749,14 @@ var flattenAllOf = (schema2) => {
10688
10749
  };
10689
10750
 
10690
10751
  // src/lib/util/traverse.ts
10691
- var traverse = (specification, transform, path103 = []) => {
10692
- const transformed = transform(specification, path103);
10752
+ var traverse = (specification, transform, path104 = []) => {
10753
+ const transformed = transform(specification, path104);
10693
10754
  if (typeof transformed !== "object" || transformed === null) {
10694
10755
  return transformed;
10695
10756
  }
10696
10757
  const result = Array.isArray(transformed) ? [] : {};
10697
10758
  for (const [key, value] of Object.entries(transformed)) {
10698
- const currentPath = [...path103, key];
10759
+ const currentPath = [...path104, key];
10699
10760
  if (Array.isArray(value)) {
10700
10761
  result[key] = value.map(
10701
10762
  (item, index) => typeof item === "object" && item != null ? traverse(item, transform, [...currentPath, index.toString()]) : item
@@ -10723,9 +10784,9 @@ var resolveLocalRef = (schema2, ref) => {
10723
10784
  if (schemaCache?.has(ref)) {
10724
10785
  return schemaCache.get(ref);
10725
10786
  }
10726
- const path103 = ref.split("/").slice(1);
10787
+ const path104 = ref.split("/").slice(1);
10727
10788
  let current = schema2;
10728
- for (const segment of path103) {
10789
+ for (const segment of path104) {
10729
10790
  if (!current || typeof current !== "object") {
10730
10791
  current = null;
10731
10792
  }
@@ -10744,7 +10805,7 @@ var dereference = async (schema2, resolvers = []) => {
10744
10805
  }
10745
10806
  const cloned = structuredClone(schema2);
10746
10807
  const visited = /* @__PURE__ */ new Set();
10747
- const resolve = async (current, path103) => {
10808
+ const resolve = async (current, path104) => {
10748
10809
  if (isIndexableObject(current)) {
10749
10810
  if (visited.has(current)) {
10750
10811
  return CIRCULAR_REF;
@@ -10752,7 +10813,7 @@ var dereference = async (schema2, resolvers = []) => {
10752
10813
  visited.add(current);
10753
10814
  if (Array.isArray(current)) {
10754
10815
  for (let index = 0; index < current.length; index++) {
10755
- current[index] = await resolve(current[index], `${path103}/${index}`);
10816
+ current[index] = await resolve(current[index], `${path104}/${index}`);
10756
10817
  }
10757
10818
  } else {
10758
10819
  if ("$ref" in current && typeof current.$ref === "string") {
@@ -10763,13 +10824,13 @@ var dereference = async (schema2, resolvers = []) => {
10763
10824
  for (const resolver of resolvers) {
10764
10825
  const resolved = await resolver($ref);
10765
10826
  if (resolved) {
10766
- result2 = await resolve(resolved, path103);
10827
+ result2 = await resolve(resolved, path104);
10767
10828
  break;
10768
10829
  }
10769
10830
  }
10770
10831
  if (result2 === void 0) {
10771
10832
  const resolved = await resolveLocalRef(cloned, $ref);
10772
- result2 = await resolve(resolved, path103);
10833
+ result2 = await resolve(resolved, path104);
10773
10834
  }
10774
10835
  if (hasSiblings) {
10775
10836
  if (result2 === CIRCULAR_REF) {
@@ -10782,7 +10843,7 @@ var dereference = async (schema2, resolvers = []) => {
10782
10843
  return result2;
10783
10844
  }
10784
10845
  for (const key in current) {
10785
- current[key] = await resolve(current[key], `${path103}/${key}`);
10846
+ current[key] = await resolve(current[key], `${path104}/${key}`);
10786
10847
  }
10787
10848
  }
10788
10849
  visited.delete(current);
@@ -10821,9 +10882,9 @@ var upgradeSchema = (schema2) => {
10821
10882
  }
10822
10883
  return sub;
10823
10884
  });
10824
- schema2 = traverse(schema2, (sub, path103) => {
10885
+ schema2 = traverse(schema2, (sub, path104) => {
10825
10886
  if (sub.example !== void 0) {
10826
- if (isSchemaPath(path103 ?? [])) {
10887
+ if (isSchemaPath(path104 ?? [])) {
10827
10888
  sub.examples = [sub.example];
10828
10889
  } else {
10829
10890
  sub.examples = {
@@ -10836,11 +10897,11 @@ var upgradeSchema = (schema2) => {
10836
10897
  }
10837
10898
  return sub;
10838
10899
  });
10839
- schema2 = traverse(schema2, (schema3, path103) => {
10900
+ schema2 = traverse(schema2, (schema3, path104) => {
10840
10901
  if (schema3.type === "object" && schema3.properties !== void 0) {
10841
- const parentPath = path103?.slice(0, -1);
10902
+ const parentPath = path104?.slice(0, -1);
10842
10903
  const isMultipart = parentPath?.some((segment, index) => {
10843
- return segment === "content" && path103?.[index + 1] === "multipart/form-data";
10904
+ return segment === "content" && path104?.[index + 1] === "multipart/form-data";
10844
10905
  });
10845
10906
  if (isMultipart) {
10846
10907
  const entries = Object.entries(schema3.properties);
@@ -10854,8 +10915,8 @@ var upgradeSchema = (schema2) => {
10854
10915
  }
10855
10916
  return schema3;
10856
10917
  });
10857
- schema2 = traverse(schema2, (schema3, path103) => {
10858
- if (path103?.includes("content") && path103.includes("application/octet-stream")) {
10918
+ schema2 = traverse(schema2, (schema3, path104) => {
10919
+ if (path104?.includes("content") && path104.includes("application/octet-stream")) {
10859
10920
  return {};
10860
10921
  }
10861
10922
  if (schema3.type === "string" && schema3.format === "binary") {
@@ -10881,11 +10942,11 @@ var upgradeSchema = (schema2) => {
10881
10942
  }
10882
10943
  return sub;
10883
10944
  });
10884
- schema2 = traverse(schema2, (schema3, path103) => {
10945
+ schema2 = traverse(schema2, (schema3, path104) => {
10885
10946
  if (schema3.type === "string" && schema3.format === "byte") {
10886
- const parentPath = path103?.slice(0, -1);
10947
+ const parentPath = path104?.slice(0, -1);
10887
10948
  const contentMediaType = parentPath?.find(
10888
- (_, index) => path103?.[index - 1] === "content"
10949
+ (_, index) => path104?.[index - 1] === "content"
10889
10950
  );
10890
10951
  return {
10891
10952
  type: "string",
@@ -10897,7 +10958,7 @@ var upgradeSchema = (schema2) => {
10897
10958
  });
10898
10959
  return schema2;
10899
10960
  };
10900
- function isSchemaPath(path103) {
10961
+ function isSchemaPath(path104) {
10901
10962
  const schemaLocations = [
10902
10963
  ["components", "schemas"],
10903
10964
  "properties",
@@ -10910,10 +10971,10 @@ function isSchemaPath(path103) {
10910
10971
  ];
10911
10972
  return schemaLocations.some((location) => {
10912
10973
  if (Array.isArray(location)) {
10913
- return location.every((segment, index) => path103[index] === segment);
10974
+ return location.every((segment, index) => path104[index] === segment);
10914
10975
  }
10915
- return path103.includes(location);
10916
- }) || path103.includes("schema") || path103.some((segment) => segment.endsWith("Schema"));
10976
+ return path104.includes(location);
10977
+ }) || path104.includes("schema") || path104.some((segment) => segment.endsWith("Schema"));
10917
10978
  }
10918
10979
 
10919
10980
  // src/lib/oas/parser/index.ts
@@ -10995,13 +11056,13 @@ var OPENAPI_PROPS = /* @__PURE__ */ new Set([
10995
11056
  "anyOf",
10996
11057
  "oneOf"
10997
11058
  ]);
10998
- var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path103 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
11059
+ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path104 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
10999
11060
  if (obj === null || typeof obj !== "object") return obj;
11000
11061
  const refPath = obj.__$ref;
11001
11062
  const isCircular = currentPath.has(obj) || typeof refPath === "string" && currentRefPaths.has(refPath);
11002
11063
  if (isCircular) {
11003
11064
  if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
11004
- const circularProp = path103.find((p) => !OPENAPI_PROPS.has(p)) || path103[0];
11065
+ const circularProp = path104.find((p) => !OPENAPI_PROPS.has(p)) || path104[0];
11005
11066
  return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
11006
11067
  }
11007
11068
  if (refs.has(obj)) return refs.get(obj);
@@ -11011,7 +11072,7 @@ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs
11011
11072
  value,
11012
11073
  currentPath,
11013
11074
  refs,
11014
- [...path103, key],
11075
+ [...path104, key],
11015
11076
  currentRefPaths
11016
11077
  );
11017
11078
  const result = Array.isArray(obj) ? obj.map((item, i) => recurse(item, i.toString())) : Object.fromEntries(
@@ -11046,7 +11107,7 @@ var resolveExtensions = (obj) => Object.fromEntries(
11046
11107
  var getAllTags = (schema2) => {
11047
11108
  const rootTags = schema2.tags ?? [];
11048
11109
  const operations = Object.values(schema2.paths ?? {}).flatMap(
11049
- (path103) => HttpMethods.map((k) => path103?.[k]).filter((op) => op != null)
11110
+ (path104) => HttpMethods.map((k) => path104?.[k]).filter((op) => op != null)
11050
11111
  );
11051
11112
  const operationTags = new Set(operations.flatMap((op) => op.tags ?? []));
11052
11113
  const hasUntaggedOperations = operations.some(
@@ -11101,7 +11162,7 @@ var getAllSlugs = (ops, schemaTags = []) => {
11101
11162
  var getOperationSlugKey = (op) => [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
11102
11163
  var getAllOperations = (paths) => {
11103
11164
  const operations = Object.entries(paths ?? {}).flatMap(
11104
- ([path103, value]) => HttpMethods.flatMap((method) => {
11165
+ ([path104, value]) => HttpMethods.flatMap((method) => {
11105
11166
  if (!value?.[method]) return [];
11106
11167
  const operation = value[method];
11107
11168
  const pathParameters = value.parameters ?? [];
@@ -11121,7 +11182,7 @@ var getAllOperations = (paths) => {
11121
11182
  return {
11122
11183
  ...operation,
11123
11184
  method,
11124
- path: path103,
11185
+ path: path104,
11125
11186
  parameters,
11126
11187
  servers,
11127
11188
  tags: operation.tags ?? []
@@ -11479,8 +11540,8 @@ var Schema = builder.objectRef("Schema").implement({
11479
11540
  }),
11480
11541
  paths: t.field({
11481
11542
  type: [PathItem],
11482
- resolve: (root) => Object.entries(root.paths ?? {}).map(([path103, value]) => ({
11483
- path: path103,
11543
+ resolve: (root) => Object.entries(root.paths ?? {}).map(([path104, value]) => ({
11544
+ path: path104,
11484
11545
  // biome-ignore lint/style/noNonNullAssertion: value is guaranteed to be defined
11485
11546
  methods: Object.keys(value)
11486
11547
  }))
@@ -11645,7 +11706,7 @@ init_joinUrl();
11645
11706
 
11646
11707
  // src/vite/api/schema-codegen.ts
11647
11708
  var unescapeJsonPointer = (uri) => decodeURIComponent(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
11648
- var getSegmentsFromPath = (path103) => path103.split("/").slice(1).map(unescapeJsonPointer);
11709
+ var getSegmentsFromPath = (path104) => path104.split("/").slice(1).map(unescapeJsonPointer);
11649
11710
  var createLocalRefMap = (obj) => {
11650
11711
  const refMap = /* @__PURE__ */ new Map();
11651
11712
  const siblingsMap = /* @__PURE__ */ new Map();
@@ -11676,16 +11737,16 @@ var replaceMarkers = (code, mergedRefs) => code.replace(/"__refMap:(.*?)"/g, '__
11676
11737
  /"__refMap\+Siblings:(.*?)"/g,
11677
11738
  (_, key) => mergedRefs.get(key) ?? `__refMap["${key}"]`
11678
11739
  );
11679
- var lookup = (schema2, path103, filePath) => {
11680
- const parts = getSegmentsFromPath(path103);
11740
+ var lookup = (schema2, path104, filePath) => {
11741
+ const parts = getSegmentsFromPath(path104);
11681
11742
  let val = schema2;
11682
11743
  for (const part of parts) {
11683
11744
  while (val.$ref?.startsWith("#/")) {
11684
- val = val.$ref === path103 ? val : lookup(schema2, val.$ref, filePath);
11745
+ val = val.$ref === path104 ? val : lookup(schema2, val.$ref, filePath);
11685
11746
  }
11686
11747
  if (val[part] === void 0) {
11687
11748
  throw new Error(
11688
- `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path103}`
11749
+ `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path104}`
11689
11750
  );
11690
11751
  }
11691
11752
  val = val[part];
@@ -11930,8 +11991,8 @@ var SchemaManager = class {
11930
11991
  }
11931
11992
  }
11932
11993
  };
11933
- getLatestSchema = (path103) => this.processedSchemas[path103]?.at(0);
11934
- getSchemasForPath = (path103) => this.processedSchemas[path103];
11994
+ getLatestSchema = (path104) => this.processedSchemas[path104]?.at(0);
11995
+ getSchemasForPath = (path104) => this.processedSchemas[path104];
11935
11996
  getSchemaImports = () => Object.values(this.processedSchemas).flat().filter((s) => s.importKey);
11936
11997
  getUrlToFilePathMap = () => {
11937
11998
  const map = /* @__PURE__ */ new Map();
@@ -14385,14 +14446,14 @@ async function generateSitemap({
14385
14446
 
14386
14447
  // src/vite/prerender/utils.ts
14387
14448
  init_joinUrl();
14388
- var resolveRoutePath = (path103) => {
14389
- const segments = path103.split("/");
14449
+ var resolveRoutePath = (path104) => {
14450
+ const segments = path104.split("/");
14390
14451
  if (segments.some((s) => s.startsWith(":") && !s.endsWith("?"))) {
14391
14452
  return void 0;
14392
14453
  }
14393
14454
  return segments.filter((s) => !s.startsWith(":")).join("/") || void 0;
14394
14455
  };
14395
- var isSkipped = (path103) => path103.includes("*") || /^\d+$/.test(path103);
14456
+ var isSkipped = (path104) => path104.includes("*") || /^\d+$/.test(path104);
14396
14457
  var resolveRoutes = (routes, parentPath = "") => routes.flatMap((route) => {
14397
14458
  if (route.path && isSkipped(route.path)) return [];
14398
14459
  const routePath = route.path ? resolveRoutePath(route.path) : void 0;
@@ -14801,15 +14862,9 @@ var missingCorePackages = (dir) => CORE_PACKAGES.filter((name) => !isPackageInst
14801
14862
 
14802
14863
  // src/cli/portal/v2.ts
14803
14864
  function assertPackagesInstalled(resolved, prepared) {
14804
- const require2 = createRequire2(path48.join(resolved.configDir, "package.json"));
14805
- const missing = requiredPackages(prepared.plan).filter((name) => {
14806
- try {
14807
- require2.resolve(name);
14808
- return false;
14809
- } catch {
14810
- return true;
14811
- }
14812
- });
14865
+ const missing = requiredPackages(prepared.plan).filter(
14866
+ (name) => !isPackageInstalled(resolved.configDir, name)
14867
+ );
14813
14868
  const missingCore = missingCorePackages(resolved.configDir);
14814
14869
  if (missing.length === 0 && missingCore.length === 0) return;
14815
14870
  throw new ConfigError(resolved.configPath, [
@@ -14902,15 +14957,15 @@ async function buildV2(options) {
14902
14957
  // src/cli/check/gateway-online.ts
14903
14958
  import { readFile as readFile13 } from "node:fs/promises";
14904
14959
  var SPEC_SEND_LIMIT = 5 * 1024 * 1024 + 64 * 1024;
14905
- var issue2 = (code, path103, message, hint) => ({ code, path: path103, message, hint });
14960
+ var issue2 = (code, path104, message, hint) => ({ code, path: path104, message, hint });
14906
14961
  function capabilityIssues(gateway, answer) {
14907
14962
  const can = answer.capabilities;
14908
14963
  const plan2 = `your ${answer.tier} plan`;
14909
14964
  const found = [];
14910
- const unsupported = (path103, what, hint) => found.push(
14965
+ const unsupported = (path104, what, hint) => found.push(
14911
14966
  issue2(
14912
14967
  "GATEWAY_CAPABILITY_UNSUPPORTED",
14913
- path103,
14968
+ path104,
14914
14969
  `${what} is not available on ${plan2}.`,
14915
14970
  hint
14916
14971
  )
@@ -15106,9 +15161,9 @@ function toPlatformPlans(plans) {
15106
15161
  }
15107
15162
 
15108
15163
  // src/cli/check/services-online.ts
15109
- var issue3 = (code, path103, message, hint) => ({
15164
+ var issue3 = (code, path104, message, hint) => ({
15110
15165
  code,
15111
- path: path103,
15166
+ path: path104,
15112
15167
  message,
15113
15168
  hint
15114
15169
  });
@@ -15187,9 +15242,10 @@ async function onlinePlansRules(resolved, projectId, api) {
15187
15242
  try {
15188
15243
  const answer = await api.validate(
15189
15244
  projectId,
15190
- wanted.map(({ includedActionKeys, ...plan2 }) => ({
15245
+ // The platform's check needs the list even when it is empty: the actions are only known after the gateway deploy.
15246
+ wanted.map((plan2) => ({
15191
15247
  ...plan2,
15192
- ...includedActionKeys ? { includedActionKeys } : {}
15248
+ includedActionKeys: plan2.includedActionKeys ?? []
15193
15249
  }))
15194
15250
  );
15195
15251
  const convert = (item) => issue3(
@@ -18084,11 +18140,11 @@ var SECRETS_COLLECTION_INSTRUCTION = "For go-live, plans must already be in apit
18084
18140
  // src/cli/platform/helpers/dev-portal-site-validation.ts
18085
18141
  init_gateway_limits();
18086
18142
  import { readFile as readFile19 } from "node:fs/promises";
18087
- import { createRequire as createRequire3 } from "node:module";
18143
+ import { createRequire as createRequire2 } from "node:module";
18088
18144
  import path59 from "node:path";
18089
18145
  var cachedFallbackTs;
18090
18146
  async function loadTypeScriptForSite(sourceDirectory) {
18091
- const require2 = createRequire3(
18147
+ const require2 = createRequire2(
18092
18148
  path59.join(path59.resolve(sourceDirectory), "package.json")
18093
18149
  );
18094
18150
  try {
@@ -21571,7 +21627,7 @@ var config_default = {
21571
21627
  };
21572
21628
 
21573
21629
  // src/cli/cmds/deploy.ts
21574
- import path85 from "node:path";
21630
+ import path86 from "node:path";
21575
21631
 
21576
21632
  // src/cli/apply/handler.ts
21577
21633
  import path82 from "node:path";
@@ -22103,8 +22159,8 @@ function normalizeActionKey(actionKey2) {
22103
22159
  const trimmed = actionKey2.trim();
22104
22160
  if (trimmed.includes(":")) {
22105
22161
  const [method2, ...pathParts] = trimmed.split(":");
22106
- const path104 = pathParts.join(":").trim();
22107
- return `${method2?.toLowerCase()}:${path104.startsWith("/") ? path104 : `/${path104}`}`;
22162
+ const path105 = pathParts.join(":").trim();
22163
+ return `${method2?.toLowerCase()}:${path105.startsWith("/") ? path105 : `/${path105}`}`;
22108
22164
  }
22109
22165
  const spaceIndex = trimmed.indexOf(" ");
22110
22166
  if (spaceIndex <= 0) {
@@ -22113,8 +22169,8 @@ function normalizeActionKey(actionKey2) {
22113
22169
  );
22114
22170
  }
22115
22171
  const method = trimmed.slice(0, spaceIndex).trim().toLowerCase();
22116
- const path103 = trimmed.slice(spaceIndex + 1).trim();
22117
- return `${method}:${path103.startsWith("/") ? path103 : `/${path103}`}`;
22172
+ const path104 = trimmed.slice(spaceIndex + 1).trim();
22173
+ return `${method}:${path104.startsWith("/") ? path104 : `/${path104}`}`;
22118
22174
  }
22119
22175
  async function applyGatewayPublicRoutes(client, projectId, routes, options) {
22120
22176
  const applied = [];
@@ -22735,8 +22791,8 @@ function normalizeActionKeyFormat(actionKey2) {
22735
22791
  const trimmed = actionKey2.trim();
22736
22792
  if (trimmed.includes(":")) {
22737
22793
  const [method2, ...pathParts] = trimmed.split(":");
22738
- const path104 = pathParts.join(":").trim();
22739
- return `${method2.toLowerCase()}:${path104.startsWith("/") ? path104 : `/${path104}`}`;
22794
+ const path105 = pathParts.join(":").trim();
22795
+ return `${method2.toLowerCase()}:${path105.startsWith("/") ? path105 : `/${path105}`}`;
22740
22796
  }
22741
22797
  const spaceIndex = trimmed.indexOf(" ");
22742
22798
  if (spaceIndex <= 0) {
@@ -22745,8 +22801,8 @@ function normalizeActionKeyFormat(actionKey2) {
22745
22801
  );
22746
22802
  }
22747
22803
  const method = trimmed.slice(0, spaceIndex).trim().toLowerCase();
22748
- const path103 = trimmed.slice(spaceIndex + 1).trim();
22749
- return `${method}:${path103.startsWith("/") ? path103 : `/${path103}`}`;
22804
+ const path104 = trimmed.slice(spaceIndex + 1).trim();
22805
+ return `${method}:${path104.startsWith("/") ? path104 : `/${path104}`}`;
22750
22806
  }
22751
22807
  function normalizePublicRoute(route) {
22752
22808
  const trimmed = route.trim();
@@ -27230,7 +27286,7 @@ async function apply(argv) {
27230
27286
 
27231
27287
  // src/cli/deploy/command.ts
27232
27288
  init_invariant();
27233
- import path84 from "node:path";
27289
+ import path85 from "node:path";
27234
27290
 
27235
27291
  // src/cli/deploy/v2.ts
27236
27292
  import { rm as rm12 } from "node:fs/promises";
@@ -27486,6 +27542,52 @@ var IdentityDeployError = class extends ApitogoError {
27486
27542
  }
27487
27543
  };
27488
27544
  var IDENTITY_STEPS = ["request", "activate"];
27545
+ var IDENTITY_CONNECTIONS_STEP = "connections";
27546
+ var SECRET_PREFIX = "secret:";
27547
+ function normalizedConnections(resolved) {
27548
+ return [...resolved.identity?.connections ?? []].map((connection) => ({
27549
+ ...connection,
27550
+ authority: connection.authority.trim().replace(/\/+$/, "")
27551
+ })).sort((a, b) => a.id.localeCompare(b.id));
27552
+ }
27553
+ function identityConnectionsHash(projectId, resolved) {
27554
+ return stableJson({
27555
+ projectId,
27556
+ connections: normalizedConnections(resolved)
27557
+ });
27558
+ }
27559
+ async function recordedConnectionIds(resolved) {
27560
+ const ids = stepOf(
27561
+ await readLedger(resolved.state),
27562
+ "identity",
27563
+ IDENTITY_CONNECTIONS_STEP
27564
+ )?.output?.ids;
27565
+ return ids ? ids.split(",").filter(Boolean) : [];
27566
+ }
27567
+ function redirectAddressesOf(output4) {
27568
+ return Object.entries(output4 ?? {}).filter(([key]) => key.startsWith("redirect.")).map(([key, redirectUri]) => ({
27569
+ id: key.slice("redirect.".length),
27570
+ redirectUri
27571
+ }));
27572
+ }
27573
+ function connectionBody(connection) {
27574
+ return {
27575
+ authority: connection.authority,
27576
+ clientId: connection.clientId,
27577
+ clientSecret: connection.clientSecret,
27578
+ scopes: connection.scopes,
27579
+ displayName: connection.displayName
27580
+ };
27581
+ }
27582
+ function referencedSecretNames(connections) {
27583
+ return [
27584
+ ...new Set(
27585
+ connections.map(
27586
+ (connection) => connection.clientSecret.slice(SECRET_PREFIX.length)
27587
+ )
27588
+ )
27589
+ ];
27590
+ }
27489
27591
  var PORTAL_CALLBACK_PATH = "/oauth/callback";
27490
27592
  var defaultSleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
27491
27593
  function identityNotDeployableReason(resolved) {
@@ -27495,14 +27597,18 @@ function identityNotDeployableReason(resolved) {
27495
27597
  return 'identity.provider "oidc" needs issuer and clientId';
27496
27598
  return void 0;
27497
27599
  }
27498
- function identityRequestBody(resolved, portalUrl) {
27600
+ function identityBodyForRedirect(resolved, redirectUri) {
27499
27601
  return {
27500
- portalRedirectUris: [
27501
- `${portalUrl.replace(/\/+$/, "")}${PORTAL_CALLBACK_PATH}`
27502
- ],
27602
+ portalRedirectUris: [redirectUri],
27503
27603
  nativeSignup: resolved.identity?.native ?? true
27504
27604
  };
27505
27605
  }
27606
+ function identityRequestBody(resolved, portalUrl) {
27607
+ return identityBodyForRedirect(
27608
+ resolved,
27609
+ `${portalUrl.replace(/\/+$/, "")}${PORTAL_CALLBACK_PATH}`
27610
+ );
27611
+ }
27506
27612
  function identityInputsHash(projectId, body) {
27507
27613
  return stableJson({ projectId, body });
27508
27614
  }
@@ -27536,6 +27642,25 @@ function rejected2(error) {
27536
27642
  }
27537
27643
  throw error;
27538
27644
  }
27645
+ function connectionRejected(error, id) {
27646
+ if (error instanceof PlatformApiError && error.status === 409) {
27647
+ throw new IdentityDeployError(
27648
+ "IDENTITY_CONNECTION_REJECTED",
27649
+ `The identity is not active yet, so connection "${id}" cannot be saved.`,
27650
+ "Run deploy again once the identity is Active."
27651
+ );
27652
+ }
27653
+ if (error instanceof PlatformApiError && error.status === 400) {
27654
+ const lines = describePlatformProblem(error);
27655
+ throw new IdentityDeployError(
27656
+ "IDENTITY_CONNECTION_REJECTED",
27657
+ `The platform refused login connection "${id}":
27658
+ ${lines.join("\n ") || error.message}`,
27659
+ "Fix the connection in apitogo.config.json (identity.connections) and run deploy again."
27660
+ );
27661
+ }
27662
+ throw error;
27663
+ }
27539
27664
  async function recordOwnProvider(resolved, projectId) {
27540
27665
  const identity = resolved.identity;
27541
27666
  const issuer = identity?.issuer?.replace(/\/+$/, "");
@@ -27580,7 +27705,10 @@ async function deployIdentity(resolved, projectId, deps, options = {}) {
27580
27705
  run: async () => {
27581
27706
  try {
27582
27707
  const answer = await client.putProjectIdentity(projectId, body);
27583
- return { status: answer.status };
27708
+ return {
27709
+ status: answer.status,
27710
+ redirectUri: body.portalRedirectUris[0] ?? ""
27711
+ };
27584
27712
  } catch (error) {
27585
27713
  return rejected2(error);
27586
27714
  }
@@ -27622,10 +27750,14 @@ async function deployIdentity(resolved, projectId, deps, options = {}) {
27622
27750
  },
27623
27751
  stillValid: async () => (await client.getProjectIdentity(projectId))?.status === "Active"
27624
27752
  };
27753
+ const wanted = normalizedConnections(resolved);
27754
+ const steps = [requestStep, activateStep];
27755
+ if (wanted.length > 0 || (await recordedConnectionIds(resolved)).length > 0)
27756
+ steps.push(connectionsStep(resolved, projectId, client, wanted));
27625
27757
  const outcomes = await runPipeline(
27626
27758
  resolved.state,
27627
27759
  "identity",
27628
- [requestStep, activateStep],
27760
+ steps,
27629
27761
  { force: options.force }
27630
27762
  );
27631
27763
  const activate = outcomes.find((outcome) => outcome.step === "activate");
@@ -27648,14 +27780,103 @@ async function deployIdentity(resolved, projectId, deps, options = {}) {
27648
27780
  );
27649
27781
  }
27650
27782
  }
27783
+ const connectionsRan = outcomes.some(
27784
+ (outcome) => outcome.step === IDENTITY_CONNECTIONS_STEP && !outcome.skipped
27785
+ );
27651
27786
  return {
27652
- status: ran ? "deployed" : "unchanged",
27787
+ status: ran || connectionsRan ? "deployed" : "unchanged",
27653
27788
  steps: outcomes.map((outcome) => ({
27654
27789
  step: outcome.step,
27655
27790
  skipped: outcome.skipped
27656
27791
  })),
27657
27792
  issuer: learned?.issuer ?? known?.issuer,
27658
- clientId: learned?.clientId ?? known?.clientId
27793
+ clientId: learned?.clientId ?? known?.clientId,
27794
+ connections: redirectAddressesOf(
27795
+ stepOf(
27796
+ await readLedger(resolved.state),
27797
+ "identity",
27798
+ IDENTITY_CONNECTIONS_STEP
27799
+ )?.output
27800
+ )
27801
+ };
27802
+ }
27803
+ function connectionsStep(resolved, projectId, client, wanted) {
27804
+ const {
27805
+ putProjectIdentityConnection,
27806
+ listProjectIdentityConnections,
27807
+ deleteProjectIdentityConnection,
27808
+ listSecrets
27809
+ } = client;
27810
+ if (!putProjectIdentityConnection || !listProjectIdentityConnections || !deleteProjectIdentityConnection || !listSecrets)
27811
+ throw new Error("The platform client has no login connection calls.");
27812
+ const stamps = async () => {
27813
+ const names = referencedSecretNames(wanted);
27814
+ if (names.length === 0) return {};
27815
+ const listed = await listSecrets.call(client, projectId);
27816
+ const byName2 = new Map(listed.secrets.map((s) => [s.name, s.updatedAtUtc]));
27817
+ const missing = names.filter((name) => !byName2.has(name));
27818
+ if (missing.length > 0)
27819
+ throw new IdentityDeployError(
27820
+ "IDENTITY_SECRET_MISSING",
27821
+ `The secret ${missing.join(", ")} is not set for this project, and a login connection needs it.`,
27822
+ `Run \`apitogo secrets set ${missing[0]}\` with the value from the provider, then deploy again.`
27823
+ );
27824
+ return Object.fromEntries(
27825
+ names.map((name) => [name, byName2.get(name)])
27826
+ );
27827
+ };
27828
+ const sameAddress = (a, b) => a.replace(/\/+$/, "").toLowerCase() === b.replace(/\/+$/, "").toLowerCase();
27829
+ return {
27830
+ name: IDENTITY_CONNECTIONS_STEP,
27831
+ hash: () => identityConnectionsHash(projectId, resolved),
27832
+ run: async () => {
27833
+ const recorded = await stamps();
27834
+ const existing = await listProjectIdentityConnections.call(
27835
+ client,
27836
+ projectId
27837
+ );
27838
+ const redirects = {};
27839
+ for (const connection of wanted) {
27840
+ try {
27841
+ const saved = await putProjectIdentityConnection.call(
27842
+ client,
27843
+ projectId,
27844
+ connection.id,
27845
+ connectionBody(connection)
27846
+ );
27847
+ redirects[`redirect.${connection.id}`] = saved.redirectUri;
27848
+ } catch (error) {
27849
+ return connectionRejected(error, connection.id);
27850
+ }
27851
+ }
27852
+ for (const old of existing)
27853
+ if (!wanted.some((connection) => connection.id === old.id))
27854
+ await deleteProjectIdentityConnection.call(client, projectId, old.id);
27855
+ return {
27856
+ ids: wanted.map((connection) => connection.id).join(","),
27857
+ secretsStamp: stableJson(recorded),
27858
+ ...redirects
27859
+ };
27860
+ },
27861
+ // The platform still has exactly these connections, and none of the secrets was changed since.
27862
+ stillValid: async () => {
27863
+ const found = await listProjectIdentityConnections.call(
27864
+ client,
27865
+ projectId
27866
+ );
27867
+ if (found.length !== wanted.length) return false;
27868
+ for (const connection of wanted) {
27869
+ const there = found.find((f) => f.id === connection.id);
27870
+ if (!there || there.clientId !== connection.clientId || !sameAddress(there.authority, connection.authority))
27871
+ return false;
27872
+ }
27873
+ const before = stepOf(
27874
+ await readLedger(resolved.state),
27875
+ "identity",
27876
+ IDENTITY_CONNECTIONS_STEP
27877
+ )?.output?.secretsStamp;
27878
+ return before === void 0 || before === stableJson(await stamps());
27879
+ }
27659
27880
  };
27660
27881
  }
27661
27882
 
@@ -27925,20 +28146,42 @@ async function planIdentityService(resolved, ledger, manifest) {
27925
28146
  }
27926
28147
  const projectId = resolved.project.id;
27927
28148
  const portalUrl = manifest?.services.portal?.url;
27928
- const body = portalUrl ? identityRequestBody(resolved, portalUrl) : void 0;
28149
+ const recorded = stepOf(ledger, "identity", "request")?.output?.redirectUri;
28150
+ const body = portalUrl ? identityRequestBody(resolved, portalUrl) : recorded ? identityBodyForRedirect(resolved, recorded) : void 0;
27929
28151
  const hash2 = projectId && body ? identityInputsHash(projectId, body) : void 0;
27930
28152
  const details = [
27931
28153
  "provider: apitogo (one issuer for this project)",
27932
28154
  `sign-up with email and password: ${identity.native ? "on" : "off"}`,
27933
- portalUrl ? `sign-in redirect: ${portalUrl.replace(/\/+$/, "")}${PORTAL_CALLBACK_PATH}` : "sign-in redirect: the portal address is not known locally; deploy takes it from the project",
28155
+ portalUrl ? `sign-in redirect: ${portalUrl.replace(/\/+$/, "")}${PORTAL_CALLBACK_PATH}` : recorded ? `sign-in redirect: ${recorded} (sent by the last deploy)` : "sign-in redirect: the portal address is not known locally; deploy takes it from the project",
27934
28156
  ...known?.issuer ? [`issuer: ${known.issuer}`] : [],
27935
28157
  ...IDENTITY_STEPS.map(
27936
28158
  (name) => `step ${name}: ${stepState(stepOf(ledger, "identity", name), hash2)}`
27937
28159
  )
27938
28160
  ];
28161
+ const connections = normalizedConnections(resolved);
28162
+ const leftOnPlatform = (await recordedConnectionIds(resolved)).length > 0;
28163
+ const connectionsHash = projectId ? identityConnectionsHash(projectId, resolved) : void 0;
28164
+ const connectionsRecord = stepOf(
28165
+ ledger,
28166
+ "identity",
28167
+ IDENTITY_CONNECTIONS_STEP
28168
+ );
28169
+ if (connections.length > 0 || leftOnPlatform) {
28170
+ for (const connection of connections)
28171
+ details.push(
28172
+ `login connection ${connection.id}: ${connection.displayName ?? connection.id} (${connection.authority})` + (known?.issuer ? `, register this redirect address with the provider: ${known.issuer.replace(/\/+$/, "")}/account/external/${connection.id}/callback` : "")
28173
+ );
28174
+ if (connections.length === 0)
28175
+ details.push(
28176
+ "login connections: the last deploy's connections will be removed"
28177
+ );
28178
+ details.push(
28179
+ `step ${IDENTITY_CONNECTIONS_STEP}: ${stepState(connectionsRecord, connectionsHash)}`
28180
+ );
28181
+ }
27939
28182
  const allDone = IDENTITY_STEPS.every(
27940
28183
  (name) => isDone(stepOf(ledger, "identity", name), hash2)
27941
- );
28184
+ ) && (connections.length === 0 && !leftOnPlatform ? true : isDone(connectionsRecord, connectionsHash));
27942
28185
  return {
27943
28186
  ...base,
27944
28187
  action: allDone ? "skip" : "deploy",
@@ -28004,7 +28247,7 @@ async function planPlansService(resolved, ledger) {
28004
28247
  }
28005
28248
  var failedStep = (ledger, service, names) => names.map((name) => ({ name, record: stepOf(ledger, service, name) })).find((step2) => step2.record?.status === "failed");
28006
28249
  var unreachable = (error) => `platform: not reachable (${error instanceof Error ? error.message : String(error)}); showing local records only`;
28007
- async function identityStatus(resolved, ledger, manifest, remote) {
28250
+ async function identityStatus(resolved, ledger, manifest, remote, connectionsRemote) {
28008
28251
  const entry = manifest?.services.identity;
28009
28252
  const failed = failedStep(ledger, "identity", IDENTITY_STEPS);
28010
28253
  const details = [];
@@ -28038,6 +28281,15 @@ async function identityStatus(resolved, ledger, manifest, remote) {
28038
28281
  );
28039
28282
  state = "drift";
28040
28283
  }
28284
+ if (connectionsRemote && platform.status === "Active") {
28285
+ const drift = await connectionLines(
28286
+ resolved,
28287
+ projectId,
28288
+ connectionsRemote,
28289
+ details
28290
+ );
28291
+ if (drift && state === "ready") state = "drift";
28292
+ }
28041
28293
  }
28042
28294
  } catch (error) {
28043
28295
  details.push(unreachable(error));
@@ -28053,6 +28305,36 @@ async function identityStatus(resolved, ledger, manifest, remote) {
28053
28305
  }
28054
28306
  return { service: "identity", state, details };
28055
28307
  }
28308
+ async function connectionLines(resolved, projectId, remote, details) {
28309
+ const configured = normalizedConnections(resolved);
28310
+ let there;
28311
+ try {
28312
+ there = await remote(projectId);
28313
+ } catch (error) {
28314
+ details.push(unreachable(error));
28315
+ return false;
28316
+ }
28317
+ for (const connection of there)
28318
+ details.push(
28319
+ `login connection ${connection.id}: ${connection.displayName} (${connection.authority}), register this redirect address with the provider: ${connection.redirectUri}`
28320
+ );
28321
+ let differ = false;
28322
+ for (const connection of configured)
28323
+ if (!there.some((t) => t.id === connection.id)) {
28324
+ details.push(
28325
+ `drift: login connection ${connection.id} is in the config but not on the platform; run deploy`
28326
+ );
28327
+ differ = true;
28328
+ }
28329
+ for (const connection of there)
28330
+ if (!configured.some((c) => c.id === connection.id)) {
28331
+ details.push(
28332
+ `drift: login connection ${connection.id} is on the platform but not in the config; deploy removes it`
28333
+ );
28334
+ differ = true;
28335
+ }
28336
+ return differ;
28337
+ }
28056
28338
  async function plansStatus(resolved, ledger, manifest, remote, wantedSkus2) {
28057
28339
  const entry = manifest?.services.plans;
28058
28340
  const failed = failedStep(ledger, "plans", PLANS_STEPS);
@@ -28488,7 +28770,8 @@ async function statusV2(dir, only, options = {}) {
28488
28770
  resolved,
28489
28771
  ledger,
28490
28772
  manifest,
28491
- options.identityRemote
28773
+ options.identityRemote,
28774
+ options.identityConnectionsRemote
28492
28775
  )
28493
28776
  );
28494
28777
  continue;
@@ -28532,6 +28815,36 @@ function formatStatus(output4) {
28532
28815
  ];
28533
28816
  }
28534
28817
 
28818
+ // src/cli/deploy/static-web-config.ts
28819
+ import { access as access14, writeFile as writeFile25 } from "node:fs/promises";
28820
+ import path84 from "node:path";
28821
+ var STATIC_WEB_CONFIG_FILE = "staticwebapp.config.json";
28822
+ var STATIC_WEB_CONFIG_VERSION = 1;
28823
+ var DEFAULT_STATIC_WEB_CONFIG = {
28824
+ navigationFallback: {
28825
+ rewrite: "/index.html",
28826
+ exclude: [
28827
+ "/assets/*",
28828
+ "/*.{png,jpg,jpeg,gif,svg,ico,css,js,mjs,json,txt,xml,webmanifest,woff,woff2,map}"
28829
+ ]
28830
+ }
28831
+ };
28832
+ async function ensureStaticWebConfig(buildDir) {
28833
+ const file = path84.join(buildDir, STATIC_WEB_CONFIG_FILE);
28834
+ try {
28835
+ await access14(file);
28836
+ return false;
28837
+ } catch {
28838
+ await writeFile25(
28839
+ file,
28840
+ `${JSON.stringify(DEFAULT_STATIC_WEB_CONFIG, null, 2)}
28841
+ `,
28842
+ "utf8"
28843
+ );
28844
+ return true;
28845
+ }
28846
+ }
28847
+
28535
28848
  // src/cli/deploy/v2.ts
28536
28849
  var DeployError = class extends ApitogoError {
28537
28850
  constructor(code, message, developerHint) {
@@ -28556,8 +28869,9 @@ function parseDeployOnly(value) {
28556
28869
  function publishStep(deps, options) {
28557
28870
  return {
28558
28871
  name: "publish",
28559
- hash: () => `${options.buildHash}|${options.projectId}|${options.env ?? ""}`,
28872
+ hash: () => `${options.buildHash}|${options.projectId}|${options.env ?? ""}|host-config-${STATIC_WEB_CONFIG_VERSION}`,
28560
28873
  run: async () => {
28874
+ await ensureStaticWebConfig(options.buildDir);
28561
28875
  const pack = deps.pack ?? packageDirectoryAsTarGz;
28562
28876
  const archive = await pack(options.buildDir, { archiveRoot: "dist" });
28563
28877
  try {
@@ -28694,7 +29008,10 @@ async function deployIdentityService(options, deps, projectId, named) {
28694
29008
  service: "identity",
28695
29009
  status: result.status,
28696
29010
  steps: result.steps,
28697
- url: result.issuer
29011
+ url: result.issuer,
29012
+ notes: (result.connections ?? []).map(
29013
+ (connection) => `login connection ${connection.id}: register this redirect address with the provider: ${connection.redirectUri}`
29014
+ )
28698
29015
  };
28699
29016
  }
28700
29017
  async function deployPlansService(options, deps, projectId, named) {
@@ -28791,7 +29108,8 @@ function formatDeploy(output4) {
28791
29108
  head,
28792
29109
  ...result.steps.map(
28793
29110
  (step2) => ` ${step2.step}: ${step2.skipped ? "skipped (unchanged)" : "ran"}`
28794
- )
29111
+ ),
29112
+ ...(result.notes ?? []).map((note) => ` ${note}`)
28795
29113
  ];
28796
29114
  });
28797
29115
  }
@@ -28803,7 +29121,7 @@ async function deployProject(argv) {
28803
29121
  const config2 = loadConfig();
28804
29122
  const output4 = await deployV2(
28805
29123
  {
28806
- dir: path84.resolve(process.cwd(), argv.dir),
29124
+ dir: path85.resolve(process.cwd(), argv.dir),
28807
29125
  only: Array.isArray(argv.only) ? argv.only.join(",") : argv.only,
28808
29126
  projectId: argv.projectId,
28809
29127
  env: argv.env,
@@ -28884,7 +29202,7 @@ var deploy_default = {
28884
29202
  }),
28885
29203
  handler: async (argv) => {
28886
29204
  await captureEvent({ argv, event: "apitogo deploy" });
28887
- if (await isConfigV2(path85.resolve(process.cwd(), argv.dir))) {
29205
+ if (await isConfigV2(path86.resolve(process.cwd(), argv.dir))) {
28888
29206
  await deployProject(argv);
28889
29207
  return;
28890
29208
  }
@@ -28893,8 +29211,8 @@ var deploy_default = {
28893
29211
  };
28894
29212
 
28895
29213
  // src/cli/export/handler.ts
28896
- import { mkdir as mkdir20, writeFile as writeFile25 } from "node:fs/promises";
28897
- import path86 from "node:path";
29214
+ import { mkdir as mkdir20, writeFile as writeFile26 } from "node:fs/promises";
29215
+ import path87 from "node:path";
28898
29216
  init_invariant();
28899
29217
  var ExportError = class extends ApitogoError {
28900
29218
  constructor(message, developerHint) {
@@ -28908,7 +29226,7 @@ async function exportOpenApi(args, deps) {
28908
29226
  `Cannot export "${args.target}".`,
28909
29227
  "Only `apitogo export openapi` exists."
28910
29228
  );
28911
- const dir = path86.resolve(process.cwd(), args.dir ?? ".");
29229
+ const dir = path87.resolve(process.cwd(), args.dir ?? ".");
28912
29230
  if (!await isConfigV2(dir))
28913
29231
  throw new ExportError(
28914
29232
  "This command needs a config version 2 project.",
@@ -28933,9 +29251,9 @@ async function exportOpenApi(args, deps) {
28933
29251
  throw error;
28934
29252
  }
28935
29253
  if (!args.out) return { text };
28936
- const file = path86.resolve(process.cwd(), args.out);
28937
- await mkdir20(path86.dirname(file), { recursive: true });
28938
- await writeFile25(file, text);
29254
+ const file = path87.resolve(process.cwd(), args.out);
29255
+ await mkdir20(path87.dirname(file), { recursive: true });
29256
+ await writeFile26(file, text);
28939
29257
  return { text, file };
28940
29258
  }
28941
29259
  async function exportCommand(args) {
@@ -28985,15 +29303,15 @@ var export_default = {
28985
29303
  };
28986
29304
 
28987
29305
  // src/cli/init/handler.ts
28988
- import path90 from "node:path";
29306
+ import path91 from "node:path";
28989
29307
 
28990
29308
  // src/cli/scaffold/run-scaffold-discovery.ts
28991
- import { access as access15, readFile as readFile31, writeFile as writeFile27 } from "node:fs/promises";
28992
- import path89 from "node:path";
29309
+ import { access as access16, readFile as readFile31, writeFile as writeFile28 } from "node:fs/promises";
29310
+ import path90 from "node:path";
28993
29311
 
28994
29312
  // src/cli/scaffold/detect-backend.ts
28995
29313
  import { readdir as readdir4, readFile as readFile29 } from "node:fs/promises";
28996
- import path87 from "node:path";
29314
+ import path88 from "node:path";
28997
29315
  var DEFAULT_RUNTIME_VERSION = {
28998
29316
  dotnet: "DOTNET_10",
28999
29317
  nodejs: "NODE_22_LTS",
@@ -29039,15 +29357,15 @@ function isRunnableNodePackage(pkg) {
29039
29357
  return typeof scripts.start === "string" || typeof pkg.main === "string";
29040
29358
  }
29041
29359
  async function detectParentBackend(siteDirectory) {
29042
- const site = path87.resolve(siteDirectory);
29043
- const directory = path87.dirname(site);
29360
+ const site = path88.resolve(siteDirectory);
29361
+ const directory = path88.dirname(site);
29044
29362
  if (directory === site) {
29045
29363
  return void 0;
29046
29364
  }
29047
29365
  const files = await listFiles(directory);
29048
29366
  const toResult = (runtime, runtimeVersion, marker) => ({
29049
29367
  directory,
29050
- sourceDirectory: path87.relative(site, directory).split(path87.sep).join("/") || ".",
29368
+ sourceDirectory: path88.relative(site, directory).split(path88.sep).join("/") || ".",
29051
29369
  runtime,
29052
29370
  runtimeVersion,
29053
29371
  marker
@@ -29055,7 +29373,7 @@ async function detectParentBackend(siteDirectory) {
29055
29373
  const csproj = files.find((f) => f.endsWith(".csproj"));
29056
29374
  const solution = files.find((f) => /\.slnx?$/.test(f));
29057
29375
  if (csproj || solution) {
29058
- const content = csproj ? await readText(path87.join(directory, csproj)) : void 0;
29376
+ const content = csproj ? await readText(path88.join(directory, csproj)) : void 0;
29059
29377
  return toResult(
29060
29378
  "dotnet",
29061
29379
  dotnetVersionFromCsproj(content),
@@ -29063,7 +29381,7 @@ async function detectParentBackend(siteDirectory) {
29063
29381
  );
29064
29382
  }
29065
29383
  if (files.includes("package.json")) {
29066
- const raw = await readText(path87.join(directory, "package.json"));
29384
+ const raw = await readText(path88.join(directory, "package.json"));
29067
29385
  try {
29068
29386
  const pkg = JSON.parse(raw ?? "");
29069
29387
  if (isRunnableNodePackage(pkg)) {
@@ -29078,7 +29396,7 @@ async function detectParentBackend(siteDirectory) {
29078
29396
  }
29079
29397
  const pythonMarker = PYTHON_MARKERS.find((m) => files.includes(m));
29080
29398
  if (pythonMarker) {
29081
- const versionSource = await readText(path87.join(directory, ".python-version")) ?? (pythonMarker === "pyproject.toml" ? (await readText(path87.join(directory, pythonMarker)))?.match(
29399
+ const versionSource = await readText(path88.join(directory, ".python-version")) ?? (pythonMarker === "pyproject.toml" ? (await readText(path88.join(directory, pythonMarker)))?.match(
29082
29400
  /requires-python\s*=\s*"([^"]+)"/
29083
29401
  )?.[1] : void 0);
29084
29402
  return toResult(
@@ -29092,16 +29410,16 @@ async function detectParentBackend(siteDirectory) {
29092
29410
 
29093
29411
  // src/cli/scaffold/wire-docs.ts
29094
29412
  import {
29095
- access as access14,
29413
+ access as access15,
29096
29414
  lstat as lstat2,
29097
29415
  mkdir as mkdir21,
29098
29416
  readdir as readdir5,
29099
29417
  readFile as readFile30,
29100
29418
  readlink,
29101
29419
  symlink as symlink2,
29102
- writeFile as writeFile26
29420
+ writeFile as writeFile27
29103
29421
  } from "node:fs/promises";
29104
- import path88 from "node:path";
29422
+ import path89 from "node:path";
29105
29423
  var DOCS_DIR_WHITELIST = [
29106
29424
  "docs",
29107
29425
  "documents",
@@ -29123,7 +29441,7 @@ var PAGES_DIR = "pages";
29123
29441
  var CONFIG_FILENAME = "apitogo.config.json";
29124
29442
  async function pathExists5(filePath) {
29125
29443
  try {
29126
- await access14(filePath);
29444
+ await access15(filePath);
29127
29445
  return true;
29128
29446
  } catch {
29129
29447
  return false;
@@ -29138,14 +29456,14 @@ async function isDirectory2(filePath) {
29138
29456
  }
29139
29457
  }
29140
29458
  function toPosix3(value) {
29141
- return value.split(path88.sep).join(path88.posix.sep);
29459
+ return value.split(path89.sep).join(path89.posix.sep);
29142
29460
  }
29143
29461
  function isWhitelistedDirName(name) {
29144
29462
  return DOCS_DIR_WHITELIST.includes(name.toLowerCase());
29145
29463
  }
29146
29464
  function isInside2(parent, child) {
29147
- const relative = path88.relative(parent, child);
29148
- return relative === "" || !relative.startsWith("..") && !path88.isAbsolute(relative);
29465
+ const relative = path89.relative(parent, child);
29466
+ return relative === "" || !relative.startsWith("..") && !path89.isAbsolute(relative);
29149
29467
  }
29150
29468
  async function collectMarkdownFiles(dir, excludeDir) {
29151
29469
  const files = [];
@@ -29159,9 +29477,9 @@ async function collectMarkdownFiles(dir, excludeDir) {
29159
29477
  if (entry.name.startsWith(".")) {
29160
29478
  continue;
29161
29479
  }
29162
- const full = path88.join(dir, entry.name);
29480
+ const full = path89.join(dir, entry.name);
29163
29481
  if (entry.isDirectory()) {
29164
- if (SKIP_SEARCH_DIRS.has(entry.name) || entry.isSymbolicLink() || excludeDir && path88.resolve(full) === excludeDir) {
29482
+ if (SKIP_SEARCH_DIRS.has(entry.name) || entry.isSymbolicLink() || excludeDir && path89.resolve(full) === excludeDir) {
29165
29483
  continue;
29166
29484
  }
29167
29485
  files.push(...await collectMarkdownFiles(full, excludeDir));
@@ -29174,11 +29492,11 @@ async function collectMarkdownFiles(dir, excludeDir) {
29174
29492
  return files;
29175
29493
  }
29176
29494
  async function collectSearchRoots(siteDirectory) {
29177
- const site = path88.resolve(siteDirectory);
29178
- const parent = path88.dirname(site);
29495
+ const site = path89.resolve(siteDirectory);
29496
+ const parent = path89.dirname(site);
29179
29497
  const roots = [];
29180
29498
  const add = (dir) => {
29181
- const resolved = path88.resolve(dir);
29499
+ const resolved = path89.resolve(dir);
29182
29500
  if (!roots.includes(resolved)) {
29183
29501
  roots.push(resolved);
29184
29502
  }
@@ -29191,7 +29509,7 @@ async function collectSearchRoots(siteDirectory) {
29191
29509
  if (!entry.isDirectory() || SKIP_SEARCH_DIRS.has(entry.name)) {
29192
29510
  continue;
29193
29511
  }
29194
- add(path88.join(parent, entry.name));
29512
+ add(path89.join(parent, entry.name));
29195
29513
  }
29196
29514
  } catch {
29197
29515
  }
@@ -29200,13 +29518,13 @@ async function collectSearchRoots(siteDirectory) {
29200
29518
  return roots;
29201
29519
  }
29202
29520
  async function discoverNearbyDocsDirectories(siteDirectory) {
29203
- const site = path88.resolve(siteDirectory);
29204
- const sitePages = path88.join(site, PAGES_DIR);
29521
+ const site = path89.resolve(siteDirectory);
29522
+ const sitePages = path89.join(site, PAGES_DIR);
29205
29523
  const searchedDirectories = await collectSearchRoots(site);
29206
29524
  const directories = [];
29207
29525
  const seen = /* @__PURE__ */ new Set();
29208
29526
  const consider = async (dir) => {
29209
- const resolved = path88.resolve(dir);
29527
+ const resolved = path89.resolve(dir);
29210
29528
  if (resolved === site || seen.has(resolved) || isInside2(sitePages, resolved)) {
29211
29529
  return;
29212
29530
  }
@@ -29223,7 +29541,7 @@ async function discoverNearbyDocsDirectories(siteDirectory) {
29223
29541
  directories.push({ sourceDirectory: resolved, files });
29224
29542
  };
29225
29543
  for (const root of searchedDirectories) {
29226
- if (isWhitelistedDirName(path88.basename(root))) {
29544
+ if (isWhitelistedDirName(path89.basename(root))) {
29227
29545
  await consider(root);
29228
29546
  }
29229
29547
  try {
@@ -29235,7 +29553,7 @@ async function discoverNearbyDocsDirectories(siteDirectory) {
29235
29553
  if (!isWhitelistedDirName(entry.name)) {
29236
29554
  continue;
29237
29555
  }
29238
- await consider(path88.join(root, entry.name));
29556
+ await consider(path89.join(root, entry.name));
29239
29557
  }
29240
29558
  } catch {
29241
29559
  }
@@ -29254,8 +29572,8 @@ function slugifyDirName(name) {
29254
29572
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "docs";
29255
29573
  }
29256
29574
  async function allocateLinkName(pagesDir, sourceDirectory, used) {
29257
- const base = slugifyDirName(path88.basename(sourceDirectory));
29258
- const parent = slugifyDirName(path88.basename(path88.dirname(sourceDirectory)));
29575
+ const base = slugifyDirName(path89.basename(sourceDirectory));
29576
+ const parent = slugifyDirName(path89.basename(path89.dirname(sourceDirectory)));
29259
29577
  const candidates = [base, `${parent}-${base}`];
29260
29578
  let index = 2;
29261
29579
  while (true) {
@@ -29263,7 +29581,7 @@ async function allocateLinkName(pagesDir, sourceDirectory, used) {
29263
29581
  if (used.has(name)) {
29264
29582
  continue;
29265
29583
  }
29266
- const target = path88.join(pagesDir, name);
29584
+ const target = path89.join(pagesDir, name);
29267
29585
  if (await pathExists5(target)) {
29268
29586
  const stat7 = await lstat2(target);
29269
29587
  if (!stat7.isDirectory() || !await isManagedLinkDir(target)) {
@@ -29294,8 +29612,8 @@ async function alreadyLinked(linkPath, sourcePath) {
29294
29612
  return false;
29295
29613
  }
29296
29614
  const current = await readlink(linkPath);
29297
- const resolved = path88.resolve(path88.dirname(linkPath), current);
29298
- return resolved === path88.resolve(sourcePath);
29615
+ const resolved = path89.resolve(path89.dirname(linkPath), current);
29616
+ return resolved === path89.resolve(sourcePath);
29299
29617
  } catch {
29300
29618
  return false;
29301
29619
  }
@@ -29307,8 +29625,8 @@ async function linkMarkdownFile(sourcePath, linkPath) {
29307
29625
  if (await pathExists5(linkPath)) {
29308
29626
  return "skipped";
29309
29627
  }
29310
- await mkdir21(path88.dirname(linkPath), { recursive: true });
29311
- const relativeTarget = path88.relative(path88.dirname(linkPath), sourcePath);
29628
+ await mkdir21(path89.dirname(linkPath), { recursive: true });
29629
+ const relativeTarget = path89.relative(path89.dirname(linkPath), sourcePath);
29312
29630
  await symlink2(
29313
29631
  relativeTarget,
29314
29632
  linkPath,
@@ -29323,7 +29641,7 @@ async function applyDocsNavigation(siteDirectory, routes) {
29323
29641
  if (routes.length === 0) {
29324
29642
  return;
29325
29643
  }
29326
- const configPath = path88.join(siteDirectory, CONFIG_FILENAME);
29644
+ const configPath = path89.join(siteDirectory, CONFIG_FILENAME);
29327
29645
  if (!await pathExists5(configPath)) {
29328
29646
  return;
29329
29647
  }
@@ -29336,12 +29654,12 @@ async function applyDocsNavigation(siteDirectory, routes) {
29336
29654
  force: false
29337
29655
  });
29338
29656
  const updated = ensureHeaderDocsNavigation(parsed, routes);
29339
- await writeFile26(configPath, `${JSON.stringify(updated, null, 2)}
29657
+ await writeFile27(configPath, `${JSON.stringify(updated, null, 2)}
29340
29658
  `, "utf8");
29341
29659
  }
29342
29660
  async function discoverAndWireDocs(siteDirectory) {
29343
- const site = path88.resolve(siteDirectory);
29344
- const pagesDir = path88.join(site, PAGES_DIR);
29661
+ const site = path89.resolve(siteDirectory);
29662
+ const pagesDir = path89.join(site, PAGES_DIR);
29345
29663
  const { directories, searchedDirectories } = await discoverNearbyDocsDirectories(site);
29346
29664
  if (directories.length === 0) {
29347
29665
  return {
@@ -29363,15 +29681,15 @@ async function discoverAndWireDocs(siteDirectory) {
29363
29681
  directory.sourceDirectory,
29364
29682
  usedNames
29365
29683
  );
29366
- const linkDirectory = path88.join(pagesDir, linkName);
29684
+ const linkDirectory2 = path89.join(pagesDir, linkName);
29367
29685
  const linked = [];
29368
29686
  const skipped = [];
29369
29687
  for (const sourcePath of directory.files) {
29370
29688
  const relativeSource = toPosix3(
29371
- path88.relative(directory.sourceDirectory, sourcePath)
29689
+ path89.relative(directory.sourceDirectory, sourcePath)
29372
29690
  );
29373
- const linkPath = path88.join(linkDirectory, relativeSource);
29374
- const relativeLink = toPosix3(path88.relative(site, linkPath));
29691
+ const linkPath = path89.join(linkDirectory2, relativeSource);
29692
+ const relativeLink = toPosix3(path89.relative(site, linkPath));
29375
29693
  const route = toRoutePath(relativeLink, PAGES_DIR);
29376
29694
  if (routes.includes(route)) {
29377
29695
  skipped.push({
@@ -29393,7 +29711,7 @@ async function discoverAndWireDocs(siteDirectory) {
29393
29711
  }
29394
29712
  sources.push({
29395
29713
  sourceDirectory: directory.sourceDirectory,
29396
- linkDirectory,
29714
+ linkDirectory: linkDirectory2,
29397
29715
  linkName,
29398
29716
  files: linked,
29399
29717
  skipped
@@ -29419,11 +29737,11 @@ async function discoverAndWireDocs(siteDirectory) {
29419
29737
  };
29420
29738
  }
29421
29739
  function siteRelative(siteDirectory, filePath) {
29422
- const relative = toPosix3(path88.relative(siteDirectory, filePath));
29740
+ const relative = toPosix3(path89.relative(siteDirectory, filePath));
29423
29741
  if (!relative) {
29424
29742
  return ".";
29425
29743
  }
29426
- if (path88.isAbsolute(relative)) {
29744
+ if (path89.isAbsolute(relative)) {
29427
29745
  return toPosix3(filePath);
29428
29746
  }
29429
29747
  if (relative.startsWith("..")) {
@@ -29503,7 +29821,7 @@ function formatInitDiscoveryReport(siteDirectory, openApiDiscovery, docsDiscover
29503
29821
  // src/cli/scaffold/run-scaffold-discovery.ts
29504
29822
  async function pathExists6(filePath) {
29505
29823
  try {
29506
- await access15(filePath);
29824
+ await access16(filePath);
29507
29825
  return true;
29508
29826
  } catch {
29509
29827
  return false;
@@ -29511,7 +29829,7 @@ async function pathExists6(filePath) {
29511
29829
  }
29512
29830
  async function wireOpenApiIntoJsonConfig(siteDirectory, openApiPath) {
29513
29831
  const input5 = toSiteRelativeOpenApiInput(siteDirectory, openApiPath);
29514
- const jsonConfigPath = path89.join(siteDirectory, "apitogo.config.json");
29832
+ const jsonConfigPath = path90.join(siteDirectory, "apitogo.config.json");
29515
29833
  const raw = await readFile31(jsonConfigPath, "utf8");
29516
29834
  const siteConfig = JSON.parse(raw);
29517
29835
  const updated = applyOpenApiToSiteConfig(siteConfig, {
@@ -29520,7 +29838,7 @@ async function wireOpenApiIntoJsonConfig(siteDirectory, openApiPath) {
29520
29838
  });
29521
29839
  const backend = updated.backend && typeof updated.backend === "object" && !Array.isArray(updated.backend) ? { ...updated.backend } : {};
29522
29840
  updated.backend = { ...backend, openApiPath: input5 };
29523
- await writeFile27(
29841
+ await writeFile28(
29524
29842
  jsonConfigPath,
29525
29843
  `${JSON.stringify(updated, null, 2)}
29526
29844
  `,
@@ -29563,7 +29881,7 @@ async function discoverAndWireOpenApiLite(siteDirectory, mode) {
29563
29881
  wired: false
29564
29882
  };
29565
29883
  }
29566
- const jsonConfigPath = path89.join(siteDirectory, "apitogo.config.json");
29884
+ const jsonConfigPath = path90.join(siteDirectory, "apitogo.config.json");
29567
29885
  if (!await pathExists6(jsonConfigPath)) {
29568
29886
  return {
29569
29887
  openApiDiscovery: {
@@ -29613,7 +29931,7 @@ async function discoverAndWireBackend(siteDirectory, mode) {
29613
29931
  if (mode !== "nearby") {
29614
29932
  return { status: "skipped", mode };
29615
29933
  }
29616
- const jsonConfigPath = path89.join(siteDirectory, "apitogo.config.json");
29934
+ const jsonConfigPath = path90.join(siteDirectory, "apitogo.config.json");
29617
29935
  if (!await pathExists6(jsonConfigPath)) {
29618
29936
  return { status: "not_found" };
29619
29937
  }
@@ -29640,7 +29958,7 @@ async function discoverAndWireBackend(siteDirectory, mode) {
29640
29958
  runtime: detected.runtime,
29641
29959
  runtimeVersion: detected.runtimeVersion
29642
29960
  };
29643
- await writeFile27(
29961
+ await writeFile28(
29644
29962
  jsonConfigPath,
29645
29963
  `${JSON.stringify(siteConfig, null, 2)}
29646
29964
  `,
@@ -29680,8 +29998,8 @@ function slugifyName2(name) {
29680
29998
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "dev-portal-site";
29681
29999
  }
29682
30000
  function resolveInitOutputDirectory(dirArg, name) {
29683
- const resolved = path90.resolve(process.cwd(), dirArg);
29684
- const base = path90.basename(resolved);
30001
+ const resolved = path91.resolve(process.cwd(), dirArg);
30002
+ const base = path91.basename(resolved);
29685
30003
  const isDot = dirArg === "." || dirArg === "./" || base === "." || resolved === process.cwd();
29686
30004
  if (isDot) {
29687
30005
  const fromName = name?.trim();
@@ -29691,7 +30009,7 @@ function resolveInitOutputDirectory(dirArg, name) {
29691
30009
  );
29692
30010
  }
29693
30011
  return {
29694
- outputDirectory: path90.resolve(process.cwd(), slugifyName2(fromName)),
30012
+ outputDirectory: path91.resolve(process.cwd(), slugifyName2(fromName)),
29695
30013
  siteName: fromName
29696
30014
  };
29697
30015
  }
@@ -29874,8 +30192,8 @@ import open2 from "open";
29874
30192
  import colors14 from "picocolors";
29875
30193
 
29876
30194
  // src/cli/platform/device-auth.ts
29877
- function url(apiUrl, path103) {
29878
- return `${apiUrl}${path103.startsWith("/") ? path103 : `/${path103}`}`;
30195
+ function url(apiUrl, path104) {
30196
+ return `${apiUrl}${path104.startsWith("/") ? path104 : `/${path104}`}`;
29879
30197
  }
29880
30198
  async function requestDeviceCode(apiUrl) {
29881
30199
  const response = await fetchWithRetry(
@@ -30057,7 +30375,7 @@ var logout_default = {
30057
30375
  };
30058
30376
 
30059
30377
  // src/cli/portal/commands.ts
30060
- import path91 from "node:path";
30378
+ import path92 from "node:path";
30061
30379
  init_invariant();
30062
30380
  function parseOnly(value) {
30063
30381
  if (value === void 0) return void 0;
@@ -30074,7 +30392,7 @@ function parseOnly(value) {
30074
30392
  async function run2(command2, argv, compute, format) {
30075
30393
  const json = argv.json === true;
30076
30394
  try {
30077
- const dir = path91.resolve(process.cwd(), argv.dir ?? ".");
30395
+ const dir = path92.resolve(process.cwd(), argv.dir ?? ".");
30078
30396
  if (!await isConfigV2(dir)) {
30079
30397
  throw new ServiceEditError(
30080
30398
  `${command2} works with a config version 2 project, and there is none in ${dir}.`,
@@ -30133,6 +30451,14 @@ function identityRemote() {
30133
30451
  return void 0;
30134
30452
  }
30135
30453
  }
30454
+ function identityConnectionsRemote() {
30455
+ try {
30456
+ const client = new PlatformApiClient(loadConfig());
30457
+ return (projectId) => client.listProjectIdentityConnections(projectId);
30458
+ } catch {
30459
+ return void 0;
30460
+ }
30461
+ }
30136
30462
  function plansRemote() {
30137
30463
  try {
30138
30464
  const client = new PlatformApiClient(loadConfig());
@@ -30152,6 +30478,7 @@ var statusOfProject = (argv) => run2(
30152
30478
  (dir, only) => statusV2(dir, only, {
30153
30479
  gatewayRemote: gatewayRemote(),
30154
30480
  identityRemote: identityRemote(),
30481
+ identityConnectionsRemote: identityConnectionsRemote(),
30155
30482
  plansRemote: plansRemote()
30156
30483
  }),
30157
30484
  formatStatus
@@ -30183,7 +30510,7 @@ var plan_default = {
30183
30510
 
30184
30511
  // src/cli/project/create-handler.ts
30185
30512
  init_invariant();
30186
- import path92 from "node:path";
30513
+ import path93 from "node:path";
30187
30514
 
30188
30515
  // src/cli/project/v2.ts
30189
30516
  init_invariant();
@@ -30216,7 +30543,9 @@ async function createProjectV2(options, deps) {
30216
30543
  modules,
30217
30544
  wait: options.wait !== false,
30218
30545
  projectId: linkedProjectId,
30219
- onProjectResolved: (projectId) => setProjectId(options.dir, projectId)
30546
+ onProjectResolved: async (projectId) => {
30547
+ await setProjectId(options.dir, projectId);
30548
+ }
30220
30549
  });
30221
30550
  const outcome = parse4(raw);
30222
30551
  if (outcome.requiresPlatformPlanSelection) {
@@ -30328,7 +30657,7 @@ async function createLinkedProject(argv, dir) {
30328
30657
  }
30329
30658
  }
30330
30659
  async function createProject(argv) {
30331
- const dir = path92.resolve(process.cwd(), argv.dir ?? ".");
30660
+ const dir = path93.resolve(process.cwd(), argv.dir ?? ".");
30332
30661
  if (await isConfigV2(dir)) {
30333
30662
  await createLinkedProject(argv, dir);
30334
30663
  return;
@@ -30452,14 +30781,14 @@ var remove_default = {
30452
30781
 
30453
30782
  // src/cli/dev/handler.ts
30454
30783
  init_joinUrl();
30455
- import path95 from "node:path";
30784
+ import path96 from "node:path";
30456
30785
 
30457
30786
  // src/vite/dev-server.ts
30458
30787
  init_logger();
30459
30788
  import fs12 from "node:fs/promises";
30460
30789
  import http from "node:http";
30461
30790
  import https from "node:https";
30462
- import path94 from "node:path";
30791
+ import path95 from "node:path";
30463
30792
  import { createHttpTerminator } from "http-terminator";
30464
30793
  import {
30465
30794
  createServer as createViteServer,
@@ -30492,7 +30821,7 @@ init_loader();
30492
30821
  // src/vite/pagefind-dev-index.ts
30493
30822
  init_invariant();
30494
30823
  init_joinUrl();
30495
- import path93 from "node:path";
30824
+ import path94 from "node:path";
30496
30825
  import { createIndex as createIndex2 } from "pagefind";
30497
30826
  import { isRunnableDevEnvironment } from "vite";
30498
30827
  async function* buildPagefindDevIndex(vite, config2) {
@@ -30545,7 +30874,7 @@ async function* buildPagefindDevIndex(vite, config2) {
30545
30874
  path: urlPath
30546
30875
  };
30547
30876
  }
30548
- const outputPath = path93.join(vite.config.publicDir, "pagefind");
30877
+ const outputPath = path94.join(vite.config.publicDir, "pagefind");
30549
30878
  await pagefindIndex.writeFiles({ outputPath });
30550
30879
  yield { type: "complete", success: true, indexed };
30551
30880
  }
@@ -30564,9 +30893,9 @@ var DevServer = class {
30564
30893
  this.protocol = "https";
30565
30894
  const { dir } = this.options;
30566
30895
  const [key, cert, ca] = await Promise.all([
30567
- fs12.readFile(path94.resolve(dir, config2.https.key)),
30568
- fs12.readFile(path94.resolve(dir, config2.https.cert)),
30569
- config2.https.ca ? fs12.readFile(path94.resolve(dir, config2.https.ca)) : void 0
30896
+ fs12.readFile(path95.resolve(dir, config2.https.key)),
30897
+ fs12.readFile(path95.resolve(dir, config2.https.cert)),
30898
+ config2.https.ca ? fs12.readFile(path95.resolve(dir, config2.https.ca)) : void 0
30570
30899
  ]);
30571
30900
  return https.createServer({ key, cert, ca });
30572
30901
  }
@@ -30583,7 +30912,7 @@ var DevServer = class {
30583
30912
  );
30584
30913
  const server = await this.createNodeServer(config2);
30585
30914
  if (config2.search?.type === "pagefind" && viteConfig.publicDir !== false) {
30586
- const publicRoot = path94.resolve(
30915
+ const publicRoot = path95.resolve(
30587
30916
  this.options.dir,
30588
30917
  typeof viteConfig.publicDir === "string" ? viteConfig.publicDir : "public"
30589
30918
  );
@@ -30600,7 +30929,7 @@ var DevServer = class {
30600
30929
  // built-in transform middleware which would treat the path as a static asset.
30601
30930
  name: "apitogo:entry-client",
30602
30931
  configureServer(server2) {
30603
- const entryPath = path94.posix.join(
30932
+ const entryPath = path95.posix.join(
30604
30933
  server2.config.base,
30605
30934
  "/__z/entry.client.tsx"
30606
30935
  );
@@ -30765,7 +31094,7 @@ init_package_json();
30765
31094
  async function dev(argv) {
30766
31095
  const packageJson3 = getZudokuPackageJson();
30767
31096
  process.env.NODE_ENV = "development";
30768
- let dir = path95.resolve(process.cwd(), argv.dir);
31097
+ let dir = path96.resolve(process.cwd(), argv.dir);
30769
31098
  if (await isConfigV2(dir)) {
30770
31099
  const { root, prepared } = await preparePortalWorkspace(dir, "development");
30771
31100
  dir = root;
@@ -30864,7 +31193,7 @@ var run_default = {
30864
31193
  };
30865
31194
 
30866
31195
  // src/cli/secrets/handler.ts
30867
- import path96 from "node:path";
31196
+ import path97 from "node:path";
30868
31197
  init_invariant();
30869
31198
 
30870
31199
  // src/cli/secrets/input.ts
@@ -30929,7 +31258,7 @@ var SecretsError = class extends ApitogoError {
30929
31258
  async function resolveProjectId2(argv, deps) {
30930
31259
  const explicit = argv.projectId?.trim();
30931
31260
  if (explicit) return explicit;
30932
- const dir = path96.resolve(process.cwd(), argv.dir ?? ".");
31261
+ const dir = path97.resolve(process.cwd(), argv.dir ?? ".");
30933
31262
  if (await isConfigV2(dir)) {
30934
31263
  const id = loadConfigV2(dir).resolved.project.id;
30935
31264
  if (id) return id;
@@ -31089,12 +31418,12 @@ var secrets_default = {
31089
31418
  };
31090
31419
 
31091
31420
  // src/cli/cmds/status.ts
31092
- import path98 from "node:path";
31421
+ import path99 from "node:path";
31093
31422
 
31094
31423
  // src/cli/status/handler.ts
31095
- import path97 from "node:path";
31424
+ import path98 from "node:path";
31096
31425
  async function status(argv) {
31097
- const sourceDirectory = path97.resolve(process.cwd(), argv.dir);
31426
+ const sourceDirectory = path98.resolve(process.cwd(), argv.dir);
31098
31427
  let config2;
31099
31428
  try {
31100
31429
  config2 = loadConfig();
@@ -31192,7 +31521,7 @@ var status_default = {
31192
31521
  }),
31193
31522
  handler: async (argv) => {
31194
31523
  await captureEvent({ argv, event: "apitogo status" });
31195
- if (await isConfigV2(path98.resolve(process.cwd(), argv.dir))) {
31524
+ if (await isConfigV2(path99.resolve(process.cwd(), argv.dir))) {
31196
31525
  await statusOfProject(argv);
31197
31526
  return;
31198
31527
  }
@@ -31201,11 +31530,11 @@ var status_default = {
31201
31530
  };
31202
31531
 
31203
31532
  // src/cli/cmds/teardown.ts
31204
- import path101 from "node:path";
31533
+ import path102 from "node:path";
31205
31534
 
31206
31535
  // src/cli/teardown/command.ts
31207
31536
  init_invariant();
31208
- import path99 from "node:path";
31537
+ import path100 from "node:path";
31209
31538
  import { createInterface as createInterface7 } from "node:readline/promises";
31210
31539
 
31211
31540
  // src/cli/teardown/v2.ts
@@ -31566,7 +31895,7 @@ async function teardownProject(argv) {
31566
31895
  const progress = createConsoleProgressReporter();
31567
31896
  const result = await teardownV2(
31568
31897
  {
31569
- dir: path99.resolve(process.cwd(), argv.dir),
31898
+ dir: path100.resolve(process.cwd(), argv.dir),
31570
31899
  projectId: argv.projectId,
31571
31900
  only: Array.isArray(argv.only) ? argv.only.join(",") : argv.only,
31572
31901
  yes: argv.yes === true,
@@ -31625,7 +31954,7 @@ async function teardownProject(argv) {
31625
31954
  }
31626
31955
 
31627
31956
  // src/cli/teardown/handler.ts
31628
- import path100 from "node:path";
31957
+ import path101 from "node:path";
31629
31958
  function resultLooksFailed3(payload) {
31630
31959
  try {
31631
31960
  const parsed = JSON.parse(payload);
@@ -31641,7 +31970,7 @@ async function teardown(argv) {
31641
31970
  );
31642
31971
  return;
31643
31972
  }
31644
- const sourceDirectory = path100.resolve(process.cwd(), argv.dir);
31973
+ const sourceDirectory = path101.resolve(process.cwd(), argv.dir);
31645
31974
  let config2;
31646
31975
  try {
31647
31976
  config2 = loadConfig();
@@ -31719,7 +32048,7 @@ var teardown_default = {
31719
32048
  }),
31720
32049
  handler: async (argv) => {
31721
32050
  await captureEvent({ argv, event: "apitogo teardown" });
31722
- if (await isConfigV2(path101.resolve(process.cwd(), argv.dir))) {
32051
+ if (await isConfigV2(path102.resolve(process.cwd(), argv.dir))) {
31723
32052
  await teardownProject(argv);
31724
32053
  return;
31725
32054
  }
@@ -31797,36 +32126,36 @@ function createApitogoCli(argv) {
31797
32126
  // src/cli/local-handoff.ts
31798
32127
  import { spawn as spawn5 } from "node:child_process";
31799
32128
  import { existsSync as existsSync9, realpathSync as realpathSync2 } from "node:fs";
31800
- import path102 from "node:path";
32129
+ import path103 from "node:path";
31801
32130
  var LOCAL_HANDOFF_ENV = "APITOGO_LOCAL_CLI";
31802
32131
  var PACKAGE_NAME = "@lukoweb/apitogo";
31803
32132
  var resolveProjectDir = (argv, cwd) => {
31804
32133
  for (let i = 0; i < argv.length; i++) {
31805
32134
  const arg = argv[i];
31806
32135
  const next = argv[i + 1];
31807
- if (arg === "--dir" && next) return path102.resolve(cwd, next);
32136
+ if (arg === "--dir" && next) return path103.resolve(cwd, next);
31808
32137
  if (arg?.startsWith("--dir=")) {
31809
- return path102.resolve(cwd, arg.slice("--dir=".length));
32138
+ return path103.resolve(cwd, arg.slice("--dir=".length));
31810
32139
  }
31811
32140
  }
31812
32141
  return cwd;
31813
32142
  };
31814
32143
  var findLocalCli = (projectDir, runningRoot) => {
31815
- let dir = path102.resolve(projectDir);
32144
+ let dir = path103.resolve(projectDir);
31816
32145
  let localPackageRoot;
31817
32146
  while (!localPackageRoot) {
31818
- const candidate = path102.join(dir, "node_modules", PACKAGE_NAME);
31819
- if (existsSync9(path102.join(candidate, "package.json"))) {
32147
+ const candidate = path103.join(dir, "node_modules", PACKAGE_NAME);
32148
+ if (existsSync9(path103.join(candidate, "package.json"))) {
31820
32149
  localPackageRoot = candidate;
31821
- } else if (dir === path102.dirname(dir)) {
32150
+ } else if (dir === path103.dirname(dir)) {
31822
32151
  return void 0;
31823
32152
  } else {
31824
- dir = path102.dirname(dir);
32153
+ dir = path103.dirname(dir);
31825
32154
  }
31826
32155
  }
31827
32156
  const localRoot = realpathSync2(localPackageRoot);
31828
32157
  if (localRoot === realpathSync2(runningRoot)) return void 0;
31829
- return path102.join(localRoot, "cli.js");
32158
+ return path103.join(localRoot, "cli.js");
31830
32159
  };
31831
32160
  var handoffToLocalCli = async (argv, runningRoot) => {
31832
32161
  if (process.env[LOCAL_HANDOFF_ENV] || process.env.ZUDOKU_ENV === "internal") {
@@ -31838,7 +32167,7 @@ var handoffToLocalCli = async (argv, runningRoot) => {
31838
32167
  );
31839
32168
  if (!localCli) return void 0;
31840
32169
  printDiagnosticsToConsole(
31841
- `Using the project's local ${PACKAGE_NAME} (${path102.dirname(localCli)})`
32170
+ `Using the project's local ${PACKAGE_NAME} (${path103.dirname(localCli)})`
31842
32171
  );
31843
32172
  const child = spawn5(process.execPath, [localCli, ...argv], {
31844
32173
  stdio: "inherit",