zudoku 0.23.3 → 0.23.4

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 (57) hide show
  1. package/dist/config/validators/common.d.ts +45 -11
  2. package/dist/config/validators/common.js +2 -1
  3. package/dist/config/validators/common.js.map +1 -1
  4. package/dist/config/validators/validate.d.ts +19 -5
  5. package/dist/lib/authentication/providers/openid.d.ts +7 -0
  6. package/dist/lib/authentication/providers/openid.js +1 -0
  7. package/dist/lib/authentication/providers/openid.js.map +1 -1
  8. package/dist/lib/plugins/api-catalog/Catalog.d.ts +2 -6
  9. package/dist/lib/plugins/api-catalog/Catalog.js +22 -15
  10. package/dist/lib/plugins/api-catalog/Catalog.js.map +1 -1
  11. package/dist/lib/plugins/api-catalog/index.d.ts +8 -1
  12. package/dist/lib/plugins/api-catalog/index.js +2 -2
  13. package/dist/lib/plugins/api-catalog/index.js.map +1 -1
  14. package/dist/lib/plugins/search-inkeep/index.js +21 -7
  15. package/dist/lib/plugins/search-inkeep/index.js.map +1 -1
  16. package/dist/vite/plugin-api.js +12 -7
  17. package/dist/vite/plugin-api.js.map +1 -1
  18. package/lib/{AuthenticationPlugin-DQy635W9.js → AuthenticationPlugin-fB7viE7A.js} +2 -2
  19. package/lib/{AuthenticationPlugin-DQy635W9.js.map → AuthenticationPlugin-fB7viE7A.js.map} +1 -1
  20. package/lib/{MdxPage-CBa4X6L5.js → MdxPage-CPBw4_lf.js} +18 -18
  21. package/lib/{MdxPage-CBa4X6L5.js.map → MdxPage-CPBw4_lf.js.map} +1 -1
  22. package/lib/OperationList-C7ac3kR5.js +5014 -0
  23. package/lib/OperationList-C7ac3kR5.js.map +1 -0
  24. package/lib/{Select-Bb_Hqc70.js → Select-D3XuKKuH.js} +3 -3
  25. package/lib/{Select-Bb_Hqc70.js.map → Select-D3XuKKuH.js.map} +1 -1
  26. package/lib/assets/{worker-BmEAZjUP.js → worker-D2kRl-cG.js} +1487 -1436
  27. package/lib/assets/worker-D2kRl-cG.js.map +1 -0
  28. package/lib/cn-qaFjX9_3.js.map +1 -1
  29. package/lib/{createServer-BVFp6Bl3.js → createServer-69sLlmQA.js} +1968 -1917
  30. package/lib/createServer-69sLlmQA.js.map +1 -0
  31. package/lib/{hook-DMHiUaIV.js → hook-DgGeo5iL.js} +2 -2
  32. package/lib/{hook-DMHiUaIV.js.map → hook-DgGeo5iL.js.map} +1 -1
  33. package/lib/{index-B6rTMjdI.js → index-C8ubT49C.js} +6 -6
  34. package/lib/{index-B6rTMjdI.js.map → index-C8ubT49C.js.map} +1 -1
  35. package/lib/{utils-R0j3Raw1.js → utils-B4O1uet5.js} +8 -8
  36. package/lib/{utils-R0j3Raw1.js.map → utils-B4O1uet5.js.map} +1 -1
  37. package/lib/zudoku.auth-clerk.js +1 -1
  38. package/lib/zudoku.auth-openid.js +70 -69
  39. package/lib/zudoku.auth-openid.js.map +1 -1
  40. package/lib/zudoku.components.js +2 -2
  41. package/lib/zudoku.openapi-worker.js +1 -1
  42. package/lib/zudoku.plugin-api-catalog.js +80 -78
  43. package/lib/zudoku.plugin-api-catalog.js.map +1 -1
  44. package/lib/zudoku.plugin-api-keys.js +3 -3
  45. package/lib/zudoku.plugin-markdown.js +1 -1
  46. package/lib/zudoku.plugin-openapi.js +3 -3
  47. package/lib/zudoku.plugin-search-inkeep.js +34 -26
  48. package/lib/zudoku.plugin-search-inkeep.js.map +1 -1
  49. package/package.json +5 -5
  50. package/src/lib/authentication/providers/openid.tsx +5 -3
  51. package/src/lib/plugins/api-catalog/Catalog.tsx +59 -60
  52. package/src/lib/plugins/api-catalog/index.tsx +14 -0
  53. package/src/lib/plugins/search-inkeep/index.tsx +27 -8
  54. package/lib/OperationList-Bj-6EKhp.js +0 -4889
  55. package/lib/OperationList-Bj-6EKhp.js.map +0 -1
  56. package/lib/assets/worker-BmEAZjUP.js.map +0 -1
  57. package/lib/createServer-BVFp6Bl3.js.map +0 -1
