oidc-spa 8.1.10 → 8.1.12
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/backend.d.ts +27 -6
- package/backend.js +124 -139
- package/backend.js.map +1 -1
- package/core/Oidc.d.ts +28 -4
- package/core/createOidc.d.ts +12 -3
- package/core/createOidc.js +1 -1
- package/core/createOidc.js.map +1 -1
- package/core/earlyInit.d.ts +1 -0
- package/core/earlyInit.js +11 -4
- package/core/earlyInit.js.map +1 -1
- package/core/loginOrGoToAuthServer.js +8 -3
- package/core/loginOrGoToAuthServer.js.map +1 -1
- package/core/oidcClientTsUserToTokens.d.ts +1 -1
- package/core/oidcClientTsUserToTokens.js.map +1 -1
- package/core/requiredPostHydrationReplaceNavigationUrl.d.ts +6 -0
- package/core/requiredPostHydrationReplaceNavigationUrl.js +12 -0
- package/core/requiredPostHydrationReplaceNavigationUrl.js.map +1 -0
- package/entrypoint.d.ts +1 -0
- package/entrypoint.js +3 -1
- package/entrypoint.js.map +1 -1
- package/esm/angular.d.ts +14 -4
- package/esm/angular.js +155 -10
- package/esm/angular.js.map +1 -1
- package/esm/backend.d.ts +48 -0
- package/esm/backend.js +259 -0
- package/esm/backend.js.map +1 -0
- package/esm/core/Oidc.d.ts +28 -4
- package/esm/core/createOidc.d.ts +12 -3
- package/esm/core/createOidc.js +1 -1
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/earlyInit.d.ts +1 -0
- package/esm/core/earlyInit.js +11 -4
- package/esm/core/earlyInit.js.map +1 -1
- package/esm/core/loginOrGoToAuthServer.js +8 -3
- package/esm/core/loginOrGoToAuthServer.js.map +1 -1
- package/esm/core/oidcClientTsUserToTokens.d.ts +1 -1
- package/esm/core/oidcClientTsUserToTokens.js.map +1 -1
- package/esm/core/requiredPostHydrationReplaceNavigationUrl.d.ts +6 -0
- package/esm/core/requiredPostHydrationReplaceNavigationUrl.js +8 -0
- package/esm/core/requiredPostHydrationReplaceNavigationUrl.js.map +1 -0
- package/esm/entrypoint.d.ts +1 -0
- package/esm/entrypoint.js +1 -0
- package/esm/entrypoint.js.map +1 -1
- package/esm/mock/oidc.d.ts +1 -1
- package/esm/mock/oidc.js.map +1 -1
- package/esm/react/react.d.ts +1 -1
- package/esm/tanstack-start/react/accessTokenValidation_rfc9068.d.ts +12 -0
- package/esm/tanstack-start/react/accessTokenValidation_rfc9068.js +95 -0
- package/esm/tanstack-start/react/accessTokenValidation_rfc9068.js.map +1 -0
- package/esm/tanstack-start/react/apiBuilder.d.ts +27 -0
- package/esm/tanstack-start/react/apiBuilder.js +58 -0
- package/esm/tanstack-start/react/apiBuilder.js.map +1 -0
- package/esm/tanstack-start/react/createOidcSpaApi.d.ts +9 -0
- package/esm/tanstack-start/react/createOidcSpaApi.js +679 -0
- package/esm/tanstack-start/react/createOidcSpaApi.js.map +1 -0
- package/esm/tanstack-start/react/index.d.ts +3 -0
- package/esm/tanstack-start/react/index.js +4 -0
- package/esm/tanstack-start/react/index.js.map +1 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError.d.ts +4 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError.js +8 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError.js.map +1 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/enableUnifiedClientRetryForSsrLoaders.d.ts +4 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/enableUnifiedClientRetryForSsrLoaders.js +86 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/enableUnifiedClientRetryForSsrLoaders.js.map +1 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/entrypoint.d.ts +1 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/entrypoint.js +13 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/entrypoint.js.map +1 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/index.d.ts +2 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/index.js +3 -0
- package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/index.js.map +1 -0
- package/esm/tanstack-start/react/types.d.ts +355 -0
- package/esm/tanstack-start/react/types.js +2 -0
- package/esm/tanstack-start/react/types.js.map +1 -0
- package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.d.ts +2 -0
- package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.js +25 -0
- package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.js.map +1 -0
- package/esm/tools/GetterOrDirectValue.d.ts +1 -0
- package/esm/tools/GetterOrDirectValue.js +2 -0
- package/esm/tools/GetterOrDirectValue.js.map +1 -0
- package/esm/tools/ZodSchemaLike.d.ts +3 -0
- package/esm/tools/ZodSchemaLike.js +2 -0
- package/esm/tools/ZodSchemaLike.js.map +1 -0
- package/esm/tools/inferIsViteDev.d.ts +1 -0
- package/esm/tools/inferIsViteDev.js +6 -0
- package/esm/tools/inferIsViteDev.js.map +1 -0
- package/esm/tools/infer_import_meta_env_BASE_URL.d.ts +1 -0
- package/esm/tools/infer_import_meta_env_BASE_URL.js +15 -0
- package/esm/tools/infer_import_meta_env_BASE_URL.js.map +1 -0
- package/esm/tools/tsafe/uncapitalize.d.ts +2 -0
- package/esm/tools/tsafe/uncapitalize.js +5 -0
- package/esm/tools/tsafe/uncapitalize.js.map +1 -0
- package/esm/vendor/backend/evt.d.ts +2 -0
- package/esm/vendor/backend/evt.js +3286 -0
- package/esm/vendor/backend/jose.d.ts +1 -0
- package/esm/vendor/backend/jose.js +3546 -0
- package/esm/vendor/backend/tsafe.d.ts +5 -0
- package/esm/vendor/backend/tsafe.js +68 -0
- package/esm/vendor/backend/zod.d.ts +1 -0
- package/esm/vendor/backend/zod.js +4023 -0
- package/esm/vendor/frontend/worker-timers.js +261 -1
- package/mock/oidc.d.ts +1 -1
- package/mock/oidc.js.map +1 -1
- package/package.json +40 -4
- package/react/react.d.ts +1 -1
- package/src/angular.ts +224 -9
- package/src/backend.ts +201 -166
- package/src/core/Oidc.ts +41 -11
- package/src/core/createOidc.ts +12 -3
- package/src/core/earlyInit.ts +19 -4
- package/src/core/loginOrGoToAuthServer.ts +11 -3
- package/src/core/oidcClientTsUserToTokens.ts +2 -2
- package/src/core/requiredPostHydrationReplaceNavigationUrl.ts +11 -0
- package/src/entrypoint.ts +1 -0
- package/src/mock/oidc.ts +2 -2
- package/src/react/react.tsx +1 -1
- package/src/tanstack-start/react/accessTokenValidation_rfc9068.ts +135 -0
- package/src/tanstack-start/react/apiBuilder.ts +151 -0
- package/src/tanstack-start/react/createOidcSpaApi.tsx +1011 -0
- package/src/tanstack-start/react/index.ts +5 -0
- package/src/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError.ts +8 -0
- package/src/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/enableUnifiedClientRetryForSsrLoaders.tsx +127 -0
- package/src/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/entrypoint.ts +15 -0
- package/src/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/index.ts +2 -0
- package/src/tanstack-start/react/types.tsx +415 -0
- package/src/tanstack-start/react/withHandlingOidcPostLoginNavigation.tsx +35 -0
- package/src/tools/GetterOrDirectValue.ts +1 -0
- package/src/tools/ZodSchemaLike.ts +3 -0
- package/src/tools/getThisCodebaseRootDirPath_cjs.ts +19 -0
- package/src/tools/inferIsViteDev.ts +6 -0
- package/src/tools/infer_import_meta_env_BASE_URL.ts +19 -0
- package/src/tools/tsafe/uncapitalize.ts +4 -0
- package/src/vendor/backend/jose.ts +1 -0
- package/src/vendor/build-runtime/babel.ts +6 -0
- package/src/vendor/build-runtime/magic-string.ts +3 -0
- package/src/vite-plugin/detectProjectType.ts +20 -0
- package/src/vite-plugin/excludeModuleExportFromOptimizedDeps.ts +20 -0
- package/src/vite-plugin/handleClientEntrypoint.ts +260 -0
- package/src/vite-plugin/index.ts +1 -0
- package/src/vite-plugin/transformCreateFileRoute.ts +240 -0
- package/src/vite-plugin/vite-plugin.ts +54 -0
- package/tools/GetterOrDirectValue.d.ts +1 -0
- package/tools/GetterOrDirectValue.js +3 -0
- package/tools/GetterOrDirectValue.js.map +1 -0
- package/tools/ZodSchemaLike.d.ts +3 -0
- package/tools/ZodSchemaLike.js +3 -0
- package/tools/ZodSchemaLike.js.map +1 -0
- package/tools/getThisCodebaseRootDirPath_cjs.d.ts +2 -0
- package/tools/getThisCodebaseRootDirPath_cjs.js +53 -0
- package/tools/getThisCodebaseRootDirPath_cjs.js.map +1 -0
- package/tools/tsafe/uncapitalize.d.ts +2 -0
- package/tools/tsafe/uncapitalize.js +8 -0
- package/tools/tsafe/uncapitalize.js.map +1 -0
- package/vendor/backend/jose.d.ts +1 -0
- package/vendor/backend/jose.js +3 -0
- package/vendor/build-runtime/babel.d.ts +6 -0
- package/vendor/build-runtime/babel.js +3 -0
- package/vendor/build-runtime/magic-string.d.ts +2 -0
- package/vendor/build-runtime/magic-string.js +2 -0
- package/vendor/frontend/oidc-client-ts.js +0 -2
- package/vite-plugin/detectProjectType.d.ts +10 -0
- package/vite-plugin/detectProjectType.js +15 -0
- package/vite-plugin/detectProjectType.js.map +1 -0
- package/vite-plugin/excludeModuleExportFromOptimizedDeps.d.ts +4 -0
- package/vite-plugin/excludeModuleExportFromOptimizedDeps.js +50 -0
- package/vite-plugin/excludeModuleExportFromOptimizedDeps.js.map +1 -0
- package/vite-plugin/handleClientEntrypoint.d.ts +10 -0
- package/vite-plugin/handleClientEntrypoint.js +211 -0
- package/vite-plugin/handleClientEntrypoint.js.map +1 -0
- package/vite-plugin/index.d.ts +1 -0
- package/vite-plugin/index.js +6 -0
- package/vite-plugin/index.js.map +1 -0
- package/vite-plugin/transformCreateFileRoute.d.ts +10 -0
- package/vite-plugin/transformCreateFileRoute.js +173 -0
- package/vite-plugin/transformCreateFileRoute.js.map +1 -0
- package/vite-plugin/vite-plugin.d.ts +5 -0
- package/vite-plugin/vite-plugin.js +46 -0
- package/vite-plugin/vite-plugin.js.map +1 -0
- package/src/vendor/backend/jsonwebtoken.ts +0 -1
- package/src/vendor/backend/node-fetch.ts +0 -2
- package/src/vendor/backend/node-jose.ts +0 -1
- package/vendor/backend/jsonwebtoken.d.ts +0 -1
- package/vendor/backend/jsonwebtoken.js +0 -3
- package/vendor/backend/node-fetch.d.ts +0 -2
- package/vendor/backend/node-fetch.js +0 -2
- package/vendor/backend/node-jose.d.ts +0 -1
- package/vendor/backend/node-jose.js +0 -3
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type ProjectType = "tanstack-start" | "react-router-framework" | "other";
|
|
2
|
+
|
|
3
|
+
type ResolvedConfigLike = {
|
|
4
|
+
plugins: readonly { name: string }[];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function detectProjectType(params: { resolvedConfig: ResolvedConfigLike }): ProjectType {
|
|
8
|
+
const { resolvedConfig } = params;
|
|
9
|
+
const pluginNames = new Set(resolvedConfig.plugins.map(plugin => plugin.name));
|
|
10
|
+
|
|
11
|
+
if (pluginNames.has("tanstack-react-start:config")) {
|
|
12
|
+
return "tanstack-start";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (pluginNames.has("react-router")) {
|
|
16
|
+
return "react-router-framework";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return "other";
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { UserConfig } from "vite";
|
|
2
|
+
import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath_cjs";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import { join as pathJoin } from "path";
|
|
5
|
+
|
|
6
|
+
export function excludeModuleExportFromOptimizedDeps(params: { userConfig: UserConfig }): UserConfig {
|
|
7
|
+
const { userConfig } = params;
|
|
8
|
+
|
|
9
|
+
const packageJsonParsed = JSON.parse(
|
|
10
|
+
fs.readFileSync(pathJoin(getThisCodebaseRootDirPath(), "package.json")).toString("utf8")
|
|
11
|
+
) as { name: string; exports: Record<string, { module?: string }> };
|
|
12
|
+
|
|
13
|
+
const modules = Object.entries(packageJsonParsed.exports)
|
|
14
|
+
.filter(([, value]) => value.module !== undefined)
|
|
15
|
+
.map(([key]) => key.replace(/^\./, packageJsonParsed.name));
|
|
16
|
+
|
|
17
|
+
((userConfig.optimizeDeps ??= {}).exclude ??= []).push(...modules);
|
|
18
|
+
|
|
19
|
+
return userConfig;
|
|
20
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import type { OidcSpaVitePluginParams } from "./vite-plugin";
|
|
2
|
+
import type { ResolvedConfig } from "vite";
|
|
3
|
+
import type { PluginContext } from "rollup";
|
|
4
|
+
import { detectProjectType, ProjectType } from "./detectProjectType";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { promises as fs } from "node:fs";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { normalizePath } from "vite";
|
|
10
|
+
import { assert } from "../tools/tsafe/assert";
|
|
11
|
+
import type { Equals } from "../tools/tsafe/Equals";
|
|
12
|
+
|
|
13
|
+
type EntryResolution = {
|
|
14
|
+
absolutePath: string;
|
|
15
|
+
normalizedPath: string;
|
|
16
|
+
watchFiles: string[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const ORIGINAL_QUERY_PARAM = "oidc-spa-original";
|
|
20
|
+
|
|
21
|
+
const GENERIC_ENTRY_CANDIDATES = ["src/main.tsx", "src/main.ts", "src/main.jsx", "src/main.js"];
|
|
22
|
+
|
|
23
|
+
const REACT_ROUTER_ENTRY_CANDIDATES = [
|
|
24
|
+
"entry.client.tsx",
|
|
25
|
+
"entry.client.ts",
|
|
26
|
+
"entry.client.jsx",
|
|
27
|
+
"entry.client.js"
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const TANSTACK_ENTRY_CANDIDATES = ["client.tsx", "client.ts", "client.jsx", "client.js"];
|
|
31
|
+
|
|
32
|
+
export function createLoadHandleEntrypoint(params: {
|
|
33
|
+
oidcSpaVitePluginParams: OidcSpaVitePluginParams;
|
|
34
|
+
resolvedConfig: ResolvedConfig;
|
|
35
|
+
}) {
|
|
36
|
+
const { oidcSpaVitePluginParams, resolvedConfig } = params;
|
|
37
|
+
|
|
38
|
+
const projectType = detectProjectType({ resolvedConfig });
|
|
39
|
+
|
|
40
|
+
const entryResolution = resolveEntryForProject({
|
|
41
|
+
config: resolvedConfig,
|
|
42
|
+
projectType
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
async function loadHandleEntrypoint(params: {
|
|
46
|
+
id: string;
|
|
47
|
+
pluginContext: PluginContext;
|
|
48
|
+
}): Promise<null | string> {
|
|
49
|
+
const { id, pluginContext } = params;
|
|
50
|
+
const { path: rawPath, queryParams } = splitId(id);
|
|
51
|
+
const normalizedRequestPath = normalizeRequestPath(rawPath);
|
|
52
|
+
if (!normalizedRequestPath) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (normalizedRequestPath !== entryResolution.normalizedPath) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const isOriginalRequest = queryParams.getAll(ORIGINAL_QUERY_PARAM).includes("true");
|
|
61
|
+
|
|
62
|
+
if (isOriginalRequest) {
|
|
63
|
+
return loadOriginalModule(entryResolution, pluginContext);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
entryResolution.watchFiles.forEach(file => pluginContext.addWatchFile(file));
|
|
67
|
+
|
|
68
|
+
const {
|
|
69
|
+
freezeFetch = true,
|
|
70
|
+
freezeXMLHttpRequest = true,
|
|
71
|
+
freezeWebSocket = true,
|
|
72
|
+
...rest
|
|
73
|
+
} = oidcSpaVitePluginParams ?? {};
|
|
74
|
+
|
|
75
|
+
assert<Equals<typeof rest, {}>>;
|
|
76
|
+
|
|
77
|
+
const stubSourceCache = [
|
|
78
|
+
`import { oidcEarlyInit } from "oidc-spa/entrypoint";`,
|
|
79
|
+
projectType === "tanstack-start" &&
|
|
80
|
+
`import { preventConsoleLoggingOfUnifiedClientRetryForSsrLoadersError } from "oidc-spa/react-tanstack-start/rfcUnifiedClientRetryForSsrLoaders/entrypoint";`,
|
|
81
|
+
`const { shouldLoadApp } = oidcEarlyInit({`,
|
|
82
|
+
` freezeFetch: ${freezeFetch},`,
|
|
83
|
+
` freezeXMLHttpRequest: ${freezeXMLHttpRequest},`,
|
|
84
|
+
` freezeWebSocket: ${freezeWebSocket},`,
|
|
85
|
+
` isPostLoginRedirectManual: ${projectType === "tanstack-start"}`,
|
|
86
|
+
`});`,
|
|
87
|
+
``,
|
|
88
|
+
`if(shouldLoadApp){`,
|
|
89
|
+
projectType === "tanstack-start" &&
|
|
90
|
+
` preventConsoleLoggingOfUnifiedClientRetryForSsrLoadersError();`,
|
|
91
|
+
` import("./${path.basename(
|
|
92
|
+
entryResolution.absolutePath
|
|
93
|
+
)}?${ORIGINAL_QUERY_PARAM}=true");`,
|
|
94
|
+
`}`
|
|
95
|
+
]
|
|
96
|
+
.filter(line => typeof line === "string")
|
|
97
|
+
.join("\n");
|
|
98
|
+
|
|
99
|
+
return stubSourceCache;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return loadHandleEntrypoint;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function resolveEntryForProject({
|
|
106
|
+
config,
|
|
107
|
+
projectType
|
|
108
|
+
}: {
|
|
109
|
+
config: ResolvedConfig;
|
|
110
|
+
projectType: ProjectType;
|
|
111
|
+
}): EntryResolution {
|
|
112
|
+
const root = config.root;
|
|
113
|
+
|
|
114
|
+
switch (projectType) {
|
|
115
|
+
case "tanstack-start": {
|
|
116
|
+
const candidate = resolveCandidate({
|
|
117
|
+
root,
|
|
118
|
+
subDirectories: ["src"],
|
|
119
|
+
filenames: TANSTACK_ENTRY_CANDIDATES
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const entryPath =
|
|
123
|
+
candidate ??
|
|
124
|
+
resolvePackageFile("@tanstack/react-start", [
|
|
125
|
+
"dist",
|
|
126
|
+
"plugin",
|
|
127
|
+
"default-entry",
|
|
128
|
+
"client.tsx"
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
const normalized = normalizeAbsolute(entryPath);
|
|
132
|
+
|
|
133
|
+
const resolution: EntryResolution = {
|
|
134
|
+
absolutePath: entryPath,
|
|
135
|
+
normalizedPath: normalized,
|
|
136
|
+
watchFiles: candidate ? [entryPath] : []
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return resolution;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case "react-router-framework": {
|
|
143
|
+
const candidate = resolveCandidate({
|
|
144
|
+
root,
|
|
145
|
+
subDirectories: ["app"],
|
|
146
|
+
filenames: REACT_ROUTER_ENTRY_CANDIDATES
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const entryPath =
|
|
150
|
+
candidate ??
|
|
151
|
+
resolvePackageFile("@react-router/dev", [
|
|
152
|
+
"dist",
|
|
153
|
+
"config",
|
|
154
|
+
"defaults",
|
|
155
|
+
"entry.client.tsx"
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
const normalized = normalizeAbsolute(entryPath);
|
|
159
|
+
|
|
160
|
+
const resolution: EntryResolution = {
|
|
161
|
+
absolutePath: entryPath,
|
|
162
|
+
normalizedPath: normalized,
|
|
163
|
+
watchFiles: candidate ? [entryPath] : []
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
return resolution;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
case "other": {
|
|
170
|
+
const candidate = resolveCandidate({
|
|
171
|
+
root,
|
|
172
|
+
subDirectories: ["."],
|
|
173
|
+
filenames: GENERIC_ENTRY_CANDIDATES
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
assert(candidate !== undefined);
|
|
177
|
+
|
|
178
|
+
const normalized = normalizeAbsolute(candidate);
|
|
179
|
+
|
|
180
|
+
const resolution: EntryResolution = {
|
|
181
|
+
absolutePath: candidate,
|
|
182
|
+
normalizedPath: normalized,
|
|
183
|
+
watchFiles: [candidate]
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
return resolution;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
default:
|
|
190
|
+
assert<Equals<typeof projectType, never>>(false);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function loadOriginalModule(
|
|
195
|
+
entry: EntryResolution,
|
|
196
|
+
context: { addWatchFile(id: string): void }
|
|
197
|
+
): Promise<string> {
|
|
198
|
+
entry.watchFiles.forEach(file => context.addWatchFile(file));
|
|
199
|
+
return fs.readFile(entry.absolutePath, "utf8");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function resolveCandidate({
|
|
203
|
+
root,
|
|
204
|
+
subDirectories,
|
|
205
|
+
filenames
|
|
206
|
+
}: {
|
|
207
|
+
root: string;
|
|
208
|
+
subDirectories: string[];
|
|
209
|
+
filenames: string[];
|
|
210
|
+
}): string | undefined {
|
|
211
|
+
for (const subDirectory of subDirectories) {
|
|
212
|
+
for (const filename of filenames) {
|
|
213
|
+
const candidate = path.resolve(root, subDirectory, filename);
|
|
214
|
+
if (existsSync(candidate)) {
|
|
215
|
+
return candidate;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function resolvePackageFile(packageName: string, segments: string[]): string {
|
|
223
|
+
const pkgPath = require.resolve(`${packageName}/package.json`);
|
|
224
|
+
return path.resolve(path.dirname(pkgPath), ...segments);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function normalizeAbsolute(filePath: string): string {
|
|
228
|
+
return normalizePath(filePath);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function splitId(id: string): { path: string; queryParams: URLSearchParams } {
|
|
232
|
+
const queryIndex = id.indexOf("?");
|
|
233
|
+
if (queryIndex === -1) {
|
|
234
|
+
return { path: id, queryParams: new URLSearchParams() };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const pathPart = id.slice(0, queryIndex);
|
|
238
|
+
const queryString = id.slice(queryIndex + 1);
|
|
239
|
+
return { path: pathPart, queryParams: new URLSearchParams(queryString) };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function normalizeRequestPath(id: string): string {
|
|
243
|
+
let requestPath = id;
|
|
244
|
+
|
|
245
|
+
if (requestPath.startsWith("\0")) {
|
|
246
|
+
requestPath = requestPath.slice(1);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (requestPath.startsWith("/@fs/")) {
|
|
250
|
+
requestPath = requestPath.slice("/@fs/".length);
|
|
251
|
+
} else if (requestPath.startsWith("file://")) {
|
|
252
|
+
requestPath = fileURLToPath(requestPath);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (path.isAbsolute(requestPath) || requestPath.startsWith(".")) {
|
|
256
|
+
return normalizePath(requestPath);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return normalizePath(requestPath);
|
|
260
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { oidcSpa } from "./vite-plugin";
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { MagicString } from "../vendor/build-runtime/magic-string";
|
|
2
|
+
import { babelParser, babelTraverse, babelTypes as t } from "../vendor/build-runtime/babel";
|
|
3
|
+
|
|
4
|
+
const ENABLE_IMPORT_SPECIFIER = "enableUnifiedClientRetryForSsrLoaders";
|
|
5
|
+
const ENABLE_IMPORT_SOURCE = "oidc-spa/react-tanstack-start/rfcUnifiedClientRetryForSsrLoaders";
|
|
6
|
+
const CREATE_FILE_ROUTE_IDENTIFIER = "createFileRoute";
|
|
7
|
+
const POST_LOGIN_IMPORT_SPECIFIER = "withHandlingOidcPostLoginNavigation";
|
|
8
|
+
const POST_LOGIN_IMPORT_SOURCE = "oidc-spa/react-tanstack-start";
|
|
9
|
+
|
|
10
|
+
type TransformParams = {
|
|
11
|
+
code: string;
|
|
12
|
+
id: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type TransformResult = {
|
|
16
|
+
code: string;
|
|
17
|
+
map: any;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function transformCreateFileRoute(params: TransformParams): TransformResult | null {
|
|
21
|
+
const { code, id } = params;
|
|
22
|
+
const cleanId = sanitizeId(id);
|
|
23
|
+
|
|
24
|
+
if (!isCandidateFile(cleanId)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let ast: ReturnType<typeof babelParser.parse>;
|
|
29
|
+
try {
|
|
30
|
+
ast = babelParser.parse(code, {
|
|
31
|
+
sourceType: "module",
|
|
32
|
+
plugins: ["typescript", "jsx"]
|
|
33
|
+
});
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const magicString = new MagicString(code);
|
|
39
|
+
let hasCreateFileRouteImport = false;
|
|
40
|
+
let hasEnableImport = false;
|
|
41
|
+
let hasPostLoginImport = false;
|
|
42
|
+
let requiresEnableImport = false;
|
|
43
|
+
let requiresPostLoginImport = false;
|
|
44
|
+
let lastImportEnd: number | undefined;
|
|
45
|
+
let mutated = false;
|
|
46
|
+
|
|
47
|
+
babelTraverse(ast, {
|
|
48
|
+
ImportDeclaration(path) {
|
|
49
|
+
const sourceValue = path.node.source.value;
|
|
50
|
+
if (typeof sourceValue !== "string") {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const end = path.node.end ?? undefined;
|
|
55
|
+
if (typeof end === "number") {
|
|
56
|
+
lastImportEnd = lastImportEnd === undefined ? end : Math.max(lastImportEnd, end);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (sourceValue === "@tanstack/react-router") {
|
|
60
|
+
if (
|
|
61
|
+
path.node.specifiers.some(
|
|
62
|
+
specifier =>
|
|
63
|
+
t.isImportSpecifier(specifier) &&
|
|
64
|
+
t.isIdentifier(specifier.imported, { name: CREATE_FILE_ROUTE_IDENTIFIER })
|
|
65
|
+
)
|
|
66
|
+
) {
|
|
67
|
+
hasCreateFileRouteImport = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (sourceValue === ENABLE_IMPORT_SOURCE) {
|
|
72
|
+
if (
|
|
73
|
+
path.node.specifiers.some(
|
|
74
|
+
specifier =>
|
|
75
|
+
t.isImportSpecifier(specifier) &&
|
|
76
|
+
t.isIdentifier(specifier.imported, { name: ENABLE_IMPORT_SPECIFIER })
|
|
77
|
+
)
|
|
78
|
+
) {
|
|
79
|
+
hasEnableImport = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (sourceValue === POST_LOGIN_IMPORT_SOURCE) {
|
|
84
|
+
if (
|
|
85
|
+
path.node.specifiers.some(
|
|
86
|
+
specifier =>
|
|
87
|
+
t.isImportSpecifier(specifier) &&
|
|
88
|
+
t.isIdentifier(specifier.imported, { name: POST_LOGIN_IMPORT_SPECIFIER })
|
|
89
|
+
)
|
|
90
|
+
) {
|
|
91
|
+
hasPostLoginImport = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
CallExpression(path) {
|
|
96
|
+
const callee = path.get("callee");
|
|
97
|
+
if (!callee.isCallExpression()) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const innerCallee = callee.get("callee");
|
|
102
|
+
if (!innerCallee.isIdentifier({ name: CREATE_FILE_ROUTE_IDENTIFIER })) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const args = path.get("arguments");
|
|
107
|
+
if (args.length === 0) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const configArg = args[0];
|
|
112
|
+
if (!configArg.isObjectExpression()) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const configNode = configArg.node;
|
|
117
|
+
let localMutated = false;
|
|
118
|
+
|
|
119
|
+
if (objectContainsLoaderOrBeforeLoad(configNode)) {
|
|
120
|
+
const start = configNode.start ?? undefined;
|
|
121
|
+
const end = configNode.end ?? undefined;
|
|
122
|
+
|
|
123
|
+
if (typeof start === "number" && typeof end === "number") {
|
|
124
|
+
magicString.appendLeft(start, `${ENABLE_IMPORT_SPECIFIER}(`);
|
|
125
|
+
magicString.appendRight(end, ")");
|
|
126
|
+
requiresEnableImport = true;
|
|
127
|
+
localMutated = true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const innerArgs = callee.node.arguments ?? [];
|
|
132
|
+
const isRootRoute =
|
|
133
|
+
innerArgs.length > 0 && t.isStringLiteral(innerArgs[0]) && innerArgs[0].value === "/";
|
|
134
|
+
|
|
135
|
+
if (isRootRoute) {
|
|
136
|
+
const componentProp = findComponentProperty(configNode);
|
|
137
|
+
if (componentProp) {
|
|
138
|
+
const valueNode = componentProp.value as t.Expression;
|
|
139
|
+
|
|
140
|
+
if (!isWrappedWithHandling(valueNode)) {
|
|
141
|
+
const start = valueNode.start ?? undefined;
|
|
142
|
+
const end = valueNode.end ?? undefined;
|
|
143
|
+
|
|
144
|
+
if (typeof start === "number" && typeof end === "number") {
|
|
145
|
+
const original = code.slice(start, end);
|
|
146
|
+
magicString.overwrite(
|
|
147
|
+
start,
|
|
148
|
+
end,
|
|
149
|
+
`${POST_LOGIN_IMPORT_SPECIFIER}(${original})`
|
|
150
|
+
);
|
|
151
|
+
requiresPostLoginImport = true;
|
|
152
|
+
localMutated = true;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (localMutated) {
|
|
159
|
+
mutated = true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (!mutated || !hasCreateFileRouteImport) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const importStatements: string[] = [];
|
|
169
|
+
|
|
170
|
+
if (requiresEnableImport && !hasEnableImport) {
|
|
171
|
+
importStatements.push(`import { ${ENABLE_IMPORT_SPECIFIER} } from "${ENABLE_IMPORT_SOURCE}";`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (requiresPostLoginImport && !hasPostLoginImport) {
|
|
175
|
+
importStatements.push(
|
|
176
|
+
`import { ${POST_LOGIN_IMPORT_SPECIFIER} } from "${POST_LOGIN_IMPORT_SOURCE}";`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (importStatements.length > 0) {
|
|
181
|
+
const insertionPoint = lastImportEnd ?? 0;
|
|
182
|
+
const prefix = insertionPoint === 0 ? "" : "\n";
|
|
183
|
+
const suffix = "\n";
|
|
184
|
+
magicString.appendLeft(insertionPoint, `${prefix}${importStatements.join("\n")}${suffix}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
code: magicString.toString(),
|
|
189
|
+
map: magicString.generateMap({ hires: true, source: cleanId })
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function findComponentProperty(node: t.ObjectExpression): t.ObjectProperty | undefined {
|
|
194
|
+
return node.properties.find(
|
|
195
|
+
prop =>
|
|
196
|
+
t.isObjectProperty(prop) &&
|
|
197
|
+
((t.isIdentifier(prop.key) && prop.key.name === "component") ||
|
|
198
|
+
(t.isStringLiteral(prop.key) && prop.key.value === "component"))
|
|
199
|
+
) as t.ObjectProperty | undefined;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function objectContainsLoaderOrBeforeLoad(node: t.ObjectExpression): boolean {
|
|
203
|
+
return node.properties.some(prop => {
|
|
204
|
+
if (!t.isObjectProperty(prop)) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const key = prop.key;
|
|
209
|
+
if (t.isIdentifier(key)) {
|
|
210
|
+
return key.name === "loader" || key.name === "beforeLoad";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (t.isStringLiteral(key)) {
|
|
214
|
+
return key.value === "loader" || key.value === "beforeLoad";
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return false;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function isWrappedWithHandling(node: t.Node): boolean {
|
|
222
|
+
return (
|
|
223
|
+
t.isCallExpression(node) && t.isIdentifier(node.callee, { name: POST_LOGIN_IMPORT_SPECIFIER })
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function isCandidateFile(id: string): boolean {
|
|
228
|
+
if (id.includes("node_modules")) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
return /\.(?:ts|tsx|js|jsx)$/.test(id);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function sanitizeId(id: string): string {
|
|
235
|
+
const queryIndex = id.indexOf("?");
|
|
236
|
+
if (queryIndex === -1) {
|
|
237
|
+
return id;
|
|
238
|
+
}
|
|
239
|
+
return id.slice(0, queryIndex);
|
|
240
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import { assert } from "../tools/tsafe/assert";
|
|
3
|
+
import type { Param0 } from "../tools/tsafe/Param0";
|
|
4
|
+
import type { oidcEarlyInit } from "../entrypoint";
|
|
5
|
+
import { createLoadHandleEntrypoint } from "./handleClientEntrypoint";
|
|
6
|
+
import { excludeModuleExportFromOptimizedDeps } from "./excludeModuleExportFromOptimizedDeps";
|
|
7
|
+
import { transformCreateFileRoute } from "./transformCreateFileRoute";
|
|
8
|
+
|
|
9
|
+
export type OidcSpaVitePluginParams = Omit<Param0<typeof oidcEarlyInit>, "isPostLoginRedirectManual">;
|
|
10
|
+
|
|
11
|
+
export function oidcSpa(params: OidcSpaVitePluginParams) {
|
|
12
|
+
let loadHandleEntrypoint: ReturnType<typeof createLoadHandleEntrypoint> | undefined = undefined;
|
|
13
|
+
|
|
14
|
+
const plugin: Plugin = {
|
|
15
|
+
name: "oidc-spa",
|
|
16
|
+
enforce: "pre",
|
|
17
|
+
config(userConfig) {
|
|
18
|
+
userConfig = excludeModuleExportFromOptimizedDeps({ userConfig });
|
|
19
|
+
return userConfig;
|
|
20
|
+
},
|
|
21
|
+
configResolved(resolvedConfig) {
|
|
22
|
+
loadHandleEntrypoint = createLoadHandleEntrypoint({
|
|
23
|
+
oidcSpaVitePluginParams: params,
|
|
24
|
+
resolvedConfig
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
transform(code, id) {
|
|
28
|
+
const transformed = transformCreateFileRoute({
|
|
29
|
+
code,
|
|
30
|
+
id
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return transformed;
|
|
34
|
+
},
|
|
35
|
+
async load(id) {
|
|
36
|
+
assert(loadHandleEntrypoint !== undefined);
|
|
37
|
+
|
|
38
|
+
{
|
|
39
|
+
const r = await loadHandleEntrypoint({
|
|
40
|
+
id,
|
|
41
|
+
pluginContext: this
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (r !== null) {
|
|
45
|
+
return r;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return plugin;
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type GetterOrDirectValue<P, T> = ((params: P) => T) | T;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GetterOrDirectValue.js","sourceRoot":"","sources":["../src/tools/GetterOrDirectValue.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ZodSchemaLike.js","sourceRoot":"","sources":["../src/tools/ZodSchemaLike.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getThisCodebaseRootDirPath = getThisCodebaseRootDirPath;
|
|
37
|
+
exports.getNearestPackageJsonDirPath = getNearestPackageJsonDirPath;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
let result = undefined;
|
|
41
|
+
function getThisCodebaseRootDirPath() {
|
|
42
|
+
if (result !== undefined) {
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
return (result = getNearestPackageJsonDirPath(__dirname));
|
|
46
|
+
}
|
|
47
|
+
function getNearestPackageJsonDirPath(dirPath) {
|
|
48
|
+
if (fs.existsSync(path.join(dirPath, "package.json"))) {
|
|
49
|
+
return dirPath;
|
|
50
|
+
}
|
|
51
|
+
return getNearestPackageJsonDirPath(path.join(dirPath, ".."));
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=getThisCodebaseRootDirPath_cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getThisCodebaseRootDirPath_cjs.js","sourceRoot":"","sources":["../src/tools/getThisCodebaseRootDirPath_cjs.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,gEAMC;AAED,oEAKC;AAlBD,uCAAyB;AACzB,2CAA6B;AAE7B,IAAI,MAAM,GAAuB,SAAS,CAAC;AAE3C,SAAgB,0BAA0B;IACtC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,MAAM,GAAG,4BAA4B,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED,SAAgB,4BAA4B,CAAC,OAAe;IACxD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,OAAO,CAAC;IACnB,CAAC;IACD,OAAO,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;AAClE,CAAC"}
|