@cobaltcore-dev/aurora 1.1.0 → 1.2.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 (183) hide show
  1. package/README.md +59 -9
  2. package/dist/client/App.d.ts +2 -2
  3. package/dist/client/AuroraApp.d.ts +33 -13
  4. package/dist/client/{AuthProvider-BS5OVv8n.mjs → AuthProvider-CVSAwW9f.mjs} +22 -8
  5. package/dist/client/AuthProvider-CVSAwW9f.mjs.map +1 -0
  6. package/dist/client/{ContentHeader-BHMUzd9H.mjs → ContentHeader-CPJbgYWn.mjs} +18 -18
  7. package/dist/client/{ContentHeader-BHMUzd9H.mjs.map → ContentHeader-CPJbgYWn.mjs.map} +1 -1
  8. package/dist/client/DeleteFlavorModal-V44QCJBd.mjs +773 -0
  9. package/dist/client/DeleteFlavorModal-V44QCJBd.mjs.map +1 -0
  10. package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs +26 -0
  11. package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs.map +1 -0
  12. package/dist/client/{FiltersInput-B8CNBg1L.mjs → FiltersInput-CKI6zWnm.mjs} +18 -18
  13. package/dist/client/{FiltersInput-B8CNBg1L.mjs.map → FiltersInput-CKI6zWnm.mjs.map} +1 -1
  14. package/dist/client/FloatingIpActionModals-CwEC5GR-.mjs +460 -0
  15. package/dist/client/FloatingIpActionModals-CwEC5GR-.mjs.map +1 -0
  16. package/dist/client/ImageToastNotifications-m6c3tVPb.mjs +1152 -0
  17. package/dist/client/ImageToastNotifications-m6c3tVPb.mjs.map +1 -0
  18. package/dist/client/SortInput-4g7nSTHW.mjs +34 -0
  19. package/dist/client/SortInput-4g7nSTHW.mjs.map +1 -0
  20. package/dist/client/{TwoColumnDescriptionList-DiDx3PnH.mjs → TwoColumnDescriptionList-NvgvErua.mjs} +2 -2
  21. package/dist/client/{TwoColumnDescriptionList-DiDx3PnH.mjs.map → TwoColumnDescriptionList-NvgvErua.mjs.map} +1 -1
  22. package/dist/client/_-CAsCx-Ay.mjs +6 -0
  23. package/dist/client/_-CAsCx-Ay.mjs.map +1 -0
  24. package/dist/client/_auth-SrDjHL6j.mjs +12 -0
  25. package/dist/client/_auth-SrDjHL6j.mjs.map +1 -0
  26. package/dist/client/_flavorId-9PcBBW52.mjs +231 -0
  27. package/dist/client/_flavorId-9PcBBW52.mjs.map +1 -0
  28. package/dist/client/{_flavorId-BN_qessZ.mjs → _flavorId-a9Gu66R1.mjs} +3 -9
  29. package/dist/client/_flavorId-a9Gu66R1.mjs.map +1 -0
  30. package/dist/client/_floatingIpId-AE9Fu8l6.mjs +210 -0
  31. package/dist/client/_floatingIpId-AE9Fu8l6.mjs.map +1 -0
  32. package/dist/client/{_floatingIpId-CwDGHkWm.mjs → _floatingIpId-AZ11Ksmu.mjs} +3 -9
  33. package/dist/client/_floatingIpId-AZ11Ksmu.mjs.map +1 -0
  34. package/dist/client/{_imageId-BtJ7GmYB.mjs → _imageId-BtAql2Kr.mjs} +104 -92
  35. package/dist/client/_imageId-BtAql2Kr.mjs.map +1 -0
  36. package/dist/client/_imageId-D76BxvFY.mjs +39 -0
  37. package/dist/client/_imageId-D76BxvFY.mjs.map +1 -0
  38. package/dist/client/{_projectId-Byt3GQDW.mjs → _projectId-7Nl1MQTJ.mjs} +5 -5
  39. package/dist/client/_projectId-7Nl1MQTJ.mjs.map +1 -0
  40. package/dist/client/_projectId-B3wmSala.mjs +281 -0
  41. package/dist/client/_projectId-B3wmSala.mjs.map +1 -0
  42. package/dist/client/_projectId-DPzv0CCp.mjs +77 -0
  43. package/dist/client/_projectId-DPzv0CCp.mjs.map +1 -0
  44. package/dist/client/_projectId-DfeVJy0G.mjs +30 -0
  45. package/dist/client/_projectId-DfeVJy0G.mjs.map +1 -0
  46. package/dist/client/_securityGroupId-C5huJNfO.mjs +1810 -0
  47. package/dist/client/_securityGroupId-C5huJNfO.mjs.map +1 -0
  48. package/dist/client/{_securityGroupId-BcbkRhsN.mjs → _securityGroupId-D85mSigA.mjs} +3 -9
  49. package/dist/client/_securityGroupId-D85mSigA.mjs.map +1 -0
  50. package/dist/client/_serviceType-DS8DxsrP.mjs +20 -0
  51. package/dist/client/_serviceType-DS8DxsrP.mjs.map +1 -0
  52. package/dist/client/_serviceType-M8d9rOT6.mjs +6 -0
  53. package/dist/client/_serviceType-M8d9rOT6.mjs.map +1 -0
  54. package/dist/client/_storageType-BRWWJtow.mjs +14 -0
  55. package/dist/client/_storageType-BRWWJtow.mjs.map +1 -0
  56. package/dist/client/_storageType-CzZ4u9x_.mjs +12 -0
  57. package/dist/client/_storageType-CzZ4u9x_.mjs.map +1 -0
  58. package/dist/client/_storageType-Dy9uCVXr.mjs +845 -0
  59. package/dist/client/_storageType-Dy9uCVXr.mjs.map +1 -0
  60. package/dist/client/_storageType-zeSZe--V.mjs.map +1 -1
  61. package/dist/client/{about-_73VmpTB.mjs → about-BmQTyLWc.mjs} +2 -2
  62. package/dist/client/{about-_73VmpTB.mjs.map → about-BmQTyLWc.mjs.map} +1 -1
  63. package/dist/client/{aurora-EbwGRLLf.mjs → aurora-CIml-f2f.mjs} +2 -2
  64. package/dist/client/{aurora-EbwGRLLf.mjs.map → aurora-CIml-f2f.mjs.map} +1 -1
  65. package/dist/client/{build-C_4vRMCq.mjs → build-WuxXRAqf.mjs} +121 -24
  66. package/dist/client/{build-C_4vRMCq.mjs.map → build-WuxXRAqf.mjs.map} +1 -1
  67. package/dist/client/components/Breadcrumbs.d.ts +1 -0
  68. package/dist/client/components/ListToolbar/SortInput.d.ts +3 -0
  69. package/dist/client/context/BreadcrumbExtensionContext.d.ts +9 -0
  70. package/dist/client/context/DynamicBreadcrumbContext.d.ts +9 -0
  71. package/dist/client/{flavors-CiHCYrtZ.mjs → flavors-B0rbqffG.mjs} +3 -5
  72. package/dist/client/flavors-B0rbqffG.mjs.map +1 -0
  73. package/dist/client/flavors-DWMZ6TuJ.mjs.map +1 -1
  74. package/dist/client/flavors-Rl20bxVU.mjs +628 -0
  75. package/dist/client/flavors-Rl20bxVU.mjs.map +1 -0
  76. package/dist/client/floatingips-Cz9k80cc.mjs +8 -0
  77. package/dist/client/floatingips-Cz9k80cc.mjs.map +1 -0
  78. package/dist/client/floatingips-xbO_mu4f.mjs +576 -0
  79. package/dist/client/floatingips-xbO_mu4f.mjs.map +1 -0
  80. package/dist/client/hooks/useBreadcrumbs.d.ts +16 -0
  81. package/dist/client/hooks/usePushBreadcrumbs.d.ts +10 -0
  82. package/dist/client/hooks/useSetBreadcrumb.d.ts +11 -0
  83. package/dist/client/{hooks-LutR2Yg3.mjs → hooks-D0yKIumu.mjs} +2 -2
  84. package/dist/client/{hooks-LutR2Yg3.mjs.map → hooks-D0yKIumu.mjs.map} +1 -1
  85. package/dist/client/images-BGQv9kKT.mjs +1983 -0
  86. package/dist/client/images-BGQv9kKT.mjs.map +1 -0
  87. package/dist/client/{images-CS4kZQyu.mjs → images-CPmMa4SQ.mjs} +3 -5
  88. package/dist/client/images-CPmMa4SQ.mjs.map +1 -0
  89. package/dist/client/images-NBf2bV43.mjs.map +1 -1
  90. package/dist/client/index.d.ts +7 -3
  91. package/dist/client/index.js +549 -535
  92. package/dist/client/index.js.map +1 -1
  93. package/dist/client/{objects-C3azvW8m.mjs → objects-BE_u5yRt.mjs} +7087 -4211
  94. package/dist/client/objects-BE_u5yRt.mjs.map +1 -0
  95. package/dist/client/objects-BN-59Th0.mjs +66 -0
  96. package/dist/client/objects-BN-59Th0.mjs.map +1 -0
  97. package/dist/client/objects-D9Luf9KB.mjs +66 -0
  98. package/dist/client/objects-D9Luf9KB.mjs.map +1 -0
  99. package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
  100. package/dist/client/routeInfo-DP3v74Wg.mjs +19 -0
  101. package/dist/client/routeInfo-DP3v74Wg.mjs.map +1 -0
  102. package/dist/client/router.d.ts +2 -2
  103. package/dist/client/{routes-CdDm-hhO.mjs → routes-CJj7SR_K.mjs} +2 -2
  104. package/dist/client/routes-CJj7SR_K.mjs.map +1 -0
  105. package/dist/client/routes-xofA3ksU.mjs +110 -0
  106. package/dist/client/routes-xofA3ksU.mjs.map +1 -0
  107. package/dist/client/securitygroups-BjhgLBHm.mjs +620 -0
  108. package/dist/client/securitygroups-BjhgLBHm.mjs.map +1 -0
  109. package/dist/client/securitygroups-CtKne8UQ.mjs +8 -0
  110. package/dist/client/securitygroups-CtKne8UQ.mjs.map +1 -0
  111. package/dist/client/{securitygroups-Byte-iSp.mjs → securitygroups-DEJQBcxm.mjs} +3 -5
  112. package/dist/client/securitygroups-DEJQBcxm.mjs.map +1 -0
  113. package/dist/client/trpcClient.d.ts +135 -3
  114. package/dist/client/useBreadcrumbs-ha3IlaxX.mjs +54 -0
  115. package/dist/client/useBreadcrumbs-ha3IlaxX.mjs.map +1 -0
  116. package/dist/client/useModalTracking-BcOKTYRN.mjs +33 -0
  117. package/dist/client/useModalTracking-BcOKTYRN.mjs.map +1 -0
  118. package/dist/client/{useSecurityGroupPermissions-C29mzb3b.mjs → useSecurityGroupPermissions-BOyLQLdC.mjs} +85 -19
  119. package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs.map +1 -0
  120. package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs +19 -0
  121. package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs.map +1 -0
  122. package/dist/client/utils/formatSwiftDate.d.ts +30 -0
  123. package/dist/server/index.d.ts +136 -4
  124. package/dist/server/index.js +845 -260
  125. package/package.json +37 -36
  126. package/dist/client/AuthProvider-BS5OVv8n.mjs.map +0 -1
  127. package/dist/client/DeleteFlavorModal-BP83t9zX.mjs +0 -721
  128. package/dist/client/DeleteFlavorModal-BP83t9zX.mjs.map +0 -1
  129. package/dist/client/FloatingIpActionModals-BraiJWBi.mjs +0 -417
  130. package/dist/client/FloatingIpActionModals-BraiJWBi.mjs.map +0 -1
  131. package/dist/client/ImageToastNotifications-BXMHJaIH.mjs +0 -1131
  132. package/dist/client/ImageToastNotifications-BXMHJaIH.mjs.map +0 -1
  133. package/dist/client/RouteError-hAF8_jbe.mjs +0 -25
  134. package/dist/client/RouteError-hAF8_jbe.mjs.map +0 -1
  135. package/dist/client/SortInput-Cqs2poV3.mjs +0 -34
  136. package/dist/client/SortInput-Cqs2poV3.mjs.map +0 -1
  137. package/dist/client/StatusError-C5KodQOq.mjs +0 -39
  138. package/dist/client/StatusError-C5KodQOq.mjs.map +0 -1
  139. package/dist/client/_auth-DJ9wHZaj.mjs +0 -11
  140. package/dist/client/_auth-DJ9wHZaj.mjs.map +0 -1
  141. package/dist/client/_flavorId-BN_qessZ.mjs.map +0 -1
  142. package/dist/client/_flavorId-CJjEB_Ao.mjs +0 -210
  143. package/dist/client/_flavorId-CJjEB_Ao.mjs.map +0 -1
  144. package/dist/client/_floatingIpId-CwDGHkWm.mjs.map +0 -1
  145. package/dist/client/_floatingIpId-foMIwbE4.mjs +0 -215
  146. package/dist/client/_floatingIpId-foMIwbE4.mjs.map +0 -1
  147. package/dist/client/_imageId-BtJ7GmYB.mjs.map +0 -1
  148. package/dist/client/_projectId-BmtCuzJu.mjs +0 -29
  149. package/dist/client/_projectId-BmtCuzJu.mjs.map +0 -1
  150. package/dist/client/_projectId-Byt3GQDW.mjs.map +0 -1
  151. package/dist/client/_projectId-NYk1IN_a.mjs +0 -291
  152. package/dist/client/_projectId-NYk1IN_a.mjs.map +0 -1
  153. package/dist/client/_projectId-QueiFczy.mjs +0 -46
  154. package/dist/client/_projectId-QueiFczy.mjs.map +0 -1
  155. package/dist/client/_securityGroupId-BcbkRhsN.mjs.map +0 -1
  156. package/dist/client/_securityGroupId-pPtJsCoe.mjs +0 -1797
  157. package/dist/client/_securityGroupId-pPtJsCoe.mjs.map +0 -1
  158. package/dist/client/_storageType-BmqrU06i.mjs +0 -2202
  159. package/dist/client/_storageType-BmqrU06i.mjs.map +0 -1
  160. package/dist/client/components/Error/StatusError.d.ts +0 -11
  161. package/dist/client/components/ProjectView/ProjectInfoBox.d.ts +0 -12
  162. package/dist/client/flavors-CiHCYrtZ.mjs.map +0 -1
  163. package/dist/client/flavors-DY-bDc8l.mjs +0 -650
  164. package/dist/client/flavors-DY-bDc8l.mjs.map +0 -1
  165. package/dist/client/floatingips-Ci4jHkaG.mjs +0 -591
  166. package/dist/client/floatingips-Ci4jHkaG.mjs.map +0 -1
  167. package/dist/client/images-91U7tr9Y2.mjs +0 -1976
  168. package/dist/client/images-91U7tr9Y2.mjs.map +0 -1
  169. package/dist/client/images-CS4kZQyu.mjs.map +0 -1
  170. package/dist/client/objects-C3azvW8m.mjs.map +0 -1
  171. package/dist/client/objects-CM265S6b.mjs +0 -56
  172. package/dist/client/objects-CM265S6b.mjs.map +0 -1
  173. package/dist/client/objects-EE9Cd1wI.mjs +0 -56
  174. package/dist/client/objects-EE9Cd1wI.mjs.map +0 -1
  175. package/dist/client/routeInfo-DXqB2HCf.mjs +0 -32
  176. package/dist/client/routeInfo-DXqB2HCf.mjs.map +0 -1
  177. package/dist/client/routes-CBd8CCuM.mjs +0 -115
  178. package/dist/client/routes-CBd8CCuM.mjs.map +0 -1
  179. package/dist/client/routes-CdDm-hhO.mjs.map +0 -1
  180. package/dist/client/securitygroups-Bd_uV4S9.mjs +0 -595
  181. package/dist/client/securitygroups-Bd_uV4S9.mjs.map +0 -1
  182. package/dist/client/securitygroups-Byte-iSp.mjs.map +0 -1
  183. package/dist/client/useSecurityGroupPermissions-C29mzb3b.mjs.map +0 -1
