@cobaltcore-dev/aurora 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/README.md +73 -77
  2. package/dist/client/AuroraApp.d.ts +15 -0
  3. package/dist/client/{AuthProvider-D-5Jpa6F.mjs → AuthProvider-Co4d0WzB.mjs} +3 -3
  4. package/dist/client/{AuthProvider-D-5Jpa6F.mjs.map → AuthProvider-Co4d0WzB.mjs.map} +1 -1
  5. package/dist/client/{ContentHeader-BXZoN3B9.mjs → ContentHeader-xQVhO2yT.mjs} +20 -20
  6. package/dist/client/{ContentHeader-BXZoN3B9.mjs.map → ContentHeader-xQVhO2yT.mjs.map} +1 -1
  7. package/dist/client/{DeleteFlavorModal-BusYn32r.mjs → DeleteFlavorModal-CHTUZ3YV.mjs} +211 -202
  8. package/dist/client/DeleteFlavorModal-CHTUZ3YV.mjs.map +1 -0
  9. package/dist/client/{EditSecurityGroupModal-Dl6m7wUe.mjs → EditSecurityGroupModal-CWHHx2Xk.mjs} +22 -22
  10. package/dist/client/{EditSecurityGroupModal-Dl6m7wUe.mjs.map → EditSecurityGroupModal-CWHHx2Xk.mjs.map} +1 -1
  11. package/dist/client/{FiltersInput-BgNaHFBt.mjs → FiltersInput-UKJpNFdr.mjs} +11 -11
  12. package/dist/client/FiltersInput-UKJpNFdr.mjs.map +1 -0
  13. package/dist/client/{FloatingIpActionModals-By2hXR9m.mjs → FloatingIpActionModals-caXn6bYo.mjs} +54 -54
  14. package/dist/client/{FloatingIpActionModals-By2hXR9m.mjs.map → FloatingIpActionModals-caXn6bYo.mjs.map} +1 -1
  15. package/dist/client/{ImageToastNotifications-fHI8jB2j.mjs → ImageToastNotifications-BWimIzu_.mjs} +227 -227
  16. package/dist/client/{ImageToastNotifications-fHI8jB2j.mjs.map → ImageToastNotifications-BWimIzu_.mjs.map} +1 -1
  17. package/dist/client/{RouteError-pDEWC_k7.mjs → RouteError-CUj_m3gu.mjs} +6 -6
  18. package/dist/client/{RouteError-pDEWC_k7.mjs.map → RouteError-CUj_m3gu.mjs.map} +1 -1
  19. package/dist/client/{SortInput-DXWSqSny.mjs → SortInput-GQlQBlAj.mjs} +6 -6
  20. package/dist/client/{SortInput-DXWSqSny.mjs.map → SortInput-GQlQBlAj.mjs.map} +1 -1
  21. package/dist/client/{_auth-CJj1Cnbm.mjs → _auth-DXJkv9QO.mjs} +3 -3
  22. package/dist/client/{_auth-CJj1Cnbm.mjs.map → _auth-DXJkv9QO.mjs.map} +1 -1
  23. package/dist/client/_flavorId-C5dc1N_j.mjs +194 -0
  24. package/dist/client/_flavorId-C5dc1N_j.mjs.map +1 -0
  25. package/dist/client/{_flavorId-BoNcxYmF.mjs → _flavorId-sUWG0xuy.mjs} +15 -15
  26. package/dist/client/_flavorId-sUWG0xuy.mjs.map +1 -0
  27. package/dist/client/{_floatingIpId-BpUfL8Im2.mjs → _floatingIpId-COK_TBrz2.mjs} +42 -42
  28. package/dist/client/{_floatingIpId-BpUfL8Im2.mjs.map → _floatingIpId-COK_TBrz2.mjs.map} +1 -1
  29. package/dist/client/{_floatingIpId-CwHiXazi.mjs → _floatingIpId-CT4y-60o.mjs} +3 -3
  30. package/dist/client/{_floatingIpId-CwHiXazi.mjs.map → _floatingIpId-CT4y-60o.mjs.map} +1 -1
  31. package/dist/client/_imageId-n3RcnhAR.mjs +534 -0
  32. package/dist/client/_imageId-n3RcnhAR.mjs.map +1 -0
  33. package/dist/client/_pcaId-B-f_6kqs.mjs +466 -0
  34. package/dist/client/_pcaId-B-f_6kqs.mjs.map +1 -0
  35. package/dist/client/{_pcaId-D1ZEaCdp.mjs → _pcaId-ChnM_t-9.mjs} +3 -3
  36. package/dist/client/{_pcaId-D1ZEaCdp.mjs.map → _pcaId-ChnM_t-9.mjs.map} +1 -1
  37. package/dist/client/_projectId-26bw-_rm.mjs +46 -0
  38. package/dist/client/_projectId-26bw-_rm.mjs.map +1 -0
  39. package/dist/client/{_projectId-DhLpIalx.mjs → _projectId-BK9UqeYw.mjs} +14 -14
  40. package/dist/client/{_projectId-DhLpIalx.mjs.map → _projectId-BK9UqeYw.mjs.map} +1 -1
  41. package/dist/client/{_projectId-D1gGribM.mjs → _projectId-CCtpAQ8m.mjs} +79 -96
  42. package/dist/client/_projectId-CCtpAQ8m.mjs.map +1 -0
  43. package/dist/client/{_projectId-OW2xkK43.mjs → _projectId-Dhb4AyBD.mjs} +3 -3
  44. package/dist/client/{_projectId-OW2xkK43.mjs.map → _projectId-Dhb4AyBD.mjs.map} +1 -1
  45. package/dist/client/{_securityGroupId-B0llWH9A.mjs → _securityGroupId-CR1mKICQ.mjs} +3 -3
  46. package/dist/client/{_securityGroupId-B0llWH9A.mjs.map → _securityGroupId-CR1mKICQ.mjs.map} +1 -1
  47. package/dist/client/{_securityGroupId-gbUnd5Wv.mjs → _securityGroupId-DroYG6cA.mjs} +254 -255
  48. package/dist/client/{_securityGroupId-gbUnd5Wv.mjs.map → _securityGroupId-DroYG6cA.mjs.map} +1 -1
  49. package/dist/client/about-969pIiZ9.mjs +92 -0
  50. package/dist/client/{about-DCe6LsKz.mjs.map → about-969pIiZ9.mjs.map} +1 -1
  51. package/dist/client/aurora-DDzsst74.mjs +19 -0
  52. package/dist/client/{aurora-CRcxVUCo.mjs.map → aurora-DDzsst74.mjs.map} +1 -1
  53. package/dist/client/{build-BJDfnAyi.mjs → build-DracvfrJ.mjs} +5 -5
  54. package/dist/client/{build-BJDfnAyi.mjs.map → build-DracvfrJ.mjs.map} +1 -1
  55. package/dist/client/{buildFilterParams-By33pG59.mjs → buildFilterParams-DoZzMKX9.mjs} +1 -1
  56. package/dist/client/{buildFilterParams-By33pG59.mjs.map → buildFilterParams-DoZzMKX9.mjs.map} +1 -1
  57. package/dist/client/{cn-C3laVXMm.mjs → cn-DM4Cy3jv.mjs} +1 -1
  58. package/dist/client/{cn-C3laVXMm.mjs.map → cn-DM4Cy3jv.mjs.map} +1 -1
  59. package/dist/client/{constants-CAjjRTo_.mjs → constants-4lVQXort.mjs} +22 -22
  60. package/dist/client/{constants-CAjjRTo_.mjs.map → constants-4lVQXort.mjs.map} +1 -1
  61. package/dist/client/{containers-NW7RnHTI.mjs → containers-DGY2hoWw.mjs} +3 -3
  62. package/dist/client/containers-DGY2hoWw.mjs.map +1 -0
  63. package/dist/client/containers-ZMFTRaQL.mjs +3277 -0
  64. package/dist/client/containers-ZMFTRaQL.mjs.map +1 -0
  65. package/dist/client/{containers-Ca5V1EBS.mjs → containers-xfsYgRyf.mjs} +2 -2
  66. package/dist/client/containers-xfsYgRyf.mjs.map +1 -0
  67. package/dist/client/{flavors-D8oElC2K.mjs → flavors-C4GtoybP.mjs} +2 -2
  68. package/dist/client/{flavors-D8oElC2K.mjs.map → flavors-C4GtoybP.mjs.map} +1 -1
  69. package/dist/client/{flavors-qvgPSI7J.mjs → flavors-CpirO_nr.mjs} +167 -148
  70. package/dist/client/flavors-CpirO_nr.mjs.map +1 -0
  71. package/dist/client/{flavors-BXPYAFyQ.mjs → flavors-DWMZ6TuJ.mjs} +2 -2
  72. package/dist/client/{flavors-BXPYAFyQ.mjs.map → flavors-DWMZ6TuJ.mjs.map} +1 -1
  73. package/dist/client/{floatingips-Be3zLoaD.mjs → floatingips-BUf_oLRl.mjs} +74 -75
  74. package/dist/client/{floatingips-Be3zLoaD.mjs.map → floatingips-BUf_oLRl.mjs.map} +1 -1
  75. package/dist/client/{formatBytes-D6oa0wU9.mjs → formatBytes-CZv_XyCY.mjs} +1 -1
  76. package/dist/client/{formatBytes-D6oa0wU9.mjs.map → formatBytes-CZv_XyCY.mjs.map} +1 -1
  77. package/dist/client/{helpers--JWXi40U.mjs → helpers-1PpYf-fC.mjs} +1 -1
  78. package/dist/client/{helpers--JWXi40U.mjs.map → helpers-1PpYf-fC.mjs.map} +1 -1
  79. package/dist/client/hooks-dSArr2Ca.mjs +2 -0
  80. package/dist/client/images-CsonlmFx.mjs +8 -0
  81. package/dist/client/images-CsonlmFx.mjs.map +1 -0
  82. package/dist/client/{images-CCYBAphP2.mjs → images-Da1t5KPh.mjs} +509 -536
  83. package/dist/client/images-Da1t5KPh.mjs.map +1 -0
  84. package/dist/client/{images-DM9I8G0p.mjs → images-NBf2bV43.mjs} +2 -2
  85. package/dist/client/images-NBf2bV43.mjs.map +1 -0
  86. package/dist/client/{images-BiEBENaj.mjs → images-QnWf63uj.mjs} +2 -2
  87. package/dist/client/{images-BiEBENaj.mjs.map → images-QnWf63uj.mjs.map} +1 -1
  88. package/dist/client/index.js +232 -236
  89. package/dist/client/index.js.map +1 -1
  90. package/dist/client/{md-BivyCkGC.mjs → md-sBiSNVSQ.mjs} +7 -7
  91. package/dist/client/{md-BivyCkGC.mjs.map → md-sBiSNVSQ.mjs.map} +1 -1
  92. package/dist/client/{network-nbSbl0X0.mjs → network-DuZm76BZ.mjs} +2 -2
  93. package/dist/client/{network-nbSbl0X0.mjs.map → network-DuZm76BZ.mjs.map} +1 -1
  94. package/dist/client/{objects-CU5ws07o.mjs → objects-B89dYCBq.mjs} +3 -3
  95. package/dist/client/objects-B89dYCBq.mjs.map +1 -0
  96. package/dist/client/{objects-GmuIOaHd.mjs → objects-CuFLUOe1.mjs} +2 -2
  97. package/dist/client/objects-CuFLUOe1.mjs.map +1 -0
  98. package/dist/client/objects-H0NN_Sja.mjs +5460 -0
  99. package/dist/client/objects-H0NN_Sja.mjs.map +1 -0
  100. package/dist/client/{pca-x9if8xU-.mjs → pca-C-UFjicP.mjs} +51 -51
  101. package/dist/client/pca-C-UFjicP.mjs.map +1 -0
  102. package/dist/client/{pca-DSM71LhW.mjs → pca-CtU6REww.mjs} +2 -2
  103. package/dist/client/{pca-DSM71LhW.mjs.map → pca-CtU6REww.mjs.map} +1 -1
  104. package/dist/client/{projects-B6BPo2Ar.mjs → projects-C-sjd9T5.mjs} +3 -3
  105. package/dist/client/{projects-B6BPo2Ar.mjs.map → projects-C-sjd9T5.mjs.map} +1 -1
  106. package/dist/client/{projects-CnmZIB2Q.mjs → projects-DNXsDnJM.mjs} +29 -25
  107. package/dist/client/projects-DNXsDnJM.mjs.map +1 -0
  108. package/dist/client/{projects-Bt0XptpG.mjs → projects-dhnQkuvV.mjs} +2 -2
  109. package/dist/client/{projects-Bt0XptpG.mjs.map → projects-dhnQkuvV.mjs.map} +1 -1
  110. package/dist/client/{projects-BilrmHLu.mjs → projects-yiK0HGSA.mjs} +2 -2
  111. package/dist/client/{projects-BilrmHLu.mjs.map → projects-yiK0HGSA.mjs.map} +1 -1
  112. package/dist/client/{securitygroups-BdzieS7Z.mjs → securitygroups-wHdrxZXd.mjs} +72 -73
  113. package/dist/client/{securitygroups-BdzieS7Z.mjs.map → securitygroups-wHdrxZXd.mjs.map} +1 -1
  114. package/dist/client/{trpcClient-BxguzNYF.mjs → trpcClient-BzPUgiM2.mjs} +1 -1
  115. package/dist/client/{trpcClient-BxguzNYF.mjs.map → trpcClient-BzPUgiM2.mjs.map} +1 -1
  116. package/dist/client/{useErrorTranslation-TZVwIAzq.mjs → useErrorTranslation-Dc0eE8Zt.mjs} +1 -1
  117. package/dist/client/{useErrorTranslation-TZVwIAzq.mjs.map → useErrorTranslation-Dc0eE8Zt.mjs.map} +1 -1
  118. package/dist/client/useListWithFiltering-DrgUwXef.mjs +157 -0
  119. package/dist/client/useListWithFiltering-DrgUwXef.mjs.map +1 -0
  120. package/dist/client/{useModal-DxxlilRm.mjs → useModal-DCs1OJh7.mjs} +1 -1
  121. package/dist/client/{useModal-DxxlilRm.mjs.map → useModal-DCs1OJh7.mjs.map} +1 -1
  122. package/dist/client/{useProjectId-CgOTejka.mjs → useProjectId-DBc5lpoU.mjs} +1 -1
  123. package/dist/client/{useProjectId-CgOTejka.mjs.map → useProjectId-DBc5lpoU.mjs.map} +1 -1
  124. package/dist/server/index.d.ts +7 -1
  125. package/dist/server/index.js +1363 -453
  126. package/package.json +7 -7
  127. package/dist/client/DeleteFlavorModal-BusYn32r.mjs.map +0 -1
  128. package/dist/client/FiltersInput-BgNaHFBt.mjs.map +0 -1
  129. package/dist/client/ListToolbar-BvtCo8dk.mjs +0 -129
  130. package/dist/client/ListToolbar-BvtCo8dk.mjs.map +0 -1
  131. package/dist/client/_flavorId-BRonXvCo.mjs +0 -188
  132. package/dist/client/_flavorId-BRonXvCo.mjs.map +0 -1
  133. package/dist/client/_flavorId-BoNcxYmF.mjs.map +0 -1
  134. package/dist/client/_imageId-CdOOJjw0.mjs +0 -527
  135. package/dist/client/_imageId-CdOOJjw0.mjs.map +0 -1
  136. package/dist/client/_pcaId-CwlH1Kvl.mjs +0 -369
  137. package/dist/client/_pcaId-CwlH1Kvl.mjs.map +0 -1
  138. package/dist/client/_projectId-D1gGribM.mjs.map +0 -1
  139. package/dist/client/_projectId-Dj_InfSc.mjs +0 -26
  140. package/dist/client/_projectId-Dj_InfSc.mjs.map +0 -1
  141. package/dist/client/about-DCe6LsKz.mjs +0 -92
  142. package/dist/client/aurora-CRcxVUCo.mjs +0 -19
  143. package/dist/client/containers-BuXUVb1N.mjs +0 -3031
  144. package/dist/client/containers-BuXUVb1N.mjs.map +0 -1
  145. package/dist/client/containers-Ca5V1EBS.mjs.map +0 -1
  146. package/dist/client/containers-NW7RnHTI.mjs.map +0 -1
  147. package/dist/client/flavors-qvgPSI7J.mjs.map +0 -1
  148. package/dist/client/hooks-D0krAKvo.mjs +0 -2
  149. package/dist/client/images-CCYBAphP2.mjs.map +0 -1
  150. package/dist/client/images-DM9I8G0p.mjs.map +0 -1
  151. package/dist/client/objects-CU5ws07o.mjs.map +0 -1
  152. package/dist/client/objects-FXN0VWLI.mjs +0 -4760
  153. package/dist/client/objects-FXN0VWLI.mjs.map +0 -1
  154. package/dist/client/objects-GmuIOaHd.mjs.map +0 -1
  155. package/dist/client/overview-B3gdnWTG.mjs +0 -15
  156. package/dist/client/overview-B3gdnWTG.mjs.map +0 -1
  157. package/dist/client/overview-DzYBiNfD.mjs +0 -15
  158. package/dist/client/overview-DzYBiNfD.mjs.map +0 -1
  159. package/dist/client/overview-EhfPY8Je.mjs +0 -15
  160. package/dist/client/overview-EhfPY8Je.mjs.map +0 -1
  161. package/dist/client/overview-XueZI4LQ.mjs +0 -173
  162. package/dist/client/overview-XueZI4LQ.mjs.map +0 -1
  163. package/dist/client/pca-x9if8xU-.mjs.map +0 -1
  164. package/dist/client/projects-CnmZIB2Q.mjs.map +0 -1
  165. package/dist/client/useListWithFiltering-CqQbAjEe.mjs +0 -32
  166. package/dist/client/useListWithFiltering-CqQbAjEe.mjs.map +0 -1
  167. package/permission_policies/compute.yaml +0 -975
  168. package/permission_policies/image.yaml +0 -71
@@ -30779,25 +30779,33 @@ var flavorRouter = {
30779
30779
  })
30780
30780
  };
30781
30781
 
30782
- // src/server/Compute/routers/permissionRouter.ts
30782
+ // src/server/policies/createPermissionRouter.ts
30783
30783
  var import_zod10 = require("zod");
30784
30784
  var import_server8 = require("@trpc/server");
30785
30785
 
30786
- // src/server/policyEngineLoader.ts
30786
+ // src/server/policies/policyEngineLoader.ts
30787
30787
  var import_path = __toESM(require("path"));
30788
30788
  var import_fs = __toESM(require("fs"));
30789
30789
  var import_policy_engine = __toESM(require_esm());
