@burdenoff/microfe-devportal 2026.716.2 → 2026.720.1

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 (58) hide show
  1. package/dist/devportal/components/PermissionGuard.d.ts +14 -1
  2. package/dist/devportal/components/PermissionGuard.d.ts.map +1 -1
  3. package/dist/devportal/components/PermissionGuard.js +16 -13
  4. package/dist/devportal/components/PermissionGuard.js.map +1 -1
  5. package/dist/devportal/hooks/usePackageUpload.d.ts.map +1 -1
  6. package/dist/devportal/hooks/usePackageUpload.js.map +1 -1
  7. package/dist/devportal/pages/AdminReviewPage.js +9 -9
  8. package/dist/devportal/pages/ApiKeysPage.js +180 -181
  9. package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
  10. package/dist/devportal/pages/ApplicationDetailPage.js +3 -3
  11. package/dist/devportal/pages/ApplicationVersionsPage.js +4 -4
  12. package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
  13. package/dist/devportal/pages/ApplicationsPage.js +4 -4
  14. package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
  15. package/dist/devportal/pages/CreateApiKeyPage.js +1 -1
  16. package/dist/devportal/pages/CreateApplicationPage.d.ts.map +1 -1
  17. package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
  18. package/dist/devportal/pages/CreateOAuthClientPage.js +1 -1
  19. package/dist/devportal/pages/CreateOrganizationPage.js +1 -1
  20. package/dist/devportal/pages/CreatePhysicalItemPage.d.ts.map +1 -1
  21. package/dist/devportal/pages/CreatePhysicalItemPage.js +147 -116
  22. package/dist/devportal/pages/CreatePhysicalItemPage.js.map +1 -1
  23. package/dist/devportal/pages/CreateWebhookPage.js +25 -25
  24. package/dist/devportal/pages/DashboardPage.d.ts.map +1 -1
  25. package/dist/devportal/pages/DashboardPage.js +110 -111
  26. package/dist/devportal/pages/DashboardPage.js.map +1 -1
  27. package/dist/devportal/pages/DelegationsPage.js +1 -1
  28. package/dist/devportal/pages/EditApplicationPage.d.ts.map +1 -1
  29. package/dist/devportal/pages/EditApplicationPage.js +4 -4
  30. package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
  31. package/dist/devportal/pages/ListingPreviewPage.d.ts.map +1 -1
  32. package/dist/devportal/pages/ListingPreviewPage.js +160 -161
  33. package/dist/devportal/pages/ListingPreviewPage.js.map +1 -1
  34. package/dist/devportal/pages/OAuthClientDetailPage.d.ts.map +1 -1
  35. package/dist/devportal/pages/OAuthClientDetailPage.js +166 -167
  36. package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
  37. package/dist/devportal/pages/OAuthClientsPage.d.ts.map +1 -1
  38. package/dist/devportal/pages/OAuthClientsPage.js +121 -122
  39. package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
  40. package/dist/devportal/pages/OrganizationDetailPage.js +3 -3
  41. package/dist/devportal/pages/OrganizationMembersPage.js +4 -4
  42. package/dist/devportal/pages/OrganizationsPage.js +1 -1
  43. package/dist/devportal/pages/PublishPage.d.ts.map +1 -1
  44. package/dist/devportal/pages/PublishPage.js +246 -246
  45. package/dist/devportal/pages/PublishPage.js.map +1 -1
  46. package/dist/devportal/pages/PublisherProfilePage.js +4 -4
  47. package/dist/devportal/pages/PublisherProfilePage.js.map +1 -1
  48. package/dist/devportal/pages/SellerDashboardPage.d.ts.map +1 -1
  49. package/dist/devportal/pages/SellerDashboardPage.js.map +1 -1
  50. package/dist/devportal/pages/SellerItemsPage.d.ts.map +1 -1
  51. package/dist/devportal/pages/SellerItemsPage.js.map +1 -1
  52. package/dist/devportal/pages/StoreSubmissionPage.js +3 -3
  53. package/dist/devportal/pages/WebhookDetailPage.js +3 -3
  54. package/dist/devportal/pages/WebhooksPage.js +129 -129
  55. package/dist/devportal/pages/WebhooksPage.js.map +1 -1
  56. package/dist/devportal/types/index.d.ts.map +1 -1
  57. package/dist/devportal/types/index.js.map +1 -1
  58. package/package.json +1 -1
@@ -2,7 +2,20 @@ import { FC, ReactNode } from 'react';
2
2
  import { DevportalPermission } from '../constants/permissions';
3
3
 
4
4
  interface PermissionGuardProps {
5
- permission: DevportalPermission;
5
+ /**
6
+ * Required RBAC permission. Optional when `authOnly` is set — self-scoped
7
+ * developer surfaces gate on authentication only (see `authOnly`).
8
+ */
9
+ permission?: DevportalPermission;
10
+ /**
11
+ * Self-scoped mode. The corresponding backend fields are gated with
12
+ * `@rbac(scopeType: "self")` — an authentication gate whose resolvers filter
13
+ * strictly to the caller's own resources. Such fields carry no RBAC
14
+ * permission in `myPermissions`, so a permission check would wrongly deny
15
+ * every normal member. In this mode we render for any authenticated user and
16
+ * let the backend self-enforce per resource.
17
+ */
18
+ authOnly?: boolean;
6
19
  children: ReactNode;
7
20
  }