@@ -7,11 +7,7 @@ var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
8
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
9
  var __commonJS = (cb, mod) => function __require() {
10
- try {
11
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
12
- } catch (e) {
13
- throw mod = 0, e;
14
- }
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15
11
  };
16
12
  var __export = (target, all) => {
17
13
  for (var name in all)
@@ -260,7 +256,7 @@ var require_error = __commonJS({
260
256
  }
261
257
  };
262
258
  exports2.SignalOpenstackError = SignalOpenstackError4;
263
- var SignalOpenstackApiError = class SignalOpenstackApiError extends Error {
259
+ var SignalOpenstackApiError2 = class SignalOpenstackApiError extends Error {
264
260
  static {
265
261
  __name(this, "SignalOpenstackApiError");
266
262
  }
@@ -271,7 +267,7 @@ var require_error = __commonJS({
271
267
  this.statusCode = statusCode;
272
268
  }
273
269
  };
274
- exports2.SignalOpenstackApiError = SignalOpenstackApiError;
270
+ exports2.SignalOpenstackApiError = SignalOpenstackApiError2;
275
271
  }
276
272
  });
277
273
 
@@ -27346,7 +27342,7 @@ var require_esm = __commonJS({
27346
27342
  Object.defineProperty(exports2, "__esModule", {
27347
27343
  value: true
27348
27344
  });
27349
- exports2.validateAndEncodeResourceId = exports2.encodeOpenstackPath = exports2.encodeOpenstackPathSegment = exports2.redactSensitiveData = exports2.loggerConfig = exports2.logger = exports2.SignalOpenstackError = exports2.SignalOpenstackSession = void 0;
27345
+ exports2.validateAndEncodeResourceId = exports2.encodeOpenstackPath = exports2.encodeOpenstackPathSegment = exports2.redactSensitiveData = exports2.loggerConfig = exports2.logger = exports2.SignalOpenstackApiError = exports2.SignalOpenstackError = exports2.SignalOpenstackSession = void 0;
27350
27346
  var session_1 = require_session();
27351
27347
  Object.defineProperty(exports2, "SignalOpenstackSession", {
27352
27348
  enumerable: true,
@@ -27361,6 +27357,12 @@ var require_esm = __commonJS({
27361
27357
  return error_1.SignalOpenstackError;
27362
27358
  }, "get")
27363
27359
  });
27360
+ Object.defineProperty(exports2, "SignalOpenstackApiError", {
27361
+ enumerable: true,
27362
+ get: /* @__PURE__ */ __name(function() {
27363
+ return error_1.SignalOpenstackApiError;
27364
+ }, "get")
27365
+ });
27364
27366
  var logger_1 = require_logger();
27365
27367
  Object.defineProperty(exports2, "logger", {
27366
27368
  enumerable: true,
@@ -28593,11 +28595,69 @@ var import_zod2 = require("zod");
28593
28595
  // src/server/trpc.ts
28594
28596
  var import_server = require("@trpc/server");
28595
28597
  var import_zod = require("zod");
28598
+ var import_signal_openstack = __toESM(require_esm());
28596
28599
  var t = import_server.initTRPC.context().create();
28600
+ var openstackErrorMiddleware = t.middleware(async ({ next }) => {
28601
+ const result = await next();
28602
+ if (!result.ok) {
28603
+ const cause = result.error.cause;
28604
+ if (cause instanceof import_signal_openstack.SignalOpenstackApiError) {
28605
+ if (cause.statusCode === 401) {
28606
+ return {
28607
+ ...result,
28608
+ error: new import_server.TRPCError({
28609
+ code: "UNAUTHORIZED",
28610
+ message: "Session expired or invalid. Please log in again.",
28611
+ cause
28612
+ })
28613
+ };
28614
+ }
28615
+ if (cause.statusCode === 400) {
28616
+ return {
28617
+ ...result,
28618
+ error: new import_server.TRPCError({
28619
+ code: "BAD_REQUEST",
28620
+ message: "The OpenStack request was invalid.",
28621
+ cause
28622
+ })
28623
+ };
28624
+ }
28625
+ if (cause.statusCode === 404) {
28626
+ return {
28627
+ ...result,
28628
+ error: new import_server.TRPCError({
28629
+ code: "NOT_FOUND",
28630
+ message: "Resource not found or not accessible. This can happen if you switched domains in another tab.",
28631
+ cause
28632
+ })
28633
+ };
28634
+ }
28635
+ if (cause.statusCode === 403) {
28636
+ return {
28637
+ ...result,
28638
+ error: new import_server.TRPCError({
28639
+ code: "FORBIDDEN",
28640
+ message: "Access denied. You may not have the required role assignment.",
28641
+ cause
28642
+ })
28643
+ };
28644
+ }
28645
+ return {
28646
+ ...result,
28647
+ error: new import_server.TRPCError({
28648
+ code: "INTERNAL_SERVER_ERROR",
28649
+ message: "An unexpected OpenStack error occurred",
28650
+ cause
28651
+ })
28652
+ };
28653
+ }
28654
+ }
28655
+ return result;
28656
+ });
28597
28657
  var router = t.router;
28598
28658
  var auroraRouter = t.router;
28599
28659
  var mergeRouters = t.mergeRouters;
28600
- var publicProcedure = t.procedure;
28660
+ var publicProcedure = t.procedure.use(openstackErrorMiddleware);
28601
28661
  var createCallerFactory = t.createCallerFactory;
28602
28662
  var protectedProcedure = publicProcedure.use(/* @__PURE__ */ __name(async function isAuthenticated(opts) {
28603
28663
  if (opts.ctx.validateSession() === false) {
@@ -28717,6 +28777,7 @@ var sessionRouter = {
28717
28777
  domain
28718
28778
  };
28719
28779
  }),
28780
+ // Errors from rescopeSession are handled by openstackErrorMiddleware
28720
28781
  setCurrentScope: protectedProcedure.input(discriminatedSchema).mutation(async ({ input, ctx }) => {
28721
28782
  switch (input.type) {
28722
28783
  case "domain": {
@@ -28724,9 +28785,15 @@ var sessionRouter = {
28724
28785
  domainId: input.domainId
28725
28786
  });
28726
28787
  const token = session?.getToken();
28788
+ if (!token?.tokenData.domain) {
28789
+ throw new import_server2.TRPCError({
28790
+ code: "NOT_FOUND",
28791
+ message: "Failed to rescope to the requested domain."
28792
+ });
28793
+ }
28727
28794
  return {
28728
28795
  project: null,
28729
- domain: token?.tokenData.domain
28796
+ domain: token.tokenData.domain
28730
28797
  };
28731
28798
  }
28732
28799
  case "project": {
@@ -28734,9 +28801,15 @@ var sessionRouter = {
28734
28801
  projectId: input.projectId
28735
28802
  });
28736
28803
  const token = session?.getToken();
28804
+ if (!token?.tokenData.project) {
28805
+ throw new import_server2.TRPCError({
28806
+ code: "NOT_FOUND",
28807
+ message: "Failed to rescope to the requested project."
28808
+ });
28809
+ }
28737
28810
  return {
28738
- project: token?.tokenData.project,
28739
- domain: token?.tokenData.project?.domain
28811
+ project: token.tokenData.project,
28812
+ domain: token.tokenData.project.domain
28740
28813
  };
28741
28814
  }
28742
28815
  case "unscoped": {
@@ -29859,7 +29932,8 @@ var imagesPaginatedResponseSchema = import_zod4.z.object({
29859
29932
  images: import_zod4.z.array(imageSchema),
29860
29933
  first: import_zod4.z.string().optional(),
29861
29934
  next: import_zod4.z.string().optional(),
29862
- schema: import_zod4.z.string().optional()
29935
+ schema: import_zod4.z.string().optional(),
29936
+ totalCount: import_zod4.z.number().optional()
29863
29937
  });
29864
29938
 
29865
29939
  // src/server/Compute/routers/imageRouter.ts
@@ -29874,22 +29948,26 @@ var imageRouter = {
29874
29948
  validateGlanceService(glance);
29875
29949
  const FRONTEND_PAGE_SIZE = 50;
29876
29950
  const OPENSTACK_PAGE_SIZE = 100;
29877
- const MIN_RESULTS_WHEN_SEARCHING = 50;
29878
29951
  const MAX_PAGES_TO_SEARCH = 1e3;
29879
29952
  const allImages = [];
29880
29953
  const hasSearchTerm = queryInput.name && queryInput.name.trim();
29881
29954
  const queryParams = new URLSearchParams();
29882
- const minimalQuery = {
29955
+ const apiQuery = {
29883
29956
  sort_key: queryInput.sort_key,
29884
29957
  sort_dir: queryInput.sort_dir,
29885
29958
  sort: queryInput.sort,
29886
29959
  limit: OPENSTACK_PAGE_SIZE,
29887
- marker
29960
+ // Only pass single-value filters to API (multi-value filters start with "in:")
29961
+ status: queryInput.status?.startsWith("in:") ? void 0 : queryInput.status,
29962
+ visibility: queryInput.visibility === "all" ? void 0 : queryInput.visibility,
29963
+ disk_format: queryInput.disk_format?.startsWith("in:") ? void 0 : queryInput.disk_format,
29964
+ container_format: queryInput.container_format?.startsWith("in:") ? void 0 : queryInput.container_format,
29965
+ protected: queryInput.protected,
29966
+ owner: queryInput.owner
29888
29967
  };
29889
- applyImageQueryParams(queryParams, minimalQuery);
29968
+ applyImageQueryParams(queryParams, apiQuery);
29890
29969
  let currentUrl = `v2/images?${queryParams.toString()}`;
29891
29970
  let pageCount = 0;
29892
- let nextMarker;
29893
29971
  while (currentUrl && pageCount < MAX_PAGES_TO_SEARCH) {
29894
29972
  const response = await glance.get(currentUrl).catch((error) => {
29895
29973
  throw mapErrorResponseToTRPCError(error, {
@@ -29902,41 +29980,7 @@ var imageRouter = {
29902
29980
  }
29903
29981
  allImages.push(...parsedData.data.images);
29904
29982
  pageCount++;
29905
- if (hasSearchTerm) {
29906
- let filteredSoFar = filterBySearchParams(allImages, queryInput.name, [
29907
- "name"
29908
- ]);
29909
- if (queryInput.visibility && queryInput.visibility !== "all") {
29910
- filteredSoFar = filteredSoFar.filter((img) => img.visibility === queryInput.visibility);
29911
- }
29912
- if (queryInput.status) {
29913
- const values = parseMultiValue(queryInput.status);
29914
- filteredSoFar = filteredSoFar.filter((img) => values.includes(img.status ?? ""));
29915
- }
29916
- if (queryInput.disk_format) {
29917
- const values = parseMultiValue(queryInput.disk_format);
29918
- filteredSoFar = filteredSoFar.filter((img) => values.includes(img.disk_format ?? ""));
29919
- }
29920
- if (queryInput.container_format) {
29921
- const values = parseMultiValue(queryInput.container_format);
29922
- filteredSoFar = filteredSoFar.filter((img) => values.includes(img.container_format ?? ""));
29923
- }
29924
- if (queryInput.protected !== void 0 && queryInput.protected !== null) {
29925
- const wantProtected = queryInput.protected === "true";
29926
- filteredSoFar = filteredSoFar.filter((img) => !!img.protected === wantProtected);
29927
- }
29928
- if (queryInput.owner) {
29929
- filteredSoFar = filteredSoFar.filter((img) => img.owner === queryInput.owner);
29930
- }
29931
- if (filteredSoFar.length >= MIN_RESULTS_WHEN_SEARCHING) {
29932
- nextMarker = parsedData.data.next;
29933
- break;
29934
- }
29935
- }
29936
- if (!hasSearchTerm) {
29937
- nextMarker = parsedData.data.next;
29938
- break;
29939
- }
29983
+ validateRelativeUrl(parsedData.data.next, "pagination URL");
29940
29984
  currentUrl = parsedData.data.next;
29941
29985
  }
29942
29986
  let filteredImages = allImages;
@@ -29967,16 +30011,21 @@ var imageRouter = {
29967
30011
  if (queryInput.owner) {
29968
30012
  filteredImages = filteredImages.filter((img) => img.owner === queryInput.owner);
29969
30013
  }
29970
- const startIndex = 0;
29971
- const endIndex = FRONTEND_PAGE_SIZE;
30014
+ let startIndex = 0;
30015
+ if (marker) {
30016
+ const markerIndex = filteredImages.findIndex((img) => img.id === marker);
30017
+ startIndex = markerIndex >= 0 ? markerIndex + 1 : 0;
30018
+ }
30019
+ const endIndex = startIndex + FRONTEND_PAGE_SIZE;
29972
30020
  const paginatedImages = filteredImages.slice(startIndex, endIndex);
29973
- const hasMore = filteredImages.length > FRONTEND_PAGE_SIZE || !!nextMarker;
29974
- const nextPageMarker = filteredImages.length > FRONTEND_PAGE_SIZE ? filteredImages[FRONTEND_PAGE_SIZE - 1]?.id : nextMarker;
30021
+ const hasMore = endIndex < filteredImages.length;
30022
+ const nextPageMarker = hasMore ? filteredImages[endIndex - 1]?.id : void 0;
29975
30023
  return {
29976
30024
  images: paginatedImages,
29977
30025
  first: void 0,
29978
30026
  next: hasMore ? nextPageMarker : void 0,
29979
- schema: "/v2/schemas/images"
30027
+ schema: "/v2/schemas/images",
30028
+ totalCount: filteredImages.length
29980
30029
  };
29981
30030
  }, "list images");
29982
30031
  }),
@@ -30112,16 +30161,25 @@ var imageRouter = {
30112
30161
  validateGlanceService(glance);
30113
30162
  const fileStream = import_node_stream.Readable.fromWeb(input);
30114
30163
  const { validatedImageId, validatedFileSize, validatedFile } = validateUploadInput(imageId, fileSize, fileStream);
30115
- uploadProgress.set(validatedImageId, {
30164
+ const token = openstackSession.getToken();
30165
+ const tokenProjectId = token?.tokenData.project?.id;
30166
+ if (!tokenProjectId) {
30167
+ throw new import_server6.TRPCError({
30168
+ code: "UNAUTHORIZED",
30169
+ message: "Project scope required for upload progress tracking"
30170
+ });
30171
+ }
30172
+ const scopedUploadId = `${tokenProjectId}:${validatedImageId}`;
30173
+ uploadProgress.set(scopedUploadId, {
30116
30174
  uploaded: 0,
30117
30175
  total: validatedFileSize
30118
30176
  });
30119
30177
  try {
30120
- const progress = uploadProgress.get(validatedImageId);
30178
+ const progress = uploadProgress.get(scopedUploadId);
30121
30179
  const progressTracker = new import_node_stream.Transform({
30122
30180
  transform(chunk, _encoding, callback) {
30123
30181
  progress.uploaded += chunk.length;
30124
- uploadProgressEmitter.emit(`progress:${validatedImageId}`, {
30182
+ uploadProgressEmitter.emit(`progress:${scopedUploadId}`, {
30125
30183
  uploaded: progress.uploaded,
30126
30184
  total: progress.total,
30127
30185
  percent: progress.total > 0 ? Math.round(progress.uploaded / progress.total * 100) : 0
@@ -30155,24 +30213,39 @@ var imageRouter = {
30155
30213
  progressTracker.destroy();
30156
30214
  throw ImageErrorHandlers.upload(uploadResponse, validatedImageId, "application/octet-stream");
30157
30215
  }
30158
- uploadProgressEmitter.emit(`progress:${validatedImageId}:complete`);
30216
+ uploadProgressEmitter.emit(`progress:${scopedUploadId}:complete`);
30159
30217
  return {
30160
30218
  success: true,
30161
30219
  imageId: validatedImageId
30162
30220
  };
30163
30221
  } catch (error) {
30164
- uploadProgressEmitter.emit(`progress:${validatedImageId}:error`, error);
30222
+ uploadProgressEmitter.emit(`progress:${scopedUploadId}:error`, error);
30165
30223
  throw ImageErrorHandlers.upload(error, validatedImageId, "application/octet-stream");
30166
30224
  } finally {
30167
- uploadProgress.delete(validatedImageId);
30225
+ uploadProgress.delete(scopedUploadId);
30168
30226
  }
30169
30227
  }, "upload image");
30170
30228
  }),
30171
30229
  watchUploadProgress: projectScopedProcedure.input(import_zod5.z.object({
30172
30230
  uploadId: import_zod5.z.string()
30173
- })).subscription(async function* ({ input }) {
30231
+ })).subscription(async function* ({ input, ctx }) {
30174
30232
  const uploadId = input.uploadId;
30175
- const current = uploadProgress.get(uploadId);
30233
+ if (uploadId.includes(":")) {
30234
+ throw new import_server6.TRPCError({
30235
+ code: "BAD_REQUEST",
30236
+ message: "Invalid uploadId format"
30237
+ });
30238
+ }
30239
+ const token = ctx.openstack?.getToken();
30240
+ const projectId = token?.tokenData.project?.id;
30241
+ if (!projectId) {
30242
+ throw new import_server6.TRPCError({
30243
+ code: "UNAUTHORIZED",
30244
+ message: "Project scope required for upload progress tracking"
30245
+ });
30246
+ }
30247
+ const scopedUploadId = `${projectId}:${uploadId}`;
30248
+ const current = uploadProgress.get(scopedUploadId);
30176
30249
  if (current) {
30177
30250
  yield {
30178
30251
  ...current,
@@ -30200,9 +30273,9 @@ var imageRouter = {
30200
30273
  waitResolver?.();
30201
30274
  waitResolver = null;
30202
30275
  }, "onError");
30203
- uploadProgressEmitter.on(`progress:${uploadId}`, onProgress);
30204
- uploadProgressEmitter.on(`progress:${uploadId}:complete`, onComplete);
30205
- uploadProgressEmitter.on(`progress:${uploadId}:error`, onError);
30276
+ uploadProgressEmitter.on(`progress:${scopedUploadId}`, onProgress);
30277
+ uploadProgressEmitter.on(`progress:${scopedUploadId}:complete`, onComplete);
30278
+ uploadProgressEmitter.on(`progress:${scopedUploadId}:error`, onError);
30206
30279
  try {
30207
30280
  while (!isComplete && !isError) {
30208
30281
  while (queue.length > 0) {
@@ -30229,9 +30302,9 @@ var imageRouter = {
30229
30302
  throw error;
30230
30303
  }
30231
30304
  } finally {
30232
- uploadProgressEmitter.off(`progress:${uploadId}`, onProgress);
30233
- uploadProgressEmitter.off(`progress:${uploadId}:complete`, onComplete);
30234
- uploadProgressEmitter.off(`progress:${uploadId}:error`, onError);
30305
+ uploadProgressEmitter.off(`progress:${scopedUploadId}`, onProgress);
30306
+ uploadProgressEmitter.off(`progress:${scopedUploadId}:complete`, onComplete);
30307
+ uploadProgressEmitter.off(`progress:${scopedUploadId}:error`, onError);
30235
30308
  }
30236
30309
  }),
30237
30310
  updateImage: projectScopedProcedure.input(updateImageInputSchema).mutation(async ({ input, ctx }) => {
@@ -30772,7 +30845,7 @@ var ERROR_CODES = {
30772
30845
  };
30773
30846
 
30774
30847
  // src/server/Compute/helpers/flavorHelpers.ts
30775
- var import_signal_openstack = __toESM(require_esm());
30848
+ var import_signal_openstack2 = __toESM(require_esm());
30776
30849
  function isErrorWithStatus(error) {
30777
30850
  return typeof error === "object" && error !== null && ("statusCode" in error || "status" in error);
30778
30851
  }
@@ -31127,9 +31200,9 @@ async function getFlavorById(compute, flavorId) {
31127
31200
  }
31128
31201
  let encodedId;
31129
31202
  try {
31130
- encodedId = (0, import_signal_openstack.validateAndEncodeResourceId)(flavorId, "Flavor");
31203
+ encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31131
31204
  } catch (error) {
31132
- if (error instanceof import_signal_openstack.SignalOpenstackError) {
31205
+ if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31133
31206
  throw new import_server7.TRPCError({
31134
31207
  code: "BAD_REQUEST",
31135
31208
  message: ERROR_CODES.GET_FLAVOR_DETAILS_INVALID_ID,
@@ -31243,9 +31316,9 @@ async function deleteFlavor(compute, flavorId) {
31243
31316
  }
31244
31317
  let encodedId;
31245
31318
  try {
31246
- encodedId = (0, import_signal_openstack.validateAndEncodeResourceId)(flavorId, "Flavor");
31319
+ encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31247
31320
  } catch (error) {
31248
- if (error instanceof import_signal_openstack.SignalOpenstackError) {
31321
+ if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31249
31322
  throw new import_server7.TRPCError({
31250
31323
  code: "BAD_REQUEST",
31251
31324
  message: ERROR_CODES.DELETE_FLAVOR_INVALID_ID,
@@ -31274,9 +31347,9 @@ __name(deleteFlavor, "deleteFlavor");
31274
31347
  async function createExtraSpecs(compute, flavorId, extra_specs) {
31275
31348
  let encodedId;
31276
31349
  try {
31277
- encodedId = (0, import_signal_openstack.validateAndEncodeResourceId)(flavorId, "Flavor");
31350
+ encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31278
31351
  } catch (error) {
31279
- if (error instanceof import_signal_openstack.SignalOpenstackError) {
31352
+ if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31280
31353
  throw new import_server7.TRPCError({
31281
31354
  code: "BAD_REQUEST",
31282
31355
  message: ERROR_CODES.CREATE_EXTRA_SPECS_FAILED,
@@ -31314,9 +31387,9 @@ __name(createExtraSpecs, "createExtraSpecs");
31314
31387
  async function getExtraSpecs(compute, flavorId) {
31315
31388
  let encodedId;
31316
31389
  try {
31317
- encodedId = (0, import_signal_openstack.validateAndEncodeResourceId)(flavorId, "Flavor");
31390
+ encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31318
31391
  } catch (error) {
31319
- if (error instanceof import_signal_openstack.SignalOpenstackError) {
31392
+ if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31320
31393
  throw new import_server7.TRPCError({
31321
31394
  code: "BAD_REQUEST",
31322
31395
  message: ERROR_CODES.GET_EXTRA_SPECS_FAILED,
@@ -31352,10 +31425,10 @@ __name(getExtraSpecs, "getExtraSpecs");
31352
31425
  async function deleteExtraSpec(compute, flavorId, key) {
31353
31426
  let encodedId, encodedKey;
31354
31427
  try {
31355
- encodedId = (0, import_signal_openstack.validateAndEncodeResourceId)(flavorId, "Flavor");
31356
- encodedKey = (0, import_signal_openstack.encodeOpenstackPathSegment)(key, "Extra spec key");
31428
+ encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31429
+ encodedKey = (0, import_signal_openstack2.encodeOpenstackPathSegment)(key, "Extra spec key");
31357
31430
  } catch (error) {
31358
- if (error instanceof import_signal_openstack.SignalOpenstackError) {
31431
+ if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31359
31432
  throw new import_server7.TRPCError({
31360
31433
  code: "BAD_REQUEST",
31361
31434
  message: ERROR_CODES.DELETE_EXTRA_SPEC_FAILED,
@@ -31380,9 +31453,9 @@ __name(deleteExtraSpec, "deleteExtraSpec");
31380
31453
  async function getFlavorAccess(compute, flavorId) {
31381
31454
  let encodedId;
31382
31455
  try {
31383
- encodedId = (0, import_signal_openstack.validateAndEncodeResourceId)(flavorId, "Flavor");
31456
+ encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31384
31457
  } catch (error) {
31385
- if (error instanceof import_signal_openstack.SignalOpenstackError) {
31458
+ if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31386
31459
  throw new import_server7.TRPCError({
31387
31460
  code: "BAD_REQUEST",
31388
31461
  message: ERROR_CODES.GET_FLAVOR_ACCESS_FAILED,
@@ -31418,9 +31491,9 @@ __name(getFlavorAccess, "getFlavorAccess");
31418
31491
  async function addTenantAccess(compute, flavorId, tenantId) {
31419
31492
  let encodedId;
31420
31493
  try {
31421
- encodedId = (0, import_signal_openstack.validateAndEncodeResourceId)(flavorId, "Flavor");
31494
+ encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31422
31495
  } catch (error) {
31423
- if (error instanceof import_signal_openstack.SignalOpenstackError) {
31496
+ if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31424
31497
  throw new import_server7.TRPCError({
31425
31498
  code: "BAD_REQUEST",
31426
31499
  message: ERROR_CODES.ADD_TENANT_ACCESS_FAILED,
@@ -31461,9 +31534,9 @@ __name(addTenantAccess, "addTenantAccess");
31461
31534
  async function removeTenantAccess(compute, flavorId, tenantId) {
31462
31535
  let encodedId;
31463
31536
  try {
31464
- encodedId = (0, import_signal_openstack.validateAndEncodeResourceId)(flavorId, "Flavor");
31537
+ encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31465
31538
  } catch (error) {
31466
- if (error instanceof import_signal_openstack.SignalOpenstackError) {
31539
+ if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31467
31540
  throw new import_server7.TRPCError({
31468
31541
  code: "BAD_REQUEST",
31469
31542
  message: ERROR_CODES.REMOVE_TENANT_ACCESS_FAILED,
@@ -31504,7 +31577,7 @@ __name(removeTenantAccess, "removeTenantAccess");
31504
31577
 
31505
31578
  // src/server/Compute/routers/flavorRouter.ts
31506
31579
  var import_server8 = require("@trpc/server");
31507
- var import_signal_openstack2 = __toESM(require_esm());
31580
+ var import_signal_openstack3 = __toESM(require_esm());
31508
31581
  var flavorRouter = {
31509
31582
  getFlavorById: projectScopedProcedure.input(import_zod9.z.object({
31510
31583
  project_id: import_zod9.z.string(),
@@ -31749,9 +31822,9 @@ var flavorRouter = {
31749
31822
  }
31750
31823
  let encodedId;
31751
31824
  try {
31752
- encodedId = (0, import_signal_openstack2.validateAndEncodeResourceId)(flavorId, "Flavor");
31825
+ encodedId = (0, import_signal_openstack3.validateAndEncodeResourceId)(flavorId, "Flavor");
31753
31826
  } catch (error) {
31754
- if (error instanceof import_signal_openstack2.SignalOpenstackError) {
31827
+ if (error instanceof import_signal_openstack3.SignalOpenstackError) {
31755
31828
  throw new import_server8.TRPCError({
31756
31829
  code: "BAD_REQUEST",
31757
31830
  message: ERROR_CODES.GET_FLAVOR_ACCESS_FAILED,
@@ -34421,7 +34494,7 @@ var cephUploadProcedure = protectedProcedure.use(/* @__PURE__ */ __name(async fu
34421
34494
 
34422
34495
  // src/server/Storage/helpers/s3ErrorMapper.ts
34423
34496
  var import_server13 = require("@trpc/server");
34424
- var import_signal_openstack3 = __toESM(require_esm());
34497
+ var import_signal_openstack4 = __toESM(require_esm());
34425
34498
  var S3_ERROR_MAP = {
34426
34499
  NoSuchBucket: "NOT_FOUND",
34427
34500
  NoSuchKey: "NOT_FOUND",
@@ -34429,6 +34502,7 @@ var S3_ERROR_MAP = {
34429
34502
  NoSuchVersion: "NOT_FOUND",
34430
34503
  NoSuchBucketPolicy: "NOT_FOUND",
34431
34504
  NoSuchCORSConfiguration: "NOT_FOUND",
34505
+ NoSuchLifecycleConfiguration: "NOT_FOUND",
34432
34506
  BucketAlreadyExists: "CONFLICT",
34433
34507
  BucketAlreadyOwnedByYou: "CONFLICT",
34434
34508
  BucketNotEmpty: "PRECONDITION_FAILED",
@@ -34458,7 +34532,7 @@ function mapS3ErrorToTRPCError(error, context) {
34458
34532
  const errorCode = s3Error.Code ?? s3Error.name ?? "";
34459
34533
  const trpcCode = S3_ERROR_MAP[errorCode] ?? "INTERNAL_SERVER_ERROR";
34460
34534
  if (!S3_ERROR_MAP[errorCode] && errorCode) {
34461
- import_signal_openstack3.logger.warn("Unmapped S3 error code", {
34535
+ import_signal_openstack4.logger.warn("Unmapped S3 error code", {
34462
34536
  errorCode,
34463
34537
  operation: context.operation,
34464
34538
  errorName: s3Error.name
@@ -34884,6 +34958,187 @@ var setCorsInputSchema = projectScopedInputSchema.extend({
34884
34958
  var deleteCorsInputSchema = projectScopedInputSchema.extend({
34885
34959
  bucketName: existingBucketNameSchema
34886
34960
  });
34961
+ var lifecycleRuleStatusSchema = import_zod13.z.enum([
34962
+ "Enabled",
34963
+ "Disabled"
34964
+ ]);
34965
+ var lifecycleExpirationSchema = import_zod13.z.object({
34966
+ Days: import_zod13.z.number().int().min(1).max(3650).optional(),
34967
+ Date: import_zod13.z.string().datetime({
34968
+ offset: true
34969
+ }).optional(),
34970
+ ExpiredObjectDeleteMarker: import_zod13.z.boolean().optional()
34971
+ }).refine((val) => {
34972
+ return val.Days !== void 0 || val.Date !== void 0 || val.ExpiredObjectDeleteMarker !== void 0;
34973
+ }, "Expiration must specify either Days, Date, or ExpiredObjectDeleteMarker").refine((val) => {
34974
+ return !(val.Days !== void 0 && val.Date !== void 0);
34975
+ }, "Expiration cannot specify both Days and Date").refine((val) => !(val.ExpiredObjectDeleteMarker !== void 0 && (val.Days !== void 0 || val.Date !== void 0)), "ExpiredObjectDeleteMarker cannot be combined with Days or Date");
34976
+ var lifecycleTransitionSchema = import_zod13.z.object({
34977
+ Days: import_zod13.z.number().int().min(1).optional(),
34978
+ Date: import_zod13.z.string().datetime({
34979
+ offset: true
34980
+ }).optional(),
34981
+ StorageClass: import_zod13.z.string().min(1)
34982
+ }).refine((val) => {
34983
+ return val.Days !== void 0 !== (val.Date !== void 0);
34984
+ }, "Transition must specify exactly one of Days or Date");
34985
+ var lifecycleNoncurrentVersionExpirationSchema = import_zod13.z.object({
34986
+ NoncurrentDays: import_zod13.z.number().int().min(1),
34987
+ NewerNoncurrentVersions: import_zod13.z.number().int().min(1).optional()
34988
+ });
34989
+ var lifecycleNoncurrentVersionTransitionSchema = import_zod13.z.object({
34990
+ NoncurrentDays: import_zod13.z.number().int().min(1),
34991
+ StorageClass: import_zod13.z.string().min(1),
34992
+ NewerNoncurrentVersions: import_zod13.z.number().int().min(1).optional()
34993
+ });
34994
+ var lifecycleAbortIncompleteMultipartUploadSchema = import_zod13.z.object({
34995
+ DaysAfterInitiation: import_zod13.z.number().int().min(1)
34996
+ });
34997
+ var lifecycleTagSchema = import_zod13.z.object({
34998
+ Key: import_zod13.z.string().min(1).max(128),
34999
+ Value: import_zod13.z.string().max(256)
35000
+ });
35001
+ var lifecycleFilterAndSchema = import_zod13.z.object({
35002
+ Prefix: import_zod13.z.string().optional(),
35003
+ Tags: import_zod13.z.array(lifecycleTagSchema).optional(),
35004
+ ObjectSizeGreaterThan: import_zod13.z.number().int().min(0).optional(),
35005
+ ObjectSizeLessThan: import_zod13.z.number().int().min(0).optional()
35006
+ }).refine((val) => {
35007
+ const predicateCount = (val.Prefix !== void 0 && val.Prefix !== "" ? 1 : 0) + (val.Tags?.length ?? 0) + (val.ObjectSizeGreaterThan !== void 0 ? 1 : 0) + (val.ObjectSizeLessThan !== void 0 ? 1 : 0);
35008
+ return predicateCount >= 2;
35009
+ }, {
35010
+ message: "And filter must contain at least 2 predicates"
35011
+ });
35012
+ var lifecycleFilterSchema = import_zod13.z.object({
35013
+ Prefix: import_zod13.z.string().optional(),
35014
+ Tag: lifecycleTagSchema.optional(),
35015
+ ObjectSizeGreaterThan: import_zod13.z.number().int().min(0).optional(),
35016
+ ObjectSizeLessThan: import_zod13.z.number().int().min(0).optional(),
35017
+ And: lifecycleFilterAndSchema.optional()
35018
+ }).refine((val) => {
35019
+ const topLevelConditions = [
35020
+ val.Prefix !== void 0,
35021
+ val.Tag !== void 0,
35022
+ val.ObjectSizeGreaterThan !== void 0,
35023
+ val.ObjectSizeLessThan !== void 0
35024
+ ].filter(Boolean).length;
35025
+ if (topLevelConditions > 1) {
35026
+ return false;
35027
+ }
35028
+ if (val.And && topLevelConditions > 0) {
35029
+ return false;
35030
+ }
35031
+ return true;
35032
+ }, {
35033
+ message: "Multiple filter conditions (Prefix, Tag, ObjectSize) must be wrapped in an And clause"
35034
+ });
35035
+ var lifecycleRuleSchema = import_zod13.z.object({
35036
+ ID: import_zod13.z.string().max(255, "Rule ID must be at most 255 characters").optional(),
35037
+ Status: lifecycleRuleStatusSchema,
35038
+ Prefix: import_zod13.z.string().optional(),
35039
+ Filter: lifecycleFilterSchema.optional(),
35040
+ Expiration: lifecycleExpirationSchema.optional(),
35041
+ Transitions: import_zod13.z.array(lifecycleTransitionSchema).optional(),
35042
+ NoncurrentVersionExpiration: lifecycleNoncurrentVersionExpirationSchema.optional(),
35043
+ NoncurrentVersionTransitions: import_zod13.z.array(lifecycleNoncurrentVersionTransitionSchema).optional(),
35044
+ AbortIncompleteMultipartUpload: lifecycleAbortIncompleteMultipartUploadSchema.optional()
35045
+ }).refine((val) => {
35046
+ return val.Expiration !== void 0 || val.Transitions !== void 0 && val.Transitions.length > 0 || val.NoncurrentVersionExpiration !== void 0 || val.NoncurrentVersionTransitions !== void 0 && val.NoncurrentVersionTransitions.length > 0 || val.AbortIncompleteMultipartUpload !== void 0;
35047
+ }, {
35048
+ message: "Rule must have at least one action (Expiration, Transition, NoncurrentVersion, or AbortIncompleteMultipartUpload)"
35049
+ }).refine((val) => {
35050
+ return !(val.Filter !== void 0 && val.Prefix !== void 0);
35051
+ }, {
35052
+ message: "Rule cannot have both Filter and legacy Prefix field set (use Filter.Prefix instead)"
35053
+ }).refine((val) => {
35054
+ if (val.Expiration?.ExpiredObjectDeleteMarker !== true) {
35055
+ return true;
35056
+ }
35057
+ const hasTagFilter = val.Filter?.Tag !== void 0 || val.Filter?.And?.Tags !== void 0 && val.Filter.And.Tags.length > 0;
35058
+ return !hasTagFilter;
35059
+ }, {
35060
+ message: "ExpiredObjectDeleteMarker cannot be combined with tag-based filters"
35061
+ }).refine((val) => {
35062
+ if (val.AbortIncompleteMultipartUpload === void 0) return true;
35063
+ const hasTagFilter = val.Filter?.Tag !== void 0 || val.Filter?.And?.Tags !== void 0 && val.Filter.And.Tags.length > 0;
35064
+ return !hasTagFilter;
35065
+ }, {
35066
+ message: "AbortIncompleteMultipartUpload cannot be combined with tag-based filters"
35067
+ });
35068
+ var lifecycleRuleReadSchema = import_zod13.z.object({
35069
+ ID: import_zod13.z.string().optional(),
35070
+ Status: import_zod13.z.string(),
35071
+ Prefix: import_zod13.z.string().optional(),
35072
+ Filter: import_zod13.z.object({
35073
+ Prefix: import_zod13.z.string().optional(),
35074
+ Tag: import_zod13.z.object({
35075
+ Key: import_zod13.z.string(),
35076
+ Value: import_zod13.z.string()
35077
+ }).optional(),
35078
+ ObjectSizeGreaterThan: import_zod13.z.number().optional(),
35079
+ ObjectSizeLessThan: import_zod13.z.number().optional(),
35080
+ And: import_zod13.z.object({
35081
+ Prefix: import_zod13.z.string().optional(),
35082
+ Tags: import_zod13.z.array(import_zod13.z.object({
35083
+ Key: import_zod13.z.string(),
35084
+ Value: import_zod13.z.string()
35085
+ })).optional(),
35086
+ ObjectSizeGreaterThan: import_zod13.z.number().optional(),
35087
+ ObjectSizeLessThan: import_zod13.z.number().optional()
35088
+ }).optional()
35089
+ }).passthrough().optional(),
35090
+ Expiration: import_zod13.z.object({
35091
+ Days: import_zod13.z.number().optional(),
35092
+ Date: import_zod13.z.union([
35093
+ import_zod13.z.string(),
35094
+ import_zod13.z.date()
35095
+ ]).optional(),
35096
+ ExpiredObjectDeleteMarker: import_zod13.z.boolean().optional()
35097
+ }).passthrough().optional(),
35098
+ Transitions: import_zod13.z.array(import_zod13.z.object({
35099
+ Days: import_zod13.z.number().optional(),
35100
+ Date: import_zod13.z.union([
35101
+ import_zod13.z.string(),
35102
+ import_zod13.z.date()
35103
+ ]).optional(),
35104
+ StorageClass: import_zod13.z.string()
35105
+ }).passthrough()).optional(),
35106
+ NoncurrentVersionExpiration: import_zod13.z.object({
35107
+ NoncurrentDays: import_zod13.z.number().optional(),
35108
+ NewerNoncurrentVersions: import_zod13.z.number().optional()
35109
+ }).passthrough().optional(),
35110
+ NoncurrentVersionTransitions: import_zod13.z.array(import_zod13.z.object({
35111
+ NoncurrentDays: import_zod13.z.number().optional(),
35112
+ StorageClass: import_zod13.z.string(),
35113
+ NewerNoncurrentVersions: import_zod13.z.number().optional()
35114
+ }).passthrough()).optional(),
35115
+ AbortIncompleteMultipartUpload: import_zod13.z.object({
35116
+ DaysAfterInitiation: import_zod13.z.number().optional()
35117
+ }).passthrough().optional()
35118
+ });
35119
+ var lifecycleConfigurationSchema = import_zod13.z.object({
35120
+ Rules: import_zod13.z.array(lifecycleRuleSchema).min(1, "At least one lifecycle rule is required").max(100, "Maximum 100 lifecycle rules per bucket")
35121
+ }).refine((val) => {
35122
+ const ids = val.Rules.map((r) => r.ID).filter((id) => id !== void 0 && id !== "");
35123
+ const uniqueIds = new Set(ids);
35124
+ return ids.length === uniqueIds.size;
35125
+ }, {
35126
+ message: "Rule IDs must be unique within a lifecycle configuration"
35127
+ });
35128
+ var getLifecycleInputSchema = projectScopedInputSchema.extend({
35129
+ bucketName: existingBucketNameSchema
35130
+ });
35131
+ var getLifecycleOutputSchema = import_zod13.z.object({
35132
+ rules: import_zod13.z.array(lifecycleRuleReadSchema).nullable(),
35133
+ skippedRuleCount: import_zod13.z.number().int().min(0)
35134
+ });
35135
+ var setLifecycleInputSchema = projectScopedInputSchema.extend({
35136
+ bucketName: existingBucketNameSchema,
35137
+ lifecycleConfiguration: lifecycleConfigurationSchema
35138
+ });
35139
+ var deleteLifecycleInputSchema = projectScopedInputSchema.extend({
35140
+ bucketName: existingBucketNameSchema
35141
+ });
34887
35142
 
34888
35143
  // src/server/Storage/routers/ceph/containerRouter.ts
34889
35144
  var containerRouter = {
@@ -36796,17 +37051,18 @@ function checkPolicySetRateLimit(bucketName, projectId) {
36796
37051
  const key = `${projectId}:${bucketName}`;
36797
37052
  const now = Date.now();
36798
37053
  const windowMs = 5 * 60 * 1e3;
36799
- for (const [k, v] of policySetRateLimits.entries()) {
36800
- if (now > v.resetAt) {
36801
- policySetRateLimits.delete(k);
36802
- }
36803
- }
36804
37054
  const limit = policySetRateLimits.get(key);
36805
37055
  if (!limit || now > limit.resetAt) {
36806
37056
  policySetRateLimits.set(key, {
36807
37057
  count: 1,
36808
37058
  resetAt: now + windowMs
36809
37059
  });
37060
+ setTimeout(() => {
37061
+ const current = policySetRateLimits.get(key);
37062
+ if (current && current.resetAt <= Date.now()) {
37063
+ policySetRateLimits.delete(key);
37064
+ }
37065
+ }, windowMs).unref();
36810
37066
  return;
36811
37067
  }
36812
37068
  if (limit.count >= 10) {
@@ -37024,17 +37280,18 @@ function checkCorsSetRateLimit(bucketName, projectId) {
37024
37280
  const key = `${projectId}:${bucketName}`;
37025
37281
  const now = Date.now();
37026
37282
  const windowMs = 60 * 1e3;
37027
- for (const [k, v] of corsSetRateLimits.entries()) {
37028
- if (now > v.resetAt) {
37029
- corsSetRateLimits.delete(k);
37030
- }
37031
- }
37032
37283
  const limit = corsSetRateLimits.get(key);
37033
37284
  if (!limit || now > limit.resetAt) {
37034
37285
  corsSetRateLimits.set(key, {
37035
37286
  count: 1,
37036
37287
  resetAt: now + windowMs
37037
37288
  });
37289
+ setTimeout(() => {
37290
+ const current = corsSetRateLimits.get(key);
37291
+ if (current && current.resetAt <= Date.now()) {
37292
+ corsSetRateLimits.delete(key);
37293
+ }
37294
+ }, windowMs).unref();
37038
37295
  return;
37039
37296
  }
37040
37297
  if (limit.count >= 10) {
@@ -37153,6 +37410,274 @@ var corsRouter = {
37153
37410
  })
37154
37411
  };
37155
37412
 
37413
+ // src/server/Storage/routers/ceph/lifecycleRouter.ts
37414
+ var import_client_s37 = require("@aws-sdk/client-s3");
37415
+ var import_server18 = require("@trpc/server");
37416
+
37417
+ // src/server/Storage/helpers/lifecycleMapper.ts
37418
+ function toMidnightUTC(date) {
37419
+ return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
37420
+ }
37421
+ __name(toMidnightUTC, "toMidnightUTC");
37422
+ function toSdkLifecycleRules(wireRules) {
37423
+ return wireRules.map((rule) => {
37424
+ const result = {
37425
+ Status: rule.Status,
37426
+ ID: rule.ID,
37427
+ Prefix: rule.Prefix,
37428
+ Filter: rule.Filter
37429
+ };
37430
+ if (rule.Expiration) {
37431
+ result.Expiration = {
37432
+ Days: rule.Expiration.Days,
37433
+ ExpiredObjectDeleteMarker: rule.Expiration.ExpiredObjectDeleteMarker,
37434
+ // Only normalize Expiration.Date to midnight UTC (AWS requirement)
37435
+ Date: rule.Expiration.Date !== void 0 ? typeof rule.Expiration.Date === "string" ? toMidnightUTC(new Date(rule.Expiration.Date)) : toMidnightUTC(rule.Expiration.Date) : void 0
37436
+ };
37437
+ }
37438
+ if (rule.Transitions) {
37439
+ result.Transitions = rule.Transitions.map((t2) => ({
37440
+ Days: t2.Days,
37441
+ StorageClass: t2.StorageClass,
37442
+ Date: t2.Date !== void 0 ? typeof t2.Date === "string" ? new Date(t2.Date) : t2.Date : void 0
37443
+ }));
37444
+ }
37445
+ if (rule.NoncurrentVersionExpiration) {
37446
+ result.NoncurrentVersionExpiration = {
37447
+ NoncurrentDays: rule.NoncurrentVersionExpiration.NoncurrentDays,
37448
+ NewerNoncurrentVersions: rule.NoncurrentVersionExpiration.NewerNoncurrentVersions
37449
+ };
37450
+ }
37451
+ if (rule.NoncurrentVersionTransitions) {
37452
+ result.NoncurrentVersionTransitions = rule.NoncurrentVersionTransitions.map((t2) => ({
37453
+ NoncurrentDays: t2.NoncurrentDays,
37454
+ StorageClass: t2.StorageClass,
37455
+ NewerNoncurrentVersions: t2.NewerNoncurrentVersions
37456
+ }));
37457
+ }
37458
+ if (rule.AbortIncompleteMultipartUpload) {
37459
+ result.AbortIncompleteMultipartUpload = {
37460
+ DaysAfterInitiation: rule.AbortIncompleteMultipartUpload.DaysAfterInitiation
37461
+ };
37462
+ }
37463
+ return result;
37464
+ });
37465
+ }
37466
+ __name(toSdkLifecycleRules, "toSdkLifecycleRules");
37467
+ var toIso = /* @__PURE__ */ __name((d) => d === void 0 ? void 0 : d instanceof Date ? d.toISOString() : String(d), "toIso");
37468
+ function toWireLifecycleRule(rule) {
37469
+ const result = {
37470
+ Status: rule.Status ?? "Enabled"
37471
+ };
37472
+ if (rule.ID !== void 0) result.ID = rule.ID;
37473
+ if (rule.Prefix !== void 0) result.Prefix = rule.Prefix;
37474
+ if (rule.Filter !== void 0) result.Filter = rule.Filter;
37475
+ if (rule.Expiration) {
37476
+ result.Expiration = {
37477
+ Days: rule.Expiration.Days,
37478
+ ExpiredObjectDeleteMarker: rule.Expiration.ExpiredObjectDeleteMarker,
37479
+ Date: toIso(rule.Expiration.Date)
37480
+ };
37481
+ }
37482
+ if (rule.Transitions) {
37483
+ result.Transitions = rule.Transitions.map((t2) => ({
37484
+ Days: t2.Days,
37485
+ StorageClass: t2.StorageClass,
37486
+ Date: toIso(t2.Date)
37487
+ }));
37488
+ }
37489
+ if (rule.NoncurrentVersionExpiration) {
37490
+ result.NoncurrentVersionExpiration = {
37491
+ NoncurrentDays: rule.NoncurrentVersionExpiration.NoncurrentDays,
37492
+ NewerNoncurrentVersions: rule.NoncurrentVersionExpiration.NewerNoncurrentVersions
37493
+ };
37494
+ }
37495
+ if (rule.NoncurrentVersionTransitions) {
37496
+ result.NoncurrentVersionTransitions = rule.NoncurrentVersionTransitions.map((t2) => ({
37497
+ NoncurrentDays: t2.NoncurrentDays,
37498
+ StorageClass: t2.StorageClass,
37499
+ NewerNoncurrentVersions: t2.NewerNoncurrentVersions
37500
+ }));
37501
+ }
37502
+ if (rule.AbortIncompleteMultipartUpload) {
37503
+ result.AbortIncompleteMultipartUpload = {
37504
+ DaysAfterInitiation: rule.AbortIncompleteMultipartUpload.DaysAfterInitiation
37505
+ };
37506
+ }
37507
+ return result;
37508
+ }
37509
+ __name(toWireLifecycleRule, "toWireLifecycleRule");
37510
+
37511
+ // src/server/Storage/routers/ceph/lifecycleRouter.ts
37512
+ var lifecycleSetRateLimits = /* @__PURE__ */ new Map();
37513
+ function checkLifecycleSetRateLimit(bucketName, projectId) {
37514
+ const key = `${projectId}:${bucketName}`;
37515
+ const now = Date.now();
37516
+ const windowMs = 60 * 1e3;
37517
+ const limit = lifecycleSetRateLimits.get(key);
37518
+ if (!limit || now >= limit.resetAt) {
37519
+ lifecycleSetRateLimits.set(key, {
37520
+ count: 1,
37521
+ resetAt: now + windowMs
37522
+ });
37523
+ setTimeout(() => {
37524
+ const current = lifecycleSetRateLimits.get(key);
37525
+ if (current && current.resetAt <= Date.now()) {
37526
+ lifecycleSetRateLimits.delete(key);
37527
+ }
37528
+ }, windowMs).unref();
37529
+ return;
37530
+ }
37531
+ if (limit.count >= 10) {
37532
+ throw new import_server18.TRPCError({
37533
+ code: "TOO_MANY_REQUESTS",
37534
+ message: "Lifecycle modification rate limit exceeded. Maximum 10 lifecycle changes per minute per bucket."
37535
+ });
37536
+ }
37537
+ limit.count++;
37538
+ }
37539
+ __name(checkLifecycleSetRateLimit, "checkLifecycleSetRateLimit");
37540
+ var lifecycleRouter = {
37541
+ /**
37542
+ * Get the current lifecycle configuration for a bucket.
37543
+ *
37544
+ * Returns an array of lifecycle rules, or null if no lifecycle configuration is set.
37545
+ * Not having a lifecycle configuration is a normal state (not an error).
37546
+ *
37547
+ * Rules are mapped and validated individually a rule that fails the lenient read schema
37548
+ * (e.g. authored outside Aurora) is skipped rather than failing the whole response;
37549
+ * `skippedRuleCount` reports how many were skipped so the client can warn and disable mutations.
37550
+ *
37551
+ * @returns { rules: LifecycleRule[] | null; skippedRuleCount: number }
37552
+ * @throws TRPCError NOT_FOUND - bucket does not exist
37553
+ * @throws TRPCError FORBIDDEN - no credentials or access denied
37554
+ */
37555
+ get: cephProtectedProcedure.input(getLifecycleInputSchema).query(async ({ ctx, input }) => {
37556
+ const s3 = ctx.getCephClient();
37557
+ const { bucketName } = input;
37558
+ try {
37559
+ const response = await s3.send(new import_client_s37.GetBucketLifecycleConfigurationCommand({
37560
+ Bucket: bucketName
37561
+ }));
37562
+ const rawRules = response.Rules ?? null;
37563
+ if (!rawRules) {
37564
+ return {
37565
+ rules: null,
37566
+ skippedRuleCount: 0
37567
+ };
37568
+ }
37569
+ const rules = [];
37570
+ let skippedRuleCount = 0;
37571
+ for (const rawRule of rawRules) {
37572
+ try {
37573
+ const parsed = lifecycleRuleReadSchema.safeParse(toWireLifecycleRule(rawRule));
37574
+ if (parsed.success) {
37575
+ rules.push(parsed.data);
37576
+ continue;
37577
+ }
37578
+ skippedRuleCount++;
37579
+ } catch {
37580
+ skippedRuleCount++;
37581
+ }
37582
+ }
37583
+ return {
37584
+ rules,
37585
+ skippedRuleCount
37586
+ };
37587
+ } catch (error) {
37588
+ const s3Error = error;
37589
+ if (s3Error.name === "NoSuchLifecycleConfiguration" || s3Error.Code === "NoSuchLifecycleConfiguration") {
37590
+ return {
37591
+ rules: null,
37592
+ skippedRuleCount: 0
37593
+ };
37594
+ }
37595
+ throw mapS3ErrorToTRPCError(error, {
37596
+ operation: "get lifecycle configuration",
37597
+ bucket: bucketName
37598
+ });
37599
+ }
37600
+ }),
37601
+ /**
37602
+ * Set (create or replace) a lifecycle configuration for a bucket.
37603
+ *
37604
+ * Accepts a lifecycle configuration with an array of rules. Validates structure
37605
+ * before sending to S3. Replaces any existing lifecycle configuration completely.
37606
+ *
37607
+ * Rules are validated for:
37608
+ * - At least one action (Expiration, Transition, NoncurrentVersion, or AbortIncompleteMultipartUpload)
37609
+ * - ID: max 255 characters (optional)
37610
+ * - Filter: proper structure for Prefix, Tag, ObjectSize conditions
37611
+ * - Total rules: 1-100 per bucket
37612
+ *
37613
+ * @returns boolean - true on success
37614
+ * @throws TRPCError BAD_REQUEST - invalid lifecycle configuration structure
37615
+ * @throws TRPCError NOT_FOUND - bucket does not exist
37616
+ * @throws TRPCError FORBIDDEN - no credentials or access denied
37617
+ * @throws TRPCError TOO_MANY_REQUESTS - rate limit exceeded (10 changes per minute per bucket)
37618
+ */
37619
+ set: cephProtectedProcedure.input(setLifecycleInputSchema).mutation(async ({ ctx, input }) => {
37620
+ const s3 = ctx.getCephClient();
37621
+ const { bucketName, lifecycleConfiguration, project_id } = input;
37622
+ checkLifecycleSetRateLimit(bucketName, project_id);
37623
+ const transformedRules = toSdkLifecycleRules(lifecycleConfiguration.Rules).map((rule) => {
37624
+ const transformed = {
37625
+ ...rule
37626
+ };
37627
+ if (transformed.Prefix !== void 0 && transformed.Filter === void 0) {
37628
+ transformed.Filter = {
37629
+ Prefix: transformed.Prefix
37630
+ };
37631
+ }
37632
+ delete transformed.Prefix;
37633
+ return transformed;
37634
+ });
37635
+ try {
37636
+ await s3.send(new import_client_s37.PutBucketLifecycleConfigurationCommand({
37637
+ Bucket: bucketName,
37638
+ LifecycleConfiguration: {
37639
+ Rules: transformedRules
37640
+ }
37641
+ }));
37642
+ return true;
37643
+ } catch (error) {
37644
+ throw mapS3ErrorToTRPCError(error, {
37645
+ operation: "set lifecycle configuration",
37646
+ bucket: bucketName
37647
+ });
37648
+ }
37649
+ }),
37650
+ /**
37651
+ * Delete (remove) a lifecycle configuration from a bucket.
37652
+ *
37653
+ * Removes all lifecycle rules from the bucket. The bucket reverts to having no lifecycle config.
37654
+ * Not an error if no lifecycle configuration was set (idempotent).
37655
+ *
37656
+ * @returns boolean - true on success
37657
+ * @throws TRPCError NOT_FOUND - bucket does not exist
37658
+ * @throws TRPCError FORBIDDEN - no credentials or access denied
37659
+ */
37660
+ delete: cephProtectedProcedure.input(deleteLifecycleInputSchema).mutation(async ({ ctx, input }) => {
37661
+ const s3 = ctx.getCephClient();
37662
+ const { bucketName } = input;
37663
+ try {
37664
+ await s3.send(new import_client_s37.DeleteBucketLifecycleCommand({
37665
+ Bucket: bucketName
37666
+ }));
37667
+ return true;
37668
+ } catch (error) {
37669
+ const s3Error = error;
37670
+ if (s3Error.name === "NoSuchLifecycleConfiguration" || s3Error.Code === "NoSuchLifecycleConfiguration") {
37671
+ return true;
37672
+ }
37673
+ throw mapS3ErrorToTRPCError(error, {
37674
+ operation: "delete lifecycle configuration",
37675
+ bucket: bucketName
37676
+ });
37677
+ }
37678
+ })
37679
+ };
37680
+
37156
37681
  // src/server/Storage/routers/permissionRouter.ts
37157
37682
  var STORAGE_MAPPINGS = {
37158
37683
  // Container Operations (works for both Swift containers and Ceph buckets)
@@ -37192,6 +37717,10 @@ var STORAGE_MAPPINGS = {
37192
37717
  engine: "storage",
37193
37718
  rule: "storage:container_update_access_control"
37194
37719
  },
37720
+ "storage:containers:update_versioning": {
37721
+ engine: "storage",
37722
+ rule: "storage:container_versioning_update"
37723
+ },
37195
37724
  // Object Operations
37196
37725
  "storage:objects:read": {
37197
37726
  engine: "storage",
@@ -37225,6 +37754,10 @@ var STORAGE_MAPPINGS = {
37225
37754
  engine: "storage",
37226
37755
  rule: "storage:object_move"
37227
37756
  },
37757
+ "storage:objects:share": {
37758
+ engine: "storage",
37759
+ rule: "storage:object_share"
37760
+ },
37228
37761
  // Folder Operations
37229
37762
  "storage:folders:create_object": {
37230
37763
  engine: "storage",
@@ -37237,6 +37770,47 @@ var STORAGE_MAPPINGS = {
37237
37770
  "storage:folders:delete": {
37238
37771
  engine: "storage",
37239
37772
  rule: "storage:folder_delete"
37773
+ },
37774
+ // Object Version Operations
37775
+ "storage:object_versions:delete": {
37776
+ engine: "storage",
37777
+ rule: "storage:object_version_delete"
37778
+ },
37779
+ "storage:object_versions:restore": {
37780
+ engine: "storage",
37781
+ rule: "storage:object_version_restore"
37782
+ },
37783
+ // Container Policy Operations
37784
+ "storage:container_policies:update": {
37785
+ engine: "storage",
37786
+ rule: "storage:container_policy_update"
37787
+ },
37788
+ "storage:container_policies:delete": {
37789
+ engine: "storage",
37790
+ rule: "storage:container_policy_delete"
37791
+ },
37792
+ // CORS Operations
37793
+ "storage:container_cors_rules:update": {
37794
+ engine: "storage",
37795
+ rule: "storage:container_cors_update"
37796
+ },
37797
+ "storage:container_cors_rules:delete": {
37798
+ engine: "storage",
37799
+ rule: "storage:container_cors_delete"
37800
+ },
37801
+ // Lifecycle Operations
37802
+ "storage:container_lifecycle_rules:update": {
37803
+ engine: "storage",
37804
+ rule: "storage:container_lifecycle_update"
37805
+ },
37806
+ "storage:container_lifecycle_rules:delete": {
37807
+ engine: "storage",
37808
+ rule: "storage:container_lifecycle_delete"
37809
+ },
37810
+ // Credential Operations
37811
+ "storage:credentials:create": {
37812
+ engine: "storage",
37813
+ rule: "storage:credential_create"
37240
37814
  }
37241
37815
  };
37242
37816
  var buildStoragePermissionRouter = /* @__PURE__ */ __name((policyDir) => createPermissionRouter({
@@ -37273,6 +37847,9 @@ var buildObjectStorageRouters = /* @__PURE__ */ __name((policyDir) => ({
37273
37847
  }),
37274
37848
  cors: auroraRouter({
37275
37849
  ...corsRouter
37850
+ }),
37851
+ lifecycle: auroraRouter({
37852
+ ...lifecycleRouter
37276
37853
  })
37277
37854
  }),
37278
37855
  ...buildStoragePermissionRouter(policyDir)
@@ -37281,7 +37858,7 @@ var buildObjectStorageRouters = /* @__PURE__ */ __name((policyDir) => ({
37281
37858
 
37282
37859
  // src/server/Project/routers/projectRouter.ts
37283
37860
  var import_zod20 = require("zod");
37284
- var import_server18 = require("@trpc/server");
37861
+ var import_server19 = require("@trpc/server");
37285
37862
 
37286
37863
  // src/server/Project/types/models.ts
37287
37864
  var import_zod19 = require("zod");
@@ -37318,10 +37895,10 @@ var projectsResponseSchema = import_zod19.z.object({
37318
37895
  });
37319
37896
 
37320
37897
  // src/server/Project/routers/projectRouter.ts
37321
- var import_signal_openstack4 = __toESM(require_esm());
37898
+ var import_signal_openstack5 = __toESM(require_esm());
37322
37899
  async function callIdentityAPI(identityEndpoint, authToken, path3) {
37323
37900
  if (!identityEndpoint) {
37324
- throw new import_server18.TRPCError({
37901
+ throw new import_server19.TRPCError({
37325
37902
  code: "INTERNAL_SERVER_ERROR",
37326
37903
  message: "Identity endpoint not configured"
37327
37904
  });
@@ -37337,7 +37914,7 @@ async function callIdentityAPI(identityEndpoint, authToken, path3) {
37337
37914
  }
37338
37915
  });
37339
37916
  if (!response.ok) {
37340
- throw new import_server18.TRPCError({
37917
+ throw new import_server19.TRPCError({
37341
37918
  code: "INTERNAL_SERVER_ERROR",
37342
37919
  message: `Identity API call failed: ${response.status} ${response.statusText}`
37343
37920
  });
@@ -37377,14 +37954,14 @@ var projectRouter = {
37377
37954
  */
37378
37955
  getAuthProjects: protectedProcedure.query(async ({ ctx }) => {
37379
37956
  if (!ctx.openstack) {
37380
- throw new import_server18.TRPCError({
37957
+ throw new import_server19.TRPCError({
37381
37958
  code: "UNAUTHORIZED",
37382
37959
  message: "No authenticated session"
37383
37960
  });
37384
37961
  }
37385
37962
  const token = ctx.openstack.getToken();
37386
37963
  if (!token?.authToken) {
37387
- throw new import_server18.TRPCError({
37964
+ throw new import_server19.TRPCError({
37388
37965
  code: "UNAUTHORIZED",
37389
37966
  message: "No auth token available"
37390
37967
  });
@@ -37427,14 +38004,14 @@ var projectRouter = {
37427
38004
  search: import_zod20.z.string().optional()
37428
38005
  }).optional()).query(async ({ ctx, input }) => {
37429
38006
  if (!ctx.openstack) {
37430
- throw new import_server18.TRPCError({
38007
+ throw new import_server19.TRPCError({
37431
38008
  code: "UNAUTHORIZED",
37432
38009
  message: "No authenticated session"
37433
38010
  });
37434
38011
  }
37435
38012
  const token = ctx.openstack.getToken();
37436
38013
  if (!token?.authToken) {
37437
- throw new import_server18.TRPCError({
38014
+ throw new import_server19.TRPCError({
37438
38015
  code: "UNAUTHORIZED",
37439
38016
  message: "No auth token available"
37440
38017
  });
@@ -37458,21 +38035,21 @@ var projectRouter = {
37458
38035
  projectId: import_zod20.z.string()
37459
38036
  })).query(async ({ ctx, input }) => {
37460
38037
  if (!ctx.openstack) {
37461
- throw new import_server18.TRPCError({
38038
+ throw new import_server19.TRPCError({
37462
38039
  code: "UNAUTHORIZED",
37463
38040
  message: "No authenticated session"
37464
38041
  });
37465
38042
  }
37466
38043
  const token = ctx.openstack.getToken();
37467
38044
  if (!token?.authToken) {
37468
- throw new import_server18.TRPCError({
38045
+ throw new import_server19.TRPCError({
37469
38046
  code: "UNAUTHORIZED",
37470
38047
  message: "No auth token available"
37471
38048
  });
37472
38049
  }
37473
38050
  let encodedId;
37474
38051
  try {
37475
- encodedId = (0, import_signal_openstack4.validateAndEncodeResourceId)(input.projectId, "Project");
38052
+ encodedId = (0, import_signal_openstack5.validateAndEncodeResourceId)(input.projectId, "Project");
37476
38053
  } catch {
37477
38054
  return null;
37478
38055
  }
@@ -37491,22 +38068,25 @@ var projectRouters = {
37491
38068
  })
37492
38069
  };
37493
38070
 
38071
+ // src/server/Network/routers/floatingIpRouter.ts
38072
+ var import_server24 = require("@trpc/server");
38073
+
37494
38074
  // src/server/helpers/errorHandling.ts
37495
- var import_server19 = require("@trpc/server");
37496
- var import_signal_openstack5 = __toESM(require_esm());
38075
+ var import_server20 = require("@trpc/server");
38076
+ var import_signal_openstack6 = __toESM(require_esm());
37497
38077
  function wrapError3(error, operation) {
37498
- if (error instanceof import_server19.TRPCError) {
38078
+ if (error instanceof import_server20.TRPCError) {
37499
38079
  return error;
37500
38080
  }
37501
- if (error instanceof import_signal_openstack5.SignalOpenstackError) {
37502
- return new import_server19.TRPCError({
38081
+ if (error instanceof import_signal_openstack6.SignalOpenstackError) {
38082
+ return new import_server20.TRPCError({
37503
38083
  code: "BAD_REQUEST",
37504
38084
  message: error.message,
37505
38085
  cause: error
37506
38086
  });
37507
38087
  }
37508
38088
  const baseErrorMessage = `Error during ${operation}`;
37509
- return new import_server19.TRPCError({
38089
+ return new import_server20.TRPCError({
37510
38090
  code: "INTERNAL_SERVER_ERROR",
37511
38091
  message: typeof error !== "string" && error.message ? `${baseErrorMessage}: ${error.message}` : baseErrorMessage,
37512
38092
  cause: error
@@ -37546,11 +38126,11 @@ function appendQueryParamsFromObject(source, options) {
37546
38126
  __name(appendQueryParamsFromObject, "appendQueryParamsFromObject");
37547
38127
 
37548
38128
  // src/server/helpers/validateOpenstackService.ts
37549
- var import_server20 = require("@trpc/server");
38129
+ var import_server21 = require("@trpc/server");
37550
38130
  var capitalize = /* @__PURE__ */ __name((str) => str.charAt(0).toUpperCase() + str.slice(1), "capitalize");
37551
38131
  function validateOpenstackService(service, serviceName) {
37552
38132
  if (!service) {
37553
- throw new import_server20.TRPCError({
38133
+ throw new import_server21.TRPCError({
37554
38134
  code: "INTERNAL_SERVER_ERROR",
37555
38135
  message: `${capitalize(serviceName)} service is not available`
37556
38136
  });
@@ -37559,7 +38139,7 @@ function validateOpenstackService(service, serviceName) {
37559
38139
  __name(validateOpenstackService, "validateOpenstackService");
37560
38140
 
37561
38141
  // src/server/Network/routers/floatingIpRouter.ts
37562
- var import_signal_openstack6 = __toESM(require_esm());
38142
+ var import_signal_openstack7 = __toESM(require_esm());
37563
38143
 
37564
38144
  // src/server/Network/types/floatingIp.ts
37565
38145
  var import_zod22 = require("zod");
@@ -37672,8 +38252,7 @@ var FloatingIpIdInputSchema = import_zod22.z.object({
37672
38252
  floatingip_id: import_zod22.z.string()
37673
38253
  });
37674
38254
  var FloatingIpCreateRequestSchema = import_zod22.z.object({
37675
- tenant_id: import_zod22.z.string(),
37676
- project_id: import_zod22.z.string(),
38255
+ project_id: import_zod22.z.string().trim().min(1, "project_id must be a non-empty string"),
37677
38256
  floating_network_id: import_zod22.z.string(),
37678
38257
  fixed_ip_address: import_zod22.z.string().optional(),
37679
38258
  floating_ip_address: import_zod22.z.string().optional(),
@@ -37807,10 +38386,10 @@ var AvailablePortsResponseSchema = import_zod22.z.object({
37807
38386
  });
37808
38387
 
37809
38388
  // src/server/Network/helpers/errorHandling.ts
37810
- var import_server22 = require("@trpc/server");
38389
+ var import_server23 = require("@trpc/server");
37811
38390
 
37812
38391
  // src/server/Network/helpers/index.ts
37813
- var import_server21 = require("@trpc/server");
38392
+ var import_server22 = require("@trpc/server");
37814
38393
  var HTTP_STATUS_ERROR_MAP = {
37815
38394
  400: "BAD_REQUEST",
37816
38395
  401: "UNAUTHORIZED",
@@ -37830,7 +38409,7 @@ var parseOrThrow = /* @__PURE__ */ __name((schema, data, context) => {
37830
38409
  const parsed = schema.safeParse(data);
37831
38410
  if (!parsed.success) {
37832
38411
  console.error(`Zod Parsing Error in ${context}:`, parsed.error.issues);
37833
- throw new import_server21.TRPCError({
38412
+ throw new import_server22.TRPCError({
37834
38413
  code: "PARSE_ERROR",
37835
38414
  message: `Failed to parse response in ${context}`
37836
38415
  });
@@ -37840,27 +38419,27 @@ var parseOrThrow = /* @__PURE__ */ __name((schema, data, context) => {
37840
38419
 
37841
38420
  // src/server/Network/helpers/errorHandling.ts
37842
38421
  var DEFAULT_HANDLERS = {
37843
- 400: (response, resourceLabel) => new import_server22.TRPCError({
38422
+ 400: (response, resourceLabel) => new import_server23.TRPCError({
37844
38423
  code: HTTP_STATUS_ERROR_MAP[400],
37845
38424
  message: `Invalid request data for ${resourceLabel}: ${response.statusText || "Unknown error"}`
37846
38425
  }),
37847
- 401: (response, resourceLabel) => new import_server22.TRPCError({
38426
+ 401: (response, resourceLabel) => new import_server23.TRPCError({
37848
38427
  code: HTTP_STATUS_ERROR_MAP[401],
37849
38428
  message: `Unauthorized access to ${resourceLabel}: ${response.statusText || "Unknown error"}`
37850
38429
  }),
37851
- 403: (response, resourceLabel) => new import_server22.TRPCError({
38430
+ 403: (response, resourceLabel) => new import_server23.TRPCError({
37852
38431
  code: HTTP_STATUS_ERROR_MAP[403],
37853
38432
  message: `Access forbidden to ${resourceLabel}: ${response.statusText || "Unknown error"}`
37854
38433
  }),
37855
- 404: (response, resourceLabel) => new import_server22.TRPCError({
38434
+ 404: (response, resourceLabel) => new import_server23.TRPCError({
37856
38435
  code: HTTP_STATUS_ERROR_MAP[404],
37857
38436
  message: `${resourceLabel} not found: ${response.statusText || "Unknown error"}`
37858
38437
  }),
37859
- 409: (response, resourceLabel) => new import_server22.TRPCError({
38438
+ 409: (response, resourceLabel) => new import_server23.TRPCError({
37860
38439
  code: HTTP_STATUS_ERROR_MAP[409],
37861
38440
  message: `Conflict - ${resourceLabel} is in use: ${response.statusText || "Unknown error"}`
37862
38441
  }),
37863
- 412: (response, resourceLabel) => new import_server22.TRPCError({
38442
+ 412: (response, resourceLabel) => new import_server23.TRPCError({
37864
38443
  code: HTTP_STATUS_ERROR_MAP[412],
37865
38444
  message: `Precondition failed - revision number mismatch in ${resourceLabel}: ${response.statusText || "Unknown error"}`
37866
38445
  })
@@ -37875,7 +38454,7 @@ var ErrorHandler = /* @__PURE__ */ __name((resourceName, customHandlers) => {
37875
38454
  if (response.status && handlers[response.status]) {
37876
38455
  return handlers[response.status](response, resourceLabel);
37877
38456
  }
37878
- return new import_server22.TRPCError({
38457
+ return new import_server23.TRPCError({
37879
38458
  code: DEFAULT_ERROR_NAME,
37880
38459
  message: `Failed to process ${resourceLabel}: ${response.statusText || "Unknown error"}`
37881
38460
  });
@@ -37921,10 +38500,18 @@ var floatingIpRouter = {
37921
38500
  create: projectScopedProcedure.input(FloatingIpCreateRequestSchema).mutation(async ({ input, ctx }) => {
37922
38501
  return withErrorHandling3(async () => {
37923
38502
  const network = getNetworkService(ctx);
38503
+ const token = ctx.openstack?.getToken();
38504
+ const projectId = token?.tokenData.project?.id;
38505
+ if (!projectId) {
38506
+ throw new import_server24.TRPCError({
38507
+ code: "UNAUTHORIZED",
38508
+ message: "No project scope in session"
38509
+ });
38510
+ }
37924
38511
  const requestBody = {
37925
38512
  floatingip: {
37926
- tenant_id: input.tenant_id,
37927
- project_id: input.project_id,
38513
+ tenant_id: projectId,
38514
+ project_id: projectId,
37928
38515
  floating_network_id: input.floating_network_id,
37929
38516
  ...input.fixed_ip_address !== void 0 && {
37930
38517
  fixed_ip_address: input.fixed_ip_address
@@ -37967,7 +38554,7 @@ var floatingIpRouter = {
37967
38554
  return withErrorHandling3(async () => {
37968
38555
  const { floatingip_id } = input;
37969
38556
  const network = getNetworkService(ctx);
37970
- const encodedId = (0, import_signal_openstack6.validateAndEncodeResourceId)(floatingip_id, "Floating IP");
38557
+ const encodedId = (0, import_signal_openstack7.validateAndEncodeResourceId)(floatingip_id, "Floating IP");
37971
38558
  const response = await network.get(`${FLOATING_IPS_BASE_URL}/${encodedId}`);
37972
38559
  if (!response.ok) {
37973
38560
  throw FloatingIpErrorHandlers.get(response, floatingip_id);
@@ -37994,7 +38581,7 @@ var floatingIpRouter = {
37994
38581
  }
37995
38582
  }
37996
38583
  };
37997
- const encodedId = (0, import_signal_openstack6.validateAndEncodeResourceId)(floatingip_id, "Floating IP");
38584
+ const encodedId = (0, import_signal_openstack7.validateAndEncodeResourceId)(floatingip_id, "Floating IP");
37998
38585
  const response = await network.put(`${FLOATING_IPS_BASE_URL}/${encodedId}`, requestBody);
37999
38586
  if (!response.ok) {
38000
38587
  throw FloatingIpErrorHandlers.update(response, floatingip_id);
@@ -38007,7 +38594,7 @@ var floatingIpRouter = {
38007
38594
  return withErrorHandling3(async () => {
38008
38595
  const { floatingip_id } = input;
38009
38596
  const network = getNetworkService(ctx);
38010
- const encodedId = (0, import_signal_openstack6.validateAndEncodeResourceId)(floatingip_id, "Floating IP");
38597
+ const encodedId = (0, import_signal_openstack7.validateAndEncodeResourceId)(floatingip_id, "Floating IP");
38011
38598
  const response = await network.del(`${FLOATING_IPS_BASE_URL}/${encodedId}`);
38012
38599
  if (!response.ok) {
38013
38600
  throw FloatingIpErrorHandlers.delete(response, floatingip_id);
@@ -38163,7 +38750,7 @@ var createSecurityGroupRuleInputSchema = projectScopedInputSchema.extend({
38163
38750
  });
38164
38751
 
38165
38752
  // src/server/Network/helpers/securityGroupHelpers.ts
38166
- var import_server23 = require("@trpc/server");
38753
+ var import_server25 = require("@trpc/server");
38167
38754
  var SecurityGroupErrorHandlers = {
38168
38755
  /**
38169
38756
  * Handles errors specific to security group list operations
@@ -38173,17 +38760,17 @@ var SecurityGroupErrorHandlers = {
38173
38760
  list: /* @__PURE__ */ __name((response) => {
38174
38761
  switch (response.status) {
38175
38762
  case 401:
38176
- return new import_server23.TRPCError({
38763
+ return new import_server25.TRPCError({
38177
38764
  code: HTTP_STATUS_ERROR_MAP[401],
38178
38765
  message: "Unauthorized access"
38179
38766
  });
38180
38767
  case 403:
38181
- return new import_server23.TRPCError({
38768
+ return new import_server25.TRPCError({
38182
38769
  code: HTTP_STATUS_ERROR_MAP[403],
38183
38770
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
38184
38771
  });
38185
38772
  default:
38186
- return new import_server23.TRPCError({
38773
+ return new import_server25.TRPCError({
38187
38774
  code: DEFAULT_ERROR_NAME,
38188
38775
  message: `Failed to list security groups: ${response.statusText || "Unknown error"}`
38189
38776
  });
@@ -38198,22 +38785,22 @@ var SecurityGroupErrorHandlers = {
38198
38785
  getById: /* @__PURE__ */ __name((response, securityGroupId) => {
38199
38786
  switch (response.status) {
38200
38787
  case 401:
38201
- return new import_server23.TRPCError({
38788
+ return new import_server25.TRPCError({
38202
38789
  code: HTTP_STATUS_ERROR_MAP[401],
38203
38790
  message: "Unauthorized access"
38204
38791
  });
38205
38792
  case 403:
38206
- return new import_server23.TRPCError({
38793
+ return new import_server25.TRPCError({
38207
38794
  code: HTTP_STATUS_ERROR_MAP[403],
38208
38795
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
38209
38796
  });
38210
38797
  case 404:
38211
- return new import_server23.TRPCError({
38798
+ return new import_server25.TRPCError({
38212
38799
  code: HTTP_STATUS_ERROR_MAP[404],
38213
38800
  message: `Security group not found: ${securityGroupId}`
38214
38801
  });
38215
38802
  default:
38216
- return new import_server23.TRPCError({
38803
+ return new import_server25.TRPCError({
38217
38804
  code: DEFAULT_ERROR_NAME,
38218
38805
  message: `Failed to fetch security group: ${response.statusText || "Unknown error"}`
38219
38806
  });
@@ -38227,32 +38814,32 @@ var SecurityGroupErrorHandlers = {
38227
38814
  create: /* @__PURE__ */ __name((response) => {
38228
38815
  switch (response.status) {
38229
38816
  case 401:
38230
- return new import_server23.TRPCError({
38817
+ return new import_server25.TRPCError({
38231
38818
  code: HTTP_STATUS_ERROR_MAP[401],
38232
38819
  message: "Unauthorized access"
38233
38820
  });
38234
38821
  case 403:
38235
- return new import_server23.TRPCError({
38822
+ return new import_server25.TRPCError({
38236
38823
  code: HTTP_STATUS_ERROR_MAP[403],
38237
38824
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
38238
38825
  });
38239
38826
  case 409:
38240
- return new import_server23.TRPCError({
38827
+ return new import_server25.TRPCError({
38241
38828
  code: HTTP_STATUS_ERROR_MAP[409],
38242
38829
  message: `Conflict: ${response.statusText || "Security group already exists"}`
38243
38830
  });
38244
38831
  case 413:
38245
- return new import_server23.TRPCError({
38832
+ return new import_server25.TRPCError({
38246
38833
  code: "BAD_REQUEST",
38247
38834
  message: `Quota exceeded for security groups. Please delete an existing security group or contact your administrator to increase your quota.`
38248
38835
  });
38249
38836
  case 400:
38250
- return new import_server23.TRPCError({
38837
+ return new import_server25.TRPCError({
38251
38838
  code: "BAD_REQUEST",
38252
38839
  message: `Invalid request: ${response.statusText || "Unknown error"}`
38253
38840
  });
38254
38841
  default:
38255
- return new import_server23.TRPCError({
38842
+ return new import_server25.TRPCError({
38256
38843
  code: "INTERNAL_SERVER_ERROR",
38257
38844
  message: `Failed to create security group: ${response.statusText || "Unknown error"}`
38258
38845
  });
@@ -38267,22 +38854,22 @@ var SecurityGroupErrorHandlers = {
38267
38854
  delete: /* @__PURE__ */ __name((response, securityGroupId) => {
38268
38855
  switch (response.status) {
38269
38856
  case 401:
38270
- return new import_server23.TRPCError({
38857
+ return new import_server25.TRPCError({
38271
38858
  code: HTTP_STATUS_ERROR_MAP[401],
38272
38859
  message: "Unauthorized access"
38273
38860
  });
38274
38861
  case 404:
38275
- return new import_server23.TRPCError({
38862
+ return new import_server25.TRPCError({
38276
38863
  code: HTTP_STATUS_ERROR_MAP[404],
38277
38864
  message: `Security group not found: ${securityGroupId}`
38278
38865
  });
38279
38866
  case 409:
38280
- return new import_server23.TRPCError({
38867
+ return new import_server25.TRPCError({
38281
38868
  code: HTTP_STATUS_ERROR_MAP[409],
38282
38869
  message: "Cannot delete security group because it is in use by one or more ports. Please remove all associations before deleting."
38283
38870
  });
38284
38871
  default:
38285
- return new import_server23.TRPCError({
38872
+ return new import_server25.TRPCError({
38286
38873
  code: DEFAULT_ERROR_NAME,
38287
38874
  message: `Failed to delete security group: ${response.statusText || "Unknown error"}`
38288
38875
  });
@@ -38297,39 +38884,39 @@ var SecurityGroupErrorHandlers = {
38297
38884
  update: /* @__PURE__ */ __name((response, securityGroupId) => {
38298
38885
  const errorMessage = response.statusText || "";
38299
38886
  if (errorMessage.toLowerCase().includes("stateful") && errorMessage.toLowerCase().includes("in use")) {
38300
- return new import_server23.TRPCError({
38887
+ return new import_server25.TRPCError({
38301
38888
  code: "CONFLICT",
38302
38889
  message: "Cannot update the 'stateful' attribute because this security group is in use by one or more ports."
38303
38890
  });
38304
38891
  }
38305
38892
  switch (response.status) {
38306
38893
  case 401:
38307
- return new import_server23.TRPCError({
38894
+ return new import_server25.TRPCError({
38308
38895
  code: HTTP_STATUS_ERROR_MAP[401],
38309
38896
  message: "Unauthorized access"
38310
38897
  });
38311
38898
  case 403:
38312
- return new import_server23.TRPCError({
38899
+ return new import_server25.TRPCError({
38313
38900
  code: HTTP_STATUS_ERROR_MAP[403],
38314
38901
  message: `Access forbidden: ${errorMessage || "Unknown error"}`
38315
38902
  });
38316
38903
  case 404:
38317
- return new import_server23.TRPCError({
38904
+ return new import_server25.TRPCError({
38318
38905
  code: HTTP_STATUS_ERROR_MAP[404],
38319
38906
  message: `Security group not found: ${securityGroupId}`
38320
38907
  });
38321
38908
  case 409:
38322
- return new import_server23.TRPCError({
38909
+ return new import_server25.TRPCError({
38323
38910
  code: HTTP_STATUS_ERROR_MAP[409],
38324
38911
  message: `Conflict: ${errorMessage || "Security group conflict"}`
38325
38912
  });
38326
38913
  case 400:
38327
- return new import_server23.TRPCError({
38914
+ return new import_server25.TRPCError({
38328
38915
  code: HTTP_STATUS_ERROR_MAP[400],
38329
38916
  message: `Invalid request: ${errorMessage || "Unknown error"}`
38330
38917
  });
38331
38918
  default:
38332
- return new import_server23.TRPCError({
38919
+ return new import_server25.TRPCError({
38333
38920
  code: DEFAULT_ERROR_NAME,
38334
38921
  message: `Failed to update security group: ${errorMessage || "Unknown error"}`
38335
38922
  });
@@ -38347,48 +38934,48 @@ var SecurityGroupRuleErrorHandlers = {
38347
38934
  switch (response.status) {
38348
38935
  case 400:
38349
38936
  if (statusText.toLowerCase().includes("cidr")) {
38350
- return new import_server23.TRPCError({
38937
+ return new import_server25.TRPCError({
38351
38938
  code: "BAD_REQUEST",
38352
38939
  message: "Invalid CIDR format. Please provide a valid IP address block (e.g., 0.0.0.0/0)"
38353
38940
  });
38354
38941
  }
38355
38942
  if (statusText.toLowerCase().includes("port")) {
38356
- return new import_server23.TRPCError({
38943
+ return new import_server25.TRPCError({
38357
38944
  code: "BAD_REQUEST",
38358
38945
  message: "Invalid port range. Ports must be between 1 and 65535, and min must be <= max"
38359
38946
  });
38360
38947
  }
38361
- return new import_server23.TRPCError({
38948
+ return new import_server25.TRPCError({
38362
38949
  code: "BAD_REQUEST",
38363
38950
  message: `Invalid request: ${statusText}`
38364
38951
  });
38365
38952
  case 401:
38366
- return new import_server23.TRPCError({
38953
+ return new import_server25.TRPCError({
38367
38954
  code: "UNAUTHORIZED",
38368
38955
  message: "Unauthorized access"
38369
38956
  });
38370
38957
  case 403:
38371
- return new import_server23.TRPCError({
38958
+ return new import_server25.TRPCError({
38372
38959
  code: "FORBIDDEN",
38373
38960
  message: `Access forbidden: ${statusText}`
38374
38961
  });
38375
38962
  case 404:
38376
- return new import_server23.TRPCError({
38963
+ return new import_server25.TRPCError({
38377
38964
  code: "NOT_FOUND",
38378
38965
  message: "Security group not found"
38379
38966
  });
38380
38967
  case 409:
38381
- return new import_server23.TRPCError({
38968
+ return new import_server25.TRPCError({
38382
38969
  code: "CONFLICT",
38383
38970
  message: "A rule with these parameters already exists in this security group"
38384
38971
  });
38385
38972
  case 413:
38386
- return new import_server23.TRPCError({
38973
+ return new import_server25.TRPCError({
38387
38974
  code: "BAD_REQUEST",
38388
38975
  message: "Quota exceeded for security group rules. Please delete existing rules or contact your administrator."
38389
38976
  });
38390
38977
  default:
38391
- return new import_server23.TRPCError({
38978
+ return new import_server25.TRPCError({
38392
38979
  code: "INTERNAL_SERVER_ERROR",
38393
38980
  message: `Failed to create security group rule: ${statusText}`
38394
38981
  });
@@ -38407,22 +38994,22 @@ var SecurityGroupRuleErrorHandlers = {
38407
38994
  delete: /* @__PURE__ */ __name((response, ruleId) => {
38408
38995
  switch (response.status) {
38409
38996
  case 401:
38410
- return new import_server23.TRPCError({
38997
+ return new import_server25.TRPCError({
38411
38998
  code: "UNAUTHORIZED",
38412
38999
  message: "Unauthorized access"
38413
39000
  });
38414
39001
  case 404:
38415
- return new import_server23.TRPCError({
39002
+ return new import_server25.TRPCError({
38416
39003
  code: "NOT_FOUND",
38417
39004
  message: `Security group rule not found: ${ruleId}`
38418
39005
  });
38419
39006
  case 412:
38420
- return new import_server23.TRPCError({
39007
+ return new import_server25.TRPCError({
38421
39008
  code: "PRECONDITION_FAILED",
38422
39009
  message: `Cannot delete security group rule: precondition failed`
38423
39010
  });
38424
39011
  default:
38425
- return new import_server23.TRPCError({
39012
+ return new import_server25.TRPCError({
38426
39013
  code: "INTERNAL_SERVER_ERROR",
38427
39014
  message: `Failed to delete security group rule: ${response.statusText || "Unknown error"}`
38428
39015
  });
@@ -38433,7 +39020,7 @@ var parseOpenStackResponse = /* @__PURE__ */ __name((data, schema, operation, er
38433
39020
  const parsed = schema.safeParse(data);
38434
39021
  if (!parsed.success) {
38435
39022
  console.error(`Zod Parsing Error in ${operation}:`, parsed.error.format());
38436
- throw new import_server23.TRPCError({
39023
+ throw new import_server25.TRPCError({
38437
39024
  code: "INTERNAL_SERVER_ERROR",
38438
39025
  message: errorMessage
38439
39026
  });
@@ -38488,7 +39075,7 @@ var sortSecurityGroups = /* @__PURE__ */ __name((items, sortKey, sortDir = "asc"
38488
39075
  }, "sortSecurityGroups");
38489
39076
 
38490
39077
  // src/server/Network/routers/securityGroupRouter.ts
38491
- var import_signal_openstack7 = __toESM(require_esm());
39078
+ var import_signal_openstack8 = __toESM(require_esm());
38492
39079
  var SECURITY_GROUPS_BASE_URL = "v2.0/security-groups";
38493
39080
  var LIST_SECURITY_GROUPS_QUERY_KEY_MAP = {
38494
39081
  tags_any: "tags-any",
@@ -38555,7 +39142,7 @@ var securityGroupRouter = {
38555
39142
  return withErrorHandling3(async () => {
38556
39143
  const { securityGroupId } = input;
38557
39144
  const network = getNetworkService(ctx);
38558
- const encodedId = (0, import_signal_openstack7.validateAndEncodeResourceId)(securityGroupId, "Security group");
39145
+ const encodedId = (0, import_signal_openstack8.validateAndEncodeResourceId)(securityGroupId, "Security group");
38559
39146
  const response = await network.get(`${SECURITY_GROUPS_BASE_URL}/${encodedId}`);
38560
39147
  if (!response.ok) {
38561
39148
  throw SecurityGroupErrorHandlers.getById(response, securityGroupId);
@@ -38591,7 +39178,7 @@ var securityGroupRouter = {
38591
39178
  return withErrorHandling3(async () => {
38592
39179
  const { securityGroupId } = input;
38593
39180
  const network = getNetworkService(ctx);
38594
- const encodedId = (0, import_signal_openstack7.validateAndEncodeResourceId)(securityGroupId, "Security group");
39181
+ const encodedId = (0, import_signal_openstack8.validateAndEncodeResourceId)(securityGroupId, "Security group");
38595
39182
  const response = await network.del(`${SECURITY_GROUPS_BASE_URL}/${encodedId}`);
38596
39183
  if (!response?.ok) {
38597
39184
  throw SecurityGroupErrorHandlers.delete(response, securityGroupId);
@@ -38615,7 +39202,7 @@ var securityGroupRouter = {
38615
39202
  }
38616
39203
  }
38617
39204
  };
38618
- const encodedId = (0, import_signal_openstack7.validateAndEncodeResourceId)(securityGroupId, "Security group");
39205
+ const encodedId = (0, import_signal_openstack8.validateAndEncodeResourceId)(securityGroupId, "Security group");
38619
39206
  const response = await network.put(`${SECURITY_GROUPS_BASE_URL}/${encodedId}`, requestBody);
38620
39207
  if (!response.ok) {
38621
39208
  throw SecurityGroupErrorHandlers.update(response, securityGroupId);
@@ -38720,7 +39307,7 @@ var deleteRBACPolicyInputSchema = projectScopedInputSchema.extend({
38720
39307
  });
38721
39308
 
38722
39309
  // src/server/Network/helpers/rbacPolicyHelpers.ts
38723
- var import_server24 = require("@trpc/server");
39310
+ var import_server26 = require("@trpc/server");
38724
39311
  var RBACPolicyErrorHandlers = {
38725
39312
  /**
38726
39313
  * Handles errors specific to RBAC policy list operations
@@ -38730,17 +39317,17 @@ var RBACPolicyErrorHandlers = {
38730
39317
  list: /* @__PURE__ */ __name((response) => {
38731
39318
  switch (response.status) {
38732
39319
  case 401:
38733
- return new import_server24.TRPCError({
39320
+ return new import_server26.TRPCError({
38734
39321
  code: HTTP_STATUS_ERROR_MAP[401],
38735
39322
  message: "Unauthorized access"
38736
39323
  });
38737
39324
  case 403:
38738
- return new import_server24.TRPCError({
39325
+ return new import_server26.TRPCError({
38739
39326
  code: HTTP_STATUS_ERROR_MAP[403],
38740
39327
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
38741
39328
  });
38742
39329
  default:
38743
- return new import_server24.TRPCError({
39330
+ return new import_server26.TRPCError({
38744
39331
  code: DEFAULT_ERROR_NAME,
38745
39332
  message: `Failed to list RBAC policies: ${response.statusText || "Unknown error"}`
38746
39333
  });
@@ -38754,32 +39341,32 @@ var RBACPolicyErrorHandlers = {
38754
39341
  create: /* @__PURE__ */ __name((response) => {
38755
39342
  switch (response.status) {
38756
39343
  case 400:
38757
- return new import_server24.TRPCError({
39344
+ return new import_server26.TRPCError({
38758
39345
  code: HTTP_STATUS_ERROR_MAP[400],
38759
39346
  message: `Invalid request: ${response.statusText || "Unknown error"}`
38760
39347
  });
38761
39348
  case 401:
38762
- return new import_server24.TRPCError({
39349
+ return new import_server26.TRPCError({
38763
39350
  code: HTTP_STATUS_ERROR_MAP[401],
38764
39351
  message: "Unauthorized access"
38765
39352
  });
38766
39353
  case 403:
38767
- return new import_server24.TRPCError({
39354
+ return new import_server26.TRPCError({
38768
39355
  code: HTTP_STATUS_ERROR_MAP[403],
38769
39356
  message: "You don't have permission to share this security group"
38770
39357
  });
38771
39358
  case 404:
38772
- return new import_server24.TRPCError({
39359
+ return new import_server26.TRPCError({
38773
39360
  code: HTTP_STATUS_ERROR_MAP[404],
38774
39361
  message: "Security group not found or target project does not exist"
38775
39362
  });
38776
39363
  case 409:
38777
- return new import_server24.TRPCError({
39364
+ return new import_server26.TRPCError({
38778
39365
  code: HTTP_STATUS_ERROR_MAP[409],
38779
39366
  message: "This security group is already shared with the specified project"
38780
39367
  });
38781
39368
  default:
38782
- return new import_server24.TRPCError({
39369
+ return new import_server26.TRPCError({
38783
39370
  code: "INTERNAL_SERVER_ERROR",
38784
39371
  message: `Failed to create RBAC policy: ${response.statusText || "Unknown error"}`
38785
39372
  });
@@ -38794,27 +39381,27 @@ var RBACPolicyErrorHandlers = {
38794
39381
  update: /* @__PURE__ */ __name((response, policyId) => {
38795
39382
  switch (response.status) {
38796
39383
  case 400:
38797
- return new import_server24.TRPCError({
39384
+ return new import_server26.TRPCError({
38798
39385
  code: HTTP_STATUS_ERROR_MAP[400],
38799
39386
  message: `Invalid request: ${response.statusText || "Unknown error"}`
38800
39387
  });
38801
39388
  case 401:
38802
- return new import_server24.TRPCError({
39389
+ return new import_server26.TRPCError({
38803
39390
  code: HTTP_STATUS_ERROR_MAP[401],
38804
39391
  message: "Unauthorized access"
38805
39392
  });
38806
39393
  case 403:
38807
- return new import_server24.TRPCError({
39394
+ return new import_server26.TRPCError({
38808
39395
  code: HTTP_STATUS_ERROR_MAP[403],
38809
39396
  message: `Access forbidden: ${response.statusText || "Unknown error"}`
38810
39397
  });
38811
39398
  case 404:
38812
- return new import_server24.TRPCError({
39399
+ return new import_server26.TRPCError({
38813
39400
  code: HTTP_STATUS_ERROR_MAP[404],
38814
39401
  message: `RBAC policy not found: ${policyId}`
38815
39402
  });
38816
39403
  default:
38817
- return new import_server24.TRPCError({
39404
+ return new import_server26.TRPCError({
38818
39405
  code: "INTERNAL_SERVER_ERROR",
38819
39406
  message: `Failed to update RBAC policy: ${response.statusText || "Unknown error"}`
38820
39407
  });
@@ -38829,22 +39416,22 @@ var RBACPolicyErrorHandlers = {
38829
39416
  delete: /* @__PURE__ */ __name((response, policyId) => {
38830
39417
  switch (response.status) {
38831
39418
  case 401:
38832
- return new import_server24.TRPCError({
39419
+ return new import_server26.TRPCError({
38833
39420
  code: HTTP_STATUS_ERROR_MAP[401],
38834
39421
  message: "Unauthorized access"
38835
39422
  });
38836
39423
  case 404:
38837
- return new import_server24.TRPCError({
39424
+ return new import_server26.TRPCError({
38838
39425
  code: HTTP_STATUS_ERROR_MAP[404],
38839
39426
  message: `RBAC policy not found: ${policyId}`
38840
39427
  });
38841
39428
  case 409:
38842
- return new import_server24.TRPCError({
39429
+ return new import_server26.TRPCError({
38843
39430
  code: HTTP_STATUS_ERROR_MAP[409],
38844
39431
  message: "Cannot delete RBAC policy because it is in use"
38845
39432
  });
38846
39433
  default:
38847
- return new import_server24.TRPCError({
39434
+ return new import_server26.TRPCError({
38848
39435
  code: DEFAULT_ERROR_NAME,
38849
39436
  message: `Failed to delete RBAC policy: ${response.statusText || "Unknown error"}`
38850
39437
  });
@@ -38855,7 +39442,7 @@ var parseOpenStackResponse2 = /* @__PURE__ */ __name((data, schema, operation, e
38855
39442
  const parsed = schema.safeParse(data);
38856
39443
  if (!parsed.success) {
38857
39444
  console.error(`Zod Parsing Error in ${operation}:`, parsed.error.format());
38858
- throw new import_server24.TRPCError({
39445
+ throw new import_server26.TRPCError({
38859
39446
  code: "INTERNAL_SERVER_ERROR",
38860
39447
  message: errorMessage
38861
39448
  });
@@ -39179,7 +39766,7 @@ var buildAppRouter = /* @__PURE__ */ __name((policyDir, extraRouters = []) => {
39179
39766
  }, "buildAppRouter");
39180
39767
 
39181
39768
  // src/server/context.ts
39182
- var import_signal_openstack8 = __toESM(require_esm());
39769
+ var import_signal_openstack9 = __toESM(require_esm());
39183
39770
 
39184
39771
  // src/server/sessionCookie.ts
39185
39772
  var import_cookie = require("@fastify/cookie");
@@ -39267,7 +39854,7 @@ async function createContext(opts, config) {
39267
39854
  writable: false
39268
39855
  });
39269
39856
  if (currentAuthToken) {
39270
- openstackSession = await (0, import_signal_openstack8.SignalOpenstackSession)(normalizedEndpoint, {
39857
+ openstackSession = await (0, import_signal_openstack9.SignalOpenstackSession)(normalizedEndpoint, {
39271
39858
  auth: {
39272
39859
  identity: {
39273
39860
  methods: [
@@ -39330,7 +39917,7 @@ async function createContext(opts, config) {
39330
39917
  }
39331
39918
  }, "getUserInfo");
39332
39919
  const createSession = /* @__PURE__ */ __name(async (params) => {
39333
- openstackSession = await (0, import_signal_openstack8.SignalOpenstackSession)(normalizedEndpoint, {
39920
+ openstackSession = await (0, import_signal_openstack9.SignalOpenstackSession)(normalizedEndpoint, {
39334
39921
  auth: {
39335
39922
  identity: {
39336
39923
  methods: [
@@ -39390,53 +39977,51 @@ async function createContext(opts, config) {
39390
39977
  return openstackSession;
39391
39978
  }
39392
39979
  const rescopeTokenPromise = (async () => {
39393
- try {
39394
- const newScope = newScopeProjectId ? {
39395
- project: {
39396
- id: newScopeProjectId
39397
- }
39398
- } : newScopeDomainId ? {
39399
- domain: {
39400
- id: newScopeDomainId
39401
- }
39402
- } : "unscoped";
39403
- await openstackSession.rescope(newScope);
39404
- const newToken = openstackSession.getToken();
39405
- const newAuthToken2 = newToken?.authToken;
39406
- if (newAuthToken2 && newAuthToken2 !== sessionToken) {
39407
- const oldPendingRescopes = sessionRescopes.get(sessionToken);
39408
- if (oldPendingRescopes) {
39409
- const existingRescopes = sessionRescopes.get(newAuthToken2);
39410
- if (existingRescopes) {
39411
- for (const [key, value] of oldPendingRescopes.entries()) {
39412
- if (!existingRescopes.has(key)) {
39413
- existingRescopes.set(key, value);
39414
- }
39980
+ const newScope = newScopeProjectId ? {
39981
+ project: {
39982
+ id: newScopeProjectId
39983
+ }
39984
+ } : newScopeDomainId ? {
39985
+ domain: {
39986
+ id: newScopeDomainId
39987
+ }
39988
+ } : "unscoped";
39989
+ await openstackSession.rescope(newScope);
39990
+ const newToken = openstackSession.getToken();
39991
+ const newAuthToken2 = newToken?.authToken;
39992
+ if (newAuthToken2 && newAuthToken2 !== sessionToken) {
39993
+ const oldPendingRescopes = sessionRescopes.get(sessionToken);
39994
+ if (oldPendingRescopes) {
39995
+ const existingRescopes = sessionRescopes.get(newAuthToken2);
39996
+ if (existingRescopes) {
39997
+ for (const [key, value] of oldPendingRescopes.entries()) {
39998
+ if (!existingRescopes.has(key)) {
39999
+ existingRescopes.set(key, value);
39415
40000
  }
39416
- } else {
39417
- sessionRescopes.set(newAuthToken2, oldPendingRescopes);
39418
40001
  }
39419
- sessionRescopes.delete(sessionToken);
40002
+ } else {
40003
+ sessionRescopes.set(newAuthToken2, oldPendingRescopes);
39420
40004
  }
39421
- }
39422
- cachedUserId = void 0;
39423
- cachedUserInfo = void 0;
39424
- return newAuthToken2 || null;
39425
- } catch (err) {
39426
- console.error("Rescope error:", err);
39427
- return null;
39428
- } finally {
39429
- pendingRescopes.delete(scopeKey);
39430
- if (pendingRescopes.size === 0) {
39431
40005
  sessionRescopes.delete(sessionToken);
39432
- const currentToken = openstackSession?.getToken()?.authToken;
39433
- if (currentToken && currentToken !== sessionToken && sessionRescopes.get(currentToken)?.size === 0) {
39434
- sessionRescopes.delete(currentToken);
39435
- }
39436
40006
  }
39437
40007
  }
40008
+ cachedUserId = void 0;
40009
+ cachedUserInfo = void 0;
40010
+ return newAuthToken2 || null;
39438
40011
  })();
40012
+ const cleanupPromise = rescopeTokenPromise.finally(() => {
40013
+ pendingRescopes.delete(scopeKey);
40014
+ if (pendingRescopes.size === 0) {
40015
+ sessionRescopes.delete(sessionToken);
40016
+ const currentToken = openstackSession?.getToken()?.authToken;
40017
+ if (currentToken && currentToken !== sessionToken && sessionRescopes.get(currentToken)?.size === 0) {
40018
+ sessionRescopes.delete(currentToken);
40019
+ }
40020
+ }
40021
+ });
39439
40022
  pendingRescopes.set(scopeKey, rescopeTokenPromise);
40023
+ cleanupPromise.catch(() => {
40024
+ });
39440
40025
  const newAuthToken = await rescopeTokenPromise;
39441
40026
  if (!newAuthToken) {
39442
40027
  return null;
@@ -39586,6 +40171,19 @@ async function createServer(config) {
39586
40171
  }, (_req, payload, done) => {
39587
40172
  done(null, payload);
39588
40173
  });
40174
+ server.register(csrfProtection_default, {
40175
+ tokenRoute: "/csrf-token",
40176
+ cookieKey: "aurora-csrf-protection",
40177
+ tokenHeader: "x-csrf-token",
40178
+ excludePaths: [
40179
+ "/extensions"
40180
+ ],
40181
+ protectionMethods: [
40182
+ "POST",
40183
+ "PUT",
40184
+ "DELETE"
40185
+ ]
40186
+ });
39589
40187
  server.post(`${bffEndpoint}/upload-image-direct`, {
39590
40188
  config: {
39591
40189
  rawBody: false
@@ -39652,19 +40250,6 @@ async function createServer(config) {
39652
40250
  });
39653
40251
  }
39654
40252
  });
39655
- server.register(csrfProtection_default, {
39656
- tokenRoute: "/csrf-token",
39657
- cookieKey: "aurora-csrf-protection",
39658
- tokenHeader: "x-csrf-token",
39659
- excludePaths: [
39660
- "/extensions"
39661
- ],
39662
- protectionMethods: [
39663
- "POST",
39664
- "PUT",
39665
- "DELETE"
39666
- ]
39667
- });
39668
40253
  server.addHook("onRequest", (request, _reply, done) => {
39669
40254
  if (request.url.includes("/compute.uploadImage")) {
39670
40255
  request.raw.setTimeout(0);