30790
- var loadPolicyEngine = /* @__PURE__ */ __name((fileName) => {
30791
- const customPath = import_path.default.join(__dirname, `../../permission_custom_policies/${fileName}`);
30792
- const defaultPath = import_path.default.join(__dirname, `../../permission_policies/${fileName}`);
30793
- const file = import_fs.default.existsSync(customPath) ? customPath : defaultPath;
30790
+ var loadPolicyEngine = /* @__PURE__ */ __name((fileName, consumerDir) => {
30791
+ if (!import_path.default.isAbsolute(consumerDir)) {
30792
+ throw new Error(`policyDir must be an absolute path, got: "${consumerDir}"`);
30793
+ }
30794
+ const candidates = [
30795
+ import_path.default.join(consumerDir, fileName),
30796
+ import_path.default.join(__dirname, `../../permission_custom_policies/${fileName}`)
30797
+ ];
30798
+ const file = candidates.find((p) => import_fs.default.existsSync(p));
30799
+ if (!file) {
30800
+ throw new Error(`Policy file "${fileName}" not found. Searched:
30801
+ ${candidates.map((p) => ` ${p}`).join("\n")}
30802
+ Pass an absolute path via the policyDir option in createServer.`);
30803
+ }
30794
30804
  return (0, import_policy_engine.createPolicyEngineFromFile)(file);
30795
30805
  }, "loadPolicyEngine");
30796
30806
 
30797
- // src/server/Compute/routers/permissionRouter.ts
30798
- var computePolicyEngine = loadPolicyEngine("compute.yaml");
30799
- var imagePolicyEngine = loadPolicyEngine("image.yaml");
30800
- var getPolicy = /* @__PURE__ */ __name((ctx, policyEngineName) => {
30807
+ // src/server/policies/createPermissionRouter.ts
30808
+ var getPolicy = /* @__PURE__ */ __name((ctx, engine) => {
30801
30809
  const openstackSession = ctx.openstack;
30802
30810
  const token = openstackSession?.getToken();
30803
30811
  if (!token) {
@@ -30806,15 +30814,80 @@ var getPolicy = /* @__PURE__ */ __name((ctx, policyEngineName) => {
30806
30814
  message: "No valid OpenStack token found"
30807
30815
  });
30808
30816
  }
30809
- const policyEngine = policyEngineName === "compute" ? computePolicyEngine : imagePolicyEngine;
30810
- return policyEngine.policy(token.tokenData, {
30817
+ return engine.policy(token.tokenData, {
30811
30818
  debug: true,
30812
30819
  defaultParams: {
30813
30820
  project_id: token.tokenData.project?.id
30814
30821
  }
30815
30822
  });
30816
30823
  }, "getPolicy");
30817
- var POLICY_MAPPINGS = {
30824
+ function createPermissionRouter(config) {
30825
+ const loadedEngines = Object.fromEntries(Object.entries(config.engines).map(([name, { fileName }]) => [
30826
+ name,
30827
+ loadPolicyEngine(fileName, config.policyDir)
30828
+ ]));
30829
+ for (const [permissionKey, mapping] of Object.entries(config.mappings)) {
30830
+ if (!Object.hasOwn(loadedEngines, mapping.engine)) {
30831
+ throw new Error(`Configuration error: Permission '${permissionKey}' references engine '${mapping.engine}', but no such engine is configured. Available engines: ${Object.keys(loadedEngines).join(", ")}`);
30832
+ }
30833
+ }
30834
+ const PERMISSION_KEY = import_zod10.z.string().superRefine((value, ctx) => {
30835
+ if (!Object.hasOwn(config.mappings, value)) {
30836
+ ctx.addIssue({
30837
+ code: "custom",
30838
+ message: `Unknown permission: ${value}`
30839
+ });
30840
+ }
30841
+ }).transform((value) => value);
30842
+ const checkSinglePermission = /* @__PURE__ */ __name((ctx, permission, engines) => {
30843
+ const mapping = config.mappings[permission];
30844
+ const engine = engines[mapping.engine];
30845
+ if (!engine) {
30846
+ throw new import_server8.TRPCError({
30847
+ code: "INTERNAL_SERVER_ERROR",
30848
+ message: `Policy engine '${mapping.engine}' not found for permission '${String(permission)}'`
30849
+ });
30850
+ }
30851
+ const policy = getPolicy(ctx, engine);
30852
+ return policy.check(mapping.rule);
30853
+ }, "checkSinglePermission");
30854
+ return {
30855
+ /**
30856
+ * Permission checking endpoint that determines whether a user has one or more specific permissions.
30857
+ *
30858
+ * Usage:
30859
+ * - `canUser({ project_id: "abc", permission: "servers:list" })` → returns `[boolean]`
30860
+ * - `canUser({ project_id: "abc", permission: ["servers:list", "flavors:create"] })` → returns `boolean[]`
30861
+ *
30862
+ * Input must be:
30863
+ * - A project_id (required, validated by projectScopedInputSchema), and
30864
+ * - A single valid permission key (string in mappings), or
30865
+ * - An array of valid permission keys.
30866
+ *
30867
+ * Invalid keys are rejected with a `BAD_REQUEST` error before the handler runs.
30868
+ * Empty array input returns an empty array (`[]`).
30869
+ * Always returns `boolean[]` for consistent destructuring on the client.
30870
+ */
30871
+ canUser: projectScopedProcedure.input(projectScopedInputSchema.extend({
30872
+ permission: import_zod10.z.union([
30873
+ PERMISSION_KEY,
30874
+ import_zod10.z.array(PERMISSION_KEY)
30875
+ ])
30876
+ })).query(async ({ ctx, input }) => {
30877
+ const permissions = Array.isArray(input.permission) ? input.permission : [
30878
+ input.permission
30879
+ ];
30880
+ if (permissions.length === 0) {
30881
+ return [];
30882
+ }
30883
+ return permissions.map((permission) => checkSinglePermission(ctx, permission, loadedEngines));
30884
+ })
30885
+ };
30886
+ }
30887
+ __name(createPermissionRouter, "createPermissionRouter");
30888
+
30889
+ // src/server/Compute/routers/permissionRouter.ts
30890
+ var COMPUTE_IMAGE_MAPPINGS = {
30818
30891
  // Servers
30819
30892
  "servers:list": {
30820
30893
  engine: "compute",
@@ -30904,47 +30977,30 @@ var POLICY_MAPPINGS = {
30904
30977
  rule: "modify_member"
30905
30978
  }
30906
30979
  };
30907
- var checkSinglePermission = /* @__PURE__ */ __name((ctx, permission) => {
30908
- const policyMapping = POLICY_MAPPINGS[permission];
30909
- const policy = getPolicy(ctx, policyMapping.engine);
30910
- return policy.check(policyMapping.rule);
30911
- }, "checkSinglePermission");
30912
- var PERMISSION_KEY = import_zod10.z.string().superRefine((value, ctx) => {
30913
- if (!Object.hasOwn(POLICY_MAPPINGS, value)) {
30914
- ctx.addIssue({
30915
- code: "custom",
30916
- message: `Unknown permission: ${value}`
30917
- });
30918
- }
30919
- }).transform((value) => value);
30920
- var permissionRouter = {
30921
- canUser: projectScopedProcedure.input(projectScopedInputSchema.extend({
30922
- permission: import_zod10.z.union([
30923
- PERMISSION_KEY,
30924
- import_zod10.z.array(PERMISSION_KEY)
30925
- ])
30926
- })).query(async ({ ctx, input }) => {
30927
- const permissions = typeof input.permission === "string" ? [
30928
- input.permission
30929
- ] : input.permission;
30930
- if (permissions.length === 0) {
30931
- return [];
30980
+ var buildPermissionRouter = /* @__PURE__ */ __name((policyDir) => createPermissionRouter({
30981
+ policyDir,
30982
+ engines: {
30983
+ compute: {
30984
+ fileName: "compute.json"
30985
+ },
30986
+ image: {
30987
+ fileName: "image.json"
30932
30988
  }
30933
- return permissions.map((permission) => checkSinglePermission(ctx, permission));
30934
- })
30935
- };
30989
+ },
30990
+ mappings: COMPUTE_IMAGE_MAPPINGS
30991
+ }), "buildPermissionRouter");
30936
30992
 
30937
30993
  // src/server/Compute/routers/index.ts
30938
- var computeRouters = {
30994
+ var buildComputeRouters = /* @__PURE__ */ __name((policyDir) => ({
30939
30995
  compute: auroraRouter({
30940
30996
  ...serverRouter,
30941
30997
  ...flavorRouter,
30942
30998
  ...imageRouter,
30943
30999
  ...keypairRouter,
30944
31000
  ...serverGroupRouter,
30945
- ...permissionRouter
31001
+ ...buildPermissionRouter(policyDir)
30946
31002
  })
30947
- };
31003
+ }), "buildComputeRouters");
30948
31004
 
30949
31005
  // src/server/Storage/routers/swift/swiftRouter.ts
30950
31006
  var import_server10 = require("@trpc/server");
@@ -33247,11 +33303,13 @@ var cephProtectedProcedure = cephCredentialMiddleware.use(/* @__PURE__ */ __name
33247
33303
 
33248
33304
  // src/server/Storage/helpers/s3ErrorMapper.ts
33249
33305
  var import_server12 = require("@trpc/server");
33306
+ var import_signal_openstack = __toESM(require_esm2());
33250
33307
  var S3_ERROR_MAP = {
33251
33308
  NoSuchBucket: "NOT_FOUND",
33252
33309
  NoSuchKey: "NOT_FOUND",
33253
33310
  NoSuchUpload: "NOT_FOUND",
33254
33311
  NoSuchVersion: "NOT_FOUND",
33312
+ NoSuchBucketPolicy: "NOT_FOUND",
33255
33313
  BucketAlreadyExists: "CONFLICT",
33256
33314
  BucketAlreadyOwnedByYou: "CONFLICT",
33257
33315
  BucketNotEmpty: "PRECONDITION_FAILED",
@@ -33265,6 +33323,7 @@ var S3_ERROR_MAP = {
33265
33323
  RequestTimeTooSkewed: "UNAUTHORIZED",
33266
33324
  InvalidBucketName: "BAD_REQUEST",
33267
33325
  KeyTooLongError: "BAD_REQUEST",
33326
+ MalformedPolicy: "BAD_REQUEST",
33268
33327
  EntityTooLarge: "PAYLOAD_TOO_LARGE",
33269
33328
  EntityTooSmall: "BAD_REQUEST"
33270
33329
  };
@@ -33276,14 +33335,21 @@ function mapS3ErrorToTRPCError(error, context) {
33276
33335
  const errorCode = s3Error.Code ?? s3Error.name ?? "";
33277
33336
  const trpcCode = S3_ERROR_MAP[errorCode] ?? "INTERNAL_SERVER_ERROR";
33278
33337
  if (!S3_ERROR_MAP[errorCode] && errorCode) {
33279
- console.warn(`[s3] Unmapped S3 error code: ${errorCode}`);
33338
+ import_signal_openstack.logger.warn("Unmapped S3 error code", {
33339
+ errorCode,
33340
+ operation: context.operation
33341
+ });
33280
33342
  }
33281
33343
  const parts = [
33282
33344
  `Failed to ${context.operation}`
33283
33345
  ];
33284
33346
  if (context.bucket) parts.push(`bucket: ${context.bucket}`);
33285
33347
  if (context.key) parts.push(`key: ${context.key}`);
33286
- if (s3Error.message) {
33348
+ if (errorCode === "AccessDenied") {
33349
+ parts.push("Access denied \u2014 your credentials are valid but lack permissions for this operation");
33350
+ } else if (errorCode === "InvalidAccessKeyId" || errorCode === "SignatureDoesNotMatch" || errorCode === "TokenRefreshRequired" || errorCode === "RequestTimeTooSkewed") {
33351
+ parts.push("Invalid access key \u2014 your credentials may be expired or incorrect");
33352
+ } else if (s3Error.message) {
33287
33353
  parts.push(s3Error.message);
33288
33354
  }
33289
33355
  throw new import_server12.TRPCError({
@@ -33318,8 +33384,14 @@ var containerSchema = import_zod13.z.object({
33318
33384
  var listContainersInputSchema2 = projectScopedInputSchema.extend({
33319
33385
  includeMetadata: import_zod13.z.boolean().optional().default(false)
33320
33386
  });
33387
+ var bucketNameSchema = import_zod13.z.string().min(3, "Bucket name must be at least 3 characters").max(63, "Bucket name must be at most 63 characters").regex(/^[a-z0-9][a-z0-9.-]*[a-z0-9]$/, "Bucket name must contain only lowercase letters, numbers, hyphens, and periods").refine((name) => !name.includes(".."), "Bucket name cannot contain consecutive periods").refine((name) => !/^\d+\.\d+\.\d+\.\d+$/.test(name), "Bucket name cannot be formatted as an IP address");
33321
33388
  var createBucketInputSchema = projectScopedInputSchema.extend({
33322
- bucketName: import_zod13.z.string().min(3).max(63)
33389
+ bucketName: bucketNameSchema,
33390
+ enableVersioning: import_zod13.z.boolean().optional().default(false)
33391
+ });
33392
+ var createBucketOutputSchema = import_zod13.z.object({
33393
+ success: import_zod13.z.boolean(),
33394
+ versioningError: import_zod13.z.string().optional()
33323
33395
  });
33324
33396
  var deleteBucketInputSchema = projectScopedInputSchema.extend({
33325
33397
  bucketName: import_zod13.z.string().min(1)
@@ -33436,6 +33508,83 @@ var s3ServiceInfoSchema = import_zod13.z.object({
33436
33508
  region: import_zod13.z.string().optional()
33437
33509
  });
33438
33510
  var getServiceInfoInputSchema = import_zod13.z.object({});
33511
+ var bucketPolicyStatementSchema = import_zod13.z.object({
33512
+ Sid: import_zod13.z.string().optional(),
33513
+ Effect: import_zod13.z.enum([
33514
+ "Allow",
33515
+ "Deny"
33516
+ ]),
33517
+ Principal: import_zod13.z.union([
33518
+ import_zod13.z.string(),
33519
+ import_zod13.z.object({
33520
+ AWS: import_zod13.z.union([
33521
+ import_zod13.z.string(),
33522
+ import_zod13.z.array(import_zod13.z.string())
33523
+ ]).optional(),
33524
+ Service: import_zod13.z.union([
33525
+ import_zod13.z.string(),
33526
+ import_zod13.z.array(import_zod13.z.string())
33527
+ ]).optional(),
33528
+ Federated: import_zod13.z.union([
33529
+ import_zod13.z.string(),
33530
+ import_zod13.z.array(import_zod13.z.string())
33531
+ ]).optional()
33532
+ })
33533
+ ]).superRefine((val, ctx) => {
33534
+ if (typeof val === "object" && !val.AWS && !val.Service && !val.Federated) {
33535
+ ctx.addIssue({
33536
+ code: "custom",
33537
+ message: "Principal object must contain at least one of: AWS, Service, or Federated"
33538
+ });
33539
+ }
33540
+ if (typeof val === "object" && val.AWS) {
33541
+ const arns = Array.isArray(val.AWS) ? val.AWS : [
33542
+ val.AWS
33543
+ ];
33544
+ for (const arn of arns) {
33545
+ if (arn !== "*" && !/^arn:aws:iam::\d{12}:(?:root|user\/.+|role\/.+)$/.test(arn)) {
33546
+ ctx.addIssue({
33547
+ code: "custom",
33548
+ message: `Invalid AWS principal ARN format: ${arn}. Expected arn:aws:iam::ACCOUNT-ID:root or arn:aws:iam::ACCOUNT-ID:(user|role)/NAME`
33549
+ });
33550
+ }
33551
+ }
33552
+ }
33553
+ }),
33554
+ Action: import_zod13.z.union([
33555
+ import_zod13.z.string(),
33556
+ import_zod13.z.array(import_zod13.z.string())
33557
+ ]),
33558
+ Resource: import_zod13.z.union([
33559
+ import_zod13.z.string(),
33560
+ import_zod13.z.array(import_zod13.z.string())
33561
+ ]),
33562
+ Condition: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.record(import_zod13.z.string(), import_zod13.z.union([
33563
+ import_zod13.z.string(),
33564
+ import_zod13.z.array(import_zod13.z.string()),
33565
+ import_zod13.z.number(),
33566
+ import_zod13.z.boolean()
33567
+ ]))).optional()
33568
+ });
33569
+ var bucketPolicyDocumentSchema = import_zod13.z.object({
33570
+ Version: import_zod13.z.string().default("2012-10-17"),
33571
+ Id: import_zod13.z.string().optional(),
33572
+ Statement: import_zod13.z.array(bucketPolicyStatementSchema).min(1, "Policy must contain at least one statement")
33573
+ });
33574
+ var getBucketPolicyInputSchema = projectScopedInputSchema.extend({
33575
+ bucketName: bucketNameSchema
33576
+ });
33577
+ var getBucketPolicyOutputSchema = import_zod13.z.object({
33578
+ policy: bucketPolicyDocumentSchema.nullable(),
33579
+ policyText: import_zod13.z.string().nullable()
33580
+ });
33581
+ var setBucketPolicyInputSchema = projectScopedInputSchema.extend({
33582
+ bucketName: bucketNameSchema,
33583
+ policy: import_zod13.z.string().min(1).max(20480, "Policy document exceeds maximum size of 20KB")
33584
+ });
33585
+ var deleteBucketPolicyInputSchema = projectScopedInputSchema.extend({
33586
+ bucketName: bucketNameSchema
33587
+ });
33439
33588
 
33440
33589
  // src/server/Storage/constants.ts
33441
33590
  var S3_MAX_KEYS_PER_REQUEST = 1e3;
@@ -33523,6 +33672,10 @@ var containerRouter = {
33523
33672
  * Uses AWS SDK CreateBucketCommand. The AWS SDK automatically adds LocationConstraint
33524
33673
  * based on the region configured in the S3 client (resolved from OpenStack service catalog).
33525
33674
  *
33675
+ * If enableVersioning is true, enables versioning immediately after bucket creation using
33676
+ * PutBucketVersioningCommand. If versioning fails, the bucket is still created successfully
33677
+ * but the response includes a versioningError field with the error message.
33678
+ *
33526
33679
  * Bucket naming rules (validated client-side and by S3 API):
33527
33680
  * - 3-63 characters
33528
33681
  * - Lowercase letters, numbers, hyphens, periods only
@@ -33536,18 +33689,37 @@ var containerRouter = {
33536
33689
  */
33537
33690
  create: cephProtectedProcedure.input(createBucketInputSchema).mutation(async ({ ctx, input }) => {
33538
33691
  const s3 = ctx.getCephClient();
33539
- const { bucketName } = input;
33692
+ const { bucketName, enableVersioning } = input;
33540
33693
  try {
33541
33694
  await s3.send(new import_client_s32.CreateBucketCommand({
33542
33695
  Bucket: bucketName
33543
33696
  }));
33544
- return true;
33545
33697
  } catch (error) {
33546
33698
  throw mapS3ErrorToTRPCError(error, {
33547
33699
  operation: "create bucket",
33548
33700
  bucket: bucketName
33549
33701
  });
33550
33702
  }
33703
+ if (enableVersioning) {
33704
+ try {
33705
+ await s3.send(new import_client_s32.PutBucketVersioningCommand({
33706
+ Bucket: bucketName,
33707
+ VersioningConfiguration: {
33708
+ Status: "Enabled"
33709
+ }
33710
+ }));
33711
+ } catch (error) {
33712
+ const errorMessage = error instanceof Error ? error.message : String(error);
33713
+ console.warn(`[s3] Bucket '${bucketName}' created successfully, but failed to enable versioning:`, errorMessage);
33714
+ return {
33715
+ success: true,
33716
+ versioningError: `Failed to enable versioning: ${errorMessage}`
33717
+ };
33718
+ }
33719
+ }
33720
+ return {
33721
+ success: true
33722
+ };
33551
33723
  }),
33552
33724
  /**
33553
33725
  * Delete an empty S3 bucket.
@@ -34367,8 +34539,307 @@ var versioningRouter = {
34367
34539
  })
34368
34540
  };
34369
34541
 
34542
+ // src/server/Storage/routers/ceph/bucketPolicyRouter.ts
34543
+ var import_client_s35 = require("@aws-sdk/client-s3");
34544
+ var import_server15 = require("@trpc/server");
34545
+ var import_zod17 = require("zod");
34546
+ var policySetRateLimits = /* @__PURE__ */ new Map();
34547
+ function checkPolicySetRateLimit(bucketName, projectId) {
34548
+ const key = `${projectId}:${bucketName}`;
34549
+ const now = Date.now();
34550
+ const windowMs = 5 * 60 * 1e3;
34551
+ for (const [k, v] of policySetRateLimits.entries()) {
34552
+ if (now > v.resetAt) {
34553
+ policySetRateLimits.delete(k);
34554
+ }
34555
+ }
34556
+ const limit = policySetRateLimits.get(key);
34557
+ if (!limit || now > limit.resetAt) {
34558
+ policySetRateLimits.set(key, {
34559
+ count: 1,
34560
+ resetAt: now + windowMs
34561
+ });
34562
+ return;
34563
+ }
34564
+ if (limit.count >= 10) {
34565
+ throw new import_server15.TRPCError({
34566
+ code: "TOO_MANY_REQUESTS",
34567
+ message: "Policy modification rate limit exceeded. Maximum 10 policy changes per 5 minutes per bucket."
34568
+ });
34569
+ }
34570
+ limit.count++;
34571
+ }
34572
+ __name(checkPolicySetRateLimit, "checkPolicySetRateLimit");
34573
+ function validateResourceARNsMatchBucket(policy, bucketName) {
34574
+ for (const statement of policy.Statement) {
34575
+ const resources = Array.isArray(statement.Resource) ? statement.Resource : [
34576
+ statement.Resource
34577
+ ];
34578
+ for (const resource of resources) {
34579
+ const arnRegex = /^arn:aws:s3:::([^/]+)/;
34580
+ const match = resource.match(arnRegex);
34581
+ if (!match) {
34582
+ throw new import_server15.TRPCError({
34583
+ code: "BAD_REQUEST",
34584
+ message: `Policy Resource '${resource}' is not a valid S3 bucket ARN for bucket '${bucketName}'. Expected: arn:aws:s3:::${bucketName} or arn:aws:s3:::${bucketName}/*`
34585
+ });
34586
+ }
34587
+ if (match[1] !== bucketName) {
34588
+ throw new import_server15.TRPCError({
34589
+ code: "BAD_REQUEST",
34590
+ message: `Policy Resource ARN '${resource}' does not match bucket '${bucketName}'`
34591
+ });
34592
+ }
34593
+ }
34594
+ }
34595
+ }
34596
+ __name(validateResourceARNsMatchBucket, "validateResourceARNsMatchBucket");
34597
+ function validatePolicySemantics(policy) {
34598
+ if (policy.Statement.length > 100) {
34599
+ throw new import_server15.TRPCError({
34600
+ code: "BAD_REQUEST",
34601
+ message: "Policy exceeds maximum of 100 statements"
34602
+ });
34603
+ }
34604
+ const denyAllStatement = policy.Statement.find((s) => {
34605
+ if (s.Effect !== "Deny") return false;
34606
+ const actions = Array.isArray(s.Action) ? s.Action : [
34607
+ s.Action
34608
+ ];
34609
+ return actions.some((a) => a === "*" || a === "s3:*");
34610
+ });
34611
+ if (denyAllStatement) {
34612
+ throw new import_server15.TRPCError({
34613
+ code: "BAD_REQUEST",
34614
+ message: "Policy contains 'Deny *' or 'Deny s3:*' which may lock out all access including the bucket owner. Please use more specific deny rules."
34615
+ });
34616
+ }
34617
+ }
34618
+ __name(validatePolicySemantics, "validatePolicySemantics");
34619
+ var bucketPolicyRouter = {
34620
+ /**
34621
+ * Get the current bucket policy.
34622
+ *
34623
+ * Returns the policy as both a parsed object and raw JSON string.
34624
+ * Returns null if no policy is set (not an error).
34625
+ *
34626
+ * @throws TRPCError NOT_FOUND - bucket does not exist
34627
+ * @throws TRPCError FORBIDDEN - no credentials or access denied
34628
+ */
34629
+ get: cephProtectedProcedure.input(getBucketPolicyInputSchema).query(async ({ ctx, input }) => {
34630
+ const s3 = ctx.getCephClient();
34631
+ const { bucketName } = input;
34632
+ try {
34633
+ const response = await s3.send(new import_client_s35.GetBucketPolicyCommand({
34634
+ Bucket: bucketName
34635
+ }));
34636
+ const policyText = response.Policy ?? null;
34637
+ if (!policyText) {
34638
+ return {
34639
+ policy: null,
34640
+ policyText: null
34641
+ };
34642
+ }
34643
+ const policyObj = JSON.parse(policyText);
34644
+ const policy = bucketPolicyDocumentSchema.parse(policyObj);
34645
+ return {
34646
+ policy,
34647
+ policyText
34648
+ };
34649
+ } catch (error) {
34650
+ const s3Error = error;
34651
+ if (s3Error.name === "NoSuchBucketPolicy" || s3Error.Code === "NoSuchBucketPolicy") {
34652
+ return {
34653
+ policy: null,
34654
+ policyText: null
34655
+ };
34656
+ }
34657
+ throw mapS3ErrorToTRPCError(error, {
34658
+ operation: "get bucket policy",
34659
+ bucket: bucketName
34660
+ });
34661
+ }
34662
+ }),
34663
+ /**
34664
+ * Set (create or replace) a bucket policy.
34665
+ *
34666
+ * Accepts a policy document as a JSON string. Validates structure before
34667
+ * sending to S3. Replaces any existing policy completely.
34668
+ *
34669
+ * @throws TRPCError BAD_REQUEST - invalid policy JSON or structure
34670
+ * @throws TRPCError NOT_FOUND - bucket does not exist
34671
+ * @throws TRPCError FORBIDDEN - no credentials or access denied
34672
+ */
34673
+ set: cephProtectedProcedure.input(setBucketPolicyInputSchema).mutation(async ({ ctx, input }) => {
34674
+ const s3 = ctx.getCephClient();
34675
+ const { bucketName, policy } = input;
34676
+ checkPolicySetRateLimit(bucketName, input.project_id);
34677
+ if (policy.length > 20480) {
34678
+ throw new import_server15.TRPCError({
34679
+ code: "PAYLOAD_TOO_LARGE",
34680
+ message: "Policy document exceeds maximum size of 20KB"
34681
+ });
34682
+ }
34683
+ const openBrackets = (policy.match(/[{[]/g) || []).length;
34684
+ if (openBrackets > 50) {
34685
+ throw new import_server15.TRPCError({
34686
+ code: "BAD_REQUEST",
34687
+ message: "Policy JSON is too deeply nested (maximum 50 levels)"
34688
+ });
34689
+ }
34690
+ try {
34691
+ const policyObj = JSON.parse(policy);
34692
+ const validatedPolicy = bucketPolicyDocumentSchema.parse(policyObj);
34693
+ validateResourceARNsMatchBucket(validatedPolicy, bucketName);
34694
+ validatePolicySemantics(validatedPolicy);
34695
+ const policyText = JSON.stringify(validatedPolicy);
34696
+ await s3.send(new import_client_s35.PutBucketPolicyCommand({
34697
+ Bucket: bucketName,
34698
+ Policy: policyText
34699
+ }));
34700
+ return true;
34701
+ } catch (error) {
34702
+ if (error instanceof SyntaxError || error instanceof import_zod17.z.ZodError) {
34703
+ const errorDetails = error instanceof import_zod17.z.ZodError ? error.message : "Invalid JSON format";
34704
+ throw new import_server15.TRPCError({
34705
+ code: "BAD_REQUEST",
34706
+ message: `Invalid policy JSON structure: ${errorDetails}`
34707
+ });
34708
+ }
34709
+ throw mapS3ErrorToTRPCError(error, {
34710
+ operation: "set bucket policy",
34711
+ bucket: bucketName
34712
+ });
34713
+ }
34714
+ }),
34715
+ /**
34716
+ * Delete (remove) a bucket policy.
34717
+ *
34718
+ * Removes the policy from the bucket. The bucket reverts to having no policy.
34719
+ * Not an error if no policy was set.
34720
+ *
34721
+ * @throws TRPCError NOT_FOUND - bucket does not exist
34722
+ * @throws TRPCError FORBIDDEN - no credentials or access denied
34723
+ */
34724
+ delete: cephProtectedProcedure.input(deleteBucketPolicyInputSchema).mutation(async ({ ctx, input }) => {
34725
+ const s3 = ctx.getCephClient();
34726
+ const { bucketName } = input;
34727
+ try {
34728
+ await s3.send(new import_client_s35.DeleteBucketPolicyCommand({
34729
+ Bucket: bucketName
34730
+ }));
34731
+ return true;
34732
+ } catch (error) {
34733
+ const s3Error = error;
34734
+ if (s3Error.name === "NoSuchBucketPolicy" || s3Error.Code === "NoSuchBucketPolicy") {
34735
+ return true;
34736
+ }
34737
+ throw mapS3ErrorToTRPCError(error, {
34738
+ operation: "delete bucket policy",
34739
+ bucket: bucketName
34740
+ });
34741
+ }
34742
+ })
34743
+ };
34744
+
34745
+ // src/server/Storage/routers/permissionRouter.ts
34746
+ var STORAGE_MAPPINGS = {
34747
+ // Container Operations (works for both Swift containers and Ceph buckets)
34748
+ "storage:containers:read": {
34749
+ engine: "storage",
34750
+ rule: "storage:container_get"
34751
+ },
34752
+ "storage:containers:list": {
34753
+ engine: "storage",
34754
+ rule: "storage:container_list"
34755
+ },
34756
+ "storage:containers:create": {
34757
+ engine: "storage",
34758
+ rule: "storage:container_create"
34759
+ },
34760
+ "storage:containers:update": {
34761
+ engine: "storage",
34762
+ rule: "storage:container_update"
34763
+ },
34764
+ "storage:containers:delete": {
34765
+ engine: "storage",
34766
+ rule: "storage:container_delete"
34767
+ },
34768
+ "storage:containers:empty": {
34769
+ engine: "storage",
34770
+ rule: "storage:container_empty"
34771
+ },
34772
+ "storage:containers:manage_acls": {
34773
+ engine: "storage",
34774
+ rule: "storage:container_check_acls"
34775
+ },
34776
+ "storage:containers:read_acls": {
34777
+ engine: "storage",
34778
+ rule: "storage:container_show_access_control"
34779
+ },
34780
+ "storage:containers:update_acls": {
34781
+ engine: "storage",
34782
+ rule: "storage:container_update_access_control"
34783
+ },
34784
+ // Object Operations
34785
+ "storage:objects:read": {
34786
+ engine: "storage",
34787
+ rule: "storage:object_get"
34788
+ },
34789
+ "storage:objects:list": {
34790
+ engine: "storage",
34791
+ rule: "storage:object_list"
34792
+ },
34793
+ "storage:objects:download": {
34794
+ engine: "storage",
34795
+ rule: "storage:object_download"
34796
+ },
34797
+ "storage:objects:create": {
34798
+ engine: "storage",
34799
+ rule: "storage:object_update"
34800
+ },
34801
+ "storage:objects:update": {
34802
+ engine: "storage",
34803
+ rule: "storage:object_update"
34804
+ },
34805
+ "storage:objects:delete": {
34806
+ engine: "storage",
34807
+ rule: "storage:object_delete"
34808
+ },
34809
+ "storage:objects:copy": {
34810
+ engine: "storage",
34811
+ rule: "storage:object_create_copy"
34812
+ },
34813
+ "storage:objects:move": {
34814
+ engine: "storage",
34815
+ rule: "storage:object_move"
34816
+ },
34817
+ // Folder Operations
34818
+ "storage:folders:create_object": {
34819
+ engine: "storage",
34820
+ rule: "storage:folder_create_object"
34821
+ },
34822
+ "storage:folders:create": {
34823
+ engine: "storage",
34824
+ rule: "storage:folder_create_folder"
34825
+ },
34826
+ "storage:folders:delete": {
34827
+ engine: "storage",
34828
+ rule: "storage:folder_delete"
34829
+ }
34830
+ };
34831
+ var buildStoragePermissionRouter = /* @__PURE__ */ __name((policyDir) => createPermissionRouter({
34832
+ policyDir,
34833
+ engines: {
34834
+ storage: {
34835
+ fileName: "storage.json"
34836
+ }
34837
+ },
34838
+ mappings: STORAGE_MAPPINGS
34839
+ }), "buildStoragePermissionRouter");
34840
+
34370
34841
  // src/server/Storage/routers/index.ts
34371
- var objectStorageRouters = {
34842
+ var buildObjectStorageRouters = /* @__PURE__ */ __name((policyDir) => ({
34372
34843
  storage: {
34373
34844
  swift: auroraRouter({
34374
34845
  ...swiftRouter
@@ -34385,52 +34856,57 @@ var objectStorageRouters = {
34385
34856
  }),
34386
34857
  versioning: auroraRouter({
34387
34858
  ...versioningRouter
34859
+ }),
34860
+ bucketPolicy: auroraRouter({
34861
+ ...bucketPolicyRouter
34388
34862
  })
34389
- })
34863
+ }),
34864
+ ...buildStoragePermissionRouter(policyDir)
34390
34865
  }
34391
- };
34866
+ }), "buildObjectStorageRouters");
34392
34867
 
34393
34868
  // src/server/Project/routers/projectRouter.ts
34394
- var import_zod18 = require("zod");
34395
- var import_server15 = require("@trpc/server");
34869
+ var import_zod19 = require("zod");
34870
+ var import_server16 = require("@trpc/server");
34396
34871
 
34397
34872
  // src/server/Project/types/models.ts
34398
- var import_zod17 = require("zod");
34399
- var baseProjectSchema = import_zod17.z.object({
34400
- id: import_zod17.z.string(),
34401
- name: import_zod17.z.string(),
34402
- enabled: import_zod17.z.boolean(),
34403
- domain_id: import_zod17.z.string().nullable().optional(),
34404
- parent_id: import_zod17.z.string().nullable().optional(),
34405
- is_domain: import_zod17.z.boolean().nullable().optional(),
34406
- tags: import_zod17.z.array(import_zod17.z.string()).nullable().optional(),
34407
- options: import_zod17.z.record(import_zod17.z.string(), import_zod17.z.string().or(import_zod17.z.boolean())).nullable().optional(),
34408
- description: import_zod17.z.string().nullable().optional(),
34409
- links: import_zod17.z.object({
34410
- self: import_zod17.z.string().url().nullable().optional()
34873
+ var import_zod18 = require("zod");
34874
+ var baseProjectSchema = import_zod18.z.object({
34875
+ id: import_zod18.z.string(),
34876
+ name: import_zod18.z.string(),
34877
+ enabled: import_zod18.z.boolean(),
34878
+ domain_id: import_zod18.z.string().nullable().optional(),
34879
+ parent_id: import_zod18.z.string().nullable().optional(),
34880
+ is_domain: import_zod18.z.boolean().nullable().optional(),
34881
+ tags: import_zod18.z.array(import_zod18.z.string()).nullable().optional(),
34882
+ options: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.string().or(import_zod18.z.boolean())).nullable().optional(),
34883
+ description: import_zod18.z.string().nullable().optional(),
34884
+ links: import_zod18.z.object({
34885
+ self: import_zod18.z.string().url().nullable().optional()
34411
34886
  }).optional()
34412
34887
  });
34413
34888
  var projectSchema = baseProjectSchema.extend({
34414
- parents: import_zod17.z.array(import_zod17.z.object({
34889
+ domain_name: import_zod18.z.string().optional(),
34890
+ parents: import_zod18.z.array(import_zod18.z.object({
34415
34891
  project: baseProjectSchema
34416
34892
  })).optional()
34417
34893
  });
34418
- var projectResponseSchema = import_zod17.z.object({
34894
+ var projectResponseSchema = import_zod18.z.object({
34419
34895
  project: projectSchema
34420
34896
  });
34421
- var projectsResponseSchema = import_zod17.z.object({
34422
- projects: import_zod17.z.array(projectSchema),
34423
- links: import_zod17.z.object({
34424
- self: import_zod17.z.string().url().optional(),
34425
- previous: import_zod17.z.string().url().nullable().optional(),
34426
- next: import_zod17.z.string().url().nullable().optional()
34897
+ var projectsResponseSchema = import_zod18.z.object({
34898
+ projects: import_zod18.z.array(projectSchema),
34899
+ links: import_zod18.z.object({
34900
+ self: import_zod18.z.string().url().optional(),
34901
+ previous: import_zod18.z.string().url().nullable().optional(),
34902
+ next: import_zod18.z.string().url().nullable().optional()
34427
34903
  }).optional()
34428
34904
  });
34429
34905
 
34430
34906
  // src/server/Project/routers/projectRouter.ts
34431
34907
  async function callIdentityAPI(identityEndpoint, authToken, path3) {
34432
34908
  if (!identityEndpoint) {
34433
- throw new import_server15.TRPCError({
34909
+ throw new import_server16.TRPCError({
34434
34910
  code: "INTERNAL_SERVER_ERROR",
34435
34911
  message: "Identity endpoint not configured"
34436
34912
  });
@@ -34446,7 +34922,7 @@ async function callIdentityAPI(identityEndpoint, authToken, path3) {
34446
34922
  }
34447
34923
  });
34448
34924
  if (!response.ok) {
34449
- throw new import_server15.TRPCError({
34925
+ throw new import_server16.TRPCError({
34450
34926
  code: "INTERNAL_SERVER_ERROR",
34451
34927
  message: `Identity API call failed: ${response.status} ${response.statusText}`
34452
34928
  });
@@ -34486,26 +34962,44 @@ var projectRouter = {
34486
34962
  */
34487
34963
  getAuthProjects: protectedProcedure.query(async ({ ctx }) => {
34488
34964
  if (!ctx.openstack) {
34489
- throw new import_server15.TRPCError({
34965
+ throw new import_server16.TRPCError({
34490
34966
  code: "UNAUTHORIZED",
34491
34967
  message: "No authenticated session"
34492
34968
  });
34493
34969
  }
34494
34970
  const token = ctx.openstack.getToken();
34495
34971
  if (!token?.authToken) {
34496
- throw new import_server15.TRPCError({
34972
+ throw new import_server16.TRPCError({
34497
34973
  code: "UNAUTHORIZED",
34498
34974
  message: "No auth token available"
34499
34975
  });
34500
34976
  }
34501
- const response = await callIdentityAPI(ctx.identityEndpoint, token.authToken, "auth/projects");
34977
+ const [response, domainsResponse] = await Promise.all([
34978
+ callIdentityAPI(ctx.identityEndpoint, token.authToken, "auth/projects"),
34979
+ callIdentityAPI(ctx.identityEndpoint, token.authToken, "auth/domains").catch(() => null)
34980
+ ]);
34502
34981
  const data = await response.json();
34503
34982
  const parsedData = projectsResponseSchema.safeParse(data);
34504
34983
  if (!parsedData.success) {
34505
34984
  console.error("Zod Parsing Error:", parsedData.error.message);
34506
34985
  return void 0;
34507
34986
  }
34508
- return parsedData.data.projects;
34987
+ const domainsData = domainsResponse ? await domainsResponse.json().catch(() => null) : null;
34988
+ const domainsResponseSchema = import_zod19.z.object({
34989
+ domains: import_zod19.z.array(import_zod19.z.object({
34990
+ id: import_zod19.z.string(),
34991
+ name: import_zod19.z.string()
34992
+ }))
34993
+ });
34994
+ const parsedDomains = domainsResponseSchema.safeParse(domainsData);
34995
+ const domainMap = new Map((parsedDomains.success ? parsedDomains.data.domains : []).map((d) => [
34996
+ d.id,
34997
+ d.name
34998
+ ]));
34999
+ return parsedData.data.projects.map((project) => ({
35000
+ ...project,
35001
+ domain_name: project.domain_id ? domainMap.get(project.domain_id) ?? void 0 : void 0
35002
+ }));
34509
35003
  }),
34510
35004
  /**
34511
35005
  * Search projects with optional text filtering
@@ -34514,18 +35008,18 @@ var projectRouter = {
34514
35008
  * filtered by the optional search term. Uses the OpenStack /v3/auth/projects
34515
35009
  * endpoint which works with any valid token.
34516
35010
  */
34517
- searchProjects: protectedProcedure.input(import_zod18.z.object({
34518
- search: import_zod18.z.string().optional()
35011
+ searchProjects: protectedProcedure.input(import_zod19.z.object({
35012
+ search: import_zod19.z.string().optional()
34519
35013
  }).optional()).query(async ({ ctx, input }) => {
34520
35014
  if (!ctx.openstack) {
34521
- throw new import_server15.TRPCError({
35015
+ throw new import_server16.TRPCError({
34522
35016
  code: "UNAUTHORIZED",
34523
35017
  message: "No authenticated session"
34524
35018
  });
34525
35019
  }
34526
35020
  const token = ctx.openstack.getToken();
34527
35021
  if (!token?.authToken) {
34528
- throw new import_server15.TRPCError({
35022
+ throw new import_server16.TRPCError({
34529
35023
  code: "UNAUTHORIZED",
34530
35024
  message: "No auth token available"
34531
35025
  });
@@ -34568,12 +35062,12 @@ var projectRouter = {
34568
35062
  * If in the future we need to access project-specific resources (compute, network, etc.),
34569
35063
  * we should create a separate procedure using projectScopedProcedure.
34570
35064
  */
34571
- getProjectById: protectedProcedure.input(import_zod18.z.object({
34572
- id: import_zod18.z.string()
35065
+ getProjectById: protectedProcedure.input(import_zod19.z.object({
35066
+ id: import_zod19.z.string()
34573
35067
  })).query(async ({ input, ctx }) => {
34574
35068
  const identityService = ctx.openstack?.service("identity");
34575
35069
  if (!ctx.openstack || !identityService) {
34576
- throw new import_server15.TRPCError({
35070
+ throw new import_server16.TRPCError({
34577
35071
  code: "INTERNAL_SERVER_ERROR",
34578
35072
  message: "Identity service unavailable"
34579
35073
  });
@@ -34595,13 +35089,13 @@ var projectRouters = {
34595
35089
  };
34596
35090
 
34597
35091
  // src/server/helpers/errorHandling.ts
34598
- var import_server16 = require("@trpc/server");
35092
+ var import_server17 = require("@trpc/server");
34599
35093
  function wrapError3(error, operation) {
34600
- if (error instanceof import_server16.TRPCError) {
35094
+ if (error instanceof import_server17.TRPCError) {
34601
35095
  return error;
34602
35096
  }
34603
35097
  const baseErrorMessage = `Error during ${operation}`;
34604
- return new import_server16.TRPCError({
35098
+ return new import_server17.TRPCError({
34605
35099
  code: "INTERNAL_SERVER_ERROR",
34606
35100
  message: typeof error !== "string" && error.message ? `${baseErrorMessage}: ${error.message}` : baseErrorMessage,
34607
35101
  cause: error
@@ -34641,11 +35135,11 @@ function appendQueryParamsFromObject(source, options) {
34641
35135
  __name(appendQueryParamsFromObject, "appendQueryParamsFromObject");
34642
35136
 
34643
35137
  // src/server/helpers/validateOpenstackService.ts
34644
- var import_server17 = require("@trpc/server");
35138
+ var import_server18 = require("@trpc/server");
34645
35139
  var capitalize = /* @__PURE__ */ __name((str) => str.charAt(0).toUpperCase() + str.slice(1), "capitalize");
34646
35140
  function validateOpenstackService(service, serviceName) {
34647
35141
  if (!service) {
34648
- throw new import_server17.TRPCError({
35142
+ throw new import_server18.TRPCError({
34649
35143
  code: "INTERNAL_SERVER_ERROR",
34650
35144
  message: `${capitalize(serviceName)} service is not available`
34651
35145
  });
@@ -34654,16 +35148,16 @@ function validateOpenstackService(service, serviceName) {
34654
35148
  __name(validateOpenstackService, "validateOpenstackService");
34655
35149
 
34656
35150
  // src/server/Network/types/floatingIp.ts
34657
- var import_zod20 = require("zod");
35151
+ var import_zod21 = require("zod");
34658
35152
 
34659
35153
  // src/server/Network/types/index.ts
34660
- var import_zod19 = require("zod");
34661
- var ISO8601TimestampSchema = import_zod19.z.string().brand("ISO8601Timestamp");
34662
- var SortDirSchema = import_zod19.z.enum([
35154
+ var import_zod20 = require("zod");
35155
+ var ISO8601TimestampSchema = import_zod20.z.string().brand("ISO8601Timestamp");
35156
+ var SortDirSchema = import_zod20.z.enum([
34663
35157
  "asc",
34664
35158
  "desc"
34665
35159
  ]);
34666
- var NetworkPortStatusSchema = import_zod19.z.enum([
35160
+ var NetworkPortStatusSchema = import_zod20.z.enum([
34667
35161
  "ACTIVE",
34668
35162
  "DOWN",
34669
35163
  "BUILD",
@@ -34671,154 +35165,154 @@ var NetworkPortStatusSchema = import_zod19.z.enum([
34671
35165
  ]);
34672
35166
 
34673
35167
  // src/server/Network/types/floatingIp.ts
34674
- var FloatingIpStatusSchema = import_zod20.z.enum([
35168
+ var FloatingIpStatusSchema = import_zod21.z.enum([
34675
35169
  "ACTIVE",
34676
35170
  "DOWN",
34677
35171
  "ERROR"
34678
35172
  ]);
34679
- var PortDetailsSchema = import_zod20.z.object({
35173
+ var PortDetailsSchema = import_zod21.z.object({
34680
35174
  /** The status of the port */
34681
35175
  status: FloatingIpStatusSchema,
34682
35176
  /** The name of the port */
34683
- name: import_zod20.z.string(),
35177
+ name: import_zod21.z.string(),
34684
35178
  /** Administrative state of the port (true = UP, false = DOWN) */
34685
- admin_state_up: import_zod20.z.boolean(),
35179
+ admin_state_up: import_zod21.z.boolean(),
34686
35180
  /** The ID of the network the port is attached to */
34687
- network_id: import_zod20.z.string(),
35181
+ network_id: import_zod21.z.string(),
34688
35182
  /** The owner of the port device */
34689
- device_owner: import_zod20.z.string(),
35183
+ device_owner: import_zod21.z.string(),
34690
35184
  /** The MAC address of the port */
34691
- mac_address: import_zod20.z.string(),
35185
+ mac_address: import_zod21.z.string(),
34692
35186
  /** The ID of the device the port is attached to */
34693
- device_id: import_zod20.z.string()
35187
+ device_id: import_zod21.z.string()
34694
35188
  });
34695
- var PortForwardingSchema = import_zod20.z.object({
35189
+ var PortForwardingSchema = import_zod21.z.object({
34696
35190
  /** Port forwarding protocol */
34697
- protocol: import_zod20.z.enum([
35191
+ protocol: import_zod21.z.enum([
34698
35192
  "tcp",
34699
35193
  "udp"
34700
35194
  ]),
34701
35195
  /** The internal fixed IP address associated with the port forwarding */
34702
- internal_ip_address: import_zod20.z.string(),
35196
+ internal_ip_address: import_zod21.z.string(),
34703
35197
  /** The internal port number or starting port of the range */
34704
- internal_port: import_zod20.z.number().optional(),
35198
+ internal_port: import_zod21.z.number().optional(),
34705
35199
  /** The internal port range (e.g., "1024:2048") */
34706
- internal_port_range: import_zod20.z.string().optional(),
35200
+ internal_port_range: import_zod21.z.string().optional(),
34707
35201
  /** The internal port ID for the port forwarding (requires floating-ip-port-forwarding-detail extension) */
34708
- internal_port_id: import_zod20.z.string().optional(),
35202
+ internal_port_id: import_zod21.z.string().optional(),
34709
35203
  /** The external port number or starting port of the range */
34710
- external_port: import_zod20.z.number().optional(),
35204
+ external_port: import_zod21.z.number().optional(),
34711
35205
  /** The external port range (e.g., "8000:9000") */
34712
- external_port_range: import_zod20.z.string().optional(),
35206
+ external_port_range: import_zod21.z.string().optional(),
34713
35207
  /** The ID of the port forwarding resource */
34714
- id: import_zod20.z.string(),
35208
+ id: import_zod21.z.string(),
34715
35209
  /** Description of the port forwarding rule (requires floating-ip-port-forwarding-description extension) */
34716
- description: import_zod20.z.string().nullable().optional()
35210
+ description: import_zod21.z.string().nullable().optional()
34717
35211
  });
34718
- var FloatingIpSchema = import_zod20.z.object({
35212
+ var FloatingIpSchema = import_zod21.z.object({
34719
35213
  /** The ID of the router for the floating IP (null if not associated) */
34720
- router_id: import_zod20.z.string().nullable(),
35214
+ router_id: import_zod21.z.string().nullable(),
34721
35215
  /** A human-readable description for the resource */
34722
- description: import_zod20.z.string().nullable().optional(),
35216
+ description: import_zod21.z.string().nullable().optional(),
34723
35217
  /** Whether this is a distributed floating IP (requires floating-ip-distributed extension) */
34724
- distributed: import_zod20.z.boolean().optional(),
35218
+ distributed: import_zod21.z.boolean().optional(),
34725
35219
  /** A valid DNS domain (requires dns-integration extension) */
34726
- dns_domain: import_zod20.z.string().optional(),
35220
+ dns_domain: import_zod21.z.string().optional(),
34727
35221
  /** A valid DNS name (requires dns-integration extension) */
34728
- dns_name: import_zod20.z.string().optional(),
35222
+ dns_name: import_zod21.z.string().optional(),
34729
35223
  /** Time at which the resource was created (UTC ISO8601 format, requires standard-attr-timestamp extension) */
34730
35224
  created_at: ISO8601TimestampSchema.optional(),
34731
35225
  /** Time at which the resource was last updated (UTC ISO8601 format, requires standard-attr-timestamp extension) */
34732
35226
  updated_at: ISO8601TimestampSchema.optional(),
34733
35227
  /** The revision number of the resource (set by server, for concurrency control) */
34734
- revision_number: import_zod20.z.number(),
35228
+ revision_number: import_zod21.z.number(),
34735
35229
  /** The ID of the project that owns the floating IP */
34736
- project_id: import_zod20.z.string(),
35230
+ project_id: import_zod21.z.string(),
34737
35231
  /** The ID of the tenant (deprecated, use project_id) */
34738
- tenant_id: import_zod20.z.string(),
35232
+ tenant_id: import_zod21.z.string(),
34739
35233
  /** The ID of the network associated with the floating IP */
34740
- floating_network_id: import_zod20.z.string(),
35234
+ floating_network_id: import_zod21.z.string(),
34741
35235
  /** The fixed IP address associated with the floating IP (null if not associated) */
34742
- fixed_ip_address: import_zod20.z.string().nullable(),
35236
+ fixed_ip_address: import_zod21.z.string().nullable(),
34743
35237
  /** The floating IP address */
34744
- floating_ip_address: import_zod20.z.string(),
35238
+ floating_ip_address: import_zod21.z.string(),
34745
35239
  /** The ID of the port associated with the floating IP (null if not associated) */
34746
- port_id: import_zod20.z.string().nullable(),
35240
+ port_id: import_zod21.z.string().nullable(),
34747
35241
  /** The ID of the floating IP address */
34748
- id: import_zod20.z.string(),
35242
+ id: import_zod21.z.string(),
34749
35243
  /** The status of the floating IP */
34750
35244
  status: FloatingIpStatusSchema,
34751
35245
  /** The information of the associated port (null if not associated, requires fip-port-details extension) */
34752
35246
  port_details: PortDetailsSchema.nullable().optional(),
34753
35247
  /** The list of tags on the resource (requires standard-attr-tag extension) */
34754
- tags: import_zod20.z.array(import_zod20.z.string()).optional(),
35248
+ tags: import_zod21.z.array(import_zod21.z.string()).optional(),
34755
35249
  /** The associated port forwarding resources for the floating IP (requires expose-port-forwarding-in-fip extension) */
34756
- port_forwardings: import_zod20.z.array(PortForwardingSchema).nullish(),
35250
+ port_forwardings: import_zod21.z.array(PortForwardingSchema).nullish(),
34757
35251
  /** The ID of the QoS policy of the network where this floating IP is plugged (requires qos-fip extension) */
34758
- qos_network_policy_id: import_zod20.z.string().optional(),
35252
+ qos_network_policy_id: import_zod21.z.string().optional(),
34759
35253
  /** The ID of the QoS policy associated with the floating IP (requires qos extension) */
34760
- qos_policy_id: import_zod20.z.string().optional()
34761
- });
34762
- var FloatingIpIdInputSchema = import_zod20.z.object({
34763
- project_id: import_zod20.z.string(),
34764
- floatingip_id: import_zod20.z.string()
34765
- });
34766
- var FloatingIpCreateRequestSchema = import_zod20.z.object({
34767
- tenant_id: import_zod20.z.string(),
34768
- project_id: import_zod20.z.string(),
34769
- floating_network_id: import_zod20.z.string(),
34770
- fixed_ip_address: import_zod20.z.string().optional(),
34771
- floating_ip_address: import_zod20.z.string().optional(),
34772
- port_id: import_zod20.z.string().optional(),
34773
- subnet_id: import_zod20.z.string().optional(),
34774
- distributed: import_zod20.z.boolean().optional(),
34775
- description: import_zod20.z.string().optional(),
34776
- dns_domain: import_zod20.z.string().optional(),
34777
- dns_name: import_zod20.z.string().optional(),
34778
- qos_policy_id: import_zod20.z.string().optional()
34779
- });
34780
- var FloatingIpUpdateRequestSchema = import_zod20.z.object({
34781
- project_id: import_zod20.z.string(),
34782
- floatingip_id: import_zod20.z.string(),
34783
- port_id: import_zod20.z.string().nullable(),
34784
- fixed_ip_address: import_zod20.z.string().optional(),
34785
- description: import_zod20.z.string().optional(),
34786
- distributed: import_zod20.z.boolean().optional()
34787
- });
34788
- var FloatingIpResponseSchema = import_zod20.z.object({
35254
+ qos_policy_id: import_zod21.z.string().optional()
35255
+ });
35256
+ var FloatingIpIdInputSchema = import_zod21.z.object({
35257
+ project_id: import_zod21.z.string(),
35258
+ floatingip_id: import_zod21.z.string()
35259
+ });
35260
+ var FloatingIpCreateRequestSchema = import_zod21.z.object({
35261
+ tenant_id: import_zod21.z.string(),
35262
+ project_id: import_zod21.z.string(),
35263
+ floating_network_id: import_zod21.z.string(),
35264
+ fixed_ip_address: import_zod21.z.string().optional(),
35265
+ floating_ip_address: import_zod21.z.string().optional(),
35266
+ port_id: import_zod21.z.string().optional(),
35267
+ subnet_id: import_zod21.z.string().optional(),
35268
+ distributed: import_zod21.z.boolean().optional(),
35269
+ description: import_zod21.z.string().optional(),
35270
+ dns_domain: import_zod21.z.string().optional(),
35271
+ dns_name: import_zod21.z.string().optional(),
35272
+ qos_policy_id: import_zod21.z.string().optional()
35273
+ });
35274
+ var FloatingIpUpdateRequestSchema = import_zod21.z.object({
35275
+ project_id: import_zod21.z.string(),
35276
+ floatingip_id: import_zod21.z.string(),
35277
+ port_id: import_zod21.z.string().nullable(),
35278
+ fixed_ip_address: import_zod21.z.string().optional(),
35279
+ description: import_zod21.z.string().optional(),
35280
+ distributed: import_zod21.z.boolean().optional()
35281
+ });
35282
+ var FloatingIpResponseSchema = import_zod21.z.object({
34789
35283
  floatingip: FloatingIpSchema
34790
35284
  });
34791
- var FloatingIpListResponseSchema = import_zod20.z.object({
35285
+ var FloatingIpListResponseSchema = import_zod21.z.object({
34792
35286
  /** A list of floating IP objects */
34793
- floatingips: import_zod20.z.array(FloatingIpSchema)
35287
+ floatingips: import_zod21.z.array(FloatingIpSchema)
34794
35288
  });
34795
- var FloatingIpQueryParametersSchema = import_zod20.z.object({
35289
+ var FloatingIpQueryParametersSchema = import_zod21.z.object({
34796
35290
  /** Project ID for rescoping (required for projectScopedProcedure) */
34797
- project_id: import_zod20.z.string(),
35291
+ project_id: import_zod21.z.string(),
34798
35292
  /** Filter by the ID of the floating IP */
34799
- id: import_zod20.z.string().optional(),
35293
+ id: import_zod21.z.string().optional(),
34800
35294
  /** Filter by the ID of the router for the floating IP */
34801
- router_id: import_zod20.z.string().nullable().optional(),
35295
+ router_id: import_zod21.z.string().nullable().optional(),
34802
35296
  /** Filter by the status of the floating IP */
34803
35297
  status: FloatingIpStatusSchema.optional(),
34804
35298
  /** Filter by the ID of the project that owns the resource */
34805
- tenant_id: import_zod20.z.string().optional(),
35299
+ tenant_id: import_zod21.z.string().optional(),
34806
35300
  /** Filter by the revision number of the resource */
34807
- revision_number: import_zod20.z.number().optional(),
35301
+ revision_number: import_zod21.z.number().optional(),
34808
35302
  /** Filter by the human-readable description of the resource */
34809
- description: import_zod20.z.string().nullable().optional(),
35303
+ description: import_zod21.z.string().nullable().optional(),
34810
35304
  /** Filter by the ID of the network associated with the floating IP */
34811
- floating_network_id: import_zod20.z.string().optional(),
35305
+ floating_network_id: import_zod21.z.string().optional(),
34812
35306
  /** Filter by the fixed IP address associated with the floating IP */
34813
- fixed_ip_address: import_zod20.z.string().optional(),
35307
+ fixed_ip_address: import_zod21.z.string().optional(),
34814
35308
  /** Filter by the floating IP address */
34815
- floating_ip_address: import_zod20.z.string().optional(),
35309
+ floating_ip_address: import_zod21.z.string().optional(),
34816
35310
  /** Filter by the ID of a port associated with the floating IP */
34817
- port_id: import_zod20.z.string().nullable().optional(),
35311
+ port_id: import_zod21.z.string().nullable().optional(),
34818
35312
  /** Sort direction (asc or desc) */
34819
35313
  sort_dir: SortDirSchema.optional(),
34820
35314
  /** Sort key - valid keys: fixed_ip_address, floating_ip_address, floating_network_id, id, router_id, status, tenant_id, project_id */
34821
- sort_key: import_zod20.z.enum([
35315
+ sort_key: import_zod21.z.enum([
34822
35316
  "fixed_ip_address",
34823
35317
  "floating_ip_address",
34824
35318
  "floating_network_id",
@@ -34829,80 +35323,80 @@ var FloatingIpQueryParametersSchema = import_zod20.z.object({
34829
35323
  "project_id"
34830
35324
  ]).optional(),
34831
35325
  /** Filter by tags (comma-separated, resources must match all tags) - requires standard-attr-tag extension */
34832
- tags: import_zod20.z.array(import_zod20.z.string()).optional(),
35326
+ tags: import_zod21.z.array(import_zod21.z.string()).optional(),
34833
35327
  /** Filter by tags with OR logic (comma-separated, resources match any tag) */
34834
- "tags-any": import_zod20.z.string().optional(),
35328
+ "tags-any": import_zod21.z.string().optional(),
34835
35329
  /** Exclude resources with these tags (comma-separated, resources must match all excluded tags) */
34836
- "not-tags": import_zod20.z.string().optional(),
35330
+ "not-tags": import_zod21.z.string().optional(),
34837
35331
  /** Exclude resources with these tags using OR logic (comma-separated, resources match any excluded tag) */
34838
- "not-tags-any": import_zod20.z.string().optional(),
35332
+ "not-tags-any": import_zod21.z.string().optional(),
34839
35333
  /** Specific fields to return (can be repeated) */
34840
- fields: import_zod20.z.union([
34841
- import_zod20.z.string(),
34842
- import_zod20.z.array(import_zod20.z.string())
35334
+ fields: import_zod21.z.union([
35335
+ import_zod21.z.string(),
35336
+ import_zod21.z.array(import_zod21.z.string())
34843
35337
  ]).optional(),
34844
35338
  /** Pagination limit */
34845
- limit: import_zod20.z.number().optional(),
35339
+ limit: import_zod21.z.number().optional(),
34846
35340
  /** Pagination marker (ID of the last item in the previous list) */
34847
- marker: import_zod20.z.string().optional(),
35341
+ marker: import_zod21.z.string().optional(),
34848
35342
  /** Pagination direction (false = ascending, true = descending) */
34849
- page_reverse: import_zod20.z.boolean().optional(),
35343
+ page_reverse: import_zod21.z.boolean().optional(),
34850
35344
  // BFF-side search (filtered in BFF layer, not sent to OpenStack)
34851
- searchTerm: import_zod20.z.string().optional()
34852
- });
34853
- var ExternalNetworksQuerySchema = import_zod20.z.object({
34854
- project_id: import_zod20.z.string(),
34855
- "router:external": import_zod20.z.literal(true).default(true)
34856
- });
34857
- var ExternalNetworkSchema = import_zod20.z.object({
34858
- id: import_zod20.z.string(),
34859
- name: import_zod20.z.string(),
34860
- project_id: import_zod20.z.string(),
34861
- "router:external": import_zod20.z.boolean().optional(),
34862
- shared: import_zod20.z.boolean(),
35345
+ searchTerm: import_zod21.z.string().optional()
35346
+ });
35347
+ var ExternalNetworksQuerySchema = import_zod21.z.object({
35348
+ project_id: import_zod21.z.string(),
35349
+ "router:external": import_zod21.z.literal(true).default(true)
35350
+ });
35351
+ var ExternalNetworkSchema = import_zod21.z.object({
35352
+ id: import_zod21.z.string(),
35353
+ name: import_zod21.z.string(),
35354
+ project_id: import_zod21.z.string(),
35355
+ "router:external": import_zod21.z.boolean().optional(),
35356
+ shared: import_zod21.z.boolean(),
34863
35357
  status: NetworkPortStatusSchema,
34864
35358
  updated_at: ISO8601TimestampSchema.optional(),
34865
- is_default: import_zod20.z.boolean().optional()
35359
+ is_default: import_zod21.z.boolean().optional()
34866
35360
  });
34867
- var ExternalNetworksResponseSchema = import_zod20.z.object({
34868
- networks: import_zod20.z.array(ExternalNetworkSchema)
35361
+ var ExternalNetworksResponseSchema = import_zod21.z.object({
35362
+ networks: import_zod21.z.array(ExternalNetworkSchema)
34869
35363
  });
34870
- var DnsDomainSchema = import_zod20.z.object({
34871
- id: import_zod20.z.string(),
34872
- name: import_zod20.z.string()
35364
+ var DnsDomainSchema = import_zod21.z.object({
35365
+ id: import_zod21.z.string(),
35366
+ name: import_zod21.z.string()
34873
35367
  });
34874
- var DnsDomainResponseSchema = import_zod20.z.object({
34875
- zones: import_zod20.z.array(DnsDomainSchema)
35368
+ var DnsDomainResponseSchema = import_zod21.z.object({
35369
+ zones: import_zod21.z.array(DnsDomainSchema)
34876
35370
  });
34877
- var AvailablePortsQuerySchema = import_zod20.z.object({
34878
- project_id: import_zod20.z.string(),
35371
+ var AvailablePortsQuerySchema = import_zod21.z.object({
35372
+ project_id: import_zod21.z.string(),
34879
35373
  /** Only ACTIVE ports are eligible for floating IP association */
34880
- status: import_zod20.z.literal("ACTIVE").default("ACTIVE"),
35374
+ status: import_zod21.z.literal("ACTIVE").default("ACTIVE"),
34881
35375
  /** Only administratively UP ports are eligible for floating IP association */
34882
- admin_state_up: import_zod20.z.literal(true).default(true)
35376
+ admin_state_up: import_zod21.z.literal(true).default(true)
34883
35377
  });
34884
- var AvailablePortSchema = import_zod20.z.object({
35378
+ var AvailablePortSchema = import_zod21.z.object({
34885
35379
  /** The ID of the port */
34886
- id: import_zod20.z.string(),
35380
+ id: import_zod21.z.string(),
34887
35381
  /** Human-readable name of the port */
34888
- name: import_zod20.z.string().nullable().optional(),
35382
+ name: import_zod21.z.string().nullable().optional(),
34889
35383
  /** List of fixed IPs assigned to the port, each entry pairs an IP address with its subnet. */
34890
- fixed_ips: import_zod20.z.array(import_zod20.z.object({
35384
+ fixed_ips: import_zod21.z.array(import_zod21.z.object({
34891
35385
  /** The fixed IP address assigned to the port */
34892
- ip_address: import_zod20.z.string(),
35386
+ ip_address: import_zod21.z.string(),
34893
35387
  /** The ID of the subnet the IP belongs to */
34894
- subnet_id: import_zod20.z.string().optional()
35388
+ subnet_id: import_zod21.z.string().optional()
34895
35389
  })).optional()
34896
35390
  });
34897
- var AvailablePortsResponseSchema = import_zod20.z.object({
34898
- ports: import_zod20.z.array(AvailablePortSchema)
35391
+ var AvailablePortsResponseSchema = import_zod21.z.object({
35392
+ ports: import_zod21.z.array(AvailablePortSchema)
34899
35393
  });
34900
35394
 
34901
35395
  // src/server/Network/helpers/errorHandling.ts
34902
- var import_server19 = require("@trpc/server");
35396
+ var import_server20 = require("@trpc/server");
34903
35397
 
34904
35398
  // src/server/Network/helpers/index.ts
34905
- var import_server18 = require("@trpc/server");
35399
+ var import_server19 = require("@trpc/server");
34906
35400
  var HTTP_STATUS_ERROR_MAP = {
34907
35401
  400: "BAD_REQUEST",
34908
35402
  401: "UNAUTHORIZED",
@@ -34922,7 +35416,7 @@ var parseOrThrow = /* @__PURE__ */ __name((schema, data, context) => {
34922
35416
  const parsed = schema.safeParse(data);
34923
35417
  if (!parsed.success) {
34924
35418
  console.error(`Zod Parsing Error in ${context}:`, parsed.error.issues);
34925
- throw new import_server18.TRPCError({
35419
+ throw new import_server19.TRPCError({
34926
35420
  code: "PARSE_ERROR",
34927
35421
  message: `Failed to parse response in ${context}`
34928
35422
  });
@@ -34932,27 +35426,27 @@ var parseOrThrow = /* @__PURE__ */ __name((schema, data, context) => {
34932
35426
 
34933
35427
  // src/server/Network/helpers/errorHandling.ts
34934
35428
  var DEFAULT_HANDLERS = {
34935
- 400: (response, resourceLabel) => new import_server19.TRPCError({
35429
+ 400: (response, resourceLabel) => new import_server20.TRPCError({
34936
35430
  code: HTTP_STATUS_ERROR_MAP[400],
34937
35431
  message: `Invalid request data for ${resourceLabel}: ${response.statusText || "Unknown error"}`
34938
35432
  }),
34939
- 401: (response, resourceLabel) => new import_server19.TRPCError({
35433
+ 401: (response, resourceLabel) => new import_server20.TRPCError({
34940
35434
  code: HTTP_STATUS_ERROR_MAP[401],
34941
35435
  message: `Unauthorized access to ${resourceLabel}: ${response.statusText || "Unknown error"}`
34942
35436
  }),
34943
- 403: (response, resourceLabel) => new import_server19.TRPCError({
35437
+ 403: (response, resourceLabel) => new import_server20.TRPCError({
34944
35438
  code: HTTP_STATUS_ERROR_MAP[403],
34945
35439
  message: `Access forbidden to ${resourceLabel}: ${response.statusText || "Unknown error"}`
34946
35440
  }),
34947
- 404: (response, resourceLabel) => new import_server19.TRPCError({
35441
+ 404: (response, resourceLabel) => new import_server20.TRPCError({
34948
35442
  code: HTTP_STATUS_ERROR_MAP[404],
34949
35443
  message: `${resourceLabel} not found: ${response.statusText || "Unknown error"}`
34950
35444
  }),
34951
- 409: (response, resourceLabel) => new import_server19.TRPCError({
35445
+ 409: (response, resourceLabel) => new import_server20.TRPCError({
34952
35446
  code: HTTP_STATUS_ERROR_MAP[409],
34953
35447
  message: `Conflict - ${resourceLabel} is in use: ${response.statusText || "Unknown error"}`
34954
35448
  }),
34955
- 412: (response, resourceLabel) => new import_server19.TRPCError({
35449
+ 412: (response, resourceLabel) => new import_server20.TRPCError({
34956
35450
  code: HTTP_STATUS_ERROR_MAP[412],
34957
35451
  message: `Precondition failed - revision number mismatch in ${resourceLabel}: ${response.statusText || "Unknown error"}`
34958
35452
  })
@@ -34967,7 +35461,7 @@ var ErrorHandler = /* @__PURE__ */ __name((resourceName, customHandlers) => {
34967
35461
  if (response.status && handlers[response.status]) {
34968
35462
  return handlers[response.status](response, resourceLabel);
34969
35463
  }
34970
- return new import_server19.TRPCError({
35464
+ return new import_server20.TRPCError({
34971
35465
  code: DEFAULT_ERROR_NAME,
34972
35466
  message: `Failed to process ${resourceLabel}: ${response.statusText || "Unknown error"}`
34973
35467
  });
@@ -35142,114 +35636,114 @@ var floatingIpRouter = {
35142
35636
  };
35143
35637
 
35144
35638
  // src/server/Network/types/securityGroup.ts
35145
- var import_zod21 = require("zod");
35146
- var securityGroupRuleSchema = import_zod21.z.object({
35147
- id: import_zod21.z.string(),
35148
- direction: import_zod21.z.enum([
35639
+ var import_zod22 = require("zod");
35640
+ var securityGroupRuleSchema = import_zod22.z.object({
35641
+ id: import_zod22.z.string(),
35642
+ direction: import_zod22.z.enum([
35149
35643
  "ingress",
35150
35644
  "egress"
35151
35645
  ]).optional(),
35152
- ethertype: import_zod21.z.enum([
35646
+ ethertype: import_zod22.z.enum([
35153
35647
  "IPv4",
35154
35648
  "IPv6"
35155
35649
  ]).optional(),
35156
- description: import_zod21.z.string().nullable().optional(),
35157
- security_group_id: import_zod21.z.string().optional(),
35158
- protocol: import_zod21.z.string().nullable().optional(),
35159
- port_range_min: import_zod21.z.number().nullable().optional(),
35160
- port_range_max: import_zod21.z.number().nullable().optional(),
35161
- remote_ip_prefix: import_zod21.z.string().nullable().optional(),
35162
- remote_group_id: import_zod21.z.string().nullable().optional(),
35163
- remote_address_group_id: import_zod21.z.string().nullable().optional(),
35164
- tenant_id: import_zod21.z.string().nullable().optional(),
35165
- project_id: import_zod21.z.string().nullable().optional(),
35166
- revision_number: import_zod21.z.number().optional(),
35167
- tags: import_zod21.z.array(import_zod21.z.string()).optional(),
35168
- created_at: import_zod21.z.string().optional(),
35169
- updated_at: import_zod21.z.string().nullable().optional()
35170
- });
35171
- var securityGroupSchema = import_zod21.z.object({
35172
- id: import_zod21.z.string(),
35173
- name: import_zod21.z.string().nullable().optional(),
35174
- description: import_zod21.z.string().nullable().optional(),
35175
- tenant_id: import_zod21.z.string().nullable().optional(),
35176
- project_id: import_zod21.z.string().nullable().optional(),
35177
- stateful: import_zod21.z.boolean().optional(),
35178
- shared: import_zod21.z.boolean().optional(),
35179
- tags: import_zod21.z.array(import_zod21.z.string()).optional(),
35180
- security_group_rules: import_zod21.z.array(securityGroupRuleSchema).optional(),
35181
- revision_number: import_zod21.z.number().optional(),
35182
- created_at: import_zod21.z.string().optional(),
35183
- updated_at: import_zod21.z.string().nullable().optional()
35184
- });
35185
- var securityGroupsResponseSchema = import_zod21.z.object({
35186
- security_groups: import_zod21.z.array(securityGroupSchema)
35650
+ description: import_zod22.z.string().nullable().optional(),
35651
+ security_group_id: import_zod22.z.string().optional(),
35652
+ protocol: import_zod22.z.string().nullable().optional(),
35653
+ port_range_min: import_zod22.z.number().nullable().optional(),
35654
+ port_range_max: import_zod22.z.number().nullable().optional(),
35655
+ remote_ip_prefix: import_zod22.z.string().nullable().optional(),
35656
+ remote_group_id: import_zod22.z.string().nullable().optional(),
35657
+ remote_address_group_id: import_zod22.z.string().nullable().optional(),
35658
+ tenant_id: import_zod22.z.string().nullable().optional(),
35659
+ project_id: import_zod22.z.string().nullable().optional(),
35660
+ revision_number: import_zod22.z.number().optional(),
35661
+ tags: import_zod22.z.array(import_zod22.z.string()).optional(),
35662
+ created_at: import_zod22.z.string().optional(),
35663
+ updated_at: import_zod22.z.string().nullable().optional()
35187
35664
  });
35188
- var securityGroupResponseSchema = import_zod21.z.object({
35665
+ var securityGroupSchema = import_zod22.z.object({
35666
+ id: import_zod22.z.string(),
35667
+ name: import_zod22.z.string().nullable().optional(),
35668
+ description: import_zod22.z.string().nullable().optional(),
35669
+ tenant_id: import_zod22.z.string().nullable().optional(),
35670
+ project_id: import_zod22.z.string().nullable().optional(),
35671
+ stateful: import_zod22.z.boolean().optional(),
35672
+ shared: import_zod22.z.boolean().optional(),
35673
+ tags: import_zod22.z.array(import_zod22.z.string()).optional(),
35674
+ security_group_rules: import_zod22.z.array(securityGroupRuleSchema).optional(),
35675
+ revision_number: import_zod22.z.number().optional(),
35676
+ created_at: import_zod22.z.string().optional(),
35677
+ updated_at: import_zod22.z.string().nullable().optional()
35678
+ });
35679
+ var securityGroupsResponseSchema = import_zod22.z.object({
35680
+ security_groups: import_zod22.z.array(securityGroupSchema)
35681
+ });
35682
+ var securityGroupResponseSchema = import_zod22.z.object({
35189
35683
  security_group: securityGroupSchema
35190
35684
  });
35191
- var securityGroupRuleResponseSchema = import_zod21.z.object({
35685
+ var securityGroupRuleResponseSchema = import_zod22.z.object({
35192
35686
  security_group_rule: securityGroupRuleSchema
35193
35687
  });
35194
35688
  var listSecurityGroupsInputSchema = projectScopedInputSchema.extend({
35195
35689
  // Sorting
35196
- sort_key: import_zod21.z.string().optional(),
35690
+ sort_key: import_zod22.z.string().optional(),
35197
35691
  sort_dir: SortDirSchema.optional(),
35198
35692
  // Basic filtering
35199
- name: import_zod21.z.string().optional(),
35200
- description: import_zod21.z.string().optional(),
35201
- tenant_id: import_zod21.z.string().optional(),
35202
- shared: import_zod21.z.boolean().optional(),
35693
+ name: import_zod22.z.string().optional(),
35694
+ description: import_zod22.z.string().optional(),
35695
+ tenant_id: import_zod22.z.string().optional(),
35696
+ shared: import_zod22.z.boolean().optional(),
35203
35697
  // Tag-based filtering (string values follow Neutron semantics)
35204
- tags: import_zod21.z.string().optional(),
35205
- tags_any: import_zod21.z.string().optional(),
35206
- not_tags: import_zod21.z.string().optional(),
35207
- not_tags_any: import_zod21.z.string().optional(),
35698
+ tags: import_zod22.z.string().optional(),
35699
+ tags_any: import_zod22.z.string().optional(),
35700
+ not_tags: import_zod22.z.string().optional(),
35701
+ not_tags_any: import_zod22.z.string().optional(),
35208
35702
  // BFF-side search (filtered in BFF layer, not sent to OpenStack)
35209
- searchTerm: import_zod21.z.string().optional()
35703
+ searchTerm: import_zod22.z.string().optional()
35210
35704
  });
35211
35705
  var getSecurityGroupByIdInputSchema = projectScopedInputSchema.extend({
35212
- securityGroupId: import_zod21.z.string()
35706
+ securityGroupId: import_zod22.z.string()
35213
35707
  });
35214
35708
  var createSecurityGroupInputSchema = projectScopedInputSchema.extend({
35215
- name: import_zod21.z.string().min(1, "Name is required"),
35216
- description: import_zod21.z.string().optional(),
35217
- stateful: import_zod21.z.boolean().optional()
35709
+ name: import_zod22.z.string().min(1, "Name is required"),
35710
+ description: import_zod22.z.string().optional(),
35711
+ stateful: import_zod22.z.boolean().optional()
35218
35712
  });
35219
35713
  var deleteSecurityGroupInputSchema = projectScopedInputSchema.extend({
35220
- securityGroupId: import_zod21.z.string()
35714
+ securityGroupId: import_zod22.z.string()
35221
35715
  });
35222
35716
  var updateSecurityGroupInputSchema = projectScopedInputSchema.extend({
35223
- securityGroupId: import_zod21.z.string(),
35224
- name: import_zod21.z.string().min(1, "Name is required").optional(),
35225
- description: import_zod21.z.string().optional(),
35226
- stateful: import_zod21.z.boolean().optional()
35717
+ securityGroupId: import_zod22.z.string(),
35718
+ name: import_zod22.z.string().min(1, "Name is required").optional(),
35719
+ description: import_zod22.z.string().optional(),
35720
+ stateful: import_zod22.z.boolean().optional()
35227
35721
  });
35228
35722
  var deleteSecurityGroupRuleInputSchema = projectScopedInputSchema.extend({
35229
- ruleId: import_zod21.z.string()
35723
+ ruleId: import_zod22.z.string()
35230
35724
  });
35231
35725
  var createSecurityGroupRuleInputSchema = projectScopedInputSchema.extend({
35232
- security_group_id: import_zod21.z.string(),
35233
- direction: import_zod21.z.enum([
35726
+ security_group_id: import_zod22.z.string(),
35727
+ direction: import_zod22.z.enum([
35234
35728
  "ingress",
35235
35729
  "egress"
35236
35730
  ]),
35237
- ethertype: import_zod21.z.enum([
35731
+ ethertype: import_zod22.z.enum([
35238
35732
  "IPv4",
35239
35733
  "IPv6"
35240
35734
  ]).default("IPv4"),
35241
- description: import_zod21.z.string().optional(),
35242
- protocol: import_zod21.z.string().nullable().optional(),
35243
- port_range_min: import_zod21.z.number().int().max(65535).nullable().optional(),
35244
- port_range_max: import_zod21.z.number().int().max(65535).nullable().optional(),
35735
+ description: import_zod22.z.string().optional(),
35736
+ protocol: import_zod22.z.string().nullable().optional(),
35737
+ port_range_min: import_zod22.z.number().int().max(65535).nullable().optional(),
35738
+ port_range_max: import_zod22.z.number().int().max(65535).nullable().optional(),
35245
35739
  // Transform empty strings to undefined for proper validation
35246
- remote_ip_prefix: import_zod21.z.string().nullable().optional().transform((val) => val === "" ? void 0 : val),
35247
- remote_group_id: import_zod21.z.string().nullable().optional().transform((val) => val === "" ? void 0 : val),
35248
- remote_address_group_id: import_zod21.z.string().nullable().optional().transform((val) => val === "" ? void 0 : val)
35740
+ remote_ip_prefix: import_zod22.z.string().nullable().optional().transform((val) => val === "" ? void 0 : val),
35741
+ remote_group_id: import_zod22.z.string().nullable().optional().transform((val) => val === "" ? void 0 : val),
35742
+ remote_address_group_id: import_zod22.z.string().nullable().optional().transform((val) => val === "" ? void 0 : val)
35249
35743
  });
35250
35744
 
35251
35745
  // src/server/Network/helpers/securityGroupHelpers.ts
35252
- var import_server20 = require("@trpc/server");
35746
+ var import_server21 = require("@trpc/server");
35253
35747
  var SecurityGroupErrorHandlers = {
35254
35748
  /**
35255
35749
  * Handles errors specific to security group list operations
@@ -35259,17 +35753,17 @@ var SecurityGroupErrorHandlers = {
35259
35753
  list: /* @__PURE__ */ __name((response) => {
35260
35754
  switch (response.status) {
35261
35755
  case 401:
35262
- return new import_server20.TRPCError({
35756
+ return new import_server21.TRPCError({
35263
35757
  code: HTTP_STATUS_ERROR_MAP[401],
35264
35758
  message: "Unauthorized access"
35265
35759
  });
35266
35760
  case 403:
35267
- return new import_server20.TRPCError({
35761
+ return new import_server21.TRPCError({
35268
35762
  code: HTTP_STATUS_ERROR_MAP[403],
35269
35763
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
35270
35764
  });
35271
35765
  default:
35272
- return new import_server20.TRPCError({
35766
+ return new import_server21.TRPCError({
35273
35767
  code: DEFAULT_ERROR_NAME,
35274
35768
  message: `Failed to list security groups: ${response.statusText || "Unknown error"}`
35275
35769
  });
@@ -35284,22 +35778,22 @@ var SecurityGroupErrorHandlers = {
35284
35778
  getById: /* @__PURE__ */ __name((response, securityGroupId) => {
35285
35779
  switch (response.status) {
35286
35780
  case 401:
35287
- return new import_server20.TRPCError({
35781
+ return new import_server21.TRPCError({
35288
35782
  code: HTTP_STATUS_ERROR_MAP[401],
35289
35783
  message: "Unauthorized access"
35290
35784
  });
35291
35785
  case 403:
35292
- return new import_server20.TRPCError({
35786
+ return new import_server21.TRPCError({
35293
35787
  code: HTTP_STATUS_ERROR_MAP[403],
35294
35788
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
35295
35789
  });
35296
35790
  case 404:
35297
- return new import_server20.TRPCError({
35791
+ return new import_server21.TRPCError({
35298
35792
  code: HTTP_STATUS_ERROR_MAP[404],
35299
35793
  message: `Security group not found: ${securityGroupId}`
35300
35794
  });
35301
35795
  default:
35302
- return new import_server20.TRPCError({
35796
+ return new import_server21.TRPCError({
35303
35797
  code: DEFAULT_ERROR_NAME,
35304
35798
  message: `Failed to fetch security group: ${response.statusText || "Unknown error"}`
35305
35799
  });
@@ -35313,32 +35807,32 @@ var SecurityGroupErrorHandlers = {
35313
35807
  create: /* @__PURE__ */ __name((response) => {
35314
35808
  switch (response.status) {
35315
35809
  case 401:
35316
- return new import_server20.TRPCError({
35810
+ return new import_server21.TRPCError({
35317
35811
  code: HTTP_STATUS_ERROR_MAP[401],
35318
35812
  message: "Unauthorized access"
35319
35813
  });
35320
35814
  case 403:
35321
- return new import_server20.TRPCError({
35815
+ return new import_server21.TRPCError({
35322
35816
  code: HTTP_STATUS_ERROR_MAP[403],
35323
35817
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
35324
35818
  });
35325
35819
  case 409:
35326
- return new import_server20.TRPCError({
35820
+ return new import_server21.TRPCError({
35327
35821
  code: HTTP_STATUS_ERROR_MAP[409],
35328
35822
  message: `Conflict: ${response.statusText || "Security group already exists"}`
35329
35823
  });
35330
35824
  case 413:
35331
- return new import_server20.TRPCError({
35825
+ return new import_server21.TRPCError({
35332
35826
  code: "BAD_REQUEST",
35333
35827
  message: `Quota exceeded for security groups. Please delete an existing security group or contact your administrator to increase your quota.`
35334
35828
  });
35335
35829
  case 400:
35336
- return new import_server20.TRPCError({
35830
+ return new import_server21.TRPCError({
35337
35831
  code: "BAD_REQUEST",
35338
35832
  message: `Invalid request: ${response.statusText || "Unknown error"}`
35339
35833
  });
35340
35834
  default:
35341
- return new import_server20.TRPCError({
35835
+ return new import_server21.TRPCError({
35342
35836
  code: "INTERNAL_SERVER_ERROR",
35343
35837
  message: `Failed to create security group: ${response.statusText || "Unknown error"}`
35344
35838
  });
@@ -35353,22 +35847,22 @@ var SecurityGroupErrorHandlers = {
35353
35847
  delete: /* @__PURE__ */ __name((response, securityGroupId) => {
35354
35848
  switch (response.status) {
35355
35849
  case 401:
35356
- return new import_server20.TRPCError({
35850
+ return new import_server21.TRPCError({
35357
35851
  code: HTTP_STATUS_ERROR_MAP[401],
35358
35852
  message: "Unauthorized access"
35359
35853
  });
35360
35854
  case 404:
35361
- return new import_server20.TRPCError({
35855
+ return new import_server21.TRPCError({
35362
35856
  code: HTTP_STATUS_ERROR_MAP[404],
35363
35857
  message: `Security group not found: ${securityGroupId}`
35364
35858
  });
35365
35859
  case 409:
35366
- return new import_server20.TRPCError({
35860
+ return new import_server21.TRPCError({
35367
35861
  code: HTTP_STATUS_ERROR_MAP[409],
35368
35862
  message: "Cannot delete security group because it is in use by one or more ports. Please remove all associations before deleting."
35369
35863
  });
35370
35864
  default:
35371
- return new import_server20.TRPCError({
35865
+ return new import_server21.TRPCError({
35372
35866
  code: DEFAULT_ERROR_NAME,
35373
35867
  message: `Failed to delete security group: ${response.statusText || "Unknown error"}`
35374
35868
  });
@@ -35383,39 +35877,39 @@ var SecurityGroupErrorHandlers = {
35383
35877
  update: /* @__PURE__ */ __name((response, securityGroupId) => {
35384
35878
  const errorMessage = response.statusText || "";
35385
35879
  if (errorMessage.toLowerCase().includes("stateful") && errorMessage.toLowerCase().includes("in use")) {
35386
- return new import_server20.TRPCError({
35880
+ return new import_server21.TRPCError({
35387
35881
  code: "CONFLICT",
35388
35882
  message: "Cannot update the 'stateful' attribute because this security group is in use by one or more ports."
35389
35883
  });
35390
35884
  }
35391
35885
  switch (response.status) {
35392
35886
  case 401:
35393
- return new import_server20.TRPCError({
35887
+ return new import_server21.TRPCError({
35394
35888
  code: HTTP_STATUS_ERROR_MAP[401],
35395
35889
  message: "Unauthorized access"
35396
35890
  });
35397
35891
  case 403:
35398
- return new import_server20.TRPCError({
35892
+ return new import_server21.TRPCError({
35399
35893
  code: HTTP_STATUS_ERROR_MAP[403],
35400
35894
  message: `Access forbidden: ${errorMessage || "Unknown error"}`
35401
35895
  });
35402
35896
  case 404:
35403
- return new import_server20.TRPCError({
35897
+ return new import_server21.TRPCError({
35404
35898
  code: HTTP_STATUS_ERROR_MAP[404],
35405
35899
  message: `Security group not found: ${securityGroupId}`
35406
35900
  });
35407
35901
  case 409:
35408
- return new import_server20.TRPCError({
35902
+ return new import_server21.TRPCError({
35409
35903
  code: HTTP_STATUS_ERROR_MAP[409],
35410
35904
  message: `Conflict: ${errorMessage || "Security group conflict"}`
35411
35905
  });
35412
35906
  case 400:
35413
- return new import_server20.TRPCError({
35907
+ return new import_server21.TRPCError({
35414
35908
  code: HTTP_STATUS_ERROR_MAP[400],
35415
35909
  message: `Invalid request: ${errorMessage || "Unknown error"}`
35416
35910
  });
35417
35911
  default:
35418
- return new import_server20.TRPCError({
35912
+ return new import_server21.TRPCError({
35419
35913
  code: DEFAULT_ERROR_NAME,
35420
35914
  message: `Failed to update security group: ${errorMessage || "Unknown error"}`
35421
35915
  });
@@ -35433,48 +35927,48 @@ var SecurityGroupRuleErrorHandlers = {
35433
35927
  switch (response.status) {
35434
35928
  case 400:
35435
35929
  if (statusText.toLowerCase().includes("cidr")) {
35436
- return new import_server20.TRPCError({
35930
+ return new import_server21.TRPCError({
35437
35931
  code: "BAD_REQUEST",
35438
35932
  message: "Invalid CIDR format. Please provide a valid IP address block (e.g., 0.0.0.0/0)"
35439
35933
  });
35440
35934
  }
35441
35935
  if (statusText.toLowerCase().includes("port")) {
35442
- return new import_server20.TRPCError({
35936
+ return new import_server21.TRPCError({
35443
35937
  code: "BAD_REQUEST",
35444
35938
  message: "Invalid port range. Ports must be between 1 and 65535, and min must be <= max"
35445
35939
  });
35446
35940
  }
35447
- return new import_server20.TRPCError({
35941
+ return new import_server21.TRPCError({
35448
35942
  code: "BAD_REQUEST",
35449
35943
  message: `Invalid request: ${statusText}`
35450
35944
  });
35451
35945
  case 401:
35452
- return new import_server20.TRPCError({
35946
+ return new import_server21.TRPCError({
35453
35947
  code: "UNAUTHORIZED",
35454
35948
  message: "Unauthorized access"
35455
35949
  });
35456
35950
  case 403:
35457
- return new import_server20.TRPCError({
35951
+ return new import_server21.TRPCError({
35458
35952
  code: "FORBIDDEN",
35459
35953
  message: `Access forbidden: ${statusText}`
35460
35954
  });
35461
35955
  case 404:
35462
- return new import_server20.TRPCError({
35956
+ return new import_server21.TRPCError({
35463
35957
  code: "NOT_FOUND",
35464
35958
  message: "Security group not found"
35465
35959
  });
35466
35960
  case 409:
35467
- return new import_server20.TRPCError({
35961
+ return new import_server21.TRPCError({
35468
35962
  code: "CONFLICT",
35469
35963
  message: "A rule with these parameters already exists in this security group"
35470
35964
  });
35471
35965
  case 413:
35472
- return new import_server20.TRPCError({
35966
+ return new import_server21.TRPCError({
35473
35967
  code: "BAD_REQUEST",
35474
35968
  message: "Quota exceeded for security group rules. Please delete existing rules or contact your administrator."
35475
35969
  });
35476
35970
  default:
35477
- return new import_server20.TRPCError({
35971
+ return new import_server21.TRPCError({
35478
35972
  code: "INTERNAL_SERVER_ERROR",
35479
35973
  message: `Failed to create security group rule: ${statusText}`
35480
35974
  });
@@ -35493,22 +35987,22 @@ var SecurityGroupRuleErrorHandlers = {
35493
35987
  delete: /* @__PURE__ */ __name((response, ruleId) => {
35494
35988
  switch (response.status) {
35495
35989
  case 401:
35496
- return new import_server20.TRPCError({
35990
+ return new import_server21.TRPCError({
35497
35991
  code: "UNAUTHORIZED",
35498
35992
  message: "Unauthorized access"
35499
35993
  });
35500
35994
  case 404:
35501
- return new import_server20.TRPCError({
35995
+ return new import_server21.TRPCError({
35502
35996
  code: "NOT_FOUND",
35503
35997
  message: `Security group rule not found: ${ruleId}`
35504
35998
  });
35505
35999
  case 412:
35506
- return new import_server20.TRPCError({
36000
+ return new import_server21.TRPCError({
35507
36001
  code: "PRECONDITION_FAILED",
35508
36002
  message: `Cannot delete security group rule: precondition failed`
35509
36003
  });
35510
36004
  default:
35511
- return new import_server20.TRPCError({
36005
+ return new import_server21.TRPCError({
35512
36006
  code: "INTERNAL_SERVER_ERROR",
35513
36007
  message: `Failed to delete security group rule: ${response.statusText || "Unknown error"}`
35514
36008
  });
@@ -35519,7 +36013,7 @@ var parseOpenStackResponse = /* @__PURE__ */ __name((data, schema, operation, er
35519
36013
  const parsed = schema.safeParse(data);
35520
36014
  if (!parsed.success) {
35521
36015
  console.error(`Zod Parsing Error in ${operation}:`, parsed.error.format());
35522
- throw new import_server20.TRPCError({
36016
+ throw new import_server21.TRPCError({
35523
36017
  code: "INTERNAL_SERVER_ERROR",
35524
36018
  message: errorMessage
35525
36019
  });
@@ -35763,46 +36257,46 @@ var securityGroupRuleRouter = {
35763
36257
  };
35764
36258
 
35765
36259
  // src/server/Network/types/rbacPolicy.ts
35766
- var import_zod22 = require("zod");
35767
- var rbacPolicySchema = import_zod22.z.object({
35768
- id: import_zod22.z.string(),
35769
- object_type: import_zod22.z.enum([
36260
+ var import_zod23 = require("zod");
36261
+ var rbacPolicySchema = import_zod23.z.object({
36262
+ id: import_zod23.z.string(),
36263
+ object_type: import_zod23.z.enum([
35770
36264
  "qos_policy",
35771
36265
  "network",
35772
36266
  "security_group"
35773
36267
  ]),
35774
- object_id: import_zod22.z.string(),
35775
- action: import_zod22.z.enum([
36268
+ object_id: import_zod23.z.string(),
36269
+ action: import_zod23.z.enum([
35776
36270
  "access_as_shared",
35777
36271
  "access_as_external"
35778
36272
  ]),
35779
- target_tenant: import_zod22.z.string(),
35780
- tenant_id: import_zod22.z.string().nullable().optional(),
35781
- project_id: import_zod22.z.string().nullable().optional()
36273
+ target_tenant: import_zod23.z.string(),
36274
+ tenant_id: import_zod23.z.string().nullable().optional(),
36275
+ project_id: import_zod23.z.string().nullable().optional()
35782
36276
  });
35783
- var rbacPoliciesResponseSchema = import_zod22.z.object({
35784
- rbac_policies: import_zod22.z.array(rbacPolicySchema)
36277
+ var rbacPoliciesResponseSchema = import_zod23.z.object({
36278
+ rbac_policies: import_zod23.z.array(rbacPolicySchema)
35785
36279
  });
35786
- var rbacPolicyResponseSchema = import_zod22.z.object({
36280
+ var rbacPolicyResponseSchema = import_zod23.z.object({
35787
36281
  rbac_policy: rbacPolicySchema
35788
36282
  });
35789
36283
  var listRBACPoliciesForSecurityGroupInputSchema = projectScopedInputSchema.extend({
35790
- securityGroupId: import_zod22.z.string()
36284
+ securityGroupId: import_zod23.z.string()
35791
36285
  });
35792
36286
  var createRBACPolicyInputSchema = projectScopedInputSchema.extend({
35793
- securityGroupId: import_zod22.z.string(),
35794
- targetTenant: import_zod22.z.string().trim().min(1, "Target project ID is required")
36287
+ securityGroupId: import_zod23.z.string(),
36288
+ targetTenant: import_zod23.z.string().trim().min(1, "Target project ID is required")
35795
36289
  });
35796
36290
  var updateRBACPolicyInputSchema = projectScopedInputSchema.extend({
35797
- policyId: import_zod22.z.string(),
35798
- targetTenant: import_zod22.z.string().trim().min(1, "Target project ID is required")
36291
+ policyId: import_zod23.z.string(),
36292
+ targetTenant: import_zod23.z.string().trim().min(1, "Target project ID is required")
35799
36293
  });
35800
36294
  var deleteRBACPolicyInputSchema = projectScopedInputSchema.extend({
35801
- policyId: import_zod22.z.string()
36295
+ policyId: import_zod23.z.string()
35802
36296
  });
35803
36297
 
35804
36298
  // src/server/Network/helpers/rbacPolicyHelpers.ts
35805
- var import_server21 = require("@trpc/server");
36299
+ var import_server22 = require("@trpc/server");
35806
36300
  var RBACPolicyErrorHandlers = {
35807
36301
  /**
35808
36302
  * Handles errors specific to RBAC policy list operations
@@ -35812,17 +36306,17 @@ var RBACPolicyErrorHandlers = {
35812
36306
  list: /* @__PURE__ */ __name((response) => {
35813
36307
  switch (response.status) {
35814
36308
  case 401:
35815
- return new import_server21.TRPCError({
36309
+ return new import_server22.TRPCError({
35816
36310
  code: HTTP_STATUS_ERROR_MAP[401],
35817
36311
  message: "Unauthorized access"
35818
36312
  });
35819
36313
  case 403:
35820
- return new import_server21.TRPCError({
36314
+ return new import_server22.TRPCError({
35821
36315
  code: HTTP_STATUS_ERROR_MAP[403],
35822
36316
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
35823
36317
  });
35824
36318
  default:
35825
- return new import_server21.TRPCError({
36319
+ return new import_server22.TRPCError({
35826
36320
  code: DEFAULT_ERROR_NAME,
35827
36321
  message: `Failed to list RBAC policies: ${response.statusText || "Unknown error"}`
35828
36322
  });
@@ -35836,32 +36330,32 @@ var RBACPolicyErrorHandlers = {
35836
36330
  create: /* @__PURE__ */ __name((response) => {
35837
36331
  switch (response.status) {
35838
36332
  case 400:
35839
- return new import_server21.TRPCError({
36333
+ return new import_server22.TRPCError({
35840
36334
  code: HTTP_STATUS_ERROR_MAP[400],
35841
36335
  message: `Invalid request: ${response.statusText || "Unknown error"}`
35842
36336
  });
35843
36337
  case 401:
35844
- return new import_server21.TRPCError({
36338
+ return new import_server22.TRPCError({
35845
36339
  code: HTTP_STATUS_ERROR_MAP[401],
35846
36340
  message: "Unauthorized access"
35847
36341
  });
35848
36342
  case 403:
35849
- return new import_server21.TRPCError({
36343
+ return new import_server22.TRPCError({
35850
36344
  code: HTTP_STATUS_ERROR_MAP[403],
35851
36345
  message: "You don't have permission to share this security group"
35852
36346
  });
35853
36347
  case 404:
35854
- return new import_server21.TRPCError({
36348
+ return new import_server22.TRPCError({
35855
36349
  code: HTTP_STATUS_ERROR_MAP[404],
35856
36350
  message: "Security group not found or target project does not exist"
35857
36351
  });
35858
36352
  case 409:
35859
- return new import_server21.TRPCError({
36353
+ return new import_server22.TRPCError({
35860
36354
  code: HTTP_STATUS_ERROR_MAP[409],
35861
36355
  message: "This security group is already shared with the specified project"
35862
36356
  });
35863
36357
  default:
35864
- return new import_server21.TRPCError({
36358
+ return new import_server22.TRPCError({
35865
36359
  code: "INTERNAL_SERVER_ERROR",
35866
36360
  message: `Failed to create RBAC policy: ${response.statusText || "Unknown error"}`
35867
36361
  });
@@ -35876,27 +36370,27 @@ var RBACPolicyErrorHandlers = {
35876
36370
  update: /* @__PURE__ */ __name((response, policyId) => {
35877
36371
  switch (response.status) {
35878
36372
  case 400:
35879
- return new import_server21.TRPCError({
36373
+ return new import_server22.TRPCError({
35880
36374
  code: HTTP_STATUS_ERROR_MAP[400],
35881
36375
  message: `Invalid request: ${response.statusText || "Unknown error"}`
35882
36376
  });
35883
36377
  case 401:
35884
- return new import_server21.TRPCError({
36378
+ return new import_server22.TRPCError({
35885
36379
  code: HTTP_STATUS_ERROR_MAP[401],
35886
36380
  message: "Unauthorized access"
35887
36381
  });
35888
36382
  case 403:
35889
- return new import_server21.TRPCError({
36383
+ return new import_server22.TRPCError({
35890
36384
  code: HTTP_STATUS_ERROR_MAP[403],
35891
36385
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
35892
36386
  });
35893
36387
  case 404:
35894
- return new import_server21.TRPCError({
36388
+ return new import_server22.TRPCError({
35895
36389
  code: HTTP_STATUS_ERROR_MAP[404],
35896
36390
  message: `RBAC policy not found: ${policyId}`
35897
36391
  });
35898
36392
  default:
35899
- return new import_server21.TRPCError({
36393
+ return new import_server22.TRPCError({
35900
36394
  code: "INTERNAL_SERVER_ERROR",
35901
36395
  message: `Failed to update RBAC policy: ${response.statusText || "Unknown error"}`
35902
36396
  });
@@ -35911,22 +36405,22 @@ var RBACPolicyErrorHandlers = {
35911
36405
  delete: /* @__PURE__ */ __name((response, policyId) => {
35912
36406
  switch (response.status) {
35913
36407
  case 401:
35914
- return new import_server21.TRPCError({
36408
+ return new import_server22.TRPCError({
35915
36409
  code: HTTP_STATUS_ERROR_MAP[401],
35916
36410
  message: "Unauthorized access"
35917
36411
  });
35918
36412
  case 404:
35919
- return new import_server21.TRPCError({
36413
+ return new import_server22.TRPCError({
35920
36414
  code: HTTP_STATUS_ERROR_MAP[404],
35921
36415
  message: `RBAC policy not found: ${policyId}`
35922
36416
  });
35923
36417
  case 409:
35924
- return new import_server21.TRPCError({
36418
+ return new import_server22.TRPCError({
35925
36419
  code: HTTP_STATUS_ERROR_MAP[409],
35926
36420
  message: "Cannot delete RBAC policy because it is in use"
35927
36421
  });
35928
36422
  default:
35929
- return new import_server21.TRPCError({
36423
+ return new import_server22.TRPCError({
35930
36424
  code: DEFAULT_ERROR_NAME,
35931
36425
  message: `Failed to delete RBAC policy: ${response.statusText || "Unknown error"}`
35932
36426
  });
@@ -35937,7 +36431,7 @@ var parseOpenStackResponse2 = /* @__PURE__ */ __name((data, schema, operation, e
35937
36431
  const parsed = schema.safeParse(data);
35938
36432
  if (!parsed.success) {
35939
36433
  console.error(`Zod Parsing Error in ${operation}:`, parsed.error.format());
35940
- throw new import_server21.TRPCError({
36434
+ throw new import_server22.TRPCError({
35941
36435
  code: "INTERNAL_SERVER_ERROR",
35942
36436
  message: errorMessage
35943
36437
  });
@@ -36024,128 +36518,344 @@ var rbacPolicyRouter = {
36024
36518
  })
36025
36519
  };
36026
36520
 
36521
+ // src/server/Network/routers/permissionRouter.ts
36522
+ var NETWORK_MAPPINGS = {
36523
+ // Network Operations
36524
+ "network:networks:read": {
36525
+ engine: "network",
36526
+ rule: "get_network"
36527
+ },
36528
+ "network:networks:list": {
36529
+ engine: "network",
36530
+ rule: "get_network"
36531
+ },
36532
+ "network:networks:create": {
36533
+ engine: "network",
36534
+ rule: "create_network"
36535
+ },
36536
+ "network:networks:update": {
36537
+ engine: "network",
36538
+ rule: "update_network"
36539
+ },
36540
+ "network:networks:delete": {
36541
+ engine: "network",
36542
+ rule: "delete_network"
36543
+ },
36544
+ // Subnet Operations
36545
+ "network:subnets:read": {
36546
+ engine: "network",
36547
+ rule: "get_subnet"
36548
+ },
36549
+ "network:subnets:list": {
36550
+ engine: "network",
36551
+ rule: "get_subnet"
36552
+ },
36553
+ "network:subnets:create": {
36554
+ engine: "network",
36555
+ rule: "create_subnet"
36556
+ },
36557
+ "network:subnets:update": {
36558
+ engine: "network",
36559
+ rule: "update_subnet"
36560
+ },
36561
+ "network:subnets:delete": {
36562
+ engine: "network",
36563
+ rule: "delete_subnet"
36564
+ },
36565
+ // Subnet Pool Operations
36566
+ "network:subnet_pools:read": {
36567
+ engine: "network",
36568
+ rule: "get_subnetpool"
36569
+ },
36570
+ "network:subnet_pools:list": {
36571
+ engine: "network",
36572
+ rule: "get_subnetpool"
36573
+ },
36574
+ "network:subnet_pools:create": {
36575
+ engine: "network",
36576
+ rule: "create_subnetpool"
36577
+ },
36578
+ "network:subnet_pools:update": {
36579
+ engine: "network",
36580
+ rule: "update_subnetpool"
36581
+ },
36582
+ "network:subnet_pools:delete": {
36583
+ engine: "network",
36584
+ rule: "delete_subnetpool"
36585
+ },
36586
+ // Router Operations
36587
+ "network:routers:read": {
36588
+ engine: "network",
36589
+ rule: "get_router"
36590
+ },
36591
+ "network:routers:list": {
36592
+ engine: "network",
36593
+ rule: "get_router"
36594
+ },
36595
+ "network:routers:create": {
36596
+ engine: "network",
36597
+ rule: "create_router"
36598
+ },
36599
+ "network:routers:update": {
36600
+ engine: "network",
36601
+ rule: "update_router"
36602
+ },
36603
+ "network:routers:delete": {
36604
+ engine: "network",
36605
+ rule: "delete_router"
36606
+ },
36607
+ "network:routers:attach_interface": {
36608
+ engine: "network",
36609
+ rule: "add_router_interface"
36610
+ },
36611
+ "network:routers:detach_interface": {
36612
+ engine: "network",
36613
+ rule: "remove_router_interface"
36614
+ },
36615
+ // Floating IP Operations
36616
+ "network:floatingips:read": {
36617
+ engine: "network",
36618
+ rule: "get_floatingip"
36619
+ },
36620
+ "network:floatingips:list": {
36621
+ engine: "network",
36622
+ rule: "get_floatingip"
36623
+ },
36624
+ "network:floatingips:create": {
36625
+ engine: "network",
36626
+ rule: "create_floatingip"
36627
+ },
36628
+ "network:floatingips:update": {
36629
+ engine: "network",
36630
+ rule: "update_floatingip"
36631
+ },
36632
+ "network:floatingips:delete": {
36633
+ engine: "network",
36634
+ rule: "delete_floatingip"
36635
+ },
36636
+ "network:floatingips:associate": {
36637
+ engine: "network",
36638
+ rule: "update_floatingip"
36639
+ },
36640
+ "network:floatingips:disassociate": {
36641
+ engine: "network",
36642
+ rule: "update_floatingip"
36643
+ },
36644
+ // Security Group Operations
36645
+ "network:security_groups:read": {
36646
+ engine: "network",
36647
+ rule: "get_security_group"
36648
+ },
36649
+ "network:security_groups:list": {
36650
+ engine: "network",
36651
+ rule: "get_security_groups"
36652
+ },
36653
+ "network:security_groups:create": {
36654
+ engine: "network",
36655
+ rule: "create_security_group"
36656
+ },
36657
+ "network:security_groups:update": {
36658
+ engine: "network",
36659
+ rule: "update_security_group"
36660
+ },
36661
+ "network:security_groups:delete": {
36662
+ engine: "network",
36663
+ rule: "delete_security_group"
36664
+ },
36665
+ // Security Group Rule Operations
36666
+ "network:security_group_rules:read": {
36667
+ engine: "network",
36668
+ rule: "get_security_group_rule"
36669
+ },
36670
+ "network:security_group_rules:list": {
36671
+ engine: "network",
36672
+ rule: "get_security_group_rules"
36673
+ },
36674
+ "network:security_group_rules:create": {
36675
+ engine: "network",
36676
+ rule: "create_security_group_rule"
36677
+ },
36678
+ "network:security_group_rules:update": {
36679
+ engine: "network",
36680
+ rule: "update_security_group_rule"
36681
+ },
36682
+ "network:security_group_rules:delete": {
36683
+ engine: "network",
36684
+ rule: "delete_security_group_rule"
36685
+ },
36686
+ // Port Operations
36687
+ "network:ports:read": {
36688
+ engine: "network",
36689
+ rule: "get_port"
36690
+ },
36691
+ "network:ports:list": {
36692
+ engine: "network",
36693
+ rule: "get_port"
36694
+ },
36695
+ "network:ports:create": {
36696
+ engine: "network",
36697
+ rule: "create_port"
36698
+ },
36699
+ "network:ports:update": {
36700
+ engine: "network",
36701
+ rule: "update_port"
36702
+ },
36703
+ "network:ports:delete": {
36704
+ engine: "network",
36705
+ rule: "delete_port"
36706
+ },
36707
+ // RBAC Policy Operations
36708
+ "network:rbac_policies:read": {
36709
+ engine: "network",
36710
+ rule: "get_rbac_policy"
36711
+ },
36712
+ "network:rbac_policies:list": {
36713
+ engine: "network",
36714
+ rule: "get_rbac_policy"
36715
+ },
36716
+ "network:rbac_policies:create": {
36717
+ engine: "network",
36718
+ rule: "create_rbac_policy"
36719
+ },
36720
+ "network:rbac_policies:update": {
36721
+ engine: "network",
36722
+ rule: "update_rbac_policy"
36723
+ },
36724
+ "network:rbac_policies:delete": {
36725
+ engine: "network",
36726
+ rule: "delete_rbac_policy"
36727
+ }
36728
+ };
36729
+ var buildNetworkPermissionRouter = /* @__PURE__ */ __name((policyDir) => createPermissionRouter({
36730
+ policyDir,
36731
+ engines: {
36732
+ network: {
36733
+ fileName: "networking.json"
36734
+ }
36735
+ },
36736
+ mappings: NETWORK_MAPPINGS
36737
+ }), "buildNetworkPermissionRouter");
36738
+
36027
36739
  // src/server/Network/routers/index.ts
36028
- var networkRouters = {
36740
+ var buildNetworkRouters = /* @__PURE__ */ __name((policyDir) => ({
36029
36741
  network: auroraRouter({
36030
36742
  floatingIp: floatingIpRouter,
36031
36743
  securityGroup: securityGroupRouter,
36032
36744
  securityGroupRule: securityGroupRuleRouter,
36033
- rbacPolicy: rbacPolicyRouter
36745
+ rbacPolicy: rbacPolicyRouter,
36746
+ ...buildNetworkPermissionRouter(policyDir)
36034
36747
  })
36035
- };
36748
+ }), "buildNetworkRouters");
36036
36749
 
36037
36750
  // src/server/Services/types/pca.ts
36038
- var import_zod23 = require("zod");
36039
- var CertificateValiditySchema = import_zod23.z.object({
36040
- not_after: import_zod23.z.number().int(),
36041
- not_before: import_zod23.z.number().int().optional()
36751
+ var import_zod24 = require("zod");
36752
+ var CertificateValiditySchema = import_zod24.z.object({
36753
+ not_after: import_zod24.z.number().int(),
36754
+ not_before: import_zod24.z.number().int().optional()
36042
36755
  });
36043
- var CertificateAuthorityCertificateSchema = import_zod23.z.object({
36756
+ var CertificateAuthorityCertificateSchema = import_zod24.z.object({
36044
36757
  /** PEM encoded certificate data. */
36045
- pem: import_zod23.z.string(),
36758
+ pem: import_zod24.z.string(),
36046
36759
  validity: CertificateValiditySchema
36047
36760
  });
36048
- var CertificateAuthorityCertificateChainSchema = import_zod23.z.object({
36049
- certificates: import_zod23.z.array(import_zod23.z.object({
36050
- pem: import_zod23.z.string()
36761
+ var CertificateAuthorityCertificateChainSchema = import_zod24.z.object({
36762
+ certificates: import_zod24.z.array(import_zod24.z.object({
36763
+ pem: import_zod24.z.string()
36051
36764
  })),
36052
36765
  /** Concatenated PEM certificates of the chain. */
36053
- pem: import_zod23.z.string()
36766
+ pem: import_zod24.z.string()
36054
36767
  });
36055
- var CertificateAuthorityAdditionalAttributeSchema = import_zod23.z.object({
36768
+ var CertificateAuthorityAdditionalAttributeSchema = import_zod24.z.object({
36056
36769
  /** ASN.1 Object Identifier of the attribute */
36057
- key: import_zod23.z.array(import_zod23.z.number().int()),
36058
- value: import_zod23.z.string()
36770
+ key: import_zod24.z.array(import_zod24.z.number().int()),
36771
+ value: import_zod24.z.string()
36059
36772
  });
36060
- var CertificateAuthoritySubjectSchema = import_zod23.z.object({
36061
- additional_attribute: import_zod23.z.array(CertificateAuthorityAdditionalAttributeSchema).optional(),
36773
+ var CertificateAuthoritySubjectSchema = import_zod24.z.object({
36774
+ additional_attribute: import_zod24.z.array(CertificateAuthorityAdditionalAttributeSchema).optional(),
36062
36775
  /** Typically domain name */
36063
- common_name: import_zod23.z.string(),
36776
+ common_name: import_zod24.z.string(),
36064
36777
  /** Country codes (ISO 3166-1 alpha-2). */
36065
- country: import_zod23.z.array(import_zod23.z.string()).optional(),
36778
+ country: import_zod24.z.array(import_zod24.z.string()).optional(),
36066
36779
  /** Locality/city names. */
36067
- locality: import_zod23.z.array(import_zod23.z.string()).optional(),
36780
+ locality: import_zod24.z.array(import_zod24.z.string()).optional(),
36068
36781
  /** Organization names. */
36069
- organization: import_zod23.z.array(import_zod23.z.string()).optional(),
36782
+ organization: import_zod24.z.array(import_zod24.z.string()).optional(),
36070
36783
  /** Organizational unit names. */
36071
- organizational_unit: import_zod23.z.array(import_zod23.z.string()).optional(),
36784
+ organizational_unit: import_zod24.z.array(import_zod24.z.string()).optional(),
36072
36785
  /** Postal/ZIP codes. */
36073
- postal_code: import_zod23.z.array(import_zod23.z.string()).optional(),
36786
+ postal_code: import_zod24.z.array(import_zod24.z.string()).optional(),
36074
36787
  /** State or province names. */
36075
- province: import_zod23.z.array(import_zod23.z.string()).optional(),
36076
- serial_number: import_zod23.z.string().optional(),
36077
- street_address: import_zod23.z.array(import_zod23.z.string()).optional()
36788
+ province: import_zod24.z.array(import_zod24.z.string()).optional(),
36789
+ serial_number: import_zod24.z.string().optional(),
36790
+ street_address: import_zod24.z.array(import_zod24.z.string()).optional()
36078
36791
  });
36079
- var CertificateAuthorityStateSchema = import_zod23.z.enum([
36792
+ var CertificateAuthorityStateSchema = import_zod24.z.enum([
36080
36793
  "CREATING",
36081
36794
  "AWAITING_CERTIFICATE",
36082
36795
  "READY",
36083
36796
  "FAILED",
36084
36797
  "UNEXPECTED"
36085
36798
  ]);
36086
- var CertificateAuthoritySchema = import_zod23.z.object({
36799
+ var CertificateAuthoritySchema = import_zod24.z.object({
36087
36800
  certificate: CertificateAuthorityCertificateSchema.optional(),
36088
36801
  /** Details of Certificate Authority certificate's issuers chain. */
36089
36802
  certificate_chain: CertificateAuthorityCertificateChainSchema.optional(),
36090
- configuration: import_zod23.z.object({
36803
+ configuration: import_zod24.z.object({
36091
36804
  /** X.509 subject of Certificate Authority. Required on create operation. */
36092
36805
  subject: CertificateAuthoritySubjectSchema
36093
36806
  }).optional(),
36094
- csr: import_zod23.z.string().optional(),
36095
- id: import_zod23.z.string(),
36807
+ csr: import_zod24.z.string().optional(),
36808
+ id: import_zod24.z.string(),
36096
36809
  /**
36097
36810
  * Required on import certificate operation.
36098
36811
  * Certificate Authority certificate chain, in PEM format. Consists of concatenated string
36099
36812
  * of Certificate Authority certificate, followed by its intermediate issuing CAs certificates
36100
36813
  * and root issuing CA certificate last.
36101
36814
  */
36102
- imported_certificate_chain: import_zod23.z.string().optional(),
36815
+ imported_certificate_chain: import_zod24.z.string().optional(),
36103
36816
  /** Identifier of OpenStack project that Certificate Authority belongs. */
36104
- project_id: import_zod23.z.string(),
36817
+ project_id: import_zod24.z.string(),
36105
36818
  /** Current operational state of Certificate Authority. */
36106
36819
  state: CertificateAuthorityStateSchema
36107
36820
  });
36108
- var CertificateAuthorityResponseSchema = import_zod23.z.object({
36109
- certificate_authority: CertificateAuthoritySchema
36110
- });
36111
- var CertificateAuthoritiesListSchema = import_zod23.z.object({
36112
- certificate_authorities: import_zod23.z.array(CertificateAuthoritySchema)
36821
+ var CertificateAuthoritiesListSchema = import_zod24.z.object({
36822
+ certificate_authorities: import_zod24.z.array(CertificateAuthoritySchema)
36113
36823
  });
36114
- var CertificateAuthorityCreateSchema = import_zod23.z.object({
36115
- configuration: import_zod23.z.object({
36824
+ var CertificateAuthorityCreateSchema = import_zod24.z.object({
36825
+ configuration: import_zod24.z.object({
36116
36826
  subject: CertificateAuthoritySubjectSchema
36117
36827
  })
36118
36828
  });
36119
- var CertificateAuthorityIdInputSchema = import_zod23.z.object({
36120
- project_id: import_zod23.z.string(),
36121
- certificate_authority_id: import_zod23.z.string().min(1)
36829
+ var CertificateAuthorityIdInputSchema = import_zod24.z.object({
36830
+ project_id: import_zod24.z.string(),
36831
+ certificate_authority_id: import_zod24.z.string().min(1)
36122
36832
  });
36123
36833
  var CertificateAuthorityImportInputSchema = CertificateAuthorityIdInputSchema.extend({
36124
- imported_certificate_chain: import_zod23.z.string().min(1)
36834
+ imported_certificate_chain: import_zod24.z.string().min(1)
36125
36835
  });
36126
36836
  var CertificateIdInputSchema = CertificateAuthorityIdInputSchema.extend({
36127
- certificate_id: import_zod23.z.string().min(1)
36837
+ certificate_id: import_zod24.z.string().min(1)
36128
36838
  });
36129
- var CertificateConfigurationSchema = import_zod23.z.object({
36839
+ var CertificateConfigurationSchema = import_zod24.z.object({
36130
36840
  validity: CertificateValiditySchema
36131
36841
  });
36132
- var CreateCertificateInputSchema = import_zod23.z.object({
36133
- project_id: import_zod23.z.string(),
36134
- certificate_authority_id: import_zod23.z.string().min(1),
36135
- csr: import_zod23.z.string().min(1),
36842
+ var CreateCertificateInputSchema = import_zod24.z.object({
36843
+ project_id: import_zod24.z.string(),
36844
+ certificate_authority_id: import_zod24.z.string().min(1),
36845
+ csr: import_zod24.z.string().min(1),
36136
36846
  configuration: CertificateConfigurationSchema
36137
36847
  });
36138
- var CertificateSchema = import_zod23.z.object({
36848
+ var CertificateSchema = import_zod24.z.object({
36139
36849
  certificate: CertificateAuthorityCertificateSchema.optional(),
36140
- certificate_authority_id: import_zod23.z.string(),
36850
+ certificate_authority_id: import_zod24.z.string(),
36141
36851
  certificate_chain: CertificateAuthorityCertificateChainSchema.optional(),
36142
36852
  configuration: CertificateConfigurationSchema.optional(),
36143
- csr: import_zod23.z.string().optional(),
36144
- id: import_zod23.z.string(),
36145
- project_id: import_zod23.z.string()
36853
+ csr: import_zod24.z.string().optional(),
36854
+ id: import_zod24.z.string(),
36855
+ project_id: import_zod24.z.string()
36146
36856
  });
36147
- var CertificatesListSchema = import_zod23.z.object({
36148
- certificates: import_zod23.z.array(CertificateSchema)
36857
+ var CertificatesListSchema = import_zod24.z.object({
36858
+ certificates: import_zod24.z.array(CertificateSchema)
36149
36859
  });
36150
36860
 
36151
36861
  // src/server/Services/routers/pcaRouter.ts
@@ -36200,16 +36910,14 @@ var pcaRouter = {
36200
36910
  */
36201
36911
  import: projectScopedProcedure.input(CertificateAuthorityImportInputSchema).mutation(async ({ input, ctx }) => {
36202
36912
  return withErrorHandling3(async () => {
36203
- const pca = ctx.openstack?.service("clavis");
36204
- validateOpenstackService(pca, "clavis");
36913
+ const pca = ctx.openstack?.service("pca");
36914
+ validateOpenstackService(pca, "pca");
36205
36915
  const url = `${PCA_BASE_URL}/${input.certificate_authority_id}:importCertificate`;
36206
36916
  const response = await pca.post(url, {
36207
- body: JSON.stringify({
36208
- imported_certificate_chain: input.imported_certificate_chain
36209
- })
36917
+ imported_certificate_chain: input.imported_certificate_chain
36210
36918
  });
36211
36919
  const data = await response.json();
36212
- return parseOrThrow(CertificateAuthorityResponseSchema, data, "pcaRouter.import").certificate_authority;
36920
+ return parseOrThrow(CertificateAuthoritySchema, data, "pcaRouter.import");
36213
36921
  }, "import certificate of certificate authority");
36214
36922
  }),
36215
36923
  listCertificates: projectScopedProcedure.input(CertificateAuthorityIdInputSchema).query(async ({ input, ctx }) => {
@@ -36252,10 +36960,10 @@ var serviceRouters = {
36252
36960
  };
36253
36961
 
36254
36962
  // src/server/routers.ts
36255
- var appRouter = mergeRouters(auroraRouter(authRouters), auroraRouter(computeRouters), auroraRouter(objectStorageRouters), auroraRouter(projectRouters), auroraRouter(networkRouters), auroraRouter(serviceRouters));
36963
+ var buildAppRouter = /* @__PURE__ */ __name((policyDir) => mergeRouters(auroraRouter(authRouters), auroraRouter(buildComputeRouters(policyDir)), auroraRouter(buildObjectStorageRouters(policyDir)), auroraRouter(projectRouters), auroraRouter(buildNetworkRouters(policyDir)), auroraRouter(serviceRouters)), "buildAppRouter");
36256
36964
 
36257
36965
  // src/server/context.ts
36258
- var import_signal_openstack = __toESM(require_esm2());
36966
+ var import_signal_openstack2 = __toESM(require_esm2());
36259
36967
 
36260
36968
  // src/server/sessionCookie.ts
36261
36969
  var import_cookie = require("@fastify/cookie");
@@ -36356,7 +37064,7 @@ async function createContext(opts, config) {
36356
37064
  writable: false
36357
37065
  });
36358
37066
  if (currentAuthToken) {
36359
- openstackSession = await (0, import_signal_openstack.SignalOpenstackSession)(normalizedEndpoint, {
37067
+ openstackSession = await (0, import_signal_openstack2.SignalOpenstackSession)(normalizedEndpoint, {
36360
37068
  auth: {
36361
37069
  identity: {
36362
37070
  methods: [
@@ -36419,7 +37127,7 @@ async function createContext(opts, config) {
36419
37127
  }
36420
37128
  }, "getUserInfo");
36421
37129
  const createSession = /* @__PURE__ */ __name(async (params) => {
36422
- openstackSession = await (0, import_signal_openstack.SignalOpenstackSession)(normalizedEndpoint, {
37130
+ openstackSession = await (0, import_signal_openstack2.SignalOpenstackSession)(normalizedEndpoint, {
36423
37131
  auth: {
36424
37132
  identity: {
36425
37133
  methods: [
@@ -36564,7 +37272,7 @@ __name(createContext, "createContext");
36564
37272
  // src/server/server.ts
36565
37273
  var import_path2 = __toESM(require("path"));
36566
37274
  var import_node_stream3 = require("stream");
36567
- var import_zod24 = require("zod");
37275
+ var import_zod25 = require("zod");
36568
37276
 
36569
37277
  // src/server/aurora-fastify-plugins/csrfProtection.ts
36570
37278
  var import_csrf_protection = __toESM(require("@fastify/csrf-protection"));
@@ -36633,22 +37341,211 @@ var csrfProtection_default = (0, import_fastify_plugin.default)(csrfPlugin, {
36633
37341
  fastify: "5.x"
36634
37342
  });
36635
37343
 
37344
+ // src/server/aurora-fastify-plugins/httpMetricsCollector.ts
37345
+ var import_fastify_plugin2 = __toESM(require("fastify-plugin"));
37346
+ var import_prom_client = require("prom-client");
37347
+ var LABEL_NAMES = [
37348
+ "status_code",
37349
+ "method",
37350
+ "route",
37351
+ "endpoint_type",
37352
+ "project_id"
37353
+ ];
37354
+ var EXCLUDE_PATHS = [
37355
+ "/metrics"
37356
+ ];
37357
+ async function httpMetricsCollectorPlugin(fastify, options) {
37358
+ const prefix = options.prefix || "aurora";
37359
+ const excludePaths = options.excludePaths || EXCLUDE_PATHS;
37360
+ const registry = options.registry || new import_prom_client.Registry();
37361
+ const bffEndpoint = options.bffEndpoint || "/polaris-bff";
37362
+ const requestsTotal = new import_prom_client.Counter({
37363
+ name: `${prefix}_requests_total`,
37364
+ help: "The total number of HTTP requests handled by the application",
37365
+ labelNames: LABEL_NAMES,
37366
+ registers: [
37367
+ registry
37368
+ ]
37369
+ });
37370
+ const requestDurationSeconds = new import_prom_client.Histogram({
37371
+ name: `${prefix}_request_duration_seconds`,
37372
+ help: "The HTTP response duration of the application",
37373
+ labelNames: LABEL_NAMES,
37374
+ registers: [
37375
+ registry
37376
+ ]
37377
+ });
37378
+ const exceptionsTotal = new import_prom_client.Counter({
37379
+ name: `${prefix}_exceptions_total`,
37380
+ help: "The total number of exceptions raised by the application",
37381
+ labelNames: [
37382
+ "exception"
37383
+ ],
37384
+ registers: [
37385
+ registry
37386
+ ]
37387
+ });
37388
+ fastify.addHook("onRequest", async (request) => {
37389
+ request.metricsStartTime = process.hrtime.bigint();
37390
+ });
37391
+ fastify.addHook("onResponse", async (request, reply) => {
37392
+ const path3 = request.url.split("?")[0];
37393
+ if (excludePaths.some((excludePath) => path3.startsWith(excludePath))) {
37394
+ return;
37395
+ }
37396
+ if (!request.metricsStartTime) {
37397
+ fastify.log.debug({
37398
+ url: request.url
37399
+ }, "Metrics start time missing, skipping metric collection");
37400
+ return;
37401
+ }
37402
+ const endTime = process.hrtime.bigint();
37403
+ const duration = Number(endTime - request.metricsStartTime) / 1e9;
37404
+ const labels = extractLabels(request, reply, bffEndpoint);
37405
+ try {
37406
+ requestsTotal.inc(labels);
37407
+ requestDurationSeconds.observe(labels, duration);
37408
+ } catch (error) {
37409
+ fastify.log.error({
37410
+ err: error
37411
+ }, "Failed to record HTTP metrics");
37412
+ }
37413
+ });
37414
+ fastify.addHook("onError", async (_request, _reply, error) => {
37415
+ try {
37416
+ exceptionsTotal.inc({
37417
+ exception: error.constructor.name
37418
+ });
37419
+ } catch (err) {
37420
+ fastify.log.error({
37421
+ err
37422
+ }, "Failed to record exception metric");
37423
+ }
37424
+ });
37425
+ fastify.decorate("metricsRegistry", registry);
37426
+ }
37427
+ __name(httpMetricsCollectorPlugin, "httpMetricsCollectorPlugin");
37428
+ function extractLabels(request, reply, bffEndpoint) {
37429
+ const urlPath = request.url.split("?")[0];
37430
+ let endpointType;
37431
+ let route = urlPath;
37432
+ let projectId = "";
37433
+ if (urlPath.includes(bffEndpoint)) {
37434
+ endpointType = "trpc";
37435
+ const procedurePath = urlPath.split(bffEndpoint + "/")[1];
37436
+ if (procedurePath) {
37437
+ const cleanPath = procedurePath.split("?")[0];
37438
+ const parts = cleanPath.split(".");
37439
+ if (parts.length >= 2) {
37440
+ const service = parts[0];
37441
+ const action = parts.slice(1).join(".");
37442
+ route = `${service}/${action}`;
37443
+ } else {
37444
+ route = cleanPath;
37445
+ }
37446
+ }
37447
+ const url = new URL(request.url, "http://localhost");
37448
+ const inputParam = url.searchParams.get("input");
37449
+ if (inputParam) {
37450
+ try {
37451
+ const input = JSON.parse(inputParam);
37452
+ if (input.project_id) {
37453
+ projectId = input.project_id;
37454
+ } else if (typeof input === "object") {
37455
+ const firstKey = Object.keys(input)[0];
37456
+ if (firstKey && input[firstKey]?.project_id) {
37457
+ projectId = input[firstKey].project_id;
37458
+ }
37459
+ }
37460
+ } catch {
37461
+ }
37462
+ }
37463
+ } else if (urlPath.startsWith("/api/")) {
37464
+ endpointType = "api";
37465
+ route = normalizeApiPath(urlPath);
37466
+ } else if (urlPath.startsWith("/@")) {
37467
+ endpointType = "vite-dev";
37468
+ route = "vite-dev";
37469
+ } else if (urlPath.match(/\.(js|jsx|ts|tsx|mjs|css|json|map)$/)) {
37470
+ endpointType = "module";
37471
+ const ext = urlPath.split(".").pop() || "unknown";
37472
+ route = `*.${ext}`;
37473
+ } else if (urlPath.match(/\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot|ico|webp)$/)) {
37474
+ endpointType = "asset";
37475
+ const ext = urlPath.split(".").pop() || "unknown";
37476
+ route = `*.${ext}`;
37477
+ } else if (urlPath === "/" || urlPath === "/index.html") {
37478
+ endpointType = "spa";
37479
+ route = "/";
37480
+ } else {
37481
+ endpointType = "spa";
37482
+ route = normalizeSpaRoute(urlPath);
37483
+ const projectMatch = urlPath.match(/^\/projects\/([^/?]+)/);
37484
+ if (projectMatch) {
37485
+ projectId = projectMatch[1];
37486
+ }
37487
+ }
37488
+ return {
37489
+ status_code: reply.statusCode.toString(),
37490
+ method: request.method.toLowerCase(),
37491
+ route,
37492
+ endpoint_type: endpointType,
37493
+ project_id: projectId
37494
+ };
37495
+ }
37496
+ __name(extractLabels, "extractLabels");
37497
+ function normalizeSpaRoute(path3) {
37498
+ const segments = path3.split("/").filter(Boolean);
37499
+ if (segments[0] === "projects" && segments.length >= 3) {
37500
+ const service = segments[2];
37501
+ return `/projects/:id/${service}`;
37502
+ }
37503
+ if (segments[0] === "accounts" && segments.length >= 2) {
37504
+ return "/accounts/:id";
37505
+ }
37506
+ return "/" + segments.map((segment) => {
37507
+ if (segment.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) {
37508
+ return ":id";
37509
+ }
37510
+ if (segment.match(/^[a-zA-Z0-9_-]{20,}$/)) {
37511
+ return ":id";
37512
+ }
37513
+ return segment;
37514
+ }).join("/");
37515
+ }
37516
+ __name(normalizeSpaRoute, "normalizeSpaRoute");
37517
+ function normalizeApiPath(path3) {
37518
+ return path3.split("/").map((segment) => {
37519
+ if (segment.match(/^\d+$/) || segment.match(/^[0-9a-f-]{36}$/i)) {
37520
+ return ":id";
37521
+ }
37522
+ return segment;
37523
+ }).join("/");
37524
+ }
37525
+ __name(normalizeApiPath, "normalizeApiPath");
37526
+ var AuroraHttpMetricsCollector = (0, import_fastify_plugin2.default)(httpMetricsCollectorPlugin, {
37527
+ name: "aurora-http-metrics-collector",
37528
+ fastify: "5.x"
37529
+ });
37530
+
36636
37531
  // src/server/server.ts
37532
+ var import_prom_client2 = require("prom-client");
36637
37533
  async function createServer(config) {
36638
37534
  const isProduction = process.env.NODE_ENV === "production";
36639
- const rawBffEndpoint = config?.bffEndpoint ?? "/polaris-bff";
37535
+ const rawBffEndpoint = config.bffEndpoint ?? "/polaris-bff";
36640
37536
  const bffEndpoint = "/" + rawBffEndpoint.split("/").filter(Boolean).join("/");
36641
- const viteRoot = config?.viteRoot ?? import_path2.default.resolve(__dirname, "../../");
37537
+ const viteRoot = config.viteRoot ?? import_path2.default.resolve(__dirname, "../../");
36642
37538
  const contextConfig = {
36643
- identityEndpoint: config?.identityEndpoint ?? "",
36644
- defaultEndpointInterface: config?.defaultEndpointInterface,
36645
- proxyUrl: config?.proxyUrl,
36646
- cephRegion: config?.cephRegion,
36647
- imageMetadataExcludedProperties: config?.imageMetadataExcludedProperties,
36648
- cookieName: config?.cookieName,
36649
- crossDomainCookie: config?.crossDomainCookie,
36650
- insecureCookies: config?.insecureCookies
37539
+ identityEndpoint: config.identityEndpoint ?? "",
37540
+ defaultEndpointInterface: config.defaultEndpointInterface,
37541
+ proxyUrl: config.proxyUrl,
37542
+ cephRegion: config.cephRegion,
37543
+ imageMetadataExcludedProperties: config.imageMetadataExcludedProperties,
37544
+ cookieName: config.cookieName,
37545
+ crossDomainCookie: config.crossDomainCookie,
37546
+ insecureCookies: config.insecureCookies
36651
37547
  };
37548
+ const appRouter = buildAppRouter(config.policyDir);
36652
37549
  const server = (0, import_fastify.default)({
36653
37550
  logger: true,
36654
37551
  bodyLimit: 1 * 1024 * 1024,
@@ -36661,6 +37558,19 @@ async function createServer(config) {
36661
37558
  server.register(import_cookie2.default, {
36662
37559
  secret: void 0
36663
37560
  });
37561
+ const metricsRegistry = new import_prom_client2.Registry();
37562
+ await server.register(AuroraHttpMetricsCollector, {
37563
+ prefix: "aurora",
37564
+ excludePaths: [
37565
+ "/metrics"
37566
+ ],
37567
+ registry: metricsRegistry,
37568
+ bffEndpoint
37569
+ });
37570
+ server.get("/metrics", async (_request, reply) => {
37571
+ reply.header("Content-Type", metricsRegistry.contentType);
37572
+ return reply.send(await metricsRegistry.metrics());
37573
+ });
36664
37574
  await server.register(import_rate_limit.default, {
36665
37575
  max: 200,
36666
37576
  timeWindow: "1 minute"
@@ -36771,7 +37681,7 @@ async function createServer(config) {
36771
37681
  router: appRouter,
36772
37682
  createContext: /* @__PURE__ */ __name((opts) => createContext(opts, contextConfig), "createContext"),
36773
37683
  onError: /* @__PURE__ */ __name((err) => {
36774
- if (err.error.cause instanceof import_zod24.ZodError) err.error.message = err.error.cause.issues.map((e) => e.message).join(",");
37684
+ if (err.error.cause instanceof import_zod25.ZodError) err.error.message = err.error.cause.issues.map((e) => e.message).join(",");
36775
37685
  }, "onError")
36776
37686
  }
36777
37687
  });