8
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionGuard.d.ts","sourceRoot":"","sources":["../../../src/devportal/components/PermissionGuard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAM3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,UAAU,oBAAoB;IAC5B,UAAU,EAAE,mBAAmB,CAAC;IAChC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CAwEpD,CAAC"}
1
+ {"version":3,"file":"PermissionGuard.d.ts","sourceRoot":"","sources":["../../../src/devportal/components/PermissionGuard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAM3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,UAAU,oBAAoB;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CA6FpD,CAAC"}
@@ -5,30 +5,33 @@ import { usePermissions as r } from "@burdenoff/fe-libs/shared/providers/shell";
5
5
  import { Fragment as i, jsx as a } from "react/jsx-runtime";
6
6
  import { useAuth as o } from "@burdenoff/fe-libs/shared/providers/shell/AuthProvider";
7
7
  //#region src/devportal/components/PermissionGuard.tsx
8
- var s = ({ permission: s, children: c }) => {
9
- let l = null, u = !1, d = !1, f = !1;
8
+ var s = ({ permission: s, authOnly: c = !1, children: l }) => {
9
+ let u = null, d = !1, f = !1, p = !1;
10
10
  try {
11
11
  let e = r();
12
- l = e.hasPermission, u = e.isLoading, d = e.permissions?.permissions?.some((e) => e.resourceType === "rbac" && e.level === "ADMIN") ?? !1;
12
+ u = e.hasPermission, d = e.isLoading, f = e.permissions?.permissions?.some((e) => e.resourceType === "rbac" && e.level === "ADMIN") ?? !1;
13
13
  } catch {
14
- l = null, u = !1, d = !1;
14
+ u = null, d = !1, f = !1;
15
15
  }
16
16
  try {
17
- f = o().isAuthenticated;
17
+ p = o().isAuthenticated;
18
18
  } catch {
19
- f = !1;
19
+ p = !1;
20
20
  }
21
- let p = typeof window < "u" && (window.location.hostname === "localhost" || window.location.hostname.endsWith(".local.burdenoff.com")) && f, { t: m } = n(), h = (e, t) => {
22
- let n = m(e);
21
+ let m = typeof window < "u" && (window.location.hostname === "localhost" || window.location.hostname.endsWith(".local.burdenoff.com")) && p, { t: h } = n(), g = (e, t) => {
22
+ let n = h(e);
23
23
  return n === e ? t : n;
24
24
  };
25
- return u ? /* @__PURE__ */ a("div", {
25
+ return d ? /* @__PURE__ */ a("div", {
26
26
  className: "flex min-h-screen items-center justify-center bg-bg-canvas",
27
27
  children: /* @__PURE__ */ a(e, {})
28
- }) : l && !l(s) && !d && !p ? /* @__PURE__ */ a(t, {
29
- title: h("devportal.accessDenied", "Access Denied"),
30
- description: h("devportal.noPermissionView", "You don't have permission to view this page.")
31
- }) : /* @__PURE__ */ a(i, { children: c });
28
+ }) : c ? u !== null && !p && !m ? /* @__PURE__ */ a(t, {
29
+ title: g("devportal.accessDenied", "Access Denied"),
30
+ description: g("devportal.noPermissionView", "You don't have permission to view this page.")
31
+ }) : /* @__PURE__ */ a(i, { children: l }) : s && u && !u(s) && !f && !m ? /* @__PURE__ */ a(t, {
32
+ title: g("devportal.accessDenied", "Access Denied"),
33
+ description: g("devportal.noPermissionView", "You don't have permission to view this page.")
34
+ }) : /* @__PURE__ */ a(i, { children: l });
32
35
  };
33
36
  //#endregion
34
37
  export { s as PermissionGuard };
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionGuard.js","names":[],"sources":["../../../src/devportal/components/PermissionGuard.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { usePermissions } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useAuth } from \"@burdenoff/fe-libs/shared/providers/shell/AuthProvider\";\nimport { AccessDenied } from \"@burdenoff/fe-libs/shared/components\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { PageLoadingState } from \"./LoadingState\";\nimport type { DevportalPermission } from \"../constants/permissions\";\n\ninterface PermissionGuardProps {\n permission: DevportalPermission;\n children: ReactNode;\n}\n\n/**\n * Wraps page content with a permission check.\n * Shows a loading state while permissions resolve, then either\n * renders children (if permitted) or an AccessDenied screen.\n */\nexport const PermissionGuard: FC<PermissionGuardProps> = ({\n permission,\n children,\n}) => {\n let hasPermission: ((permission: DevportalPermission) => boolean) | null =\n null;\n let isLoading = false;\n let isRbacAdmin = false;\n let isAuthenticated = false;\n\n try {\n const permissions = usePermissions();\n hasPermission = permissions.hasPermission as (\n permission: DevportalPermission,\n ) => boolean;\n isLoading = permissions.isLoading;\n isRbacAdmin =\n permissions.permissions?.permissions?.some(\n (entry) => entry.resourceType === \"rbac\" && entry.level === \"ADMIN\",\n ) ?? false;\n } catch {\n // Standalone/dev mode intentionally allows rendering without shell RBAC context.\n hasPermission = null;\n isLoading = false;\n isRbacAdmin = false;\n }\n\n try {\n const auth = useAuth();\n isAuthenticated = auth.isAuthenticated;\n } catch {\n isAuthenticated = false;\n }\n\n const isLocalShellDev =\n typeof window !== \"undefined\" &&\n (window.location.hostname === \"localhost\" ||\n window.location.hostname.endsWith(\".local.burdenoff.com\"));\n\n const allowLocalShellBypass = isLocalShellDev && isAuthenticated;\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n if (isLoading) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-bg-canvas\">\n <PageLoadingState />\n </div>\n );\n }\n\n if (\n hasPermission &&\n !hasPermission(permission) &&\n !isRbacAdmin &&\n !allowLocalShellBypass\n ) {\n return (\n <AccessDenied\n title={tr(\"devportal.accessDenied\", \"Access Denied\")}\n description={tr(\n \"devportal.noPermissionView\",\n \"You don't have permission to view this page.\",\n )}\n />\n );\n }\n\n return <>{children}</>;\n};\n"],"mappings":";;;;;;;AAkBA,IAAa,KAA6C,EACxD,eACA,kBACI;CACJ,IAAI,IACF,MACE,IAAY,IACZ,IAAc,IACd,IAAkB;AAEtB,KAAI;EACF,IAAM,IAAc,GAAgB;AAKpC,EAJA,IAAgB,EAAY,eAG5B,IAAY,EAAY,WACxB,IACE,EAAY,aAAa,aAAa,MACnC,MAAU,EAAM,iBAAiB,UAAU,EAAM,UAAU,QAC7D,IAAI;SACD;AAIN,EAFA,IAAgB,MAChB,IAAY,IACZ,IAAc;;AAGhB,KAAI;AAEF,MADa,GAAS,CACC;SACjB;AACN,MAAkB;;CAQpB,IAAM,IAJJ,OAAO,SAAW,QACjB,OAAO,SAAS,aAAa,eAC5B,OAAO,SAAS,SAAS,SAAS,uBAAuB,KAEZ,GAC3C,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;;AA4BpC,QAzBI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAoB,CAAA;EAChB,CAAA,GAKR,KACA,CAAC,EAAc,EAAW,IAC1B,CAAC,KACD,CAAC,IAGC,kBAAC,GAAD;EACE,OAAO,EAAG,0BAA0B,gBAAgB;EACpD,aAAa,EACX,8BACA,+CACD;EACD,CAAA,GAIC,kBAAA,GAAA,EAAG,aAAY,CAAA"}
1
+ {"version":3,"file":"PermissionGuard.js","names":[],"sources":["../../../src/devportal/components/PermissionGuard.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { usePermissions } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useAuth } from \"@burdenoff/fe-libs/shared/providers/shell/AuthProvider\";\nimport { AccessDenied } from \"@burdenoff/fe-libs/shared/components\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { PageLoadingState } from \"./LoadingState\";\nimport type { DevportalPermission } from \"../constants/permissions\";\n\ninterface PermissionGuardProps {\n /**\n * Required RBAC permission. Optional when `authOnly` is set — self-scoped\n * developer surfaces gate on authentication only (see `authOnly`).\n */\n permission?: DevportalPermission;\n /**\n * Self-scoped mode. The corresponding backend fields are gated with\n * `@rbac(scopeType: \"self\")` — an authentication gate whose resolvers filter\n * strictly to the caller's own resources. Such fields carry no RBAC\n * permission in `myPermissions`, so a permission check would wrongly deny\n * every normal member. In this mode we render for any authenticated user and\n * let the backend self-enforce per resource.\n */\n authOnly?: boolean;\n children: ReactNode;\n}\n\n/**\n * Wraps page content with a permission check.\n * Shows a loading state while permissions resolve, then either\n * renders children (if permitted) or an AccessDenied screen.\n */\nexport const PermissionGuard: FC<PermissionGuardProps> = ({\n permission,\n authOnly = false,\n children,\n}) => {\n let hasPermission: ((permission: DevportalPermission) => boolean) | null =\n null;\n let isLoading = false;\n let isRbacAdmin = false;\n let isAuthenticated = false;\n\n try {\n const permissions = usePermissions();\n hasPermission = permissions.hasPermission as (\n permission: DevportalPermission,\n ) => boolean;\n isLoading = permissions.isLoading;\n isRbacAdmin =\n permissions.permissions?.permissions?.some(\n (entry) => entry.resourceType === \"rbac\" && entry.level === \"ADMIN\",\n ) ?? false;\n } catch {\n // Standalone/dev mode intentionally allows rendering without shell RBAC context.\n hasPermission = null;\n isLoading = false;\n isRbacAdmin = false;\n }\n\n try {\n const auth = useAuth();\n isAuthenticated = auth.isAuthenticated;\n } catch {\n isAuthenticated = false;\n }\n\n const isLocalShellDev =\n typeof window !== \"undefined\" &&\n (window.location.hostname === \"localhost\" ||\n window.location.hostname.endsWith(\".local.burdenoff.com\"));\n\n const allowLocalShellBypass = isLocalShellDev && isAuthenticated;\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n if (isLoading) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-bg-canvas\">\n <PageLoadingState />\n </div>\n );\n }\n\n // Self-scoped surface: gate on authentication only. The backend\n // (@rbac scopeType: \"self\") filters to the caller's own resources, so we\n // must not require an RBAC permission the member legitimately lacks.\n if (authOnly) {\n // When the shell RBAC context is unavailable (standalone/dev), render.\n if (hasPermission !== null && !isAuthenticated && !allowLocalShellBypass) {\n return (\n <AccessDenied\n title={tr(\"devportal.accessDenied\", \"Access Denied\")}\n description={tr(\n \"devportal.noPermissionView\",\n \"You don't have permission to view this page.\",\n )}\n />\n );\n }\n return <>{children}</>;\n }\n\n if (\n permission &&\n hasPermission &&\n !hasPermission(permission) &&\n !isRbacAdmin &&\n !allowLocalShellBypass\n ) {\n return (\n <AccessDenied\n title={tr(\"devportal.accessDenied\", \"Access Denied\")}\n description={tr(\n \"devportal.noPermissionView\",\n \"You don't have permission to view this page.\",\n )}\n />\n );\n }\n\n return <>{children}</>;\n};\n"],"mappings":";;;;;;;AA+BA,IAAa,KAA6C,EACxD,eACA,cAAW,IACX,kBACI;CACJ,IAAI,IACF,MACE,IAAY,IACZ,IAAc,IACd,IAAkB;AAEtB,KAAI;EACF,IAAM,IAAc,GAAgB;AAKpC,EAJA,IAAgB,EAAY,eAG5B,IAAY,EAAY,WACxB,IACE,EAAY,aAAa,aAAa,MACnC,MAAU,EAAM,iBAAiB,UAAU,EAAM,UAAU,QAC7D,IAAI;SACD;AAIN,EAFA,IAAgB,MAChB,IAAY,IACZ,IAAc;;AAGhB,KAAI;AAEF,MADa,GAAS,CACC;SACjB;AACN,MAAkB;;CAQpB,IAAM,IAJJ,OAAO,SAAW,QACjB,OAAO,SAAS,aAAa,eAC5B,OAAO,SAAS,SAAS,SAAS,uBAAuB,KAEZ,GAC3C,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;;AAgDpC,QA7CI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAoB,CAAA;EAChB,CAAA,GAON,IAEE,MAAkB,QAAQ,CAAC,KAAmB,CAAC,IAE/C,kBAAC,GAAD;EACE,OAAO,EAAG,0BAA0B,gBAAgB;EACpD,aAAa,EACX,8BACA,+CACD;EACD,CAAA,GAGC,kBAAA,GAAA,EAAG,aAAY,CAAA,GAItB,KACA,KACA,CAAC,EAAc,EAAW,IAC1B,CAAC,KACD,CAAC,IAGC,kBAAC,GAAD;EACE,OAAO,EAAG,0BAA0B,gBAAgB;EACpD,aAAa,EACX,8BACA,+CACD;EACD,CAAA,GAIC,kBAAA,GAAA,EAAG,aAAY,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePackageUpload.d.ts","sourceRoot":"","sources":["../../../src/devportal/hooks/usePackageUpload.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AA2JD,wBAAgB,gBAAgB,CAC9B,oBAAoB,EAAE,MAAM,GAAG,SAAS,EACxC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,iBAAiB,EAAE,CAAC,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,EAC7D,UAAU,SAAwB;eAnKvB,OAAO;cACR,MAAM;WACT,MAAM,GAAG,IAAI;mBA0KL,IAAI,KAAG,OAAO,CAAC,mBAAmB,CAAC;EAoDnD"}
1
+ {"version":3,"file":"usePackageUpload.d.ts","sourceRoot":"","sources":["../../../src/devportal/hooks/usePackageUpload.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AA6JD,wBAAgB,gBAAgB,CAC9B,oBAAoB,EAAE,MAAM,GAAG,SAAS,EACxC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,iBAAiB,EAAE,CAAC,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,EAC7D,UAAU,SAAwB;eArKvB,OAAO;cACR,MAAM;WACT,MAAM,GAAG,IAAI;mBA4KL,IAAI,KAAG,OAAO,CAAC,mBAAmB,CAAC;EAoDnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePackageUpload.js","names":[],"sources":["../../../src/devportal/hooks/usePackageUpload.ts"],"sourcesContent":["/**\n * usePackageUpload — uploads a zip package to wspace-files-svc and returns a\n * stable downloadUrl to store as ApplicationVersion.packageUrl.\n *\n * Flow (mirrors uploadBlobToFiles in @burdenoff/fe-libs/storage):\n * 1. ensureFolderByPath(\"/DevPortal/Packages\") → folderId\n * 2. initiateUpload → { sessionId, presignedUrl }\n * 3. PUT blob to presignedUrl (progress tracked via XHR)\n * 4. completeUpload → { file.downloadUrl }\n *\n * Uses raw fetch for GraphQL mutations so we can target the workspace gateway\n * without a second ApolloProvider.\n */\nimport { useCallback, useState } from \"react\";\n\nexport interface PackageUploadResult {\n fileId: string;\n downloadUrl: string;\n}\n\nexport interface PackageUploadState {\n uploading: boolean;\n progress: number;\n error: string | null;\n}\n\ntype GqlFetcher = (\n query: string,\n variables: Record<string, unknown>,\n) => Promise<Record<string, unknown>>;\n\nfunction makeFetcher(\n workspacesGatewayUrl: string,\n authToken: string | undefined,\n workspaceId: string | undefined,\n workspaceToken: string | undefined,\n): GqlFetcher {\n return async (query, variables) => {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (authToken) headers[\"Authorization\"] = `Bearer ${authToken}`;\n if (workspaceToken)\n headers[\"X-Workspace-Authorization\"] = `Bearer ${workspaceToken}`;\n if (workspaceId) headers[\"x-workspace-id\"] = workspaceId;\n\n const endpoint = workspacesGatewayUrl.endsWith(\"/graphql\")\n ? workspacesGatewayUrl\n : `${workspacesGatewayUrl}/workspaces/graphql`;\n\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers,\n credentials: \"include\",\n body: JSON.stringify({ query, variables }),\n });\n if (!res.ok) {\n throw new Error(\n `GraphQL request failed: ${res.status} ${res.statusText}`,\n );\n }\n const json = (await res.json()) as {\n data?: Record<string, unknown>;\n errors?: Array<{ message: string }>;\n };\n if (json.errors?.length) {\n throw new Error(json.errors.map((e) => e.message).join(\"; \"));\n }\n return json.data ?? {};\n };\n}\n\nasync function ensureFolder(gql: GqlFetcher, path: string): Promise<string> {\n const data = await gql(\n `mutation DevPortal_EnsureFolder($path: String!) {\n ensureFolderByPath(path: $path) { id }\n }`,\n { path },\n );\n const id = (data.ensureFolderByPath as { id?: string } | undefined)?.id;\n if (!id) throw new Error(\"ensureFolderByPath returned no id\");\n return id;\n}\n\nasync function initiateUpload(\n gql: GqlFetcher,\n file: File,\n folderId: string,\n): Promise<{ sessionId: string; uploadUrl: string }> {\n const ext = file.name.includes(\".\")\n ? file.name.substring(file.name.lastIndexOf(\".\") + 1)\n : \"zip\";\n const data = await gql(\n `mutation DevPortal_InitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) {\n uploadUrl\n session { id }\n }\n }`,\n {\n input: {\n fileName: file.name,\n fileSize: String(file.size),\n mimeType: file.type || \"application/zip\",\n extension: ext,\n folderId,\n visibility: \"PUBLIC\",\n },\n },\n );\n const result = data.initiateUpload as\n { uploadUrl?: string; session?: { id?: string } } | undefined;\n const sessionId = result?.session?.id;\n const uploadUrl = result?.uploadUrl;\n if (!sessionId || !uploadUrl) {\n throw new Error(\"initiateUpload did not return sessionId or uploadUrl\");\n }\n return { sessionId, uploadUrl };\n}\n\nasync function putToPresignedUrl(\n file: File,\n uploadUrl: string,\n onProgress: (pct: number) => void,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.upload.addEventListener(\"progress\", (evt) => {\n if (evt.lengthComputable) {\n onProgress(10 + Math.round((evt.loaded / evt.total) * 80));\n }\n });\n xhr.addEventListener(\"load\", () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`S3 PUT failed: ${xhr.status}`));\n }\n });\n xhr.addEventListener(\"error\", () =>\n reject(new Error(\"S3 PUT network error\")),\n );\n xhr.addEventListener(\"abort\", () => reject(new Error(\"S3 PUT aborted\")));\n xhr.open(\"PUT\", uploadUrl);\n xhr.setRequestHeader(\"Content-Type\", file.type || \"application/zip\");\n xhr.send(file);\n });\n}\n\nasync function completeUpload(\n gql: GqlFetcher,\n sessionId: string,\n folderId: string,\n fileSize: number,\n): Promise<PackageUploadResult> {\n const data = await gql(\n `mutation DevPortal_CompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) {\n file { id downloadUrl }\n }\n }`,\n {\n input: {\n sessionId,\n folderId,\n fileSize: String(fileSize),\n },\n },\n );\n const file = (\n data.completeUpload as\n { file?: { id?: string; downloadUrl?: string } } | undefined\n )?.file;\n if (!file?.id || !file.downloadUrl) {\n throw new Error(\"completeUpload did not return file id or downloadUrl\");\n }\n return { fileId: file.id, downloadUrl: file.downloadUrl };\n}\n\nexport function usePackageUpload(\n workspacesGatewayUrl: string | undefined,\n authToken: string | undefined,\n workspaceId: string | undefined,\n getWorkspaceToken: (() => Promise<string | null>) | undefined,\n folderPath = \"/DevPortal/Packages\",\n) {\n const [state, setState] = useState<PackageUploadState>({\n uploading: false,\n progress: 0,\n error: null,\n });\n\n const upload = useCallback(\n async (file: File): Promise<PackageUploadResult> => {\n if (!workspacesGatewayUrl) {\n throw new Error(\n \"workspacesGatewayUrl is not configured. Pass it as a prop to DevportalRoot.\",\n );\n }\n\n const freshToken = getWorkspaceToken\n ? await getWorkspaceToken()\n : undefined;\n const gql = makeFetcher(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n freshToken ?? undefined,\n );\n\n setState({ uploading: true, progress: 0, error: null });\n try {\n const folderId = await ensureFolder(gql, folderPath);\n setState((s) => ({ ...s, progress: 5 }));\n\n const { sessionId, uploadUrl } = await initiateUpload(\n gql,\n file,\n folderId,\n );\n setState((s) => ({ ...s, progress: 10 }));\n\n await putToPresignedUrl(file, uploadUrl, (pct) =>\n setState((s) => ({ ...s, progress: pct })),\n );\n setState((s) => ({ ...s, progress: 90 }));\n\n const result = await completeUpload(\n gql,\n sessionId,\n folderId,\n file.size,\n );\n setState({ uploading: false, progress: 100, error: null });\n return result;\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Upload failed\";\n setState({ uploading: false, progress: 0, error: message });\n throw err;\n }\n },\n [workspacesGatewayUrl, authToken, workspaceId, getWorkspaceToken],\n );\n\n return { upload, ...state };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"usePackageUpload.js","names":[],"sources":["../../../src/devportal/hooks/usePackageUpload.ts"],"sourcesContent":["/**\n * usePackageUpload — uploads a zip package to wspace-files-svc and returns a\n * stable downloadUrl to store as ApplicationVersion.packageUrl.\n *\n * Flow (mirrors uploadBlobToFiles in @burdenoff/fe-libs/storage):\n * 1. ensureFolderByPath(\"/DevPortal/Packages\") → folderId\n * 2. initiateUpload → { sessionId, presignedUrl }\n * 3. PUT blob to presignedUrl (progress tracked via XHR)\n * 4. completeUpload → { file.downloadUrl }\n *\n * Uses raw fetch for GraphQL mutations so we can target the workspace gateway\n * without a second ApolloProvider.\n */\nimport { useCallback, useState } from \"react\";\n\nexport interface PackageUploadResult {\n fileId: string;\n downloadUrl: string;\n}\n\nexport interface PackageUploadState {\n uploading: boolean;\n progress: number;\n error: string | null;\n}\n\ntype GqlFetcher = (\n query: string,\n variables: Record<string, unknown>,\n) => Promise<Record<string, unknown>>;\n\nfunction makeFetcher(\n workspacesGatewayUrl: string,\n authToken: string | undefined,\n workspaceId: string | undefined,\n workspaceToken: string | undefined,\n): GqlFetcher {\n return async (query, variables) => {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (authToken) headers[\"Authorization\"] = `Bearer ${authToken}`;\n if (workspaceToken)\n headers[\"X-Workspace-Authorization\"] = `Bearer ${workspaceToken}`;\n if (workspaceId) headers[\"x-workspace-id\"] = workspaceId;\n\n const endpoint = workspacesGatewayUrl.endsWith(\"/graphql\")\n ? workspacesGatewayUrl\n : `${workspacesGatewayUrl}/workspaces/graphql`;\n\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers,\n credentials: \"include\",\n body: JSON.stringify({ query, variables }),\n });\n if (!res.ok) {\n throw new Error(\n `GraphQL request failed: ${res.status} ${res.statusText}`,\n );\n }\n const json = (await res.json()) as {\n data?: Record<string, unknown>;\n errors?: Array<{ message: string }>;\n };\n if (json.errors?.length) {\n throw new Error(json.errors.map((e) => e.message).join(\"; \"));\n }\n return json.data ?? {};\n };\n}\n\nasync function ensureFolder(gql: GqlFetcher, path: string): Promise<string> {\n const data = await gql(\n `mutation DevPortal_EnsureFolder($path: String!) {\n ensureFolderByPath(path: $path) { id }\n }`,\n { path },\n );\n const id = (data.ensureFolderByPath as { id?: string } | undefined)?.id;\n if (!id) throw new Error(\"ensureFolderByPath returned no id\");\n return id;\n}\n\nasync function initiateUpload(\n gql: GqlFetcher,\n file: File,\n folderId: string,\n): Promise<{ sessionId: string; uploadUrl: string }> {\n const ext = file.name.includes(\".\")\n ? file.name.substring(file.name.lastIndexOf(\".\") + 1)\n : \"zip\";\n const data = await gql(\n `mutation DevPortal_InitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) {\n uploadUrl\n session { id }\n }\n }`,\n {\n input: {\n fileName: file.name,\n fileSize: String(file.size),\n mimeType: file.type || \"application/zip\",\n extension: ext,\n folderId,\n visibility: \"PUBLIC\",\n },\n },\n );\n const result = data.initiateUpload as\n | { uploadUrl?: string; session?: { id?: string } }\n | undefined;\n const sessionId = result?.session?.id;\n const uploadUrl = result?.uploadUrl;\n if (!sessionId || !uploadUrl) {\n throw new Error(\"initiateUpload did not return sessionId or uploadUrl\");\n }\n return { sessionId, uploadUrl };\n}\n\nasync function putToPresignedUrl(\n file: File,\n uploadUrl: string,\n onProgress: (pct: number) => void,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.upload.addEventListener(\"progress\", (evt) => {\n if (evt.lengthComputable) {\n onProgress(10 + Math.round((evt.loaded / evt.total) * 80));\n }\n });\n xhr.addEventListener(\"load\", () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`S3 PUT failed: ${xhr.status}`));\n }\n });\n xhr.addEventListener(\"error\", () =>\n reject(new Error(\"S3 PUT network error\")),\n );\n xhr.addEventListener(\"abort\", () => reject(new Error(\"S3 PUT aborted\")));\n xhr.open(\"PUT\", uploadUrl);\n xhr.setRequestHeader(\"Content-Type\", file.type || \"application/zip\");\n xhr.send(file);\n });\n}\n\nasync function completeUpload(\n gql: GqlFetcher,\n sessionId: string,\n folderId: string,\n fileSize: number,\n): Promise<PackageUploadResult> {\n const data = await gql(\n `mutation DevPortal_CompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) {\n file { id downloadUrl }\n }\n }`,\n {\n input: {\n sessionId,\n folderId,\n fileSize: String(fileSize),\n },\n },\n );\n const file = (\n data.completeUpload as\n | { file?: { id?: string; downloadUrl?: string } }\n | undefined\n )?.file;\n if (!file?.id || !file.downloadUrl) {\n throw new Error(\"completeUpload did not return file id or downloadUrl\");\n }\n return { fileId: file.id, downloadUrl: file.downloadUrl };\n}\n\nexport function usePackageUpload(\n workspacesGatewayUrl: string | undefined,\n authToken: string | undefined,\n workspaceId: string | undefined,\n getWorkspaceToken: (() => Promise<string | null>) | undefined,\n folderPath = \"/DevPortal/Packages\",\n) {\n const [state, setState] = useState<PackageUploadState>({\n uploading: false,\n progress: 0,\n error: null,\n });\n\n const upload = useCallback(\n async (file: File): Promise<PackageUploadResult> => {\n if (!workspacesGatewayUrl) {\n throw new Error(\n \"workspacesGatewayUrl is not configured. Pass it as a prop to DevportalRoot.\",\n );\n }\n\n const freshToken = getWorkspaceToken\n ? await getWorkspaceToken()\n : undefined;\n const gql = makeFetcher(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n freshToken ?? undefined,\n );\n\n setState({ uploading: true, progress: 0, error: null });\n try {\n const folderId = await ensureFolder(gql, folderPath);\n setState((s) => ({ ...s, progress: 5 }));\n\n const { sessionId, uploadUrl } = await initiateUpload(\n gql,\n file,\n folderId,\n );\n setState((s) => ({ ...s, progress: 10 }));\n\n await putToPresignedUrl(file, uploadUrl, (pct) =>\n setState((s) => ({ ...s, progress: pct })),\n );\n setState((s) => ({ ...s, progress: 90 }));\n\n const result = await completeUpload(\n gql,\n sessionId,\n folderId,\n file.size,\n );\n setState({ uploading: false, progress: 100, error: null });\n return result;\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Upload failed\";\n setState({ uploading: false, progress: 0, error: message });\n throw err;\n }\n },\n [workspacesGatewayUrl, authToken, workspaceId, getWorkspaceToken],\n );\n\n return { upload, ...state };\n}\n"],"mappings":"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"}
@@ -5,9 +5,9 @@ import { getErrorMessage as l } from "../hooks/useGraphQL.js";
5
5
  import { PageLayout as u, PageSection as d } from "../components/PageLayout.js";
6
6
  import { PermissionGuard as f } from "../components/PermissionGuard.js";
7
7
  import "../components/index.js";
8
- import { DEVPORTAL_PERMISSIONS as p } from "../constants/permissions.js";
9
- import { useDevportalPermission as m } from "../hooks/usePermission.js";
8
+ import { useDevportalPermission as p } from "../hooks/usePermission.js";
10
9
  import "../hooks/index.js";
10
+ import { DEVPORTAL_PERMISSIONS as m } from "../constants/permissions.js";
11
11
  import { useState as h } from "react";
12
12
  import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
13
13
  import { AlertCircle as _, CheckCircle as v, ChevronDown as y, ChevronUp as b, Clock as x, Download as S, Eye as C, FileJson as w, GitBranch as T, Loader2 as E, Package as D, Search as O, XCircle as k } from "lucide-react";
@@ -66,7 +66,7 @@ var M = ({ manifest: e, tr: t }) => {
66
66
  let { navigate: s, basePath: c } = e(), { t: l } = g(), u = (e, t) => {
67
67
  let n = l(e);
68
68
  return n === e ? t : n;
69
- }, [d, f] = h(!1), [_, x] = h(""), w = m(p.APP_APPROVE), D = m(p.APP_REJECT), { data: O } = i({
69
+ }, [d, f] = h(!1), [_, x] = h(""), w = p(m.APP_APPROVE), D = p(m.APP_REJECT), { data: O } = i({
70
70
  variables: { id: t.id },
71
71
  skip: !d,
72
72
  fetchPolicy: "cache-first"
@@ -380,7 +380,7 @@ var M = ({ manifest: e, tr: t }) => {
380
380
  })]
381
381
  });
382
382
  }, L = ({ version: e, appId: t, appType: n, onApprove: r, onReject: i, processing: a, tr: o }) => {
383
- let [s, c] = h(""), l = m(p.APP_APPROVE), u = m(p.APP_REJECT);
383
+ let [s, c] = h(""), l = p(m.APP_APPROVE), u = p(m.APP_REJECT);
384
384
  return /* @__PURE__ */ j("div", {
385
385
  className: "rounded-md border bg-bg-surface p-4 space-y-3",
386
386
  children: [
@@ -487,7 +487,7 @@ var M = ({ manifest: e, tr: t }) => {
487
487
  let { t: e } = g(), i = (t, n) => {
488
488
  let r = e(t);
489
489
  return r === t ? n : r;
490
- }, [m, y] = h(""), [b, S] = h(/* @__PURE__ */ new Set()), [C, w] = h(/* @__PURE__ */ new Set()), [D, k] = h(null), [M, N] = h(null), P = (e) => S((t) => new Set(t).add(e)), L = (e) => S((t) => {
490
+ }, [p, y] = h(""), [b, S] = h(/* @__PURE__ */ new Set()), [C, w] = h(/* @__PURE__ */ new Set()), [D, k] = h(null), [M, N] = h(null), P = (e) => S((t) => new Set(t).add(e)), L = (e) => S((t) => {
491
491
  let n = new Set(t);
492
492
  return n.delete(e), n;
493
493
  }), R = (e) => w((t) => new Set(t).add(e)), z = (e) => w((t) => {
@@ -502,7 +502,7 @@ var M = ({ manifest: e, tr: t }) => {
502
502
  }), { data: W, refetch: G } = o({
503
503
  variables: { limit: 100 },
504
504
  fetchPolicy: "cache-and-network"
505
- }), [K] = n(), [q] = s(), [J] = r(), [Y] = c(), X = B?.applications?.edges?.map((e) => e.node) ?? [], Z = W?.applicationsWithPendingVersions?.edges?.map((e) => e.node) ?? [], Q = new Set(Z.map((e) => e.id)), $ = m ? X.filter((e) => e.name.toLowerCase().includes(m.toLowerCase()) || (e.shortDescription ?? "").toLowerCase().includes(m.toLowerCase())) : X, ee = async (e, t) => {
505
+ }), [K] = n(), [q] = s(), [J] = r(), [Y] = c(), X = B?.applications?.edges?.map((e) => e.node) ?? [], Z = W?.applicationsWithPendingVersions?.edges?.map((e) => e.node) ?? [], Q = new Set(Z.map((e) => e.id)), $ = p ? X.filter((e) => e.name.toLowerCase().includes(p.toLowerCase()) || (e.shortDescription ?? "").toLowerCase().includes(p.toLowerCase())) : X, ee = async (e, t) => {
506
506
  P(e), k(null), N(null);
507
507
  try {
508
508
  let n = await K({ variables: {
@@ -589,7 +589,7 @@ var M = ({ manifest: e, tr: t }) => {
589
589
  ]
590
590
  })
591
591
  }) : /* @__PURE__ */ A(f, {
592
- permission: p.REVIEW_MANAGE,
592
+ permission: m.REVIEW_MANAGE,
593
593
  children: /* @__PURE__ */ j(u, {
594
594
  title: i("devportal.appReviewQueue", "App Review Queue"),
595
595
  description: i("devportal.appReviewQueueFullDescription", "Review submitted applications for approval or rejection"),
@@ -658,7 +658,7 @@ var M = ({ manifest: e, tr: t }) => {
658
658
  }), /* @__PURE__ */ A("input", {
659
659
  type: "text",
660
660
  placeholder: i("devportal.searchSubmittedApps", "Search submitted apps..."),
661
- value: m,
661
+ value: p,
662
662
  onChange: (e) => y(e.target.value),
663
663
  className: "w-full rounded-md border bg-bg-surface pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
664
664
  })]
@@ -669,7 +669,7 @@ var M = ({ manifest: e, tr: t }) => {
669
669
  illustration: "empty-data",
670
670
  icon: /* @__PURE__ */ A(v, { size: 32 }),
671
671
  title: i("devportal.noAppsPendingReview", "No apps pending review"),
672
- description: m ? i("devportal.noAppsMatchSearch", "No apps match your search") : i("devportal.allApplicationsReviewed", "All submitted applications have been reviewed")
672
+ description: p ? i("devportal.noAppsMatchSearch", "No apps match your search") : i("devportal.allApplicationsReviewed", "All submitted applications have been reviewed")
673
673
  }) : /* @__PURE__ */ A("div", {
674
674
  className: "space-y-3",
675
675
  children: $.map((e) => /* @__PURE__ */ A(F, {