zudoku 0.0.0-monetization-standalone.zd1543a39 → 0.0.0-monetization-standalone.zada7f04c

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 (93) hide show
  1. package/dist/app/main.js +1 -1
  2. package/dist/app/main.js.map +1 -1
  3. package/dist/config/create-plugin.d.ts +1 -1
  4. package/dist/config/create-plugin.js +7 -5
  5. package/dist/config/create-plugin.js.map +1 -1
  6. package/dist/config/loader.js +2 -2
  7. package/dist/config/loader.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/lib/components/Slot.test.js +1 -1
  11. package/dist/lib/components/Slot.test.js.map +1 -1
  12. package/dist/lib/components/Zudoku.d.ts +4 -1
  13. package/dist/lib/components/Zudoku.js +2 -2
  14. package/dist/lib/components/Zudoku.js.map +1 -1
  15. package/dist/lib/components/index.d.ts +3 -1
  16. package/dist/lib/core/ZudokuContext.d.ts +2 -1
  17. package/dist/lib/core/ZudokuContext.js +3 -1
  18. package/dist/lib/core/ZudokuContext.js.map +1 -1
  19. package/dist/lib/core/__internal.d.ts +1 -0
  20. package/dist/lib/core/__internal.js +2 -0
  21. package/dist/lib/core/__internal.js.map +1 -1
  22. package/dist/lib/core/plugins.d.ts +5 -1
  23. package/dist/lib/core/plugins.js.map +1 -1
  24. package/dist/lib/core/transform-config.d.ts +3 -1
  25. package/dist/lib/core/transform-config.js +33 -13
  26. package/dist/lib/core/transform-config.js.map +1 -1
  27. package/dist/lib/core/transform-config.test.d.ts +1 -0
  28. package/dist/lib/core/transform-config.test.js +83 -0
  29. package/dist/lib/core/transform-config.test.js.map +1 -0
  30. package/dist/lib/hooks/useEvent.test.js +1 -1
  31. package/dist/lib/hooks/useEvent.test.js.map +1 -1
  32. package/dist/vite/config.js +5 -2
  33. package/dist/vite/config.js.map +1 -1
  34. package/dist/vite/plugin-config.js +16 -4
  35. package/dist/vite/plugin-config.js.map +1 -1
  36. package/lib/{ClaudeLogo-CUaQXKLK.js → ClaudeLogo-K64Qm6gS.js} +2 -2
  37. package/lib/{ClaudeLogo-CUaQXKLK.js.map → ClaudeLogo-K64Qm6gS.js.map} +1 -1
  38. package/lib/{MdxPage-BiAVpP8K.js → MdxPage-Cr99RARi.js} +5 -5
  39. package/lib/{MdxPage-BiAVpP8K.js.map → MdxPage-Cr99RARi.js.map} +1 -1
  40. package/lib/{OAuthErrorPage-DhJo-O2B.js → OAuthErrorPage-BRXS5AMu.js} +3 -3
  41. package/lib/{OAuthErrorPage-DhJo-O2B.js.map → OAuthErrorPage-BRXS5AMu.js.map} +1 -1
  42. package/lib/{OasProvider-DFMZwyNn.js → OasProvider-sP_SqSM7.js} +2 -2
  43. package/lib/{OasProvider-DFMZwyNn.js.map → OasProvider-sP_SqSM7.js.map} +1 -1
  44. package/lib/{OperationList-CnmLfOuu.js → OperationList-DR0APPhk.js} +5 -5
  45. package/lib/{OperationList-CnmLfOuu.js.map → OperationList-DR0APPhk.js.map} +1 -1
  46. package/lib/{SchemaList-B5ikunUd.js → SchemaList-DgqAAHSI.js} +6 -6
  47. package/lib/{SchemaList-B5ikunUd.js.map → SchemaList-DgqAAHSI.js.map} +1 -1
  48. package/lib/{SchemaView-rjji7zMf.js → SchemaView-7IyQYEqk.js} +3 -3
  49. package/lib/{SchemaView-rjji7zMf.js.map → SchemaView-7IyQYEqk.js.map} +1 -1
  50. package/lib/{SignUp-DHWDXat-.js → SignUp-D3zhMk7q.js} +2 -2
  51. package/lib/{SignUp-DHWDXat-.js.map → SignUp-D3zhMk7q.js.map} +1 -1
  52. package/lib/{Toc-vMbSQCkj.js → Toc-GluXkcIk.js} +2 -2
  53. package/lib/{Toc-vMbSQCkj.js.map → Toc-GluXkcIk.js.map} +1 -1
  54. package/lib/{circular-CLhJAE3S.js → circular-Bunzbpsy.js} +2 -2
  55. package/lib/{circular-CLhJAE3S.js.map → circular-Bunzbpsy.js.map} +1 -1
  56. package/lib/{createServer-BYtu5Pcr.js → createServer-Dl4Xwsm4.js} +4 -4
  57. package/lib/{createServer-BYtu5Pcr.js.map → createServer-Dl4Xwsm4.js.map} +1 -1
  58. package/lib/{errors-DkJIl45d.js → errors-D2NINcVk.js} +2 -2
  59. package/lib/{errors-DkJIl45d.js.map → errors-D2NINcVk.js.map} +1 -1
  60. package/lib/{firebase-CmsW0j7-.js → firebase-BVAmGV_v.js} +10 -10
  61. package/lib/{firebase-CmsW0j7-.js.map → firebase-BVAmGV_v.js.map} +1 -1
  62. package/lib/{index-k0PVZBYl.js → index-BfTLawvZ.js} +7 -7
  63. package/lib/{index-k0PVZBYl.js.map → index-BfTLawvZ.js.map} +1 -1
  64. package/lib/{index-D35F-SCL.js → index-DTjrb36R.js} +2 -2
  65. package/lib/{index-D35F-SCL.js.map → index-DTjrb36R.js.map} +1 -1
  66. package/lib/{index-ofqkdEjL.js → index-DYfX9H7i.js} +34 -29
  67. package/lib/{index-ofqkdEjL.js.map → index-DYfX9H7i.js.map} +1 -1
  68. package/lib/{index.esm-DFzsB75P.js → index.esm-GMDd_9gw.js} +2 -2
  69. package/lib/index.esm-GMDd_9gw.js.map +1 -0
  70. package/lib/zudoku.__internal.js +494 -471
  71. package/lib/zudoku.__internal.js.map +1 -1
  72. package/lib/zudoku.auth-azureb2c.js +3 -3
  73. package/lib/zudoku.auth-clerk.js +1 -1
  74. package/lib/zudoku.auth-firebase.js +3 -3
  75. package/lib/zudoku.auth-openid.js +3 -3
  76. package/lib/zudoku.auth-supabase.js +3 -3
  77. package/lib/zudoku.components.js +1 -1
  78. package/lib/zudoku.plugin-api-catalog.js +2 -2
  79. package/lib/zudoku.plugin-api-keys.js +1 -1
  80. package/lib/zudoku.plugin-markdown.js +1 -1
  81. package/lib/zudoku.plugin-openapi.js +1 -1
  82. package/lib/zudoku.plugins.js.map +1 -1
  83. package/package.json +1 -2
  84. package/src/app/main.tsx +1 -1
  85. package/src/lib/components/Slot.test.tsx +1 -1
  86. package/src/lib/components/Zudoku.tsx +13 -3
  87. package/src/lib/core/ZudokuContext.ts +7 -1
  88. package/src/lib/core/__internal.tsx +2 -0
  89. package/src/lib/core/plugins.ts +7 -3
  90. package/src/lib/core/transform-config.test.tsx +99 -0
  91. package/src/lib/core/transform-config.ts +52 -14
  92. package/src/lib/hooks/useEvent.test.tsx +1 -1
  93. package/lib/index.esm-DFzsB75P.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { j as n } from "./jsx-runtime-BzflLqGi.js";
