zudoku 0.71.4 → 0.71.6
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.
- package/dist/cli/cli.js +18 -15
- package/dist/declarations/app/utils/createRedirectRoutes.d.ts +3 -0
- package/dist/declarations/index.d.ts +1 -0
- package/dist/declarations/lib/testing/index.d.ts +3 -1
- package/dist/declarations/lib/util/problemJson.d.ts +10 -0
- package/package.json +1 -1
- package/src/app/main.tsx +2 -2
- package/src/app/utils/createRedirectRoutes.ts +11 -0
- package/src/index.ts +4 -0
- package/src/lib/plugins/api-keys/index.tsx +1 -18
- package/src/lib/plugins/openapi/SchemaInfo.tsx +5 -1
- package/src/lib/testing/index.tsx +5 -0
- package/src/lib/util/flattenAllOfProcessor.ts +36 -20
- package/dist/declarations/app/utils/createRedirectLoader.d.ts +0 -4
- package/src/app/utils/createRedirectLoader.ts +0 -21
package/dist/cli/cli.js
CHANGED
|
@@ -3794,7 +3794,7 @@ import {
|
|
|
3794
3794
|
// package.json
|
|
3795
3795
|
var package_default = {
|
|
3796
3796
|
name: "zudoku",
|
|
3797
|
-
version: "0.71.
|
|
3797
|
+
version: "0.71.5",
|
|
3798
3798
|
type: "module",
|
|
3799
3799
|
sideEffects: [
|
|
3800
3800
|
"**/*.css",
|
|
@@ -5263,25 +5263,28 @@ var flattenAllOfProcessor = async ({ schema: schema2, file }) => {
|
|
|
5263
5263
|
const parser = new $RefParser();
|
|
5264
5264
|
await parser.resolve(schema2);
|
|
5265
5265
|
const $refs = parser.$refs;
|
|
5266
|
-
const
|
|
5266
|
+
const resolved = traverse(schema2, (spec) => {
|
|
5267
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec) || !("allOf" in spec) || !Array.isArray(spec.allOf)) {
|
|
5268
|
+
return spec;
|
|
5269
|
+
}
|
|
5270
|
+
const resolvedAllOf = spec.allOf.map((item) => {
|
|
5271
|
+
if (item && typeof item === "object" && "$ref" in item && typeof item.$ref === "string") {
|
|
5272
|
+
try {
|
|
5273
|
+
return $refs.get(item.$ref) ?? item;
|
|
5274
|
+
} catch {
|
|
5275
|
+
return item;
|
|
5276
|
+
}
|
|
5277
|
+
}
|
|
5278
|
+
return item;
|
|
5279
|
+
});
|
|
5280
|
+
return { ...spec, allOf: resolvedAllOf };
|
|
5281
|
+
});
|
|
5282
|
+
const flattened = traverse(resolved, (spec) => {
|
|
5267
5283
|
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
|
|
5268
5284
|
return spec;
|
|
5269
5285
|
}
|
|
5270
5286
|
const isSchemaObject = "type" in spec || "properties" in spec || "allOf" in spec || "anyOf" in spec || "oneOf" in spec;
|
|
5271
5287
|
if (!isSchemaObject) return spec;
|
|
5272
|
-
if ("allOf" in spec && Array.isArray(spec.allOf)) {
|
|
5273
|
-
const resolvedAllOf = spec.allOf.map((item) => {
|
|
5274
|
-
if (item && typeof item === "object" && "$ref" in item && typeof item.$ref === "string") {
|
|
5275
|
-
try {
|
|
5276
|
-
return $refs.get(item.$ref) ?? item;
|
|
5277
|
-
} catch {
|
|
5278
|
-
return item;
|
|
5279
|
-
}
|
|
5280
|
-
}
|
|
5281
|
-
return item;
|
|
5282
|
-
});
|
|
5283
|
-
return flattenAllOf({ ...spec, allOf: resolvedAllOf });
|
|
5284
|
-
}
|
|
5285
5288
|
return flattenAllOf(spec);
|
|
5286
5289
|
});
|
|
5287
5290
|
return flattened;
|
|
@@ -10,4 +10,5 @@ export type { MDXImport } from "./lib/plugins/markdown/index.js";
|
|
|
10
10
|
export { defaultLanguages } from "./lib/shiki.js";
|
|
11
11
|
export { cn } from "./lib/ui/util.js";
|
|
12
12
|
export { joinUrl } from "./lib/util/joinUrl.js";
|
|
13
|
+
export { type ProblemJson, throwIfProblemJson, } from "./lib/util/problemJson.js";
|
|
13
14
|
export type { MdxComponentsType } from "./lib/util/MdxComponents.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type QueryKey } from "@tanstack/react-query";
|
|
2
|
+
import type { ZudokuRedirect } from "../../config/validators/validate.js";
|
|
2
3
|
import type { ZudokuContextOptions } from "../core/ZudokuContext.js";
|
|
3
4
|
type QueryData = {
|
|
4
5
|
queryKey: QueryKey;
|
|
@@ -9,6 +10,7 @@ type StaticZudokuProps = ZudokuContextOptions & {
|
|
|
9
10
|
queryData?: QueryData[];
|
|
10
11
|
env?: Record<string, string>;
|
|
11
12
|
isAuthenticated?: boolean;
|
|
13
|
+
redirects?: ZudokuRedirect[];
|
|
12
14
|
};
|
|
13
|
-
declare const StaticZudoku: ({ path, queryData, env, isAuthenticated, ...options }: StaticZudokuProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
declare const StaticZudoku: ({ path, queryData, env, isAuthenticated, redirects, ...options }: StaticZudokuProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
16
|
export { StaticZudoku, type StaticZudokuProps, type QueryData };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ProblemJson = {
|
|
2
|
+
type: string;
|
|
3
|
+
title?: string;
|
|
4
|
+
status?: number;
|
|
5
|
+
detail?: string;
|
|
6
|
+
instance?: string;
|
|
7
|
+
[extension: string]: unknown;
|
|
8
|
+
};
|
|
9
|
+
export declare const getProblemJson: (response: Response) => Promise<ProblemJson | undefined>;
|
|
10
|
+
export declare const throwIfProblemJson: (response: Response) => Promise<void>;
|
package/package.json
CHANGED
package/src/app/main.tsx
CHANGED
|
@@ -29,7 +29,7 @@ import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
|
|
|
29
29
|
import { RouterError } from "../lib/errors/RouterError.js";
|
|
30
30
|
import { ZuploEnv } from "./env.js";
|
|
31
31
|
import { processRoutes } from "./processRoutes.js";
|
|
32
|
-
import {
|
|
32
|
+
import { createRedirectRoutes } from "./utils/createRedirectRoutes.js";
|
|
33
33
|
|
|
34
34
|
export const shikiReady: Promise<HighlighterCore> =
|
|
35
35
|
import("../lib/shiki.js").then(async ({ highlighterPromise }) => {
|
|
@@ -121,6 +121,7 @@ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
|
|
|
121
121
|
);
|
|
122
122
|
|
|
123
123
|
return [
|
|
124
|
+
...createRedirectRoutes(config.redirects),
|
|
124
125
|
{
|
|
125
126
|
element: (
|
|
126
127
|
<Zudoku {...options} env={import.meta.env}>
|
|
@@ -132,7 +133,6 @@ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
|
|
|
132
133
|
</Zudoku>
|
|
133
134
|
),
|
|
134
135
|
hydrateFallbackElement: <div>Loading...</div>,
|
|
135
|
-
loader: createRedirectLoader(config.redirects, config.basePath),
|
|
136
136
|
children: [
|
|
137
137
|
{
|
|
138
138
|
element: (
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { redirect, type RouteObject } from "react-router";
|
|
2
|
+
import type { ZudokuRedirect } from "../../config/validators/validate.js";
|
|
3
|
+
import { joinUrl } from "../../lib/util/joinUrl.js";
|
|
4
|
+
|
|
5
|
+
export const createRedirectRoutes = (
|
|
6
|
+
redirects?: ZudokuRedirect[],
|
|
7
|
+
): RouteObject[] =>
|
|
8
|
+
(redirects ?? []).map((r) => ({
|
|
9
|
+
path: joinUrl(r.from),
|
|
10
|
+
loader: () => redirect(r.to, 301),
|
|
11
|
+
}));
|
package/src/index.ts
CHANGED
|
@@ -26,4 +26,8 @@ export type { MDXImport } from "./lib/plugins/markdown/index.js";
|
|
|
26
26
|
export { defaultLanguages } from "./lib/shiki.js";
|
|
27
27
|
export { cn } from "./lib/ui/util.js";
|
|
28
28
|
export { joinUrl } from "./lib/util/joinUrl.js";
|
|
29
|
+
export {
|
|
30
|
+
type ProblemJson,
|
|
31
|
+
throwIfProblemJson,
|
|
32
|
+
} from "./lib/util/problemJson.js";
|
|
29
33
|
export type { MdxComponentsType } from "./lib/util/MdxComponents.js";
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
import type { ZudokuContext } from "../../core/ZudokuContext.js";
|
|
11
11
|
import invariant from "../../util/invariant.js";
|
|
12
12
|
import { joinUrl } from "../../util/joinUrl.js";
|
|
13
|
+
import { throwIfProblemJson } from "../../util/problemJson.js";
|
|
13
14
|
import { SettingsApiKeys } from "./SettingsApiKeys.js";
|
|
14
15
|
|
|
15
16
|
const DEFAULT_GATEWAY_URL = "https://api.zuploedge.com";
|
|
@@ -70,24 +71,6 @@ export interface ApiConsumer {
|
|
|
70
71
|
key?: ApiKey;
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
const parseJsonSafe = async (response: Response) => {
|
|
74
|
-
try {
|
|
75
|
-
return await response.json();
|
|
76
|
-
} catch {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const throwIfProblemJson = async (response: Response) => {
|
|
82
|
-
const contentType = response.headers.get("content-type");
|
|
83
|
-
if (!response.ok && contentType?.includes("application/problem+json")) {
|
|
84
|
-
const data = await parseJsonSafe(response);
|
|
85
|
-
if (data.type && data.title) {
|
|
86
|
-
throw new Error(data.detail ?? data.title);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
74
|
const developerHintOptions = {
|
|
92
75
|
developerHint:
|
|
93
76
|
"This project is not linked to a Zuplo deployment. Run `zuplo link` to get started with API Keys.",
|
|
@@ -260,7 +260,11 @@ export const SchemaInfo = () => {
|
|
|
260
260
|
{tag.description && (
|
|
261
261
|
<ItemDescription asChild>
|
|
262
262
|
<Markdown
|
|
263
|
-
components={{
|
|
263
|
+
components={{
|
|
264
|
+
// Because the description is wrapped in a <p> and a <Link> already
|
|
265
|
+
p: ({ children }) => children,
|
|
266
|
+
a: (props) => <span {...props} />,
|
|
267
|
+
}}
|
|
264
268
|
content={tag.description}
|
|
265
269
|
className="prose-sm text-pretty"
|
|
266
270
|
/>
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
} from "@tanstack/react-query";
|
|
6
6
|
import { HelmetProvider } from "@zudoku/react-helmet-async";
|
|
7
7
|
import { createMemoryRouter, Outlet, RouterProvider } from "react-router";
|
|
8
|
+
import { createRedirectRoutes } from "../../app/utils/createRedirectRoutes.js";
|
|
9
|
+
import type { ZudokuRedirect } from "../../config/validators/validate.js";
|
|
8
10
|
import type { AuthenticationPlugin } from "../authentication/authentication.js";
|
|
9
11
|
import { useAuthState } from "../authentication/state.js";
|
|
10
12
|
import { RenderContext } from "../components/context/RenderContext.js";
|
|
@@ -26,6 +28,7 @@ type StaticZudokuProps = ZudokuContextOptions & {
|
|
|
26
28
|
queryData?: QueryData[];
|
|
27
29
|
env?: Record<string, string>;
|
|
28
30
|
isAuthenticated?: boolean;
|
|
31
|
+
redirects?: ZudokuRedirect[];
|
|
29
32
|
};
|
|
30
33
|
|
|
31
34
|
const getRoutesByOptions = (options: ZudokuContextOptions) => {
|
|
@@ -52,6 +55,7 @@ const StaticZudoku = ({
|
|
|
52
55
|
queryData,
|
|
53
56
|
env = {},
|
|
54
57
|
isAuthenticated,
|
|
58
|
+
redirects,
|
|
55
59
|
...options
|
|
56
60
|
}: StaticZudokuProps) => {
|
|
57
61
|
if (isAuthenticated) {
|
|
@@ -93,6 +97,7 @@ const StaticZudoku = ({
|
|
|
93
97
|
const routes = getRoutesByOptions(options);
|
|
94
98
|
const router = createMemoryRouter(
|
|
95
99
|
[
|
|
100
|
+
...createRedirectRoutes(redirects),
|
|
96
101
|
{
|
|
97
102
|
element: (
|
|
98
103
|
<Zudoku {...options} env={env}>
|
|
@@ -11,7 +11,42 @@ export const flattenAllOfProcessor: Processor = async ({ schema, file }) => {
|
|
|
11
11
|
await parser.resolve(schema);
|
|
12
12
|
const $refs = parser.$refs;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// Pre-resolve all $refs inside allOf items throughout the schema before
|
|
15
|
+
// flattening. flattenAllOf recurses internally into oneOf/anyOf/properties
|
|
16
|
+
// without going through $ref resolution, so we must ensure all allOf items
|
|
17
|
+
// are resolved upfront. This prevents stale $ref keys from being merged
|
|
18
|
+
// into parent schemas when they point to paths removed during flattening.
|
|
19
|
+
const resolved = traverse(schema, (spec) => {
|
|
20
|
+
if (
|
|
21
|
+
!spec ||
|
|
22
|
+
typeof spec !== "object" ||
|
|
23
|
+
Array.isArray(spec) ||
|
|
24
|
+
!("allOf" in spec) ||
|
|
25
|
+
!Array.isArray(spec.allOf)
|
|
26
|
+
) {
|
|
27
|
+
return spec;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const resolvedAllOf = spec.allOf.map((item) => {
|
|
31
|
+
if (
|
|
32
|
+
item &&
|
|
33
|
+
typeof item === "object" &&
|
|
34
|
+
"$ref" in item &&
|
|
35
|
+
typeof item.$ref === "string"
|
|
36
|
+
) {
|
|
37
|
+
try {
|
|
38
|
+
return $refs.get(item.$ref) ?? item;
|
|
39
|
+
} catch {
|
|
40
|
+
return item;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return item;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return { ...spec, allOf: resolvedAllOf };
|
|
47
|
+
}) as OpenAPIDocument;
|
|
48
|
+
|
|
49
|
+
const flattened = traverse(resolved, (spec) => {
|
|
15
50
|
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
|
|
16
51
|
return spec;
|
|
17
52
|
}
|
|
@@ -25,25 +60,6 @@ export const flattenAllOfProcessor: Processor = async ({ schema, file }) => {
|
|
|
25
60
|
|
|
26
61
|
if (!isSchemaObject) return spec;
|
|
27
62
|
|
|
28
|
-
if ("allOf" in spec && Array.isArray(spec.allOf)) {
|
|
29
|
-
const resolvedAllOf = spec.allOf.map((item) => {
|
|
30
|
-
if (
|
|
31
|
-
item &&
|
|
32
|
-
typeof item === "object" &&
|
|
33
|
-
"$ref" in item &&
|
|
34
|
-
typeof item.$ref === "string"
|
|
35
|
-
) {
|
|
36
|
-
try {
|
|
37
|
-
return $refs.get(item.$ref) ?? item;
|
|
38
|
-
} catch {
|
|
39
|
-
return item;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return item;
|
|
43
|
-
});
|
|
44
|
-
return flattenAllOf({ ...spec, allOf: resolvedAllOf }) as RecordAny;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
63
|
return flattenAllOf(spec) as RecordAny;
|
|
48
64
|
}) as OpenAPIDocument;
|
|
49
65
|
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { redirect } from "react-router";
|
|
2
|
-
import type { ZudokuRedirect } from "../../config/validators/validate.js";
|
|
3
|
-
import { joinUrl } from "../../lib/util/joinUrl.js";
|
|
4
|
-
|
|
5
|
-
export const createRedirectLoader = (
|
|
6
|
-
redirects?: ZudokuRedirect[],
|
|
7
|
-
basePath?: string,
|
|
8
|
-
) => {
|
|
9
|
-
if (!redirects) return undefined;
|
|
10
|
-
|
|
11
|
-
const prefix = basePath ? joinUrl(basePath) : "";
|
|
12
|
-
const map = new Map(redirects.map((r) => [joinUrl(r.from), r.to]));
|
|
13
|
-
return ({ request }: { request: Request }) => {
|
|
14
|
-
let pathname = joinUrl(new URL(request.url).pathname);
|
|
15
|
-
if (prefix && pathname.startsWith(prefix)) {
|
|
16
|
-
pathname = pathname.slice(prefix.length) || "/";
|
|
17
|
-
}
|
|
18
|
-
const to = map.get(joinUrl(pathname));
|
|
19
|
-
return to ? redirect(to, 301) : null;
|
|
20
|
-
};
|
|
21
|
-
};
|