@@ -1,37 +1,45 @@
1
1
  import slugify from "@sindresorhus/slugify";
2
- import { Fragment } from "react";
2
+ import { useSuspenseQuery } from "@tanstack/react-query";
3
+ import { useSearchParams } from "react-router";
3
4
  import { Head, Link } from "zudoku/components";
5
+ import { useAuthState } from "../../authentication/state.js";
4
6
  import { Markdown } from "../../components/Markdown.js";
5
- import { useExposedProps } from "../../util/useExposedProps.js";
6
- import type { ApiCatalogItem, CatalogCategory } from "./index.js";
7
+ import { cn } from "../../util/cn.js";
8
+ import type { ApiCatalogPluginOptions } from "./index.js";
9
+
10
+ const getKey = (category: string, tag: string) => slugify(`${category}-${tag}`);
7
11
 
8
12
  export const Catalog = ({
9
13
  items,
14
+ filterCatalogItems = (items) => items,
10
15
  categories,
11
16
  label = "API Library",
12
- }: {
13
- label: string;
14
- items: ApiCatalogItem[];
15
- categories: CatalogCategory[];
16
- }) => {
17
- const { searchParams, setSearchParams } = useExposedProps();
17
+ }: Omit<ApiCatalogPluginOptions, "navigationId">) => {
18
+ const [searchParams, setSearchParams] = useSearchParams();
18
19
  const activeCategory = searchParams.get("category");
20
+ const auth = useAuthState();
21
+
22
+ const catalogItems = useSuspenseQuery({
23
+ queryFn: () => filterCatalogItems(items, { auth }),
24
+ queryKey: ["catalogItems", auth],
25
+ });
26
+
19
27
  return (
20
28
  <section className="pt-[--padding-content-top] pb-[--padding-content-bottom]">
21
29
  <Head>
22
30
  <title>{label}</title>
23
31
  </Head>
24
32
  <div className="grid grid-cols-12 gap-12">
25
- <div className="flex flex-col gap-4 col-span-3 px-4 not-prose sticky top-48">
26
- <div className="justify-between">
27
- {categories.map((category, idx) => (
28
- <Fragment key={category.label}>
33
+ <div className="flex flex-col gap-4 col-span-3 not-prose sticky top-48">
34
+ <div className="max-w-[--side-nav-width] flex flex-col gap-4 justify-between">
35
+ {categories?.map((category, idx) => (
36
+ <div key={category.label}>
29
37
  <div className="flex justify-between mb-2.5">
30
38
  <span className="font-medium text-sm">{category.label}</span>
31
39
  {idx === 0 && activeCategory && (
32
40
  <button
33
41
  type="button"
34
- className="text-end text-sm mr-8 text-foreground/60 hover:text-foreground"
42
+ className="text-end text-sm text-foreground/60 hover:text-foreground"
35
43
  onClick={() => setSearchParams({})}
36
44
  >
37
45
  Clear
@@ -39,45 +47,41 @@ export const Catalog = ({
39
47
  )}
40
48
  </div>
41
49
  <ul className="space-y-1 [&>li]:py-2">
42
- {Array.from(
43
- new Set(
44
- category.tags
45
- .map((tag) => ({
46
- tag,
47
- count: items.filter((api) =>
48
- api.categories.find((c) => c.tags.includes(tag)),
49
- ).length,
50
- }))
51
- .map(({ tag, count }) => (
52
- <li
53
- key={slugify(category.label + " " + tag)}
54
- className={`flex px-4 rounded-lg -translate-x-4 justify-between text-sm cursor-pointer hover:text-primary transition ${
55
- slugify(tag) === activeCategory
56
- ? "font-medium bg-border/30 rounded"
57
- : ""
58
- }`}
59
- onClick={() =>
60
- setSearchParams({
61
- category: slugify(category.label + " " + tag),
62
- })
63
- }
50
+ {category.tags
51
+ .map((tag) => ({
52
+ tag,
53
+ count: items.filter((api) =>
54
+ api.categories.find((c) => c.tags.includes(tag)),
55
+ ).length,
56
+ }))
57
+ .map(({ tag, count }) => {
58
+ const slug = getKey(category.label, tag);
59
+ const isActive = slug === activeCategory;
60
+
61
+ return (
62
+ <li
63
+ key={slug}
64
+ className={cn(
65
+ "flex rounded-lg justify-between text-sm cursor-pointer hover:text-primary transition px-[--padding-nav-item] -mx-[--padding-nav-item]",
66
+ isActive && "bg-border/30 rounded",
67
+ )}
68
+ onClick={() => setSearchParams({ category: slug })}
69
+ >
70
+ <span>{tag}</span>
71
+ <span
72
+ className={cn(
73
+ "flex items-center justify-center border rounded-md w-8 text-xs font-semibold",
74
+ isActive &&
75
+ "bg-primary border-primary text-primary-foreground",
76
+ )}
64
77
  >
65
- <span>{tag}</span>
66
- <span
67
- className={`flex items-center justify-center border rounded-md w-8 text-xs font-semibold ${
68
- slugify(tag) === activeCategory
69
- ? "bg-primary border-primary text-primary-foreground"
70
- : ""
71
- }`}
72
- >
73
- {count}
74
- </span>
75
- </li>
76
- )),
77
- ),
78
- )}
78
+ {count}
79
+ </span>
80
+ </li>
81
+ );
82
+ })}
79
83
  </ul>
80
- </Fragment>
84
+ </div>
81
85
  ))}
82
86
  </div>
83
87
  </div>
@@ -85,17 +89,15 @@ export const Catalog = ({
85
89
  <h3 className="mt-0 text-2xl font-bold mb-4">{label}</h3>
86
90
 
87
91
  <div className="grid grid-cols-2 gap-4">
88
- {items
92
+ {catalogItems.data
89
93
  .filter(
90
94
  (api) =>
91
95
  !activeCategory ||
92
96
  api.categories.find((c) =>
93
- c.tags.find(
94
- (t) => slugify(c.label + " " + t) === activeCategory,
95
- ),
97
+ c.tags.find((t) => getKey(c.label, t) === activeCategory),
96
98
  ),
97
99
  )
98
- .map((api, i) => (
100
+ .map((api) => (
99
101
  <Link
100
102
  to={{
101
103
  pathname: `/${api.path}`,
@@ -104,10 +106,7 @@ export const Catalog = ({
104
106
  className="no-underline hover:!text-foreground"
105
107
  key={api.path}
106
108
  >
107
- <div
108
- className="border h-full rounded p-4 flex flex-col gap-2 cursor-pointer hover:bg-border/20 font-normal"
109
- key={i}
110
- >
109
+ <div className="border h-full rounded p-4 flex flex-col gap-2 cursor-pointer hover:bg-border/20 font-normal">
111
110
  <span className="font-semibold">{api.label}</span>
112
111
  <Markdown
113
112
  className="text-sm whitespace-pre-wrap mb-6 line-clamp-2"
@@ -1,3 +1,4 @@
1
+ import type { AuthState } from "../../authentication/state.js";
1
2
  import type { ZudokuPlugin } from "../../core/plugins.js";
2
3
  import { Catalog } from "./Catalog.js";
3
4
 
@@ -18,18 +19,30 @@ export type ApiCatalogPluginOptions = {
18
19
  label: string;
19
20
  categories?: CatalogCategory[];
20
21
  items: ApiCatalogItem[];
22
+ filterCatalogItems?: filterCatalogItems;
21
23
  };
22
24
 
25
+ export type CatalogContext<ProviderData = unknown> = {
26
+ auth: AuthState<ProviderData>;
27
+ };
28
+
29
+ export type filterCatalogItems<ProviderData = unknown> = (
30
+ items: ApiCatalogItem[],
31
+ { auth }: CatalogContext<ProviderData>,
32
+ ) => ApiCatalogItem[];
33
+
23
34
  export const apiCatalogPlugin = ({
24
35
  navigationId,
25
36
  items,
26
37
  label,
27
38
  categories,
39
+ filterCatalogItems,
28
40
  }: {
29
41
  navigationId: string;
30
42
  label: string;
31
43
  categories?: CatalogCategory[];
32
44
  items: ApiCatalogItem[];
45
+ filterCatalogItems?: filterCatalogItems;
33
46
  }): ZudokuPlugin => {
34
47
  return {
35
48
  getRoutes: () => {
@@ -40,6 +53,7 @@ export const apiCatalogPlugin = ({
40
53
  <Catalog
41
54
  label={label}
42
55
  items={items}
56
+ filterCatalogItems={filterCatalogItems}
43
57
  categories={categories ?? []}
44
58
  />
45
59
  ),
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo, useRef } from "react";
1
+ import { useEffect, useMemo, useRef, useState } from "react";
2
2
  import { ClientOnly } from "../../components/ClientOnly.js";
3
3
  import type { ZudokuPlugin } from "../../core/plugins.js";
4
4
  import { aiChatSettings, baseSettings } from "./inkeep.js";
@@ -39,6 +39,10 @@ const InkeepSearch = ({
39
39
  settings: PluginInkeepBaseSettings;
40
40
  }) => {
41
41
  const ref = useRef<HTMLDivElement>(null);
42
+ const widgetRef = useRef<InkeepWidget | null>(null);
43
+ const [isInkeepAvailable, setIsInkeepAvailable] = useState(
44
+ typeof Inkeep !== "undefined",
45
+ );
42
46
 
43
47
  const config: InkeepEmbedConfig = useMemo(
44
48
  () => ({
@@ -59,12 +63,27 @@ const InkeepSearch = ({
59
63
  );
60
64
 
61
65
  useEffect(() => {
62
- const inkeepWidget = Inkeep().embed(config);
63
- inkeepWidget.render({
64
- ...config,
65
- isOpen,
66
- });
67
- });
66
+ if (isInkeepAvailable) return;
67
+
68
+ const checkInkeep = setInterval(() => {
69
+ if (typeof Inkeep !== "undefined") {
70
+ setIsInkeepAvailable(true);
71
+ clearInterval(checkInkeep);
72
+ }
73
+ }, 100);
74
+
75
+ return () => clearInterval(checkInkeep);
76
+ }, [isInkeepAvailable]);
77
+
78
+ useEffect(() => {
79
+ if (!isInkeepAvailable || widgetRef.current) return;
80
+
81
+ widgetRef.current = Inkeep().embed(config);
82
+ }, [config, isInkeepAvailable]);
83
+
84
+ useEffect(() => {
85
+ widgetRef.current?.render({ ...config, isOpen });
86
+ }, [config, isOpen]);
68
87
 
69
88
  return <div ref={ref} />;
70
89
  };
@@ -79,7 +98,7 @@ export const inkeepSearchPlugin = (
79
98
  type="module"
80
99
  src="https://unpkg.com/@inkeep/uikit-js@0.3.19/dist/embed.js"
81
100
  defer
82
- ></script>
101
+ />
83
102
  );
84
103
  },
85
104
  renderSearch: ({