2
2
  import { PublicClientApplication as A, EventType as f } from "@azure/msal-browser";
3
- import { E as I } from "./index-ofqkdEjL.js";
3
+ import { E as I } from "./index-DYfX9H7i.js";
4
4
  import { C as T } from "./ClientOnly-E7hGysn1.js";
5
5
  import { j as S, u as h } from "./ZudokuContext-CnEI8jPU.js";
6
- import { C, A as c } from "./errors-DkJIl45d.js";
7
- import { C as k, O as w } from "./OAuthErrorPage-DhJo-O2B.js";
6
+ import { C, A as c } from "./errors-D2NINcVk.js";
7
+ import { C as k, O as w } from "./OAuthErrorPage-BRXS5AMu.js";
8
8
  const u = "/oauth/callback";
9
9
  class y extends C {
10
10
  msalInstance;
@@ -1,6 +1,6 @@
1
1
  import { j as a } from "./jsx-runtime-BzflLqGi.js";
2
2
  import { LogOutIcon as m } from "lucide-react";
3
- import { S as p, a as f, b as h } from "./SignUp-DHWDXat-.js";
3
+ import { S as p, a as f, b as h } from "./SignUp-D3zhMk7q.js";
4
4
  import { u as r } from "./ZudokuContext-CnEI8jPU.js";
5
5
  const R = ({
6
6
  clerkPubKey: u,
@@ -1,8 +1,8 @@
1
1
  import "./jsx-runtime-BzflLqGi.js";
2
- import { y as e } from "./firebase-CmsW0j7-.js";
2
+ import { y as e } from "./firebase-BVAmGV_v.js";
3
3
  import "./invariant-BJAl77rw.js";
4
- import "./errors-DkJIl45d.js";
5
- import "./SignUp-DHWDXat-.js";
4
+ import "./errors-D2NINcVk.js";
5
+ import "./SignUp-D3zhMk7q.js";
6
6
  import "./ZudokuContext-CnEI8jPU.js";
7
7
  export {
8
8
  e as default
@@ -1,10 +1,10 @@
1
1
  import { j as D } from "./jsx-runtime-BzflLqGi.js";
2
2
  import { a as Le } from "./invariant-BJAl77rw.js";
3
- import { E as Ue } from "./index-ofqkdEjL.js";
3
+ import { E as Ue } from "./index-DYfX9H7i.js";
4
4
  import { C as xe } from "./ClientOnly-E7hGysn1.js";
5
5
  import { j as Ce, u as S } from "./ZudokuContext-CnEI8jPU.js";
6
- import { C as Ie, O as re, A as R } from "./errors-DkJIl45d.js";
7
- import { C as je, O as Oe } from "./OAuthErrorPage-DhJo-O2B.js";
6
+ import { C as Ie, O as re, A as R } from "./errors-D2NINcVk.js";
7
+ import { C as je, O as Oe } from "./OAuthErrorPage-BRXS5AMu.js";
8
8
  var J = { exports: {} }, De = J.exports, oe;
9
9
  function Je() {
10
10
  return oe || (oe = 1, (function(t) {
@@ -1,12 +1,12 @@
1
1
  import { j as a } from "./jsx-runtime-BzflLqGi.js";
2
2
  import { createClient as g } from "@supabase/supabase-js";
3
- import { C as m, A as h } from "./errors-DkJIl45d.js";
4
- import { S as f } from "./SignUp-DHWDXat-.js";
3
+ import { C as m, A as h } from "./errors-D2NINcVk.js";
4
+ import { S as f } from "./SignUp-D3zhMk7q.js";
5
5
  import { u } from "./ZudokuContext-CnEI8jPU.js";
6
6
  import { Auth as v } from "@supabase/auth-ui-react";
7
7
  import { ThemeSupa as S } from "@supabase/auth-ui-shared";
8
8
  import { b as T } from "./chunk-EPOLDU6W-C6C8jAwd.js";
9
- import { H as A } from "./index-ofqkdEjL.js";
9
+ import { H as A } from "./index-DYfX9H7i.js";
10
10
  const c = ({
11
11
  client: i,
12
12
  config: e,
@@ -7,7 +7,7 @@ import "./ui/Callout.js";
7
7
  import "./invariant-BJAl77rw.js";
8
8
  import "./ClientOnly-E7hGysn1.js";
9
9
  import "./ZudokuContext-CnEI8jPU.js";
10
- import { B as d, y as k, C as l, p as h, n as y, o as S, L as Z, m as E, r as H, S as g, q as w, Z as x, t as A, w as B, x as L, v as M, z as T, a as c } from "./index-ofqkdEjL.js";
10
+ import { B as d, y as k, C as l, p as h, n as y, o as S, L as Z, m as E, r as H, S as g, q as w, Z as x, t as A, w as B, x as L, v as M, z as T, a as c } from "./index-DYfX9H7i.js";
11
11
  import "./Spinner-CI6bRyZw.js";
12
12
  export {
13
13
  d as Button,
@@ -1,10 +1,10 @@
1
1
  import { j as t } from "./jsx-runtime-BzflLqGi.js";
2
- import { s as f } from "./index-D35F-SCL.js";
2
+ import { s as f } from "./index-DTjrb36R.js";
3
3
  import { c as b, m as j } from "./chunk-EPOLDU6W-C6C8jAwd.js";
4
4
  import { u as x, j as d } from "./ZudokuContext-CnEI8jPU.js";
5
5
  import { u as v } from "./useSuspenseQuery-CSB_rVek.js";
6
6
  import { H as y } from "./index.esm-B_0dvNjB.js";
7
- import { H as N, L as k, M as S } from "./index-ofqkdEjL.js";
7
+ import { H as N, L as k, M as S } from "./index-DYfX9H7i.js";
8
8
  const w = ({
9
9
  items: o,
10
10
  filterCatalogItems: r = (i) => i,
@@ -3,7 +3,7 @@ import { TrashIcon as me, CircleSlashIcon as z, CheckIcon as xe, XIcon as ye, Pe
3
3
  import { Z as M, i as E } from "./invariant-BJAl77rw.js";
4
4
  import * as F from "react";
5
5
  import { createContext as Q, useRef as A, useLayoutEffect as Ce, useEffect as ie, useId as H, useContext as V, useInsertionEffect as we, useMemo as L, useCallback as ke, Children as Ee, isValidElement as Ie, useState as I } from "react";
6
- import { D as be, c as ee, B as Ke, E as De } from "./index-ofqkdEjL.js";
6
+ import { D as be, c as ee, B as Ke, E as De } from "./index-DYfX9H7i.js";
7
7
  import { b as re } from "./index-Ba6RP577.js";
8
8
  import { F as Pe, g as Ae, j as Se, h as Re, d as Ne, I as Oe, a as Te, b as qe, k as Me, c as Fe } from "./Frame-DKlOmSkU.js";
9
9
  import { A as D, a as P, b as ae } from "./Mermaid-DEztDKFw.js";
@@ -4,7 +4,7 @@ const p = (t) => ({
4
4
  ([e, a]) => ({
5
5
  path: e,
6
6
  lazy: async () => {
7
- const { MdxPage: n } = await import("./MdxPage-BiAVpP8K.js"), { default: o, ...s } = await a();
7
+ const { MdxPage: n } = await import("./MdxPage-Cr99RARi.js"), { default: o, ...s } = await a();
8
8
  return {
9
9
  element: /* @__PURE__ */ r.jsx(
10
10
  n,
@@ -3,7 +3,7 @@ import "lucide-react";
3
3
  import "./chunk-EPOLDU6W-C6C8jAwd.js";
4
4
  import "./ui/Button.js";
5
5
  import "./ZudokuContext-CnEI8jPU.js";
6
- import { y as e, U as n, z as s } from "./index-k0PVZBYl.js";
6
+ import { y as e, U as n, z as s } from "./index-BfTLawvZ.js";
7
7
  export {
8
8
  e as GetNavigationOperationsQuery,
9
9
  n as UNTAGGED_PATH,
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugins.js","sources":["../src/lib/core/plugins.ts"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport type { Location, RouteObject } from \"react-router\";\nimport type { Navigation } from \"../../config/validators/NavigationSchema.js\";\nimport type { ProtectedRoutesInput } from \"../../config/validators/ProtectedRoutesSchema.js\";\nimport type { ZudokuConfig } from \"../../config/validators/validate.js\";\nimport type { AuthenticationPlugin } from \"../authentication/authentication.js\";\nimport type { MdxComponentsType } from \"../util/MdxComponents.js\";\nimport type {\n ApiIdentity,\n ZudokuContext,\n ZudokuEvents,\n} from \"./ZudokuContext.js\";\n\nexport type ZudokuPlugin =\n | CommonPlugin\n | ProfileMenuPlugin\n | NavigationPlugin\n | ApiIdentityPlugin\n | SearchProviderPlugin\n | EventConsumerPlugin\n | AuthenticationPlugin\n | TransformConfigPlugin;\n\nexport type { AuthenticationPlugin, RouteObject };\n\nexport interface NavigationPlugin {\n getRoutes: () => RouteObject[];\n getNavigation?: (path: string, context: ZudokuContext) => Promise<Navigation>;\n getProtectedRoutes?: () => ProtectedRoutesInput;\n}\n\nexport const createApiIdentityPlugin = (\n plugin: ApiIdentityPlugin,\n): ApiIdentityPlugin => plugin;\n\nexport const createProfileMenuPlugin = (\n plugin: ProfileMenuPlugin,\n): ProfileMenuPlugin => plugin;\n\nexport interface ApiIdentityPlugin {\n getIdentities: (context: ZudokuContext) => Promise<ApiIdentity[]>;\n}\n\nexport interface SearchProviderPlugin {\n renderSearch: (o: {\n isOpen: boolean;\n onClose: () => void;\n }) => React.JSX.Element | null;\n}\n\nexport interface ProfileMenuPlugin {\n getProfileMenuItems: (context: ZudokuContext) => ProfileNavigationItem[];\n}\n\nexport type ProfileNavigationItem = {\n label: string;\n path?: string;\n weight?: number;\n category?: \"top\" | \"middle\" | \"bottom\";\n children?: ProfileNavigationItem[];\n icon?: LucideIcon;\n};\n\nexport interface ConfigHookContext {\n mode: typeof process.env.ZUDOKU_ENV;\n rootDir: string;\n configPath: string;\n}\n\nexport interface TransformConfigPlugin {\n transformConfig?: (\n config: ZudokuConfig,\n ctx: ConfigHookContext,\n ) => Partial<ZudokuConfig> | void | Promise<Partial<ZudokuConfig> | void>;\n}\n\nexport interface CommonPlugin {\n initialize?: (\n context: ZudokuContext,\n ) => Promise<void | boolean> | void | boolean;\n getHead?: (args: { location: Location }) => ReactNode | undefined;\n getMdxComponents?: () => MdxComponentsType;\n}\n\nexport type EventConsumerPlugin<Event extends ZudokuEvents = ZudokuEvents> = {\n events: { [K in keyof Event]?: Event[K] };\n};\n\nexport const isEventConsumerPlugin = (\n obj: ZudokuPlugin,\n): obj is EventConsumerPlugin =>\n \"events\" in obj && typeof obj.events === \"object\";\n\nexport const isProfileMenuPlugin = (\n obj: ZudokuPlugin,\n): obj is ProfileMenuPlugin =>\n \"getProfileMenuItems\" in obj && typeof obj.getProfileMenuItems === \"function\";\n\nexport const isNavigationPlugin = (\n obj: ZudokuPlugin,\n): obj is NavigationPlugin =>\n \"getRoutes\" in obj && typeof obj.getRoutes === \"function\";\n\nexport const isAuthenticationPlugin = (\n obj: ZudokuPlugin,\n): obj is AuthenticationPlugin =>\n \"signUp\" in obj && typeof obj.signUp === \"function\";\n\nexport const isSearchPlugin = (\n obj: ZudokuPlugin,\n): obj is SearchProviderPlugin =>\n \"renderSearch\" in obj && typeof obj.renderSearch === \"function\";\n\nexport const needsInitialization = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"initialize\" in obj && typeof obj.initialize === \"function\";\n\nexport const hasHead = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"getHead\" in obj && typeof obj.getHead === \"function\";\n\nexport const isMdxProviderPlugin = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"getMdxComponents\" in obj && typeof obj.getMdxComponents === \"function\";\n\nexport const isApiIdentityPlugin = (\n obj: ZudokuPlugin,\n): obj is ApiIdentityPlugin =>\n \"getIdentities\" in obj && typeof obj.getIdentities === \"function\";\n\nexport const isTransformConfigPlugin = (\n obj: ZudokuPlugin,\n): obj is TransformConfigPlugin =>\n \"transformConfig\" in obj && typeof obj.transformConfig === \"function\";\n"],"names":["createApiIdentityPlugin","plugin","createProfileMenuPlugin","isEventConsumerPlugin","obj","isProfileMenuPlugin","isNavigationPlugin","isAuthenticationPlugin","isSearchPlugin","needsInitialization","hasHead","isMdxProviderPlugin","isApiIdentityPlugin","isTransformConfigPlugin"],"mappings":"AAgCO,MAAMA,IAA0B,CACrCC,MACsBA,GAEXC,IAA0B,CACrCD,MACsBA,GAmDXE,IAAwB,CACnCC,MAEA,YAAYA,KAAO,OAAOA,EAAI,UAAW,UAE9BC,IAAsB,CACjCD,MAEA,yBAAyBA,KAAO,OAAOA,EAAI,uBAAwB,YAExDE,IAAqB,CAChCF,MAEA,eAAeA,KAAO,OAAOA,EAAI,aAAc,YAEpCG,IAAyB,CACpCH,MAEA,YAAYA,KAAO,OAAOA,EAAI,UAAW,YAE9BI,IAAiB,CAC5BJ,MAEA,kBAAkBA,KAAO,OAAOA,EAAI,gBAAiB,YAE1CK,IAAsB,CAACL,MAClC,gBAAgBA,KAAO,OAAOA,EAAI,cAAe,YAEtCM,IAAU,CAACN,MACtB,aAAaA,KAAO,OAAOA,EAAI,WAAY,YAEhCO,IAAsB,CAACP,MAClC,sBAAsBA,KAAO,OAAOA,EAAI,oBAAqB,YAElDQ,IAAsB,CACjCR,MAEA,mBAAmBA,KAAO,OAAOA,EAAI,iBAAkB,YAE5CS,IAA0B,CACrCT,MAEA,qBAAqBA,KAAO,OAAOA,EAAI,mBAAoB;"}
1
+ {"version":3,"file":"zudoku.plugins.js","sources":["../src/lib/core/plugins.ts"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport type { Location, RouteObject } from \"react-router\";\nimport type { Navigation } from \"../../config/validators/NavigationSchema.js\";\nimport type { ProtectedRoutesInput } from \"../../config/validators/ProtectedRoutesSchema.js\";\nimport type { ZudokuConfig } from \"../../config/validators/validate.js\";\nimport type { AuthenticationPlugin } from \"../authentication/authentication.js\";\nimport type { MdxComponentsType } from \"../util/MdxComponents.js\";\nimport type {\n ApiIdentity,\n ZudokuContext,\n ZudokuEvents,\n} from \"./ZudokuContext.js\";\n\nexport type ZudokuPlugin =\n | CommonPlugin\n | ProfileMenuPlugin\n | NavigationPlugin\n | ApiIdentityPlugin\n | SearchProviderPlugin\n | EventConsumerPlugin\n | AuthenticationPlugin\n | TransformConfigPlugin;\n\nexport type { AuthenticationPlugin, RouteObject };\n\nexport interface NavigationPlugin {\n getRoutes: () => RouteObject[];\n getNavigation?: (path: string, context: ZudokuContext) => Promise<Navigation>;\n getProtectedRoutes?: () => ProtectedRoutesInput;\n}\n\nexport const createApiIdentityPlugin = (\n plugin: ApiIdentityPlugin,\n): ApiIdentityPlugin => plugin;\n\nexport const createProfileMenuPlugin = (\n plugin: ProfileMenuPlugin,\n): ProfileMenuPlugin => plugin;\n\nexport interface ApiIdentityPlugin {\n getIdentities: (context: ZudokuContext) => Promise<ApiIdentity[]>;\n}\n\nexport interface SearchProviderPlugin {\n renderSearch: (o: {\n isOpen: boolean;\n onClose: () => void;\n }) => React.JSX.Element | null;\n}\n\nexport interface ProfileMenuPlugin {\n getProfileMenuItems: (context: ZudokuContext) => ProfileNavigationItem[];\n}\n\nexport type ProfileNavigationItem = {\n label: string;\n path?: string;\n weight?: number;\n category?: \"top\" | \"middle\" | \"bottom\";\n children?: ProfileNavigationItem[];\n icon?: LucideIcon;\n};\n\nexport interface ConfigHookContext {\n mode: typeof process.env.ZUDOKU_ENV;\n rootDir: string;\n configPath: string;\n}\n\nexport interface TransformConfigContext {\n config: ZudokuConfig;\n merge: <T extends Partial<ZudokuConfig>>(partial: T) => ZudokuConfig & T;\n}\n\nexport interface TransformConfigPlugin {\n transformConfig?: (\n context: TransformConfigContext,\n ) => ZudokuConfig | void | Promise<ZudokuConfig | void>;\n}\n\nexport interface CommonPlugin {\n initialize?: (\n context: ZudokuContext,\n ) => Promise<void | boolean> | void | boolean;\n getHead?: (args: { location: Location }) => ReactNode | undefined;\n getMdxComponents?: () => MdxComponentsType;\n}\n\nexport type EventConsumerPlugin<Event extends ZudokuEvents = ZudokuEvents> = {\n events: { [K in keyof Event]?: Event[K] };\n};\n\nexport const isEventConsumerPlugin = (\n obj: ZudokuPlugin,\n): obj is EventConsumerPlugin =>\n \"events\" in obj && typeof obj.events === \"object\";\n\nexport const isProfileMenuPlugin = (\n obj: ZudokuPlugin,\n): obj is ProfileMenuPlugin =>\n \"getProfileMenuItems\" in obj && typeof obj.getProfileMenuItems === \"function\";\n\nexport const isNavigationPlugin = (\n obj: ZudokuPlugin,\n): obj is NavigationPlugin =>\n \"getRoutes\" in obj && typeof obj.getRoutes === \"function\";\n\nexport const isAuthenticationPlugin = (\n obj: ZudokuPlugin,\n): obj is AuthenticationPlugin =>\n \"signUp\" in obj && typeof obj.signUp === \"function\";\n\nexport const isSearchPlugin = (\n obj: ZudokuPlugin,\n): obj is SearchProviderPlugin =>\n \"renderSearch\" in obj && typeof obj.renderSearch === \"function\";\n\nexport const needsInitialization = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"initialize\" in obj && typeof obj.initialize === \"function\";\n\nexport const hasHead = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"getHead\" in obj && typeof obj.getHead === \"function\";\n\nexport const isMdxProviderPlugin = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"getMdxComponents\" in obj && typeof obj.getMdxComponents === \"function\";\n\nexport const isApiIdentityPlugin = (\n obj: ZudokuPlugin,\n): obj is ApiIdentityPlugin =>\n \"getIdentities\" in obj && typeof obj.getIdentities === \"function\";\n\nexport const isTransformConfigPlugin = (\n obj: ZudokuPlugin,\n): obj is TransformConfigPlugin =>\n \"transformConfig\" in obj && typeof obj.transformConfig === \"function\";\n"],"names":["createApiIdentityPlugin","plugin","createProfileMenuPlugin","isEventConsumerPlugin","obj","isProfileMenuPlugin","isNavigationPlugin","isAuthenticationPlugin","isSearchPlugin","needsInitialization","hasHead","isMdxProviderPlugin","isApiIdentityPlugin","isTransformConfigPlugin"],"mappings":"AAgCO,MAAMA,IAA0B,CACrCC,MACsBA,GAEXC,IAA0B,CACrCD,MACsBA,GAuDXE,IAAwB,CACnCC,MAEA,YAAYA,KAAO,OAAOA,EAAI,UAAW,UAE9BC,IAAsB,CACjCD,MAEA,yBAAyBA,KAAO,OAAOA,EAAI,uBAAwB,YAExDE,IAAqB,CAChCF,MAEA,eAAeA,KAAO,OAAOA,EAAI,aAAc,YAEpCG,IAAyB,CACpCH,MAEA,YAAYA,KAAO,OAAOA,EAAI,UAAW,YAE9BI,IAAiB,CAC5BJ,MAEA,kBAAkBA,KAAO,OAAOA,EAAI,gBAAiB,YAE1CK,IAAsB,CAACL,MAClC,gBAAgBA,KAAO,OAAOA,EAAI,cAAe,YAEtCM,IAAU,CAACN,MACtB,aAAaA,KAAO,OAAOA,EAAI,WAAY,YAEhCO,IAAsB,CAACP,MAClC,sBAAsBA,KAAO,OAAOA,EAAI,oBAAqB,YAElDQ,IAAsB,CACjCR,MAEA,mBAAmBA,KAAO,OAAOA,EAAI,iBAAkB,YAE5CS,IAA0B,CACrCT,MAEA,qBAAqBA,KAAO,OAAOA,EAAI,mBAAoB;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.0.0-monetization-standalone.zd1543a39",
3
+ "version": "0.0.0-monetization-standalone.zada7f04c",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -154,7 +154,6 @@
154
154
  "dependencies": {
155
155
  "@apidevtools/json-schema-ref-parser": "14.1.1",
156
156
  "@envelop/core": "5.3.2",
157
- "@fastify/deepmerge": "3.1.0",
158
157
  "@graphql-typed-document-node/core": "3.2.0",
159
158
  "@lekoarts/rehype-meta-as-attributes": "3.0.3",
160
159
  "@mdx-js/react": "3.1.1",
package/src/app/main.tsx CHANGED
@@ -111,7 +111,7 @@ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
111
111
  return [
112
112
  {
113
113
  element: (
114
- <Zudoku {...options}>
114
+ <Zudoku {...options} env={import.meta.env}>
115
115
  <BuildCheck
116
116
  buildId={import.meta.env.ZUPLO_BUILD_ID}
117
117
  environmentType={import.meta.env.ZUPLO_ENVIRONMENT_TYPE}
@@ -20,7 +20,7 @@ import { Slot } from "./Slot.js";
20
20
 
21
21
  const createWrapper = (slots: Record<string, ReactNode> = {}) => {
22
22
  const queryClient = new QueryClient();
23
- const context = new ZudokuContext({}, queryClient);
23
+ const context = new ZudokuContext({}, queryClient, {});
24
24
 
25
25
  const wrapper = ({ children }: PropsWithChildren) => (
26
26
  <MemoryRouter initialEntries={["/", "/page"]}>
@@ -32,7 +32,13 @@ import { ZudokuProvider } from "./context/ZudokuProvider.js";
32
32
  let zudokuContext: ZudokuContext | undefined;
33
33
 
34
34
  const ZudokuInner = memo(
35
- ({ children, ...props }: PropsWithChildren<ZudokuContextOptions>) => {
35
+ ({
36
+ children,
37
+ env,
38
+ ...props
39
+ }: PropsWithChildren<
40
+ ZudokuContextOptions & { env: Record<string, string> }
41
+ >) => {
36
42
  const components = useMemo(
37
43
  () => ({ ...DEFAULT_COMPONENTS, ...props.overrides }),
38
44
  [props.overrides],
@@ -66,7 +72,7 @@ const ZudokuInner = memo(
66
72
  setDidNavigate(true);
67
73
  }, [didNavigate, navigation.location]);
68
74
 
69
- zudokuContext ??= new ZudokuContext(props, queryClient);
75
+ zudokuContext ??= new ZudokuContext(props, queryClient, env);
70
76
 
71
77
  const heads = props.plugins?.flatMap((plugin) =>
72
78
  hasHead(plugin) ? (plugin.getHead?.({ location }) ?? []) : [],
@@ -98,7 +104,11 @@ const ZudokuInner = memo(
98
104
 
99
105
  ZudokuInner.displayName = "ZudokuInner";
100
106
 
101
- const Zudoku = (props: ZudokuContextOptions) => {
107
+ const Zudoku = (
108
+ props: PropsWithChildren<
109
+ ZudokuContextOptions & { env: Record<string, string> }
110
+ >,
111
+ ) => {
102
112
  return (
103
113
  <ErrorBoundary FallbackComponent={TopLevelError}>
104
114
  <ZudokuInner {...props} />
@@ -132,10 +132,15 @@ export class ZudokuContext {
132
132
  public readonly getAuthState: () => AuthState;
133
133
  public readonly queryClient: QueryClient;
134
134
  public readonly options: ZudokuContextOptions;
135
+ public readonly env: Record<string, string | undefined>;
135
136
  private readonly navigationPlugins: NavigationPlugin[];
136
137
  private emitter = createNanoEvents<ZudokuEvents>();
137
138
 
138
- constructor(options: ZudokuContextOptions, queryClient: QueryClient) {
139
+ constructor(
140
+ options: ZudokuContextOptions,
141
+ queryClient: QueryClient,
142
+ env: Record<string, string | undefined>,
143
+ ) {
139
144
  const pluginProtectedRoutes = Object.fromEntries(
140
145
  (options.plugins ?? []).flatMap((plugin) => {
141
146
  if (!isNavigationPlugin(plugin)) return [];
@@ -152,6 +157,7 @@ export class ZudokuContext {
152
157
  };
153
158
 
154
159
  this.queryClient = queryClient;
160
+ this.env = env;
155
161
  this.options = { ...options, protectedRoutes };
156
162
  this.plugins = options.plugins ?? [];
157
163
  this.navigation = options.navigation ?? [];
@@ -17,6 +17,7 @@ import { StatusPage as StatusPageImport } from "../components/StatusPage.js";
17
17
  import { RouterError as RouterErrorImport } from "../errors/RouterError.js";
18
18
  import { ServerError as ServerErrorImport } from "../errors/ServerError.js";
19
19
  import { RouteGuard as RouteGuardImport } from "./RouteGuard.js";
20
+ import { runPluginTransformConfig as runPluginTransformConfigImport } from "./transform-config.js";
20
21
 
21
22
  export const Layout = LayoutImport;
22
23
  export const RouterError = RouterErrorImport;
@@ -28,3 +29,4 @@ export const Head = Helmet;
28
29
  export const StatusPage = StatusPageImport;
29
30
  export const BuildCheck = BuildCheckImport;
30
31
  export const Meta = MetaImport;
32
+ export const runPluginTransformConfig = runPluginTransformConfigImport;
@@ -68,11 +68,15 @@ export interface ConfigHookContext {
68
68
  configPath: string;
69
69
  }
70
70
 
71
+ export interface TransformConfigContext {
72
+ config: ZudokuConfig;
73
+ merge: <T extends Partial<ZudokuConfig>>(partial: T) => ZudokuConfig & T;
74
+ }
75
+
71
76
  export interface TransformConfigPlugin {
72
77
  transformConfig?: (
73
- config: ZudokuConfig,
74
- ctx: ConfigHookContext,
75
- ) => Partial<ZudokuConfig> | void | Promise<Partial<ZudokuConfig> | void>;
78
+ context: TransformConfigContext,
79
+ ) => ZudokuConfig | void | Promise<ZudokuConfig | void>;
76
80
  }
77
81
 
78
82
  export interface CommonPlugin {
@@ -0,0 +1,99 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { isPlainObject, mergeConfig } from "./transform-config.js";
3
+
4
+ describe("isPlainObject", () => {
5
+ test("returns true for plain objects", () => {
6
+ expect(isPlainObject({})).toBe(true);
7
+ expect(isPlainObject({ a: 1 })).toBe(true);
8
+ });
9
+
10
+ test("returns false for arrays", () => {
11
+ expect(isPlainObject([])).toBe(false);
12
+ expect(isPlainObject([1, 2, 3])).toBe(false);
13
+ });
14
+
15
+ test("returns false for null and undefined", () => {
16
+ expect(isPlainObject(null)).toBe(false);
17
+ expect(isPlainObject(undefined)).toBe(false);
18
+ });
19
+
20
+ test("returns false for class instances", () => {
21
+ expect(isPlainObject(new Date())).toBe(false);
22
+ expect(isPlainObject(new Map())).toBe(false);
23
+ expect(isPlainObject(/regex/)).toBe(false);
24
+ });
25
+ });
26
+
27
+ describe("mergeConfig", () => {
28
+ test("merges flat objects", () => {
29
+ const target = { a: 1, b: 2 };
30
+ const source = { b: 3, c: 4 };
31
+ expect(mergeConfig(target, source)).toEqual({ a: 1, b: 3, c: 4 });
32
+ });
33
+
34
+ test("merges nested objects", () => {
35
+ const target = { nested: { a: 1, b: 2 } } as Record<string, unknown>;
36
+ const source = { nested: { b: 3, c: 4 } };
37
+ expect(mergeConfig(target, source)).toEqual({
38
+ nested: { a: 1, b: 3, c: 4 },
39
+ });
40
+ });
41
+
42
+ test("replaces arrays instead of merging", () => {
43
+ const target = { arr: [1, 2, 3] };
44
+ const source = { arr: [4, 5] };
45
+ expect(mergeConfig(target, source)).toEqual({ arr: [4, 5] });
46
+ });
47
+
48
+ test("preserves React elements without deep cloning", () => {
49
+ const element = <div className="test">Hello</div>;
50
+ const target = { banner: { message: "old" } };
51
+ const source = { banner: { message: element } };
52
+
53
+ const result = mergeConfig(target, source);
54
+
55
+ // Should be the exact same reference, not a clone
56
+ expect(result.banner.message).toBe(element);
57
+ });
58
+
59
+ test("does not clone React element children", () => {
60
+ const child = <strong>Bold</strong>;
61
+ const element = <div>{child} text</div>;
62
+ const target = { site: { banner: {} } };
63
+ const source = { site: { banner: { message: element } } };
64
+
65
+ const result = mergeConfig(target, source);
66
+
67
+ // The element should be identical (same reference)
68
+ expect(result.site.banner.message).toBe(element);
69
+ // Children should be preserved exactly
70
+ expect(result.site.banner.message.props.children).toBe(
71
+ element.props.children,
72
+ );
73
+ });
74
+
75
+ test("handles null and undefined values", () => {
76
+ const target = { a: 1, b: 2 };
77
+ const source = { a: null, c: undefined };
78
+ expect(mergeConfig(target, source)).toEqual({
79
+ a: null,
80
+ b: 2,
81
+ c: undefined,
82
+ });
83
+ });
84
+
85
+ test("replaces non-plain objects", () => {
86
+ const date = new Date("2024-01-01");
87
+ const target = { date: new Date("2020-01-01") };
88
+ const source = { date };
89
+ const result = mergeConfig(target, source);
90
+ expect(result.date).toBe(date);
91
+ });
92
+
93
+ test("does not mutate target", () => {
94
+ const target = { a: 1, nested: { b: 2 } };
95
+ const source = { a: 2, nested: { c: 3 } };
96
+ mergeConfig(target, source);
97
+ expect(target).toEqual({ a: 1, nested: { b: 2 } });
98
+ });
99
+ });
@@ -1,28 +1,66 @@
1
- import createDeepmerge from "@fastify/deepmerge";
1
+ import { isValidElement } from "react";
2
2
  import type { ConfigWithMeta } from "../../config/loader.js";
3
- import { type ConfigHookContext, isTransformConfigPlugin } from "./plugins.js";
3
+ import { isTransformConfigPlugin } from "./plugins.js";
4
4
 
5
- const mergeConfig = createDeepmerge({
6
- mergeArray: (opt) => (_, source) => opt.clone(source),
7
- });
5
+ export const isPlainObject = (
6
+ value: unknown,
7
+ ): value is Record<string, unknown> =>
8
+ typeof value === "object" &&
9
+ value !== null &&
10
+ !Array.isArray(value) &&
11
+ Object.getPrototypeOf(value) === Object.prototype;
8
12
 
9
- export const runTransformConfigHooks = async (
13
+ export const mergeConfig = <
14
+ T extends Record<string, unknown>,
15
+ S extends Record<string, unknown>,
16
+ >(
17
+ target: T,
18
+ source: S,
19
+ ): T & S => {
20
+ const result = { ...target } as T & S;
21
+
22
+ for (const key of Object.keys(source) as (keyof S)[]) {
23
+ const sourceValue = source[key];
24
+ const targetValue = target[key as keyof T];
25
+
26
+ // Don't merge React elements, arrays, or non-plain objects - just replace
27
+ if (
28
+ isValidElement(sourceValue) ||
29
+ Array.isArray(sourceValue) ||
30
+ !isPlainObject(sourceValue)
31
+ ) {
32
+ (result as Record<string, unknown>)[key as string] = sourceValue;
33
+ } else if (isPlainObject(targetValue)) {
34
+ (result as Record<string, unknown>)[key as string] = mergeConfig(
35
+ targetValue,
36
+ sourceValue,
37
+ );
38
+ } else {
39
+ (result as Record<string, unknown>)[key as string] = sourceValue;
40
+ }
41
+ }
42
+
43
+ return result;
44
+ };
45
+
46
+ export const runPluginTransformConfig = async (
10
47
  config: ConfigWithMeta,
11
48
  ): Promise<ConfigWithMeta> => {
12
- const ctx = {
13
- mode: config.__meta.mode,
14
- rootDir: config.__meta.rootDir,
15
- configPath: config.__meta.configPath,
16
- } satisfies ConfigHookContext;
17
49
  const plugins = config.plugins ?? [];
18
50
 
19
51
  let result = config;
20
52
 
21
53
  for (const plugin of plugins.filter(isTransformConfigPlugin)) {
22
- const partial = await plugin.transformConfig?.(result, ctx);
23
- if (!partial) continue;
54
+ const merge = <T extends Record<string, unknown>>(partial: T) =>
55
+ mergeConfig(result, partial);
56
+
57
+ const transformed = await plugin.transformConfig?.({
58
+ config: result,
59
+ merge,
60
+ });
61
+ if (!transformed) continue;
24
62
 
25
- result = mergeConfig(result, partial) as ConfigWithMeta;
63
+ result = transformed as ConfigWithMeta;
26
64
  }
27
65
 
28
66
  return result;
@@ -13,7 +13,7 @@ import { useEvent } from "./useEvent.js";
13
13
 
14
14
  const createTestContext = () => {
15
15
  const queryClient = new QueryClient();
16
- const context = new ZudokuContext({}, queryClient);
16
+ const context = new ZudokuContext({}, queryClient, {});
17
17
  const wrapper = ({ children }: PropsWithChildren) => (
18
18
  <QueryClientProvider client={queryClient}>
19
19
  <ZudokuProvider context={context}>{children}</ZudokuProvider>
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.esm-DFzsB75P.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}