create-zudo-doc 0.2.1 → 0.2.2

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/compose.d.ts CHANGED
@@ -78,9 +78,8 @@ export declare function validateDependencies(features: FeatureDefinition[], allS
78
78
  * - `pages/_mdx-components.ts` — image-enlarge.ts injects the
79
79
  * EnlargeableParagraph p-override (ENLARGE_SVG, EnlargeableParagraph def,
80
80
  * `p:` map entry) when imageEnlarge is enabled.
81
- *
82
- * The .tsx anchor form is still supported in `ANCHOR_LINE_RE` for forward
83
- * compatibility.
81
+ * - `pages/lib/_body-end-islands.tsx` — tauri.ts injects the FindInPageInit
82
+ * island (import, displayName, Island mount) when tauri is enabled.
84
83
  */
85
84
  export declare const ANCHOR_FILES: string[];
86
85
  /**
package/dist/compose.js CHANGED
@@ -164,11 +164,14 @@ export function validateDependencies(features, allSelectedNames) {
164
164
  * - `pages/_mdx-components.ts` — image-enlarge.ts injects the
165
165
  * EnlargeableParagraph p-override (ENLARGE_SVG, EnlargeableParagraph def,
166
166
  * `p:` map entry) when imageEnlarge is enabled.
167
- *
168
- * The .tsx anchor form is still supported in `ANCHOR_LINE_RE` for forward
169
- * compatibility.
167
+ * - `pages/lib/_body-end-islands.tsx` — tauri.ts injects the FindInPageInit
168
+ * island (import, displayName, Island mount) when tauri is enabled.
170
169
  */
171
- export const ANCHOR_FILES = ["src/styles/global.css", "pages/_mdx-components.ts"];
170
+ export const ANCHOR_FILES = [
171
+ "src/styles/global.css",
172
+ "pages/_mdx-components.ts",
173
+ "pages/lib/_body-end-islands.tsx",
174
+ ];
172
175
  /**
173
176
  * Main composition entry point. Orchestrates the full feature composition
174
177
  * pipeline for a generated project.
@@ -2,10 +2,15 @@ import type { FeatureModule } from "../compose.js";
2
2
  /**
3
3
  * Tauri feature.
4
4
  *
5
- * W7A (#1736): post-cutover, the FindInPage island is mounted by the
6
- * pages/lib body-end wrapper. The find-match highlight CSS is unconditional
7
- * in `templates/base/src/styles/global.css` (matches host). Only the
8
- * postProcess hooks (Cargo.toml / tauri.conf.json / .gitignore patches)
9
- * remain feature-scoped.
5
+ * #2052: the FindInPageInit island (Cmd/Ctrl+F find bar for the Tauri
6
+ * WebView, where the browser-native find UI is unavailable) is wired into
7
+ * `pages/lib/_body-end-islands.tsx` via the three injections below — import,
8
+ * displayName, and Island mount. zfb's island scanner only registers
9
+ * components reachable through static import chains (page → wrapper →
10
+ * component), so without this injection the feature-copied component files
11
+ * are orphaned dead code that never hydrates. The find-match highlight CSS
12
+ * is unconditional in `templates/base/src/styles/global.css` (matches host);
13
+ * the component runtime-gates itself (renders null unless
14
+ * `window.__TAURI_INTERNALS__` exists), so no settings field is needed.
10
15
  */
11
16
  export declare const tauriFeature: FeatureModule;
@@ -3,15 +3,58 @@ import path from "path";
3
3
  /**
4
4
  * Tauri feature.
5
5
  *
6
- * W7A (#1736): post-cutover, the FindInPage island is mounted by the
7
- * pages/lib body-end wrapper. The find-match highlight CSS is unconditional
8
- * in `templates/base/src/styles/global.css` (matches host). Only the
9
- * postProcess hooks (Cargo.toml / tauri.conf.json / .gitignore patches)
10
- * remain feature-scoped.
6
+ * #2052: the FindInPageInit island (Cmd/Ctrl+F find bar for the Tauri
7
+ * WebView, where the browser-native find UI is unavailable) is wired into
8
+ * `pages/lib/_body-end-islands.tsx` via the three injections below — import,
9
+ * displayName, and Island mount. zfb's island scanner only registers
10
+ * components reachable through static import chains (page → wrapper →
11
+ * component), so without this injection the feature-copied component files
12
+ * are orphaned dead code that never hydrates. The find-match highlight CSS
13
+ * is unconditional in `templates/base/src/styles/global.css` (matches host);
14
+ * the component runtime-gates itself (renders null unless
15
+ * `window.__TAURI_INTERNALS__` exists), so no settings field is needed.
11
16
  */
12
17
  export const tauriFeature = (choices) => ({
13
18
  name: "tauri",
14
- injections: [],
19
+ injections: [
20
+ // 1. Import the island entry. Inserted AFTER the
21
+ // `// @slot:body-end-islands:imports` anchor.
22
+ {
23
+ file: "pages/lib/_body-end-islands.tsx",
24
+ anchor: "// @slot:body-end-islands:imports",
25
+ position: "after",
26
+ content: `import FindInPageInit from "@/components/find-in-page-init";`,
27
+ },
28
+ // 2. Stable island marker name (same belt-and-braces guard as the
29
+ // sibling islands in the file). Inserted AFTER the
30
+ // `// @slot:body-end-islands:display-names` anchor.
31
+ {
32
+ file: "pages/lib/_body-end-islands.tsx",
33
+ anchor: "// @slot:body-end-islands:display-names",
34
+ position: "after",
35
+ content: `(FindInPageInit as { displayName?: string }).displayName = "FindInPageInit";`,
36
+ },
37
+ // 3. Island mount. Inserted AFTER the
38
+ // `{/* @slot:body-end-islands:extra-islands */}` anchor.
39
+ // when="load" (not "idle"): the island's job is to intercept
40
+ // Cmd/Ctrl+F via a keydown listener, so it must hydrate as soon as
41
+ // the islands runtime mounts — same rationale as the
42
+ // clientRouterBootstrap click intercept above it. Deferring to idle
43
+ // would leave a post-load window where Cmd+F does nothing, which is
44
+ // the very bug this injection fixes.
45
+ {
46
+ file: "pages/lib/_body-end-islands.tsx",
47
+ anchor: "{/* @slot:body-end-islands:extra-islands */}",
48
+ position: "after",
49
+ content: ` {/* Tauri-only find-in-page (Cmd/Ctrl+F) bar. Renders null outside
50
+ a Tauri WebView, so the island is inert in plain browser builds
51
+ of the same scaffold. */}
52
+ {Island({
53
+ when: "load",
54
+ children: <FindInPageInit />,
55
+ }) as unknown as VNode}`,
56
+ },
57
+ ],
15
58
  postProcess: async (targetDir) => {
16
59
  // Patch Cargo.toml package name
17
60
  const cargoPath = path.join(targetDir, "src-tauri/Cargo.toml");
package/dist/scaffold.js CHANGED
@@ -278,7 +278,7 @@ function generatePackageJson(choices) {
278
278
  // .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
279
279
  // lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
280
280
  // version moves, so a fresh scaffold pulls the version we just published.
281
- "@takazudo/zudo-doc": "^0.2.1",
281
+ "@takazudo/zudo-doc": "^0.2.2",
282
282
  // zod — used by the generated zfb.config.ts. zfb-config-gen emits
283
283
  // `import { z } from "zod"` for the content-collection schema +
284
284
  // `z.toJSONSchema(...)` conversion. Without this dep, the consumer
@@ -332,7 +332,7 @@ function generatePackageJson(choices) {
332
332
  // @takazudo/zudo-doc/integrations/doc-history which in turn imports
333
333
  // @takazudo/zudo-doc-history-server/git-history. Without this dep the
334
334
  // plugin host fails at init with ERR_MODULE_NOT_FOUND — W8A (#1739).
335
- deps["@takazudo/zudo-doc-history-server"] = "^0.2.1";
335
+ deps["@takazudo/zudo-doc-history-server"] = "^0.2.2";
336
336
  // W7A (#1736): doc-history-plugin.mjs spawns `tsx -e <inline-script>` to
337
337
  // run the v2 runtime in a TS-aware Node subprocess; without tsx the
338
338
  // plugin's preBuild step exits with ENOENT before zfb finishes config
@@ -69,7 +69,10 @@ export function generateSettingsFile(choices) {
69
69
  lines.push(` } satisfies Record<string, LocaleConfig>,`);
70
70
  }
71
71
  else {
72
- lines.push(` locales: {} satisfies Record<string, LocaleConfig>,`);
72
+ // `as`, not `satisfies`: satisfies keeps the inferred type at literal {},
73
+ // so Object.entries(settings.locales) in the generated zfb.config.ts
74
+ // yields unknown values and `zfb check` fails with TS18046 (#2053).
75
+ lines.push(` locales: {} as Record<string, LocaleConfig>,`);
73
76
  }
74
77
  // mermaid is controlled by the markdown.features block in zfb.config.ts
75
78
  // (zfb next.12+). This field is retained for compatibility with framework
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zudo-doc",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Create a new zudo-doc documentation site",
5
5
  "license": "MIT",
6
6
  "author": "Takeshi Takatsudo",
@@ -37,6 +37,7 @@ import ClientRouterBootstrap from "@/components/client-router-bootstrap";
37
37
  import DesignTokenPanelBootstrap from "@/components/design-token-panel-bootstrap";
38
38
  import ImageEnlarge, { ImageEnlargeSsrFallback } from "@/components/image-enlarge";
39
39
  import { PageLoadingOverlay } from "@takazudo/zudo-doc/page-loading";
40
+ // @slot:body-end-islands:imports
40
41
 
41
42
  // Set explicit `displayName` on each default-exported island so zfb's
42
43
  // `captureComponentName` produces a stable marker even after the SSR
@@ -51,6 +52,7 @@ import { PageLoadingOverlay } from "@takazudo/zudo-doc/page-loading";
51
52
  (DesignTokenPanelBootstrap as { displayName?: string }).displayName =
52
53
  "DesignTokenPanelBootstrap";
53
54
  (ImageEnlarge as { displayName?: string }).displayName = "ImageEnlarge";
55
+ // @slot:body-end-islands:display-names
54
56
 
55
57
  /**
56
58
  * Default sr-only label rendered as the AiChatModal SSR fallback. This
@@ -196,6 +198,7 @@ export function BodyEndIslands({
196
198
  <h2 class="sr-only">AI Assistant</h2>
197
199
  {aiChat}
198
200
  {imageEnlarge}
201
+ {/* @slot:body-end-islands:extra-islands */}
199
202
  </>
200
203
  );
201
204
  }
@@ -45,11 +45,14 @@ import {
45
45
  VersionSwitcher,
46
46
  type VersionSwitcherLabels,
47
47
  } from "@takazudo/zudo-doc/i18n-version";
48
- // BARE (non-island-wrapped) ThemeToggle from the dedicated subpath
49
- // (#2012 E2). The `./theme` barrel exports an Island-wrapped variant;
50
- // this wrapper composes its own Island below, and the bare subpath
51
- // avoids nesting an island inside an island.
52
- import { ThemeToggle } from "@takazudo/zudo-doc/theme-toggle";
48
+ // ThemeToggle via the project-source shim (`@/components/theme-toggle`)
49
+ // rather than the package subpath directly. zfb's island scanner does not
50
+ // register "use client" modules under node_modules (zfb#999), so importing
51
+ // the package component here would emit an island marker with no registry
52
+ // entry and the toggle would never hydrate (zudolab/zudo-doc#2048). The shim
53
+ // re-wraps the bare (non-island-wrapped) package ThemeToggle; this wrapper
54
+ // composes its own Island below, avoiding nesting an island inside an island.
55
+ import { ThemeToggle } from "@/components/theme-toggle";
53
56
  import SidebarToggle from "@/components/sidebar-toggle";
54
57
  import { settings } from "@/config/settings";
55
58
  import { defaultLocale, locales, t, type Locale } from "@/config/i18n";
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  // W6A stub — no-op default export.
2
4
  //
3
5
  // The host (zudo-doc showcase) ships a full AI-chat modal island here. In
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  // W6A stub — no-op default + DocHistory named exports.
2
4
  //
3
5
  // When the docHistory feature is enabled, the feature template
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  // W6A stub — no-op default + ImageEnlargeSsrFallback named exports.
2
4
  //
3
5
  // When the imageEnlarge feature is enabled, the feature template
@@ -288,7 +288,7 @@ export default function SidebarTree({ nodes, currentSlug, rootMenuItems, backToM
288
288
  type="text"
289
289
  placeholder={filterPlaceholder}
290
290
  value={query}
291
- onChange={(e) => setQuery(e.target.value)}
291
+ onChange={(e) => setQuery(e.currentTarget.value)}
292
292
  className="bg-transparent text-small outline-none w-full text-fg placeholder:text-muted"
293
293
  />
294
294
  </div>
@@ -0,0 +1,23 @@
1
+ "use client";
2
+
3
+ // Scanner-visible ThemeToggle shim. zfb's island scanner does not register
4
+ // "use client" modules located under node_modules (Takazudo/zudo-front-builder#999),
5
+ // so importing the package ThemeToggle straight into the server-rendered header
6
+ // emits an island marker with no matching registry entry — the toggle renders
7
+ // but never hydrates, on every page (zudolab/zudo-doc#2048). This thin
8
+ // project-source wrapper gives the scanner a local binding to register; it
9
+ // re-wraps the bare (non-island-wrapped) package component unchanged.
10
+ import type { JSX } from "preact";
11
+ import {
12
+ ThemeToggle as ZudoDocThemeToggle,
13
+ type ThemeToggleProps,
14
+ } from "@takazudo/zudo-doc/theme-toggle";
15
+
16
+ export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
17
+ return <ZudoDocThemeToggle {...props} />;
18
+ }
19
+ ThemeToggle.displayName = "ThemeToggle";
20
+
21
+ export type { ThemeToggleProps };
22
+
23
+ export default ThemeToggle;
@@ -0,0 +1,167 @@
1
+ // Local type shim for the bare `zfb/config` specifier.
2
+ //
3
+ // `@takazudo/zfb` is consumed as a published npm package (version pinned
4
+ // in the root `package.json`). The package exposes its real config types
5
+ // under the *scoped* subpath `@takazudo/zfb/config` → `dist/config.d.ts`.
6
+ // But `zfb.config.ts` imports from the *bare* specifier `zfb/config`,
7
+ // which zfb's build tool aliases to a runtime-only stub at parse time
8
+ // (`zfb-config-stub.mjs` — `defineConfig` is identity, carrying no types).
9
+ // No real file backs `zfb/config` in `node_modules`, so this ambient
10
+ // declaration is what supplies the `ZfbConfig` type to `zfb.config.ts`.
11
+ //
12
+ // IMPORTANT — this block is the source of truth for the type `zfb check`
13
+ // (plain `tsc --noEmit`) binds against the config. An ambient `declare
14
+ // module` wins over node resolution AND over tsconfig `paths`, so it must
15
+ // be kept in sync BY HAND with the published `@takazudo/zfb/config`
16
+ // (`dist/config.d.ts`). When it lags the engine, valid config fields fail
17
+ // `pnpm check` with TS2353 (see Takazudo/zudo-front-builder#678 +
18
+ // zudolab/zudo-doc#1834 — `bundle` was missing here, blocking next.22's
19
+ // `bundle.exclude`).
20
+
21
+ declare module "zfb/config" {
22
+ /** JSX framework runtime. */
23
+ export type Framework = "preact" | "react";
24
+
25
+ /** A content collection registered with the zfb engine. */
26
+ export interface CollectionDef {
27
+ /** Identifier used at the call site (e.g. `"docs"`). */
28
+ name: string;
29
+ /** Directory (relative to the project root) holding the entries. */
30
+ path: string;
31
+ /**
32
+ * Optional schema. Reserved for v1.1 — accepted but not enforced
33
+ * today. Authored as zod and converted to JSON Schema via
34
+ * `z.toJSONSchema()` at the boundary.
35
+ */
36
+ schema?: Record<string, unknown>;
37
+ }
38
+
39
+ /** Tailwind options; absent = defaults. */
40
+ export interface TailwindConfig {
41
+ enabled?: boolean;
42
+ }
43
+
44
+ /** User-supplied plugin configuration entry. */
45
+ export interface PluginConfig {
46
+ name: string;
47
+ options?: Record<string, unknown>;
48
+ }
49
+
50
+ /**
51
+ * Bundler options. Mirrors `BundleConfig` in crates/zfb/src/config.rs
52
+ * and the published `@takazudo/zfb/config` (`dist/config.d.ts`). Added
53
+ * in next.22 (`bundle.exclude`, #664) and extended in next.23
54
+ * (`mainFields` / `external`, #676).
55
+ */
56
+ export interface BundleConfig {
57
+ /**
58
+ * Project-relative, gitignore-style globs for source files the bundler
59
+ * must NOT pull into the esbuild graph (e.g. test fixtures or
60
+ * `*.stories.tsx`). Matched files are skipped from the shadow-tree walk
61
+ * and dropped from any eager `import.meta.glob(...)` expansion.
62
+ */
63
+ exclude?: string[];
64
+ /**
65
+ * Explicit esbuild `main-fields` for the `--platform=neutral` page/SSR
66
+ * pass (empty by default under `neutral`), letting CJS-`main`-only deps
67
+ * resolve. Mirrors `BundleConfig::main_fields`.
68
+ */
69
+ mainFields?: string[];
70
+ /**
71
+ * Bare specifiers to mark external in the `--platform=neutral` pass so
72
+ * esbuild leaves them unbundled. Mirrors `BundleConfig::external`.
73
+ */
74
+ external?: string[];
75
+ }
76
+
77
+ /** Mirrors the Rust `Config` struct one-for-one. */
78
+ export interface ZfbConfig {
79
+ outDir?: string;
80
+ publicDir?: string;
81
+ host?: string;
82
+ port?: number;
83
+ framework?: Framework;
84
+ collections?: CollectionDef[];
85
+ tailwind?: TailwindConfig;
86
+ /**
87
+ * Bundler options. `bundle.exclude` keeps project-relative globs out of
88
+ * the esbuild graph — used here to skip `packages/md-plugins/__fixtures__/**`
89
+ * so the MDX link resolver no longer walks the test fixtures (silences
90
+ * ~15 pre-existing broken-link warnings). Mirrors `Config::bundle`.
91
+ */
92
+ bundle?: BundleConfig;
93
+ plugins?: PluginConfig[];
94
+ adapter?: string;
95
+ /**
96
+ * Strip `.md` / `.mdx` from in-page `<a href>` paths and append a
97
+ * trailing `/` so author-written `[label](other.mdx)` references
98
+ * resolve to the rendered route URL. Mirrors Config::strip_md_ext
99
+ * in crates/zfb/src/config.rs (zudolab/zfb#131).
100
+ */
101
+ stripMdExt?: boolean;
102
+ /**
103
+ * Site base path. Prefixed onto stable HTML asset URLs (CSS / JS
104
+ * `<link>` and `<script>` tags). Normalised to start AND end with
105
+ * `/`; `undefined` / `""` / `"/"` all behave identically (no
106
+ * prefix). Mirrors Config::base in crates/zfb/src/config.rs
107
+ * (Takazudo/zudo-front-builder#154).
108
+ */
109
+ base?: string;
110
+ /**
111
+ * Configures the syntect-based syntax highlighter shipped with zfb.
112
+ * Mirrors `code_highlight` in crates/zfb/src/config.rs (Takazudo/zudo-front-builder#188 / sub #194; landed in commit 339e30f).
113
+ * When omitted, the engine falls back to the hardcoded default theme `base16-ocean.dark`.
114
+ */
115
+ codeHighlight?: {
116
+ theme?: string;
117
+ themesDir?: string;
118
+ };
119
+ /**
120
+ * Markdown link resolver (port of `remarkResolveMarkdownLinks`).
121
+ * Mirrors `Config::resolve_markdown_links` in crates/zfb/src/config.rs
122
+ * (Takazudo/zudo-front-builder PR #234 / zudolab/zudo-doc#1577).
123
+ * When `enabled: true`, the build appends `ResolveLinksPlugin` to the
124
+ * mdast pipeline so author-written `[label](./other.mdx)` links are
125
+ * rewritten to the corresponding rendered route URL — bypassing the
126
+ * file→directory transformation that breaks relative paths in dist
127
+ * HTML when `foo.mdx` becomes `foo/index.html`.
128
+ */
129
+ resolveMarkdownLinks?: {
130
+ enabled?: boolean;
131
+ docsDir?: string;
132
+ dirs?: Array<{ dir: string; routePrefix: string }>;
133
+ onBrokenLinks?: "warn" | "error" | "ignore";
134
+ };
135
+ /**
136
+ * Whether the basePath rewriter should append a trailing `/` to
137
+ * extensionless absolute hrefs. Mirrors `Config::trailing_slash` in
138
+ * crates/zfb/src/config.rs (Takazudo/zudo-front-builder PR #234 /
139
+ * zudolab/zudo-doc#1579). Off by default — preserves byte-for-byte
140
+ * parity with the pre-`trailingSlash` build for projects that
141
+ * haven't opted in.
142
+ */
143
+ trailingSlash?: boolean;
144
+ /**
145
+ * Markdown / MDX pipeline options. Mirrors `Config::markdown` →
146
+ * `MarkdownConfig` in crates/zfb/src/config.rs. zfb next.12 moved the
147
+ * former-Core features under `markdown.features` and next.13 ships the
148
+ * rest as opt-in; zudo-doc uses `markdown.features` to opt back into the
149
+ * former-Core four plus the additional opt-in features (#1804). Each
150
+ * `features` value is per-feature: `true` for boolean-shorthand features,
151
+ * or an options object for object-typed features.
152
+ */
153
+ markdown?: {
154
+ gfm?: boolean | Record<string, boolean>;
155
+ toc?: Record<string, unknown>;
156
+ externalLinks?: Record<string, unknown>;
157
+ cjkFriendly?: boolean;
158
+ features?: Record<string, boolean | Record<string, unknown>>;
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Identity helper: returns the supplied config as-is, but typed
164
+ * against `ZfbConfig`. Use as the default export of `zfb.config.ts`.
165
+ */
166
+ export function defineConfig(config: ZfbConfig): ZfbConfig;
167
+ }
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { useState, useEffect, useCallback, useMemo, useRef } from "preact/compat";
2
4
  import type { Change } from "diff";
3
5
  import type { DocHistoryData, DocHistoryEntry } from "@/types/doc-history";
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { useState, useEffect, useRef } from "preact/compat";
2
4
  import type { JSX } from "preact";
3
5
 
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { useState, useEffect, useRef } from "preact/compat";
2
4
  import { FindBar } from "./find-bar";
3
5
  import { createFindInPage } from "@/utils/find-in-page";
@@ -30,14 +32,18 @@ export default function FindInPageInit() {
30
32
  return () => document.removeEventListener("keydown", handler);
31
33
  }, [isTauri]);
32
34
 
33
- // Clear search on zfb page navigation
35
+ // Clear search on zfb page navigation. zfb navigates via SPA body swap and
36
+ // fires "zfb:before-preparation" on document before nav — it never fires the
37
+ // native "pagehide" (full-unload) event. The literal is inlined because
38
+ // downstream scaffolds do not depend on @takazudo/zudo-doc as a runtime dep
39
+ // (same reason as the designTokenPanel bootstrap).
34
40
  useEffect(() => {
35
41
  const handler = () => {
36
42
  findInPageRef.current.stop();
37
43
  setVisible(false);
38
44
  };
39
- document.addEventListener("pagehide", handler);
40
- return () => document.removeEventListener("pagehide", handler);
45
+ document.addEventListener("zfb:before-preparation", handler);
46
+ return () => document.removeEventListener("zfb:before-preparation", handler);
41
47
  }, []);
42
48
 
43
49
  if (!isTauri) return null;